Валидация форм в контроллере
Laravel предоставляет несколько способов для валидации входящих данных. По умолчанию базовый контроллер использует трейт ValidatesRequests
, который обеспечивает удобный способ валидации HTTP-запросов c большим количеством правил валидации.
Во-первых, представим что мы имеем следующие роуты в файле routes/web.php
, маршрут GET
отображает форму для создания нового поста в блоге, маршрут POST
будет сохранять новую запись в базе данных:
resources/routes/web.phpRoute::get('post/create', [PostController::class, 'create']);
Route::post('post', [PostController::class, 'store']);
Создадим простой контроллер, который обрабатывает эти роуты. Реализуем метод create()
, а метод store()
пока оставим пустым:
app/Http/Controllers/PostController.php<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller {
// Показать форму для создания новой записи блога @return Response
public function create() {
return view('post.create');
}
// Сохранить в базу данных новую запись блога @param Request $request @return Response
public function store(Request $request) {
//
}
}
Если посмотреть исходный код базового контроллера App\Http\Controllers\Controller
, то можно увидеть, что он включает в себя трейт ValidatesRequests
, который обеспечивает все контроллеры методом validate()
. Метод принимает два параметра — экземпляр HTTP-запроса и правила валидации.
Если все правила валидации пройдены успешно — код выполняется дальше. Иначе будет выброшено исключение и сообщение об ошибке будет отправлено обратно пользователю. Ответ будет направлен обратно с заполненными flash-переменными, а на AJAX-запрос будет отправлен JSON.
app/Http/Controllers/PostController.php// Сохранить в базу данных новую запись блога @param Request $request @return Response
public function store(Request $request) {
$this->validate($request, [
'title' => 'required|unique:posts|max:100',
'body' => 'required',
]);
// Проверка пройдена, можно записывать в БД
}
Чтобы остановить выполнение остальных правил после первой неудачной проверки, нужно добавить bail
в начало списка всех правил. Если правило unique
для атрибута title
не выполняется, правило max
не проверяется:
$this->validate($request, [
'title' => 'bail|required|unique:posts|max:100',
'body' => 'required',
]);
Если данные HTTP-запроса содержат вложенные параметры, можно указать их, используя синтаксис с точкой:
$this->validate($request, [
'title' => 'required|unique:posts|max:100',
'author.name' => 'required',
'body' => 'required',
]);
Начиная с версии Laravel 5.5 можно для валидации данных использовать метод validate()
объекта Illuminate\Http\Request
:
app/Http/Controllers/PostController.php// Сохранить в базу данных новую запись блога @param Request $request @return Response
public function store(Request $request) {
$request->validate([
'title' => 'required|unique:posts|max:100',
'body' => 'required',
]);
// проверка пройдена, можно записывать в БД
}
Мы уже знаем, что в случае ошибок пользователь будет перенаправлен на предыдущую страницу. Кроме того, все ошибки валидации будут автоматически записаны во flash-переменные. Нам не нужно явно передавать сообщения об ошибках в шаблоне роута GET
. Потому что Laravel будет проверять наличие ошибок в текущем сеансе и автоматически привязывать их к шаблону, если они доступны.
В нашем случае пользователь будет перенаправлен в метод create()
контроллера и можно отобразить сообщения об ошибках в шаблоне:
resources/views/post/create.blade.php<h1>Создать пост</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
С помощью директивы @error
можно быстро проверить, существуют ли сообщения об ошибках для данного атрибута. Внутри директивы @error
можно использовать переменную $message
, чтобы показать текст ошибки:
<input type="text" name="title" class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
По умолчанию в Laravel включены глобальные посредники TrimStrings
и ConvertEmptyStringsToNull
. Они перечислены в свойстве $middleware
класса App\Http\Kernel
. Из-за этого нужно часто помечать дополнительные поля как nullable
, если не нужно, чтобы валидатор считал не действительным значение null
. В примере мы указываем что поле publish_at
может быть null
или должно содержать дату. Если модификатор nullable
отсутствует, значение null
будет считаться недопустимым:
$this->validate($request, [
'title' => 'required|unique:posts|max:100',
'body' => 'required',
'publish_at' => 'nullable|date',
]);