Dynamic Rules/Validators

How can I add some additional rules to my AR model from controller?

Before I save some model I want do add some rules dynamicly…

Thanks for help.

You should create a new scenario for this rule.

I think that writing rules of model in the controller breaks the mvc concept. Is better to create a new scenario in order to abstract to the controller wich fields should be validated.

Notice that the controller code is never hardcoding fields name (even the primary key is used throught the property primary key).

If scenario is not what you’re after, then you can try to take advantage of CController::afterValidation().


public function afterValidate()

{

	

	if($this->someParam!=='rightValue') {

		$this->addError('someParam','Something os wrong');

		return; // or continue

	}

	return parent::afterValidate();

}

Just think of a way to add validators dynamically - i.e. have private variable $_dynamicValidators=array(), make a clever way to add validators, and run them in a loop at afterValidate() - it shouldn’t be hard.

A blueprint of its kind.

After validate is an event of the model, not of the controller.

You can even write some special validation rule, but I think that the most confortable solution is to use scenarios.

What I meant was to do something with a model so it would be possible to do the following in controller:




if($someCase) {

    $model->addDynamicValidator('title', array('required'));

}



That will modify model’s private variable $_dynamicValidators, which is used in same model’s afterValidate().

That would be really handy in the model itself as some rules may depend of a variable.

For example in a User model I can have several scenario (registration, updateProfile etc.) And in the updateProfile scenario some rules might be active depending on a checkbox. So let say the password rule must be active only if the user tick the checkbox "Update my password".

I am thinking of doing that in the onBeforeValidate function but this will create duplicate code (So I basically need to write my own validation logic in it as defined in the registration scenario, which does not look pretty). See below an example:


    /**

     * Declares the validation rules.

     */

    public function rules()

    {

        return array(

            // Rules for registration

            array('nickname, password, passwordVerification, email, emailVerification, gender, verifyCode', 'required', 'on' => 'register'),

            array('nickname', 'uniqueNickname', 'on' => 'register'),

            array('nickname', 'checkUsername', 'on' => 'register'),

            array('password', 'length', 'min' => 8, 'max' => 40, 'on' => 'register'),

            array('passwordVerification', 'compare', 'compareAttribute' => 'password', 'on' => 'register'),

            array('emailVerification', 'compare', 'compareAttribute' => 'email', 'on' => 'register'),

            array('newsletter', 'numerical', 'integerOnly' => true, 'on' => 'register'),

            array('rules', 'required', 'requiredValue' => 1, 'on' => 'register', 'message' => 'Le règlement doit être accepter pour finaliser l\'inscription.'),

            array('verifyCode', 'captcha', 'allowEmpty' => !extension_loaded('gd'), 'on' => 'register'),

            

            // Rules for login

            array('nickname', 'length', 'min' => 4, 'max' => 20, 'on' => 'register, login'),

            array('password', 'required', 'on' => 'login'),

            array('rememberMe', 'numerical', 'integerOnly' => true, 'on' => 'login'),

            array('email', 'email'),

            array('email', 'uniqueEmail'),

            

            // Rules for profile

            array('email, newEmail', 'email', 'on' => 'profile'),

            array('updatePassword, oldPassword, newPassword, passwordVerification, updateEmail, newEmail, emailVerification ', 'safe', 'on' => 'profile'),

        );

    }



And in the onBeforeValidation method:




    public function onBeforeValidate($event)

    {

        if ($this->getScenario() == 'profile') {

            if ($this->updatePassword) {

                $this->checkCurrentPassword();

                // Again I need to check if the password matches conditions set in the registration as the checkbox is ticked

                if ($this->newPassword != $this->passwordVerification) {

                    $this->addError('newPassword', 'Les mots de passe ne sont pas identiques');

                    $this->addError('passwordVerification', '');

                }

            }

            

            if ($this->updateEmail) {

                if ($this->newEmail != $this->emailVerification) {

                    $this->addError('newEmail', 'les adresses emails ne correspondent pas');

                    $this->addError('emailVerification', '');

                }

            }

        }

    }



Any chance to have this in a future release? Or is there any better way of doing that?