Валидация данных из формы в Laravel

На практике применяю как правило 2 подхода:

  1. через обработку экземпляра класса Illuminate\Http\Request
  2. через обработку экземпляра класса, являющегося наследником класса 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

Материалы по теме

Тэги:

Тэг в списке: