Form Request: валидация в отдельном классе

Form Request выносит правила валидации и авторизацию в отдельный класс, оставляя контроллеры тонкими и переиспользуя логику проверки.

Суть: класс-наследник FormRequest содержит метод rules() с правилами и authorize() с проверкой прав. Достаточно указать его типом в методе контроллера — валидация выполнится сама.

Когда форма усложняется, правила валидации в контроллере разрастаются и начинают повторяться в методах store и update. Form Request решает это: он переносит правила и авторизацию в отдельный, специально предназначенный класс. Контроллер становится чистым, а правила — переиспользуемыми и удобными для тестирования.

Магия в том, что вам не нужно вручную вызывать валидацию. Достаточно объявить Form Request как тип аргумента метода контроллера — Laravel автоматически создаст его, проверит права через authorize(), прогонит правила из rules() и, при успехе, отдаст вам уже проверенные данные.

Создание Form Request

php artisan make:request StoreProductRequest
<?php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreProductRequest extends FormRequest
{
    // проверка прав: может ли пользователь делать этот запрос
    public function authorize(): bool
    {
        return $this->user()?->is_admin ?? false;
    }

    // правила валидации
    public function rules(): array
    {
        return [
            'name'  => 'required|string|max:255',
            'price' => 'required|numeric|min:0',
        ];
    }

    // свои тексты ошибок (необязательно)
    public function messages(): array
    {
        return ['name.required' => 'Укажите название товара'];
    }
}

Контроллер становится предельно чистым — никакой валидации в теле метода:

<?php
use App\Http\Requests\StoreProductRequest;

public function store(StoreProductRequest $request)
{
    // сюда попадём только если authorize() = true
    // и все правила rules() пройдены
    Product::create($request->validated());

    return redirect('/products');
}

Как работает под капотом

Когда Laravel видит в сигнатуре метода тип StoreProductRequest, он через контейнер создаёт объект и ещё до входа в метод запускает проверку. Сначала вызывается authorize(): если он вернул false — ответ 403, метод не выполняется. Затем прогоняются rules(): при ошибке — редирект назад (как у обычного validate). И только если оба этапа пройдены, ваш код начинает работать.

  Запрос -> метод store(StoreProductRequest $r)
               |
        1. authorize()  --false--> 403 Forbidden
               | true
        2. rules()      --ошибки--> redirect + $errors
               | ок
        3. тело контроллера ($r->validated())

Смоделируем двухэтапную проверку «авторизация, затем правила» на Python.

Попробуй сам ▶

# Form Request: сначала authorize(), потом rules()
def authorize(user):
    return user.get('is_admin', False)

def rules(data):
    errors = {}
    if not data.get('name'):
        errors['name'] = 'обязательно'
    return errors

def handle(user, data):
    if not authorize(user):
        return '403 Forbidden'
    errors = rules(data)
    if errors:
        return f'redirect + ошибки: {errors}'
    return '200 OK — товар создан'

print(handle({'is_admin': False}, {'name': 'Книга'}))
print(handle({'is_admin': True},  {'name': ''}))
print(handle({'is_admin': True},  {'name': 'Книга'}))

Частые ошибки

  • Оставить authorize() с return false. Сгенерированный класс по умолчанию запрещает всё — не забудьте задать логику или вернуть true.
  • Снова валидировать в контроллере. Form Request уже всё проверил — дублировать не нужно.
  • Использовать $request->all() вместо validated(). Это теряет смысл проверки и открывает mass assignment.

Best practices

  • Заводите отдельные Form Request на создание и обновление (Store... и Update...).
  • Берите данные только через $request->validated().
  • Сложную авторизацию выносите в политики (Policy) и вызывайте из authorize().

Итог: Form Request инкапсулирует правила и авторизацию, делая контроллеры тонкими и переиспользуя проверки. Дальше переходим к большой теме — аутентификации пользователей.

Проверьте себя
1. Какие два метода обычно содержит Form Request?
Aup() и down()
Brules() и authorize()
Cindex() и show()
Dget() и post()
2. Когда выполняется проверка Form Request?
AВ конце метода контроллера
BАвтоматически до входа в метод, если класс указан типом аргумента
CТолько вручную
DНикогда