
Laravel: як додати нове правило у валідатор
18.04.2021 20:42 | Laravel
Ubuntu: 20.02
PHP: 8.0.3
Laravel: 8.36.2
Якщо заглянемо у офіційні доки, то знайдемо там користувацькі об'єкти правил, замикання і неявні правила. Але не побачимо використання Validator::extend()
. Можливо тому, що фішка далеко не нова і буда додана задовго до поточної (8-й) версії фреймворка. Нещодавно знову зіткнувся, тому залишу коротке нагадування про те, як використовувати.
Припустимо, ми хочемо змусити користувачів використовувати складні паролі. Тобто пароль повинен включати:
- як мінімум одну велику літеру
- як мінімум одну цифру
- як мінімум один спеціальний символ
Плюс пароль повинен бути не менше N символів, і також ми хочемо додати відповідне повідомлення про помилку.
Почнемо з того, що додамо налаштування з мінімальною довжиною пароля у файл config/auth.php
:
<?php
return [
...
'password_min_length' => 10,
...
];
Для валідації будемо використовувати регулярний вираз (стаття не про регулярки, тому тут розбирати його не буду, якщо є необхідність, рекомендую, як мінімум, ознайомитися зі статтею в вікі). Йдемо в AppServiceProvider
(app/Providers/AppServiceProvider.php
) і в редагуємо метод boot()
:
<?php
...
class AppServiceProvider extends ServiceProvider
{
...
public function boot()
{
$min = config('auth.password_min_length');
$pattern = '/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{'.$min.',}$/';
Validator::extend('strong_password',
function ($attributes, $value, $parameters, $validator) use ($pattern) {
return is_string($value) && preg_match($pattern, $value);
}
);
}
}
Ось, власне, код методу extend()
, який можна подивитися у vendor/laravel/framework/src/Illuminate/Validation/Factory.php
:
/**
* Register a custom validator extension.
*
* @param string $rule
* @param \Closure|string $extension
* @param string|null $message
* @return void
*/
public function extend($rule, $extension, $message = null)
{
$this->extensions[$rule] = $extension;
if ($message) {
$this->fallbackMessages[Str::snake($rule)] = $message;
}
}
Як бачимо, третім аргументом можна передати і повідомлення. Однак, зверніть увагу - це fallback, який буде використовуватися в разі, якщо ключ (в нашому випадку strong_password
) не буде знайдений в мовних файлах переводів проекту. Загалом, можна додати текст помилки і тут, але якщо сайт планується мультимовним або може стати таким у певний момент, нам все одно доведеться перекладати меседж. Тому, розмістимо текст помилки там, де їй і місце, тобто в resources/lang/en/validation.php
(і аналогічних файлах інших мов, якщо такі є). Допишемо пару ключ - значення після перекладів з коробки:
<?php
return [
'accepted' => 'The :attribute must be accepted.',
...
'uuid' => 'The :attribute must be a valid UUID.',
'strong_password' => 'The :attribute must be at least :min characters, contain at least one upper case letter, at least one digit and at least one special character.',
...
];
Залишилося застосувати правило у валідації реєстрації, скажімо так:
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|strong_password:'.config('auth.password_min_length').'|confirmed',
]);
Але тут нас чекає сюрприз: якщо :attribute
буде замінений на назву поля, то :min
в повідомленні про помилку так і залишиться. Тому додамо в провайдер ще й replacer
:
Validator::replacer('strong_password', function ($message, $attribute, $rule, $parameters) {
return str_replace(':min', $parameters[0], $message);
});
Ось, власне, і все. Успіхів!