Валидация в Laravel: что нужно знать заранее
Первый Form Request, правила из массива и коробочные сообщения об ошибках. Что настроить в проекте на Laravel 11.x за один заход, чтобы валидация не превратилась в кашу в контроллере.

К концу этого материала у вас будет рабочая валидация формы регистрации: правила вынесены в отдельный класс, ошибки возвращаются в JSON для API и в сессию для обычных форм, сообщения переведены на русский. На всё уйдёт минут двадцать, если проект на Laravel уже запущен. Речь про Laravel 11.x — базовый механизм валидации не менялся с версии 8, но структура каталогов и часть команд artisan в 11-й другие, это отмечу отдельно.
Что нужно иметь до начала
Проверьте это до того, как писать первую строку кода — иначе споткнётесь на середине:
- установленный проект на Laravel 11.x (проверить:
php artisan --version); - работающий
php artisan serveили другой способ открыть приложение в браузере; - хотя бы один маршрут с формой или эндпоинт, который принимает POST-данные;
- понимание, что валидация в Laravel живёт на уровне запроса, а не модели — модель этих правил не знает.
Три способа запустить валидацию
Laravel даёт три входа в один и тот же механизм. Начните с первого, к третьему придёте сами, когда правил станет много.
1. Метод validate прямо в контроллере
Самый короткий путь. Метод validate есть на объекте запроса. Если данные не проходят — Laravel сам прервёт выполнение и вернёт ответ: редирект с ошибками для обычной формы или JSON со статусом 422 для запроса, который ждёт JSON.
// app/Http/Controllers/UserController.php
public function store(Request $request)
{
// Если валидация не прошла, до строки ниже выполнение не дойдёт
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
]);
// $validated — массив только с прошедшими проверку полями
User::create($validated);
return redirect()->route('users.index');
}
Как понять, что работает: отправьте форму с пустым email — вернётесь на страницу, а в шаблоне сработает @error('email'). Отправьте валидные данные — увидите редирект на список.
2. Правила массивом вместо строки
Строка 'required|email' удобна, пока правило простое. Как только появляется правило с параметрами внутри (например Rule::exists с замыканием) — переходите на массив, иначе не закодируете условие.
use Illuminate\Validation\Rule;
$request->validate([
'email' => ['required', 'email', Rule::unique('users')->ignore($userId)],
'role' => ['required', Rule::in(['admin', 'editor', 'viewer'])],
]);
Здесь Rule::unique(...)->ignore($userId) проверяет уникальность email, но игнорирует текущего пользователя — типичный случай при редактировании профиля, когда человек сохраняет форму, не меняя почту.
3. Form Request — куда всё это переезжает
Когда правил больше пяти или их надо переиспользовать, контроллер раздувается. Правила выносятся в отдельный класс Form Request.
# Laravel 11.x
php artisan make:request StoreUserRequest
Команда создаст файл app/Http/Requests/StoreUserRequest.php. Заполните два метода:
// app/Http/Requests/StoreUserRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreUserRequest extends FormRequest
{
// Кто вообще имеет право отправлять этот запрос
public function authorize(): bool
{
return true; // пока пускаем всех; здесь позже будет проверка прав
}
// Сами правила
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'unique:users,email'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
];
}
}
Теперь контроллер худеет до одной подсказки типа в аргументе:
public function store(StoreUserRequest $request)
{
// Валидация уже прошла до входа в метод
User::create($request->validated());
return redirect()->route('users.index');
}
Как понять, что работает: если authorize() вернёт false, вы получите ответ 403 ещё до валидации. Если правило не пройдёт — стандартный 422 или редирект, контроллер не выполнится.
Главная ошибка новичка — вернутьauthorize()значениеfalseи потом полдня искать, почему форма отдаёт 403 вместо ошибок валидации. Проверка прав идёт раньше проверки данных.
Русские сообщения об ошибках
По умолчанию Laravel отвечает по-английски: «The email field is required». Есть два уровня перевода.
Общие фразы (само слово «обязательно», «не более N символов») задаются языковыми файлами. Точечные сообщения под конкретное поле — методом messages() прямо в Form Request:
public function messages(): array
{
return [
'email.required' => 'Укажите почту.',
'email.unique' => 'Такая почта уже зарегистрирована.',
'password.min' => 'Пароль короче 8 символов.',
];
}
Ключ — это поле.правило. Метод attributes() в том же классе задаёт, как поле называется в общих сообщениях: чтобы вместо «поле email» было «поле почта».
Где данные, а где ошибки
Два метода легко перепутать, а поведение у них разное.
| Метод | Что возвращает | Когда брать |
|---|---|---|
$request->validated() | Только поля, для которых есть правила | Для записи в базу — лишнего не попадёт |
$request->all() | Всё, что пришло в запросе | Почти никогда для сохранения — риск массового присвоения |
$request->safe()->only([...]) | Подмножество прошедших валидацию полей | Когда из формы нужна только часть данных |
Берите validated(), а не all(). Разница в том, что all() протащит в модель любое поле из формы, включая то, которое пользователь дописал сам через инструменты разработчика в браузере.
Если не получилось
- Форма отдаёт 403 вместо ошибок валидации. В Form Request метод
authorize()возвращаетfalse. Поставьтеreturn true;, пока не настроили реальную проверку прав. - «The GET method is not supported for route». Форма отправляется методом GET или в шаблоне не хватает директивы
@csrfвнутри<form>. Laravel отклоняет POST без CSRF-токена. - Ошибки не показываются в шаблоне. После неудачной валидации Laravel редиректит назад с ошибками в сессии. Если вы делаете редирект вручную и не через
back(), ошибки теряются. В Blade проверяйте через@error('email') {{ $message }} @enderror. - Правило unique падает с «table not found». В
unique:users,emailпервым идёт имя таблицы, а не модели. Указывайте реальное имя таблицы во множественном числе. - Валидация JSON-запроса возвращает HTML-страницу с ошибкой. Запрос не помечен как ожидающий JSON. Добавьте заголовок
Accept: application/json— тогда Laravel отдаст 422 с JSON вместо редиректа.
Что делать дальше
Базовая валидация настроена. Дальше по мере роста проекта:
- вынесите повторяющиеся наборы правил в переиспользуемые Form Request или в собственные правила через
php artisan make:rule; - для сложной логики «поле A обязательно, только если B заполнено» посмотрите в документации правила
required_if,sometimesи методwithValidator(); - настройте языковые файлы, если приложение отдаёт ошибки пользователям, а не только фронтенду.
Условная валидация и кастомные правила — отдельная тема, здесь мы разобрали только запуск валидации и её вынос из контроллера.
Защитник прав потребителей: Досудебные претензии на возврат товара со ссылками на ЗоЗПП.
Спросить за 15 ₽Источники: Laravel Documentation — Validation, Laravel Documentation — Form Request Validation
Частые вопросы
У меня Laravel 10, а не 11 — код подойдёт?
Что вернётся, если валидация не прошла — редирект или ошибка?
validate в контроллере или Form Request — что выбрать?
Почему форма отдаёт 403, хотя данные вроде правильные?
Можно ли писать правила прямо на модели, как в некоторых фреймворках?
Чем validated() лучше all() при сохранении в базу?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.