dynamic validation rules

Hi,

I’ve searching though the forum similar topics, but did not find anything substantial about it.

I want to set validation rules depending on variables, look at the example:




public function rules()

{


for($i=1; $i<=self::MAX_COLUMNS; $i++)

        {

            if (isset($this->{'type'.$i}))

            {

            switch($this->{'type'.$i})

            {

                case 'integer':

                    $rules[] = array('val'.$i, 'numerical', 'integerOnly'=>true, 'on'=>'add');

                    break;

                case 'double':

                    $rules[] = array('val'.$i, 'numerical', 'on'=>'add');

                    break;

                case 'timelong':

                    $rules[] = array('val'.$i, 'date', 'format'=>'HH:MM:s.frac', 'on'=>'add');

                    break;                

            }


return $rules;

}



where $this->type1, $this->type2, etc. are variables that determine the rules.

I need it dynamic, but rules() method is fired before settings that variables :\

Is it possible to do?

Thanks,

BarBQ

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.

Anyway, thanks for your time!

p.s. by the way, I am from Poland too :)