rules are get from model before data is loaded (rules are needed to decide which attributes are safe for massive change and which do not). this is why this way you do not achieve results by conditionally returning rules in rules() function.
solution: you have to provide a rule which points to model function (inline validator) which will do needed logic:
public function rules() {
return array(
array( 'any_field_from_model', 'dynamicValidator' )
);
}
public function dynamicValidator($attribute, $params ) {
for($i=1; $i<=self::MAX_COLUMNS; $i++) {
if( $this->{'type'.$i} ) {
...
if( some validation fails ) {
$this->addError( 'invalid_field', 'Field "invalid_field" is invalid...' );
}
...
}
}
}
there is possibility to use standard validation classes but you have to call them directly, not by only returning rules array…
I think I found a nice solution. In a model class definition:
public function __construct($types=null)
{
for($i=1; $i<=self::MAX_COLUMNS; $i++)
{
if (isset($types['type'.$i])) $this->{'type'.$i}=$types['type'.$i];
}
}
where $types is an array that I pass form data in controller action. Constructor is running at first, so variables are set before rules() is fired and I don’t lose standard yii validation functionality.