Adrian Gunawan
Adrian Gunawan

Reputation: 14429

Yii - dynamically change rules from controller

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

Upvotes: 7

Views: 11707

Answers (5)

Tomasz.J
Tomasz.J

Reputation: 1

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;
}

Upvotes: 0

RB_
RB_

Reputation: 1192

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;
    }
}

Upvotes: 1

bores
bores

Reputation: 111

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.

Upvotes: 11

Nate Barr
Nate Barr

Reputation: 4660

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

Upvotes: 3

Rezan Achmad
Rezan Achmad

Reputation: 1910

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

Upvotes: 14

Related Questions