Валидация данных из формы в Laravel
На практике применяю как правило 2 подхода:
- через обработку экземпляра класса
Illuminate\Http\Request
- через обработку экземпляра класса, являющегося наследником класса
Illuminate\Foundation\Http\FormRequest
1. Валидация путём обработки Illuminate\Http\Request
Сначала в контроллере не забываем подключить нужное пространство имён:
use Illuminate\Http\Request;
Далее в контроллере в нужном action-е для соответствующей переменной добавляем правила для валидации:
/** * @return Void */ public function add(Request $request): Void { $validation = $request->validate([ 'name' => 'min:3|max:50', 'surname' => 'min:3|max:50', 'middlename' => 'min:3|max:50' ]); return; }
В приведённом выше примере для полей Фамилия, Имя и Отчество заданы правила, что поля должны содержать не меньше 3 символов и не больше 50.
2. Валидация путём обработки наследника от Illuminate\Foundation\Http\FormRequest
В начале нужно с помощью artisan нужно сгенерировать класс, который отнаследуется от Illuminate\Foundation\Http\FormRequest
с помощью команды:
php artisan make:request [class_name]
где [class_name] - это название класса наследника, например PersonalRequest
После этого в папке app/Http создастся папка Requests(если до текущего момента её ещё не было) с файлом PersonalRequest.php
Рассмотрим пример этого файла с уже добавленными методами класса, в которых заданы правила и метки для атрибутов:
namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class PersonalRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize(): bool { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules(): array { return [ 'name' => 'required|min:3|max:50', 'surname' => 'required|min:3|max:50' ]; } /** * Get custom attributes for validator errors. * * @return array */ public function attributes(): array { return [ 'name' => 'имя', 'surname' => 'фамилия', 'middlename' => 'отчество', ]; } /** * Get custom messages for validator errors. * * @return array */ public function messages(): array { return [ 'name.required' => 'Поле имя является обязательным', 'surname.required' => 'Поле фамилия является обязательным', 'name.min' => 'Имя должно быть не меньше 3 символов', 'surname.min' => 'Фамилия должна быть не меньше 3 символов', ]; } }
Рассмотрим подробнее методы.
/** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize(): bool { return true; }
В методе authorize()
нужно вернуть либо true
если форму может отправлять только авторизованный пользователь, либо false
если отправлять форму могут в том числе и не авторизованные пользователи.
/** * Get the validation rules that apply to the request. * * @return array */ public function rules(): array { return [ 'name' => 'required|min:3|max:50', 'surname' => 'required|min:3|max:150', 'middlename' => 'required|min:3|max:100' ]; }
В методе rules
возвращается массив в котором для каждого из полей формы перечислены через прямую черту |
правила валидации. В приведённом примере поле name
должно быть обязательным для заполнения, содержать минимум 3 символа и максимум 50. Для поля surname
заданы аналогичные настройки, только максимальная длина будет уже 150 символов, а у поля middlename
максимальная длина составляет 100.
/** * Get custom attributes for validator errors. * * @return array */ public function attributes(): array { return [ 'name' => 'имя', 'surname' => 'фамилия', 'middlename' => 'отчество', ]; }
В методе attributes
задаются метки для атрибутов. То есть эти названия будут выводиться в текстах ошибок. То есть при выводе ошибок вместо названия атрибута name
будет выводиться имя
, вместо surname
будет выводиться фамилия
, вместо middlename
будет выводиться отчество
.
/** * Get custom messages for validator errors. * * @return array */ public function messages(): array { return [ 'name.required' => 'Поле имя является обязательным', 'surname.required' => 'Поле фамилия является обязательным', 'name.min' => 'Имя должно быть не меньше 3 символов', 'surname.min' => 'Фамилия должна быть не меньше 3 символов', ]; }
В методе messages
задаются тексты ошибок при невыполнении того или иного условия валидации. Формат массив следующий:
[ '[имя поля].[условие проверки]' => 'Текст ошибки...', ... ]
Применение полученного валидатора выглядит очень просто. Нужно в качестве входного параметра в action контроллера нужно передать параметр типа PersonalRequest
. То есть action контроллера будет иметь такой вид:
/** * @return Void */ public function add(PersonalRequest $request): Void { ... return; }
после этого все ошибки валидации будут автоматически попадать в объект $errors
, который является экземпляром класса Illuminate\Support\MessageBag
.
После этого остаётся только в шаблоне с формой вывести все ошибки в нужном виде.
@if($errors->any())
- @foreach($errors->all() as $error)
-
{{ $error }}
- @endforeach
@endif
Также ещё один момент хотел отметить. Это пригодится для тех кто разрабатывает REST API
в каком-нибудь сервисе. По умолчанию когда валидация не проходит, то происходит обратный редирект на последний адрес откуда был текущий контроллер и action. Вот тут https://laravel.com/docs/8.x/validation#form-request-validation подробнее:
If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an XHR request, an HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.В моём вольном переводе:
Если валидация не прошла, то будет сгенерирован ответ редиректа для отправки пользователя на последнюю локацию. Ошибки также будут сохранены в сессию, а потому они будут доступны для отображения. Если запрос был XHR-запросом, то HTTP ответ с 422 кодом ответа будет возвращён пользователю включая представление ошибок в формате json.
Соответственно нужно переопределить метод failedValidation
, в котором определяются список действий, которые выполняются в том случае если валидация не прошла успешно.
Вот реализация метода failedValidation
в базовом классе FormRequest
для 8-й версии Laravel:
/** * Handle a failed validation attempt. * * @param \Illuminate\Contracts\Validation\Validator $validator * @return void * * @throws \Illuminate\Validation\ValidationException */ protected function failedValidation(Validator $validator) { throw (new ValidationException($validator)) ->errorBag($this->errorBag) ->redirectTo($this->getRedirectUrl()); }
Как видно тут по умолчанию при не успешной валидации происходит редирект как и описано в документации. Реализацию возврата ошибок в формате json
как и описано в документации можно реализовать следующим образом:
/** * Custom handle a failed validation attempt. * * @param Validator $validator */ protected function failedValidation(Validator $validator) { throw new HttpResponseException(response()->json($validator->errors(), 422)); }
После этого редиректа уже не происходит, а происходит возврат ошибок в формате json в контроллере, что хорошо подходит для реализации REST API
. За подсказку данного решения спасибо Stackoverflow
: https://stackoverflow.com/questions/46350307/disable-request-validation-redirect-in-laravel-5-4#answers