Правила валидации модели

Обсуждение документации. Переводы Cookbook и авторские рецепты.
Ответить
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Правила валидации модели

Сообщение slavcodev »

Периодически на форуме появляются вопросы
Почему в методе rules() атрибуты равны null
Как мне в rules() добавлять правила в зависимости от значения атрибута (поле формы)
Попытаюсь объяснить это в этом рецепте, и возможно сохранить время новичкам, а так же тем кто не пропускает ни одной темы на форуме.

Метод rules() нужен для создания валидаторов. Этот метод вызывается один раз, перед тем как, ВНИМАНИЕ, будет первый раз нужен этот список валидаторов, а не перед непосредственно валидацией.

Когда же первый раз нужен список валидаторов, спросите Вы? Разве не перед валидацией?

Нет. Список валидаторов может понадобится в behaviors, events, да в общем говоря, везде в коде.

В фреймворке, по умолчанию список валидаторов первый раз нужен ДО массового присвоения значений

Код: Выделить всё

$model->attributes = ... 
Т.к. для массового присвоения нужно знать какие атрибуты безопасные. Вот для чего нужен список валидаторов.

Повторю, список нужен ДО массового присвоения. Т.е. когда значения у атрибутов еще НЕ установлены.
Было не правильно до массового присвоения создавать один список, а перед валидацией другой. Не находите?

Как же быть если нужны динамические правила? На это случай фреймворк предоставляет Вам сразу 3 возможности. Выбирайте понравившийся или более подходящую под конкретную задачу.

1) Сценарии

Код: Выделить всё

public function rules()
{
    $rules = array();
    if ($this->scenario === 'scenario1') {
        $rules[] = array('attribute', 'required', 'requiredValue' => 'value1');
    } elsef ($this->scenario === 'scenario2') {
        $rules[] = array('attribute', 'required', 'requiredValue' => 'value2');
    }
    return $rules;
} 
2) Инлайн-валидаторы

Код: Выделить всё

public function rules()
{
    return array(
        array('attribute', 'validateAttribute', 'on' => 'insert, update', 'message' => 'Не верный атрибут');
    );
}

public function validateAttribute($attribute, array $params = array())
{
    $error = isset($params['message']) ? $params['message'] : 'Invalid attribute';

    if ($this->type === 'type1' && $this->$attribute !== 'value1') {
        $this->addError($attribute, $error);
    } elseif ($this->type === 'type2' && $this->$attribute !== 'value2') {
        $this->addError($attribute, $error);
    }
}
3) Ну и напоследок, beforeValidate событие

Код: Выделить всё

public function dynamicRules()
{
    $rules = array();
    if ($this->category === 'website') {
        $rules[] = array('value', 'url', 'on' => 'insert, update',);
    } elseif ($this->category === 'mail') {
        $rules[] = array('value', 'email', 'on' => 'insert, update',);
    }
    return $rules;
}

protected function beforeValidate()
{
    if (!parent::beforeValidate()) {
        return false;
    }

    foreach ($this->dynamicRules() as $params) {
        $attribute = array_shift($params);
        $name = array_shift($params);
        $validator = CValidator::createValidator($name, $this, $attribute, $params);
        $this->validatorList->add($validator);
    }

    return true;
} 
Очень надеюсь, что больше вопросов про rules() и валидацию, не осталось.
Жду Yii 3!
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Правила валидации модели

Сообщение lancecoder »

mc-bear писал(а):

Код: Выделить всё

public function rules()
{
    $rules = array();
    if ($this->scenario === 'scenario1') {
        $rules[] = array('attribute', 'required', 'requiredValue' => 'value1');
    } elsef ($this->scenario === 'scenario2') {
        $rules[] = array('attribute', 'required', 'requiredValue' => 'value2');
    }
    return $rules;
} 
наверно лучше

Код: Выделить всё

public function rules()
{
return array(
array('attribute', 'required', 'requiredValue' => 'value1', 'on'=>'scenario1');
array('attribute', 'required', 'requiredValue' => 'value2', 'on'=>'scenario2');
);
} 
new AR(scenario);
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Правила валидации модели

Сообщение slavcodev »

Может и лучше. Вот только если правил много, надо учитывать что в твоем варианте, вне зависимости от сценария, будут созданы два объекта CRequiredValidator.
Жду Yii 3!
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Правила валидации модели

Сообщение lancecoder »

почему это 2? одновременно 2 сценария?
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Правила валидации модели

Сообщение lancecoder »

Код: Выделить всё

static function selectScenario(array $array, $scenario, $unset=true){
        $elements=array();
        foreach ($array as $name=>$element){
            $on=array();
            if(isset($element['on']) && is_array($element['on']))
                $on=$element['on'];
            else if(isset($element['on']))
                $on=preg_split('/[\s,]+/',$element['on'],-1,PREG_SPLIT_NO_EMPTY);

            if(empty($on) || in_array($scenario, $on))
            {
                if($unset)unset($element['on']);
                $elements[$name]=$element;
            }
        }

        return $elements;
    }
 
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Правила валидации модели

Сообщение slavcodev »

Что это за selectScenario?
Жду Yii 3!
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Правила валидации модели

Сообщение slavcodev »

lancecoder писал(а):почему это 2? одновременно 2 сценария?
Потому что два. Будет создано два валидатора, но проверен один с подходящим сценарием.
ЗЫ: Неплохо бы проверить, перед как спорить. ;)
Жду Yii 3!
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Правила валидации модели

Сообщение lancecoder »

mc-bear писал(а):
lancecoder писал(а):почему это 2? одновременно 2 сценария?
Потому что два. Будет создано два валидатора, но проверен один с подходящим сценарием.
ЗЫ: Неплохо бы проверить, перед как спорить. ;)
тут согласен, что надо было проверить :) да и по логике я был не прав) смена сценария же может проходить http://www.yiiframework.com/doc/api/1.1 ... ors-detail
lc писал(а):selectScenario() это у меня в хелпере, выдирает из массива елементы по совпадающему ключу(on),
взята из какого Tb класса
p.s. так что твой вариант в любом случае надо совершенствовать и при смене сценария, вроде везде через setScenario в коде, добавлять валидаторы, хоть через ту же функцию selectScenario ;)
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Правила валидации модели

Сообщение slavcodev »

ИМХО, сценарии в Yii были введены как неизменное состоянии модели на протяжении жизни объекта.
Именно поэтому это единственный параметр в конструкторе.
Поэтому смена сценария во время работы с моделью плохая практика.

PS: Tb* для меня не авторитет, я давно не смотрел что там изменилось, но код первых версий, меня не впечатлил, и я отказался от их использования. Не в обиду разработчикам, просто наверное не мое.
Жду Yii 3!
Аватара пользователя
lancecoder
Сообщения: 2532
Зарегистрирован: 2012.06.26, 17:16

Re: Правила валидации модели

Сообщение lancecoder »

для меня Tb тоже не является авторитетом, я к тому что и в "ядре" где то есть аналогичный код, я уточнил
а на счет не сменяемости сценария поспорил бы :) доказательства public setScenario, createValidators
а сменные сценарии штука вообще удобная, если эти сценарии превратить в своеобразные фильтры, как то так

Код: Выделить всё

$userForm=new UserForm ('insert');
$userForm->attributes=$_POST['UserForm'];
$userForm->scenario='changePassword';
$userForm->validate(); //тут валидатор может быть filter md5 или default
$userForm->scenario='insert';
$userForm->save();
 
Ответить