第33回: フォームリクエストクラス — バリデーションを「コントローラの外」に出す

章: 第4章: Laravelフレームワーク

コントローラのメソッドの半分以上がバリデーションコードになっていませんか?

$request->validate([...]) をコントローラに直書きし続けると、メソッドが肥大化して可読性もテスト性も下がります。フォームリクエストクラスに切り出すことで、バリデーションと認可のロジックを1ヶ所に集約できます。

コントローラにバリデーションを詰め込むと何が起きるか

同じバリデーションルールが複数のアクションにコピーされ、変更のたびに複数箇所を修正するリスクが生まれます。FormRequestクラスを使えば、ルールを1ヶ所で管理でき、コントローラはスッキリします。

FormRequestの良い例・悪い例

観点 悪い例 良い例
バリデーション場所 コントローラのメソッド内に直書き FormRequest::rules() にまとめる
認可 コントローラ内で if ($user->cannot(...)) abort(403) FormRequest::authorize() に移す
エラーメッセージ デフォルトのまま messages() メソッドで日本語化
再利用 ルールをコピーペースト 複数アクションで同じFormRequestクラスを使う

チェックポイント: authorize() が常に true を返す実装は、アクセス制御を放棄しているサインです。認証済みユーザーのみ許可する場合は return $this->user() !== null;、さらに所有者確認が必要なら Policy と組み合わせましょう。

コードサンプル


<?php
// php artisan make:request StorePostRequest
class StorePostRequest extends FormRequest {
    public function authorize(): bool { return true; }
    public function rules(): array {
        return [
            'title' => ['required', 'string', 'max:255'],
            'body'  => ['required', 'string'],
        ];
    }
}
// コントローラはスッキリ
public function store(StorePostRequest $request): RedirectResponse {
    Post::create($request->validated());
    return redirect()->route('posts.index');
}

まとめ & 次のステップ

  • フォームリクエストクラスでバリデーションと認可をコントローラから分離できます
  • validated() を使うことで許可したフィールドのみ取得でき、マスアサインメントが安全になります
  • messages() メソッドでエラーメッセージを日本語化しましょう
  • authorize() を適切に実装し、権限のないリクエストを早期に拒否しましょう
  • テストでは $this->actingAs($user)->post(...) で認可の動作確認を行いましょう

次回は ミドルウェア を学びます。HTTPリクエストの前後に共通処理を差し込む仕組みを整理しましょう。

Related Articles