Вот уже почти год, как я работаю на 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. Потому что:
['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.
Какие правила должны быть в AR-модели? И должны ли они там быть?
В Yii валидация моделей происходит на уровне AR модели, какие правила нужны такие и пишите.
Должны ли они там быть — риторический вопрос. С точки зрения архитектуры приложения не должны. С точки зрения RAPID development — это удобный и простой инструмент валидации данных.
При обновлении записи, например у нас изменился пароль, но логин остался прежним, валидатор не пропустит, так как в базе уже существует такой логин, какие есть варианты для обхода этой проблемы !?
UniqueValidator проверяет, что дубль записи это не таже запись, поэтому проблемы быть не должно.
ДД!
Как будет выглядеть валидация, если мы хотим проверить на уникальность комбинацию 3-х или 4-х полей?
Все зависит от того, что вы понимаете под комбинацией. Если уникальным должно быть сочетание всех полей, то:
Если уникальным должно быть каждое поле в сравнении с самим собой:
Если уникальным должно быть сочетание пары полей:
я правильно понял, код
[[‘doc_num’], ‘unique’, ‘targetAttribute’ => [‘doc_num’, ‘date’, ‘BIN_payer’]],
провалидирует комбинацию из этих 3-х полей на уникальность?
Да, проверит наличие «doc_num AND date AND BIN_payer» и запишет ошибку в doc_num если она есть
А можно ли сделать валидацию на уникальность без перезагрузки ?
Только ajax запросом, т.к для проверки на уникальность нужно сделать запрос в БД.
Если обновлять запись, и не менять уникальные поля, то валидация не пропускает