Проверка значения на уникальность — UniqueValidator в Yii2

Декабрь 16th, 2016
Метки:

Вот уже почти год, как я работаю на Laravel (требование заказчика), но всем сердцем продолжаю любить Yii. С недавнего времени начала в свободное время контрибутить в сам фреимворк с мелкими баг-фиксами и улучшениями. И сегодня хочу рассказать про UniqueValidator, который проверяет уникальность значения. Документация на него немного запутанная, поэтому уверена что дополнительные разъяснения кому-нибудь да пригодятся.

Базовая запись валидатора выглядит так:

public function rules()
{
  return [
     ['login', 'unique'],
     ...
  ]
}

И тут все ясно — поле login должно быть уникальным (т.е в текущей таблице не должно быть уже такой записи). Если проверять нужно уникальность поля в другой таблице то можно задать в targetClass правильную модель, что тоже в принципе понятно. Аттрибут filter полезен если нужны какие-то дополнительные проверки, например что логин не должен совпадать с логином активного пользователя:

public function rules()
{
  return [
     ['login', 'unique', 'filter' => 'is_active = true'],
     ...
  ]
}

Фильтр может быть выражением (в запросе оно пойдет как AND) или анонимной функцией, в которой можно модефицировать $query

Как правильно указывать targetAttribute

При более сложных проверках наибольшие проблемы вызывает targetAttribute. Потому что:

     ['login', 'unique', 'targetAttribute' => 'name'],

проверит что текущее значение login у валидируемой модели не существует в таблице в поле name. А запись

     ['login', 'unique', 'targetAttribute' => ['name']],

проверит что текущее значение name у валидируемой модели не существует в таблице в поле name. Во втором случаи значение login в проверке учавствовать не будет совсем! Оно только получит сообщение об ошибке.

Баг или фича?

Фича :) К примеру вам нужно проверить что у вас уникальная пара login AND name.

     ['login', 'unique', 'targetAttribute' => ['login', 'name']],

Каждый из targetAttribute будет сверяться со своим полем в модели, т.е login с login a name с name.
Если же нужно проверить значение login и для поля name то выглядить это будет так:

     ['login', 'unique', 'targetAttribute' => ['login', 'login' => 'name']],

НО тут важно понимать, что запись будет НЕ уникальной только тогда когда значение login будет в базе в поле login И name. Т.е если логин такой уже существует, а name у этой записи не совпадает с логином — то запись уникальна.
Если вам нужно проверить, что login не совпадает с существующим login ИЛИ существующем name то запись должна быть такой:

     ['login', 'unique'],
     ['login', 'unique', 'targetAttribute' => 'name'],

Запомните: все аттрибуты переданные в targetAttribute в виде массива в запросе к базе соединяются через AND.

Если остались вопросы — пишите в комментах. Так же можно задавать вопросы по любым другим валидаторам.
Напомню список все существующих стандартных валидаторов Yii2: boolean, captcha, compare, date, datetime, time, default, double, each, email, exist, file, filter, image, in, integer, match, number, required, safe, string, trim, unique, url и ip.


Метки:

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

4 комментариев »

    Arman

    Какие правила должны быть в AR-модели? И должны ли они там быть?

      Developer

      В Yii валидация моделей происходит на уровне AR модели, какие правила нужны такие и пишите.
      Должны ли они там быть — риторический вопрос. С точки зрения архитектуры приложения не должны. С точки зрения RAPID development — это удобный и простой инструмент валидации данных.


    Evgenij

    При обновлении записи, например у нас изменился пароль, но логин остался прежним, валидатор не пропустит, так как в базе уже существует такой логин, какие есть варианты для обхода этой проблемы !?

      Developer

      UniqueValidator проверяет, что дубль записи это не таже запись, поэтому проблемы быть не должно.


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









Копирование материалов разрешено при наличии активной ссылки на источник
Яндекс.Метрика