Ahhh finally someone with similar problem.
I had similar problems while parsing a form with many checkboxes which revealed additional fields. My solution is a little bit different then proposed here.
I created behaviour which allows to run many scenarios at time. Let's say we have some generic validators for fields which are common for all cases and these are without any scenarios assigned. Then we have some different rules which should be used only when "Option A" checkbox is checked - let's assign it a scenario "A". Now, it's not uncommon to have 2 or more checkboxes in a form which reveals more input fields. For each set let's create validation rules and assign them a scenarios names "B" and "C". Now in controller we can check for conditions, and if they are met (in this case if particular checkbox is checked) we can append a scenario to active scenario list. Aforementioned behaviour will make sure all relevant rules are applied.
Example:
ContactForm.php (model)
public function behaviors() {
return array(
'MetaScenario' => array(
'class' => 'application.components.MetaScenario',
'mark' => 'META'
),
);
}
/**
* Declares the validation rules.
*
*/
public function rules() {
$rules = array(
array('name, surname, mail', 'required'),
array('mail', 'email'),
array('verifyCode', 'captcha'),
// accommodation
array('dateFrom, dateTo, people', 'required', 'on' => 'accommodation'),
array('people', 'numerical', 'integerOnly' => true, 'on' => 'accommodation'),
// equipment
array('rentFrom, rentTo', 'required', 'on' => 'equipment'),
);
$this->createMetaRules(&$rules, $this->getScenario());
return $rules;
}
controller
public function actionContact()
{
$contact=new ContactForm;
if(isset($_POST['ContactForm']))
{
$scenario = 'META';
$scenario .= $_POST['ContactForm']['accommodation']=='Hotel'?'_accommodation':'';
$scenario .= ($_POST['ContactForm']['equipment']=='Rented')?'_equipment':'';
$contact->setScenario($scenario);
$contact->attributes=$_POST['ContactForm'];
if($contact->validate())
...
}
and metaScenario itself:
<?php
class MetaScenario extends CBehavior {
/**
*
* @var string Trigger for meta scenario
*/
public $mark;
/**
* Generate meta scenario based on scenario name
* @param array $rules Reference to rules array should be passed.
* @param string $scenario Scenario string. In model use $this->getScenario()
* @return boolean
*/
public function createMetaRules($rules,$scenario){
if (strpos($scenario, $this->mark)===FALSE){
return false;
}
$metaList = $this->createMetaList($scenario);
//check for rules from scenario list and add them to main rule array if found
foreach ($rules as &$rule)
{
if (array_key_exists('on', $rule))
{
if(is_array($rule['on'])){
$on=$rule['on'];
}else{
$on=preg_split('/[\s,]+/',$rule['on'],-1,PREG_SPLIT_NO_EMPTY);
}
$tmp = array_intersect($metaList, $on);
if(!empty($tmp)){
array_push($on, $scenario);
$rule['on'] = $on;
}
};
}
return true;
}
/**
* Create scenario list and gets rid of mark
* @param string $scenario Scenario string.
* @return array scenarios list.
*/
private function createMetaList($scenario)
{
$metaList = explode('_',$scenario);
$metaList = array_slice($metaList, 1);
return $metaList;
}
}
?>
of course this is a limited example and only relevant bits of model and controller are shown. I wrote that some time ago and now I can see lot's of room for improvement

. In case anyone is interested I'll be happy to improve it a bit.