Laravel. Валидация данных. Часть третья из трех
21.09.2020
Теги: Laravel • Web-разработка • Теория • Форма • Фреймворк • ШаблонСайта
Создание валидатора вручную
Если по каким-то причинам нет желания использовать трейт ValidatesRequests
и его метод validate()
, можно создать экземпляр валидатора вручную с помощью фасада Validator
, используя метод make()
. Первый аргумент метода — данные, подлежащие проверке, второй аргумент — правила валидации, которые применяются к этим данным.
<?php namespace App\Http\Controllers; use App\Post; use Illuminate\Http\Request; class PostController extends Controller { /* ... */ public function store(Request $request) { $validator = Validator::make($request->all(), [ 'title' => 'required|unique:posts|min:3|max:100', 'excerpt' => 'required|min:100|max:200', 'body' => 'required', ]); // данные не прошли проверку, выполняем редирект if ($validator->fails()) { return redirect('post/create') ->withErrors($validator) ->withInput(); } // данные прошли проверку, можно сохранять в БД } /* ... */ }
Если проверка не пройдена, можно использовать метод withErrors()
, чтобы записать сообщения об ошибках в сессию. При использовании этого метода, переменная $errors
будет автоматически передана в шаблон после редиректа, позволяя отобразить сообщения пользователю.
Хук после валидации
Валидатор позволяет использовать функции обратного вызова после завершения всех проверок. Это дает возможность выполнить еще несколько проверок и/или добавить еще несколько сообщений об ошибках.
<?php namespace App\Http\Controllers; use App\Post; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; class PostController extends Controller { /* ... */ public function store(Request $request) { $validator = Validator::make($request->all(), [ 'title' => 'required|unique:posts|min:3|max:100', 'excerpt' => 'required|min:100|max:200', 'body' => 'required', ]); // доп.проверка и запись доп.сообщения об ошибке $validator->after(function ($validator) { if ($this->somethingInvalid()) { $validator->errors()->add('field', 'Это еще одно сообщение об ошибке'); } }); // данные не прошли проверку, выполняем редирект if ($validator->fails()) { return redirect('post/create') ->withErrors($validator) ->withInput(); } // данные прошли проверку, можно сохранять в БД } /* ... */ }
Работа с сообщениями об ошибках
Вызов метода errors()
в экземпляре валидатора возвращает экземпляр Illuminate\Support\MessageBag
, который имеет ряд методов для работы с сообщениями об ошибках (подробнее здесь). Переменная $errors
, которая автоматически становится доступной для всех шаблонов, также является экземпляром класса MessageBag
.
$errors = $validator->errors();
Получить первое сообщения об ошибке для заданного поля:
echo $errors->first('email');
Получить все сообщения об ошибках для выбранного поля:
foreach ($errors->get('email') as $message) { echo $message, '<br>'; }
Получить сообщения, если поле формы является массивом:
foreach ($errors->get('attachments.*') as $message) { echo $message, '<br>'; }
Получить все сообщения об ошибках для всех полей:
foreach ($errors->all() as $message) { echo $message, '<br>'; }
Определить наличие сообщения для определенного поля:
if ($errors->has('email')) { foreach ($errors->get('email') as $message) { echo $message, '<br>'; } }
Текст сообщений об ошибках
Текст сообщений об ошибках задается в файлах, которые расположены в директории resources/lang/(en|ru)
. Директория ru
изначально не существует, так что ее надо создать и скопировать в нее все из директории en
. Сообщения валидации данных, как нетрудно догадаться, расположены в файле validation.php
.
<?php return [ /* |-------------------------------------------------------------------------- | Validation Language Lines |-------------------------------------------------------------------------- | | The following language lines contain the default error messages used by | the validator class. Some of these rules have multiple versions such | as the size rules. Feel free to tweak each of these messages here. | */ 'accepted' => 'The :attribute must be accepted.', 'active_url' => 'The :attribute is not a valid URL.', 'after' => 'The :attribute must be a date after :date.', 'after_or_equal' => 'The :attribute must be a date after or equal to :date.', 'alpha' => 'The :attribute may only contain letters.', 'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.', 'alpha_num' => 'The :attribute may only contain letters and numbers.', 'array' => 'The :attribute must be an array.', 'before' => 'The :attribute must be a date before :date.', 'before_or_equal' => 'The :attribute must be a date before or equal to :date.', 'between' => [ 'numeric' => 'The :attribute must be between :min and :max.', 'file' => 'The :attribute must be between :min and :max kilobytes.', 'string' => 'The :attribute must be between :min and :max characters.', 'array' => 'The :attribute must have between :min and :max items.', ], 'boolean' => 'The :attribute field must be true or false.', 'confirmed' => 'The :attribute confirmation does not match.', 'date' => 'The :attribute is not a valid date.', 'date_equals' => 'The :attribute must be a date equal to :date.', 'date_format' => 'The :attribute does not match the format :format.', 'different' => 'The :attribute and :other must be different.', 'digits' => 'The :attribute must be :digits digits.', 'digits_between' => 'The :attribute must be between :min and :max digits.', 'dimensions' => 'The :attribute has invalid image dimensions.', 'distinct' => 'The :attribute field has a duplicate value.', 'email' => 'The :attribute must be a valid email address.', 'ends_with' => 'The :attribute must end with one of the following: :values.', 'exists' => 'The selected :attribute is invalid.', 'file' => 'The :attribute must be a file.', 'filled' => 'The :attribute field must have a value.', 'gt' => [ 'numeric' => 'The :attribute must be greater than :value.', 'file' => 'The :attribute must be greater than :value kilobytes.', 'string' => 'The :attribute must be greater than :value characters.', 'array' => 'The :attribute must have more than :value items.', ], 'gte' => [ 'numeric' => 'The :attribute must be greater than or equal :value.', 'file' => 'The :attribute must be greater than or equal :value kilobytes.', 'string' => 'The :attribute must be greater than or equal :value characters.', 'array' => 'The :attribute must have :value items or more.', ], 'image' => 'The :attribute must be an image.', 'in' => 'The selected :attribute is invalid.', 'in_array' => 'The :attribute field does not exist in :other.', 'integer' => 'The :attribute must be an integer.', 'ip' => 'The :attribute must be a valid IP address.', 'ipv4' => 'The :attribute must be a valid IPv4 address.', 'ipv6' => 'The :attribute must be a valid IPv6 address.', 'json' => 'The :attribute must be a valid JSON string.', 'lt' => [ 'numeric' => 'The :attribute must be less than :value.', 'file' => 'The :attribute must be less than :value kilobytes.', 'string' => 'The :attribute must be less than :value characters.', 'array' => 'The :attribute must have less than :value items.', ], 'lte' => [ 'numeric' => 'The :attribute must be less than or equal :value.', 'file' => 'The :attribute must be less than or equal :value kilobytes.', 'string' => 'The :attribute must be less than or equal :value characters.', 'array' => 'The :attribute must not have more than :value items.', ], 'max' => [ 'numeric' => 'The :attribute may not be greater than :max.', 'file' => 'The :attribute may not be greater than :max kilobytes.', 'string' => 'The :attribute may not be greater than :max characters.', 'array' => 'The :attribute may not have more than :max items.', ], 'mimes' => 'The :attribute must be a file of type: :values.', 'mimetypes' => 'The :attribute must be a file of type: :values.', 'min' => [ 'numeric' => 'The :attribute must be at least :min.', 'file' => 'The :attribute must be at least :min kilobytes.', 'string' => 'The :attribute must be at least :min characters.', 'array' => 'The :attribute must have at least :min items.', ], 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', 'password' => 'The password is incorrect.', 'present' => 'The :attribute field must be present.', 'regex' => 'The :attribute format is invalid.', 'required' => 'The :attribute field is required.', 'required_if' => 'The :attribute field is required when :other is :value.', 'required_unless' => 'The :attribute field is required unless :other is in :values.', 'required_with' => 'The :attribute field is required when :values is present.', 'required_with_all' => 'The :attribute field is required when :values are present.', 'required_without' => 'The :attribute field is required when :values is not present.', 'required_without_all' => 'The :attribute field is required when none of :values are present.', 'same' => 'The :attribute and :other must match.', 'size' => [ 'numeric' => 'The :attribute must be :size.', 'file' => 'The :attribute must be :size kilobytes.', 'string' => 'The :attribute must be :size characters.', 'array' => 'The :attribute must contain :size items.', ], 'starts_with' => 'The :attribute must start with one of the following: :values.', 'string' => 'The :attribute must be a string.', 'timezone' => 'The :attribute must be a valid zone.', 'unique' => 'The :attribute has already been taken.', 'uploaded' => 'The :attribute failed to upload.', 'url' => 'The :attribute format is invalid.', 'uuid' => 'The :attribute must be a valid UUID.', /* |-------------------------------------------------------------------------- | Custom Validation Language Lines |-------------------------------------------------------------------------- | | Here you may specify custom validation messages for attributes using the | convention "attribute.rule" to name the lines. This makes it quick to | specify a specific custom language line for a given attribute rule. | */ 'custom' => [ 'attribute-name' => [ 'rule-name' => 'custom-message', ], ], /* |-------------------------------------------------------------------------- | Custom Validation Attributes |-------------------------------------------------------------------------- | | The following language lines are used to swap our attribute placeholder | with something more reader friendly such as "E-Mail Address" instead | of "email". This simply helps us make our message more expressive. | */ 'attributes' => [], ];
Нужно перевести на русский те сообщения об ошибках, которые используются на сайте. Если сообщение об ошибке по умолчанию не подходит для какого-то поля — можно задать свой вариант именно для этого поля:
<?php return [ /* ... */ 'custom' => [ 'title' => [ 'required' => 'Поле «:attribute» обязательно для заполнения', 'unique' => 'Такое значение поля «:attribute» уже используется', 'min' => 'Поле «:attribute» должно быть не меньше :min символов', 'max' => 'Поле «:attribute» должно быть не больше :max символов', ], 'excerpt' => [ 'required' => 'Поле «:attribute» обязательно для заполнения', ], 'body' => [ 'required' => 'Поле «:attribute» обязательно для заполнения', ], ], /* ... */ ];
Кроме того, нужно задать более понятные имена для полей — вместо title
, excerpt
и body
:
<?php return [ /* ... */ 'attributes' => [ 'title' => 'Заголовок', 'excerpt' => 'Анонс поста', 'body' => 'Текст поста' ], /* ... */ ];
Еще один способ задать текст сообщений об ошибках — передать их третьим аргументом методу make()
:
<?php namespace App\Http\Controllers; use App\Post; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; class PostController extends Controller { /* ... */ public function store(Request $request) { $rules = [ 'title' => 'required|unique:posts|min:3|max:100', 'excerpt' => 'required|min:100|max:200', 'body' => 'required', ]; $messages = [ 'required' => 'Поле «:attribute» обязательно для заполнения', 'unique' => 'Такое значение поля «:attribute» уже используется', 'min' => 'Поле «:attribute» должно быть не меньше :min символов', 'max' => 'Поле «:attribute» должно быть не больше :max символов', ]; $attributes = [ 'title' => 'Заголовок', 'excerpt' => 'Анонс поста', 'body' => 'Текст поста' ]; $validator = Validator::make( $request->all(), $rules, $messages, $attributes ); // данные не прошли проверку, выполняем редирект if ($validator->fails()) { return redirect('post/create') ->withErrors($validator) ->withInput(); } // данные прошли проверку, можно сохранять в БД } /* ... */ }
Показ сообщений об ошибках
Мы уже знаем, что в шаблонах будет доступна переменная $errors
, которая является экземпляром класса MessageBag
.
<!-- 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
Дополнительно
- Laravel. Валидация данных. Часть вторая из трех
- Laravel. Валидация данных. Часть первая из трех
- Блог на Laravel 7, часть 9. Панель управления — создание, публикация, удаление комментариев
- Блог на Laravel 7, часть 8. Панель управления — CRUD для категорий, тегов и пользователей
- Блог на Laravel 7, часть 7. Панель управления — создание, публикация, удаление постов
- Блог на Laravel 7, часть 2. Регистрация и аутентификация, восстановление пароля
- Laravel. Отправка почты по событию
Поиск: Laravel • Web-разработка • Теория • Форма • Фреймворк • Шаблон сайта • Валидация