Home » Php » php – Yii – dynamically change rules from controller

php – Yii – dynamically change rules from controller

Posted by: admin July 12, 2020 Leave a comment

Questions:

Let’s say I have a product which can have a colour. Depending on the product type, the colour field may or may not be required.

If colour is always required, I would have the following in the product model

public function rules()
{
    return array(
        array('colour', 'required')
    );
}

However, I want this to be dynamic depending on the product type.

Should this be done in the controller? I would imagine having something like the following in the controller:

public function actionOrder() {
    // ....
    if ($product->HasColour) {
        // set the colour validation to be required
    } else {
        // set the colour validation to be not required
    }
}

What is the best way to approach this?

Thanks

How to&Answers:

You can use scenario. In the model:

class Model extends CActiveRecord {
    // ....
    public function rules() {
        return array(
            array('colour', 'required', 'on' => 'hasColour')
        );
    }
    // ....
}

And in the controller:

public function actionOrder() {
    // ....
    $model = new Product();
    if ($product->HasColour) {
        $model->setScenario('hasColour');
    }
}

So, required colour will be validated when the model’s scenario is hasColour

Answer:

class LoginForm extends CFormModel
{
    public $username;
    public $password;
}

$form = new LoginForm();
$form->validatorList->add(
    CValidator::createValidator('required', $form, 'username, password')
);

Now $form has two required fields.

Answer:

One approach is to use a custom validation rule. For example, the rule:

array('colour', 'requiredOnHasColour'),

And then the validator method in the same model class:

public function requiredOnHasColour($attribute, $params) {
    if ($this->hasColour && $this->$attribute == null)
        $this->addError($attribute, 'Colour is required.');
}

More info: Create your own validation rule

Answer:

If you want to do more complicated logic, then scenarios might not satisfy your needs. Then you can override method init and do all the logic that define validation rules over there, adding results to $validationRules array. And the in rules() method you just return that array. Something like that:

 class Person extends CActiveRecord
{
    public function init(){
        if( TRUE){
            $this->validationRules[] = array('first_name','required');
            $this->validationRules[] = array('last_name','required');
        }

    }

    public $validationRules = array(
        array('email', 'required'),
        array('email, email1, email2, email3', 'email', 'message'=>'Email format is invalid'),
        array('email, address, email1, email2, email3', 'length', 'max'=>255),

    );

    public function rules()
    {
        return $this->validationRules;
    }
}

Answer:

In your ActiveRecord you can add in any place dynamic validator. For example i overwrite parent method setAttributes and add $this->validatorList->add() depends on selected value in $this->type attribute. Official docs: https://www.yiiframework.com/doc/api/1.1/CValidator

public function setAttributes($values, $safeOnly = true)
{
    $result = parent::setAttributes($values, $safeOnly);

    if (self::TYPE_PHONE == $this->type) {
        $this->validatorList->add(CValidator::createValidator('required', $this, ['phone', 'phonePrefix']));
    } elseif (self::TYPE_EMAIL == $this->type) {
        $this->validatorList->add(CValidator::createValidator('required', $this, ['email']));
    }

    return $result;
}