Day 5・入力の検証と横断的関心事 — バリデーション・ミドルウェア・Blade
FormRequest — 検証ロジックを専用クラスに寄せる
コントローラを薄く保ち、検証と認可を再利用可能な1クラスにまとめる設計。
コントローラに検証を書き続けると何が起きるか
前のレッスンではコントローラ内で「validate()」を呼びました。しかしルールが増え、認可の判定や独自メッセージが加わると、コントローラのメソッドが検証コードで膨らんでいきます。同じルールを複数のメソッドで使い回したいときにコピペも発生します。
は、この検証と認可のロジックを専用クラスに切り出す仕組みです。コントローラの引数の型を FormRequest にするだけで、Laravelがメソッドの実行前に自動で検証をかけてくれます。
悪い例と良い例
検証をコントローラに直書き
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 に寄せてコントローラを薄く
public function store(StorePostRequest $request)
{
// 検証も認可も StorePostRequest 側で済んでいる
Post::create($request->validated());
return redirect()->route('posts.index');
}FormRequest クラスの中身
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' => 'タイトルは必須です。',
];
}
}なぜ検証を専用クラスに寄せるのか
第一に、コントローラの責務を「受け取って・呼び出して・返す」だけに絞れます(薄いコントローラ)。第二に、同じ検証ルールを複数の入口で再利用できます。第三に、認可(authorize)を検証と同じ場所にまとめられるため、『誰が・何を・どんな形で』送ってよいかが1クラスを見れば分かります。
authorize による認可の一元化
authorize() が false を返すと、Laravelはメソッドを実行せず 403 を返します。「検証(形式が正しいか)」と「認可(その人に権限があるか)」を同じクラスに置くことで、入口のチェックが散らばりません。認証と認可の違いは Day3 の内容ともつながります。
コントローラの引数に型を書くだけで動く仕組み
Laravelはメソッドの引数の型ヒントを見て、必要なクラスを自動生成して渡します(サービスコンテナによる解決)。FormRequestを型に指定すると、注入の過程で検証と認可が自動実行される、という流れです。
面接ではこう言う
「検証と認可はFormRequestに寄せて、コントローラは薄く保ちます。コントローラは『受け取って、必要な処理を呼んで、結果を返す』だけにしたいので、入力の正しさと権限の判定は入口の専用クラスに集約します。同じルールを再利用でき、テストもしやすくなります」
読んでも腑に落ちない所は、AIに噛み砕いてもらいましょう。
理解度チェック
答えられれば、面接で説明できる状態に一歩近づきます。
FormRequest に検証を寄せる主な利点として、当てはまらないものは?
なぜ検証ロジックをコントローラではなくFormRequestに置くのですか。
記述式です。まず自分の言葉で答えを考えてから、模範解答を開いて自己採点してください。