Правило unique - це SELECT перед вставкою. Між перевіркою й записом інший запит встигає вставити той самий email.
Запит A: SELECT ... email = 'a@x.com' -> немає
Запит B: SELECT ... email = 'a@x.com' -> немає
Запит A: INSERT a@x.com -> ок
Запит B: INSERT a@x.com -> дубль
Що робити:
- Унікальний індекс у базі - єдина справжня гарантія. Валідація лишається для зрозумілого повідомлення в нормальному випадку.
- Обробити порушення індексу - Laravel кидає
UniqueConstraintViolationException, його перетворюють на ту саму помилку валідації. АбоcreateOrFirst(), який робить це сам.
try {
$user = User::create($data);
} catch (UniqueConstraintViolationException) {
throw ValidationException::withMessages(['email' => __('validation.unique', ['attribute' => 'email'])]);
}
Деталі правила, про які питають:
- при оновленні виключають поточний запис:
Rule::unique('users')->ignore($user->id);ignore()ніколи не беруть з даних запиту - лише з моделі, інакше клієнт підставить чужий ID; withoutTrashed()не враховує м'яко видалені записи;- регістр:
Ada@x.comіada@x.comрізні дляunique, тож email нормалізують до нижнього регістру ще до валідації.