Yii2. Свой валидатор

В посте про валидацию в Yii2 я коснулась основ валидации и дала краткое описание встроенных валидаторов. Но что, если ни один из них нам не подходит. В этом случае мы можем написать свой.

Есть три способа реализации своего валидатора:
  1. написать inline-функцию для валидации;
  2. реализовать метод в модели с именем вашего валидатора;
  3. реализовать класс, унаследованный от Validator.
Во всех примерах ниже будет реализована валидация одного примера. Предположим, у нас есть некий справочник запчастей. У каждой запчасти есть тип. Необходимо, чтобы в рамках одного типа серийные номера запчастей были уникальны.
В такой постановке нам не подходят валидаторы exist и unique, потому что первый проверяет только на существование (и даже параметр filter нам не поможет), а второй на уникальность в рамках всего справочника.

Inline-функция

public function rules()
{
    return [
        ['serial_number', function ($attribute, $params) {
                if ($this->type_id) {
                    $existModel = Type::find()->byType($this->type_id)->bySerialNumber($this->$attribute)->one();
                    if ($existModel) {
                        $this->addError($attribute, 'Serial number must be unique for type.');
                    }
                }
            }
        ],
    ];
}

Метод модели

public function rules()
{
    return [
        ['serial_number', 'uniqueByType']
    ];
}

public function uniqueByType($attribute, $params) {
    if ($this->type_id) {
        $existModel = Type::find()->byType($this->type_id)->bySerialNumber($this->$attribute)->one();
        if ($existModel) {
            $this->addError($attribute, 'Serial number must be unique for type.');
        }
    }
}

Класс Validator

В этом примере есть одно отличие – я добавила параметр compare, в котором можно задать наименование атрибута типа запчасти. Обратите внимание, что в этом примере я опустила необходимые проверки (например, что параметр compare вообще задан).
use \yii\validators\Validator;

class UniqueByTypeValidator extends Validator
{
    public $compare;

    public function validateAttribute($model, $attribute)
    {
        $compare = $this->compare;
        if ($this->$compare) {
            $existModel = Type::find()->byType($this->$compare)->bySerialNumber($this->$attribute)->one();
            if ($existModel) {
                $this->addError($attribute, 'Serial number must be unique for type.');
            }
        }
    }
}
Посты по теме:
Yii2: встроенные валидаторы. Описание, параметры
Yii2: валидация, правила валидации, встроенные валидаторы

Комментарии

  1. лайк, что тут скажешь... Коротко по делу. Редкость

    ОтветитьУдалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. Доходчиво, просто. Замечательно! Забрал в инструменты (это, то место, которым постоянно пользуешься, если с памятью твоей - встала). :-)

    ОтветитьУдалить
  4. что проверяется в строке
    if ($this->type_id) {

    ОтветитьУдалить
    Ответы
    1. Как описано в примере: У каждой запчасти есть тип. Соответственно, строится запрос на поиск других запчастей в справочнике с таким же типом (type_id) и серийным номером (serial_number). Если будет найдена хоть одна запись ($existModel) - значит серийный номер в рамках этого типа не уникален.

      Удалить
  5. Добрый день!
    Могли бы подсказать что имеется ввиду под Type:: если у меня в правилах
    public function rules()
    {
    return [
    ....
    ['password', 'validatePassword'],
    ];
    }

    ОтветитьУдалить
  6. Здравствуйте. У меня такая ситуация. Я упаковал работу с большой формой в 1 модель формы. Форма пишет данные в 4 таблицы. При этом для каждой таблицы я использую отдельную модель. Модель каждой таблицы я использую в модели формы, с которой я и работаю. Валидация полей проходит в модели формы, но так как она не связана с таблицами в бд, а лишь посредник, в ней не работает валидация по unique. Хочу написать свою, но не знаю как:
    1. Определять динамически таблицу и поле, в которых нужно проверять. Например, [['number_k', 'organization_id'], 'unique'], если поля number_k и organization_id в разных таблицах. Как в своей функции валидации определить с каких они таблиц и вообще получить сами названия полей в своей функции?

    Или может есть более интересный способ?

    ОтветитьУдалить
    Ответы
    1. Почему-то не определяет почту. Буду очень рад ответу buttalbakl@gmail.com

      Удалить

Отправить комментарий

Популярные сообщения