Всё о валидации в Laravel

Валидация данных в Ларавел

В этой статье мы расскажем, как можно проверить входящие данные через Контроллеры, Запросы формы (FormRequest) и Правила.

Контроллеры

По умолчанию все контроллеры, расширяющие базовый контроллер, наследуют трейт ValidatesRequests. Он даёт возможность использовать метод validate в ваших контроллерах.

Например, предположим, что пользователь (User) создаёт статью (Article). Возможно, он вводит Название (name) и какой-то Текст (body) для этой статьи, и у статьи есть дата публикации (publish_at). Тогда валидация в контроллере может выглядеть так:

public function store(Request $request) {
    $this->validate($request, [
        'name' => 'required|string',
        'body' => 'required|string',
        'publish_at' => 'required|date_format:Y-m-d H:i:s'
    ]);

    // Данные валидны и будет запущен следующий код
    ...
}

public function store(Request $request) {
    // Примечание: также доступен синтаксис массива
    $request->validate([
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ]);

    // Данные валидны и будет запущен следующий код
    ...
}

public function store() {
    request()->validate([
      // Правила валидации...
    ]);

    // Данные валидны и будет запущен следующий код
    ...
}

public function store() {
    $this->validate(request(), [
      // Правила валидации...
    ]);

    // Данные валидны и будет запущен следующий код
    ...
}

Следует также отметить, что в ответе метод validate будут проверенные данные:

public function store(Request $request) {
    $validatedData = $request->validate([
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ]);

    // Я знаю, что ключами в проверенных данных будет только те, что были проверенны успешно, например: name, body, published_at
    $this->articleService->store($validatedData);
}

Или вы можете сделать так:

public function store(Request $request) {
    $request->validate([
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ]);

    // Я знаю, что ключами в проверенных данных будет только те, что были проверенны успешно, например: name, body, published_at
    $this->articleService->store($request->only('name', 'body', 'published_at'));
}

Список доступных правил валидации можно найти здесь.

Запросы форм

Если вы хотите извлечь всю валидационную логику из контроллеров, или же одновременно выполнять и авторизацию и валидацию, то Laravel предоставляет вам класс Запроса формы (Form Request).

Вы можете создать класс Запроса формы, используя один из множества встроенных генераторов:

php artisan make:request StoreArticleRequest

Эта команда создаст следующий класс в app/Http/Requests:

class StoreArticleRequest extends FormRequest
{

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            //
        ];
    }
}

Класс идёт с двумя методами: authorize and rules.

Authorize

Этот метод позволяет предотвратить запуск кода, если возвращает false. Laravel выбросит ошибку 401.

Пример использования:

public function authorize()
{
    return $this->user()->can('create articles');
}

Rules

Этот метод возвращает массив с правилами, которые мы использовали ранее в контроллере

public function rules()
{
    return [
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ];
}

Примечание: Вы можете тапйхинтить в этот метод любые необходимые вам зависимости.

Итак, как же использовать этот класс? Тайпхинтим его прямо в метод контроллера:

public function store(StoreArticleRequest $request) {
    // Валидация успешно пройдена
}

Если валидация не пройдет, то пользователя редиректнет обратно с ошибками, записанными в сессию. Если это был AJAX-запрос, то выдаст ошибку 422 Unprocessable Entity.

Вы можете получить проверенные данные, также как и раньше:

public function store(StoreArticleRequest $request) {
    $validatedData = $request->validated();

    // Добавление в базу данных
    ...
}

Классы кастомных Правил

Если вам не хватает встроенных правил валидации, то вы можете создать своё собственное. Используем одну из команд make:

php artisan make:rule IsValidStateInUSA

Он создаст следующий класс в app/Rules:

class IsValidStateInUSA implements Rule
{

    public function passes($attribute, $value)
    {
        //
    }

    public function message()
    {
        return 'Сообщение об ошибке валидации.';
    }
}

В методе pass находится логика, позволяющая использовать эту проверку. Метод message содержит сообщение, показываемое в случае неудачной проверки.

В нашей проверке IsValidStateInUSA (Это код существующего штата США?), нам нужно, чтобы передаваемый элемент был одним из 50 имеющихся кодов:

class IsValidStateInUSA implements Rule
{

    public function passes($attribute, $value)
    {
        return in_array(strtoupper($value), [
          'AL',
          'AK',
          'AZ',
          ...
        ]);
    }

    public function message()
    {
        return 'Несуществующий код штата США.';
    }
}

Чтобы использовать это правило в контроллере или запросе формы — просто добавляете его вот так:

public function store(Request $request) {
    $request->validate([
      'state' => ['required', new IsValidStateInUSA],
    ]);

    ...
}

Обработка ошибок валидации

Если проверка не пройдена, Laravel автоматически редиректит пользователя обратно, с переменной $errors в сессии.

Создайте файл messages.blade.php и подключите его в свой основной макета:

@if($errors->any())
    <div class="alert alert-danger" role="alert">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">×</span>
        </button>

        @foreach($errors->all() as $error)
            {{ $error }}<br/>
        @endforeach
    </div>
@endif

Он покажет все ошибки из сессии или, если вы предпочитаете обрабатывать их по одной, то можете использовать blade-хелпер @error:

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

Переменная $message будет передана ​внутрь тега @error.

Настройка сообщений об ошибках

Вы можете настроить эти сообщения с помощью третьего параметра метода validate:

public function store(Request $request) {
    $this->validate($request, [
        'name' => 'required|string',
        'body' => 'required|string',
        'publish_at' => 'required|date_format:Y-m-d H:i:s'
    ], [
      'name.required' => 'Поле Название статьи обязательно для заполнения',
      'body.required'  => 'Поле Текст статьи обязательно для заполнения',
      'publish_at.date_format' => 'Поле Дата публикации имеет неверный формат'
    ]);

    // Данные валидны и будет запущен следующий код
    ...
}

При работе с Запросом формы можно настроить сообщения об ошибках в методе messages:

public function messages()
{
    return [
 			'name.required' => 'Поле Название статьи обязательно для заполнения',
      'body.required'  => 'Поле Текст статьи обязательно для заполнения',
      'publish_at.date_format' => 'Поле Дата публикации имеет неверный формат'
    ];
}

Самая свежая и подробная документация по валидации в Laravel находится здесь.

Автор: Anthony Rappa
Перевод: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.