LLaravel Bootcamp

Day 5入力の検証と横断的関心事 — バリデーション・ミドルウェア・Blade

FormRequest — 検証ロジックを専用クラスに寄せる

コントローラを薄く保ち、検証と認可を再利用可能な1クラスにまとめる設計。

コントローラに検証を書き続けると何が起きるか

前のレッスンではコントローラ内で「validate()」を呼びました。しかしルールが増え、認可の判定や独自メッセージが加わると、コントローラのメソッドが検証コードで膨らんでいきます。同じルールを複数のメソッドで使い回したいときにコピペも発生します。

は、この検証と認可のロジックを専用クラスに切り出す仕組みです。コントローラの引数の型を FormRequest にするだけで、Laravelがメソッドの実行前に自動で検証をかけてくれます。

悪い例と良い例

検証をコントローラに直書き

PHP
public function store(Request $request)
{
    $validated = $request->validate([
        'title'   => ['required', 'string', 'max:255'],
        'body'    => ['required', 'string'],
        'user_id' => ['required', 'exists:users,id'],
    ]);

    // 認可も手書きで混ざる
    if (! $request->user()->can('create', Post::class)) {
        abort(403);
    }

    Post::create($validated);
    return redirect()->route('posts.index');
}

FormRequest に寄せてコントローラを薄く

PHP
public function store(StorePostRequest $request)
{
    // 検証も認可も StorePostRequest 側で済んでいる
    Post::create($request->validated());
    return redirect()->route('posts.index');
}

FormRequest クラスの中身

PHP
class StorePostRequest extends FormRequest
{
    // この操作を今のユーザーに許可するか(認可)
    public function authorize(): bool
    {
        return $this->user()->can('create', Post::class);
    }

    // 検証ルール
    public function rules(): array
    {
        return [
            'title'   => ['required', 'string', 'max:255'],
            'body'    => ['required', 'string'],
            'user_id' => ['required', 'exists:users,id'],
        ];
    }

    // 独自のエラーメッセージ(任意)
    public function messages(): array
    {
        return [
            'title.required' => 'タイトルは必須です。',
        ];
    }
}
app/Http/Requests/StorePostRequest.php

なぜ検証を専用クラスに寄せるのか

第一に、コントローラの責務を「受け取って・呼び出して・返す」だけに絞れます(薄いコントローラ)。第二に、同じ検証ルールを複数の入口で再利用できます。第三に、認可(authorize)を検証と同じ場所にまとめられるため、『誰が・何を・どんな形で』送ってよいかが1クラスを見れば分かります。

authorize による認可の一元化

authorize() が false を返すと、Laravelはメソッドを実行せず 403 を返します。「検証(形式が正しいか)」と「認可(その人に権限があるか)」を同じクラスに置くことで、入口のチェックが散らばりません。認証と認可の違いは Day3 の内容ともつながります。

コントローラの引数に型を書くだけで動く仕組み

Laravelはメソッドの引数の型ヒントを見て、必要なクラスを自動生成して渡します(サービスコンテナによる解決)。FormRequestを型に指定すると、注入の過程で検証と認可が自動実行される、という流れです。

面接ではこう言う

「検証と認可はFormRequestに寄せて、コントローラは薄く保ちます。コントローラは『受け取って、必要な処理を呼んで、結果を返す』だけにしたいので、入力の正しさと権限の判定は入口の専用クラスに集約します。同じルールを再利用でき、テストもしやすくなります」

読んでも腑に落ちない所は、AIに噛み砕いてもらいましょう。

理解度チェック

答えられれば、面接で説明できる状態に一歩近づきます。

Q1

FormRequest に検証を寄せる主な利点として、当てはまらないものは?

Q2

なぜ検証ロジックをコントローラではなくFormRequestに置くのですか。

記述式です。まず自分の言葉で答えを考えてから、模範解答を開いて自己採点してください。