Валидация — одна из тех «мелочей», которые могут постепенно разрушить кодовую базу. Поначалу это просто пара вызовов  request()->validate()  внутри ваших контроллеров, но по мере добавления новых полей и эндпоинтов вы получаете дублирующиеся массивы валидации и контроллеры, переполненные условными операторами.

Laravel  Form Requests решают эту проблему, вынося логику валидации и авторизации в отдельные классы.

Сначала это пара вызовов  request()->validate()  внутри контроллеров.
Затем вы добавляете больше полей, больше эндпоинтов, больше правил… и внезапно у вас появляются:

  • дублирующиеся массивы валидации,
  • контроллеры, забитые условными операторами,
  • несогласованные сообщения об ошибках,
  • и проверки в духе «кому разрешено это делать?», перемешанные с логикой валидации.

Философия: Контроллеры оркеструют, Form Requests валидируют

Form Request — это кастомный класс, который централизует:

  •  rules(): вашу логику валидации.
  •  authorize(): проверку того, кому разрешено выполнять действие.
  •  messages(): кастомные сообщения об ошибках.
  •  prepareForValidation(): нормализацию данных перед применением правил.

Коротко говоря:

Контроллеры оркеструют. Form Requests валидируют (и могут авторизовать).


Зачем использовать Form Requests?

1) Сохраняйте контроллеры чистыми

Контроллеры остаются сосредоточенными на том, что делать, а не на том, как валидировать.

2) Безопасное повторное использование правил

 StorePostRequest  и  UpdatePostRequest  могут переиспользовать или расширять правила без копипаста.

3) Централизация авторизации для действия

Метод  authorize()  может отлично дополнять Policies:

  • Policy определяет  права доступа к ресурсу
  • Form Request определяет  право на выполнение действия (например, «можно ли создать?»)

4) Упрощение тестирования

Form Requests позволяют легко и просто тестировать валидацию и граничные случаи.


Создание Form Request

 php artisan make:request StoreProjectRequest
 

Вы получите что-то вроде:

 // app/Http/Requests/StoreProjectRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreProjectRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [];
    }
}
 

Базовый пример: сохранение Project

Form Request

 // app/Http/Requests/StoreProjectRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class StoreProjectRequest extends FormRequest
{
    public function authorize(): bool
    {
        // Option A: keep it simple
        return auth()->check();

        // Option B: delegate to a Policy (recommended in many apps)
        // return $this->user()->can('create', Project::class);
    }

    public function rules(): array
    {
        return [
            'name'        => ['required', 'string', 'min:3', 'max:120'],
            'description' => ['nullable', 'string', 'max:2000'],
            'status'      => ['required', Rule::in(['draft', 'active'])],
            'starts_at'   => ['nullable', 'date'],
        ];
    }
}
 

Контроллер остается компактным

 // app/Http/Controllers/ProjectController.php
use App\Http\Requests\StoreProjectRequest;

class ProjectController
{
    public function store(StoreProjectRequest $request)
    {
        $data = $request->validated();

        // ... create logic (model/service/use case)
        // Project::create([...$data, 'user_id' => $request->user()->id]);

        return redirect()->back()->with('status', 'Project created!');
    }
}
 

Обратите внимание на главные преимущества:

  • валидация вынесена из контроллера
  •  $request->validated()  гарантирует, что пройдут только проверенные поля

Улучшение сообщений об ошибках (опционально)

 public function messages(): array
{
    return [
        'name.required' => 'Please provide a project name.',
        'name.min'      => 'Project name must be at least :min characters.',
    ];
}

public function attributes(): array
{
    return [
        'starts_at' => 'start date',
    ];
}
 

Нормализация входных данных с помощью prepareForValidation()

Очень полезно для очистки данных до того, как сработают правила валидации.

 protected function prepareForValidation(): void
{
    $this->merge([
        'name' => trim((string) $this->input('name')),
    ]);
}
 

Частые сценарии использования:

  • обрезка пробелов у строк (trim),
  • приведение «on» к булевому значению,
  • маппинг устаревших ключей (legacy keys),
  • установка значений по умолчанию для отсутствующих полей.

Продвинутый паттерн: общие правила для Store/Update

Часто ваши правила обновления слегка отличаются (например, ограничения уникальности).

 // app/Http/Requests/UpdateProjectRequest.php
use Illuminate\Validation\Rule;

public function rules(): array
{
    $projectId = $this->route('project')?->id;

    return [
        'name' => [
            'required', 'string', 'max:120',
            Rule::unique('projects', 'name')->ignore($projectId),
        ],
        'status' => ['required', Rule::in(['draft', 'active', 'archived'])],
    ];
}
 

Как Form Requests сочетаются с Policies

Чистая архитектура выглядит так:

  •  Policy → права доступа на уровне ресурса («можно ли обновить ЭТОТ проект?»)
  •  Form Request → валидация входных данных (+ опциональные проверки на уровне действия)

Пример:

  • Контроллер вызывает  $this->authorize('update', $project)  (Policy)
  • Form Request валидирует поля и формирует структуру входных данных

Такое разделение делает логику авторизации явной и пригодной для повторного использования.


Быстрое тестирование валидации

Даже несколько тестов помогут предотвратить регрессии.

 public function test_project_name_is_required(): void
{
    $response = $this->post('/projects', [
        'name' => '',
        'status' => 'draft',
    ]);

    $response->assertSessionHasErrors(['name']);
}
 

Чек-лист для сохранения

  • [ ] Создавайте Form Request для каждого действия ( StoreXRequest ,  UpdateXRequest )
  • [ ] Делайте контроллеры тонкими:  $request->validated() 
  • [ ] Нормализуйте входные данные в  prepareForValidation()  при необходимости
  • [ ] Используйте Policies для проверки прав на ресурсы; опционально вызывайте их в  authorize() 
  • [ ] Добавляйте 3–5 тестов для критически важных правил валидации

Итог

Laravel Form Requests — это простая привычка, которая сохраняет проект чистым по мере его роста:

  • контроллеры остаются читаемыми,
  • правила валидации остаются согласованными,
  • авторизация становится более понятной,
  • а рефакторинг — более безопасным.