#03 Laravel基礎

FormRequestでバリデーションを整理する

コントローラー直書きの問題

「Laravel生活」シリーズでは、 バリデーション? フォームに入力されたデータが正しい形式かをチェックする処理。「メールアドレスの形式か」「空欄でないか」などを検証する。 をコントローラーに直接書きました。

// 📁 app/Http/Controllers/PostController.php

public function store(Request $request)
{
    $request->validate([
        'title'   => 'required|max:100',
        'body'    => 'required',
        'status'  => 'required|in:draft,published',
    ]);

    Post::create($request->only('title', 'body', 'status'));
    return redirect()->route('posts.index');
}

ルールが少ないうちは問題ありません。しかし入力項目が多くなると、バリデーション部分がコントローラーを圧迫します。それを解決するのが フォームリクエスト? バリデーションルールを専用クラスにまとめる仕組み。コントローラーをすっきりさせるために使う。 です。


FormRequestを生成する

php artisan make:request StorePostRequest

app/Http/Requests/StorePostRequest.php が生成されます。

<?php
// 📁 app/Http/Requests/StorePostRequest.php(自動生成直後)

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return false; // ← まずここを変更する
    }

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

authorize() と rules() を実装する

<?php
// 📁 app/Http/Requests/StorePostRequest.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    // このリクエストを実行できるかの権限チェック
    // とりあえず全員許可する場合は true を返す
    public function authorize(): bool
    {
        return true;
    }

    // バリデーションルール
    public function rules(): array
    {
        return [
            'title'   => ['required', 'max:100'],
            'body'    => ['required'],
            'status'  => ['required', 'in:draft,published'],
        ];
    }

    // エラーメッセージを日本語化する(任意)
    public function messages(): array
    {
        return [
            'title.required' => 'タイトルは必須です',
            'title.max'      => 'タイトルは100文字以内で入力してください',
            'body.required'  => '本文は必須です',
            'status.required' => 'ステータスを選択してください',
            'status.in'      => 'ステータスの値が不正です',
        ];
    }
}

コントローラーで使う

コントローラーの引数の型を Request から StorePostRequest に変えるだけです。

<?php
// 📁 app/Http/Controllers/PostController.php

namespace App\Http\Controllers;

use App\Http\Requests\StorePostRequest; // ← インポートを追加
use App\Models\Post;

class PostController extends Controller
{
    public function store(StorePostRequest $request) // ← 型を変更
    {
        // バリデーションは FormRequest が自動で実行済み
        // ここに来た時点でデータは検証済み
        Post::create($request->only('title', 'body', 'status'));
        return redirect()->route('posts.index')->with('success', '投稿を作成しました');
    }
}

StorePostRequest を型宣言すると、Laravelが自動でバリデーションを実行します。失敗した場合は自動でフォームに戻り、エラーが $errors 変数に格納されます。


更新用の FormRequest も作る

作成と更新でルールが違う場合は別のクラスを作ります。

php artisan make:request UpdatePostRequest
<?php
// 📁 app/Http/Requests/UpdatePostRequest.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

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

    public function rules(): array
    {
        return [
            'title'  => ['required', 'max:100'],
            'body'   => ['required'],
            'status' => ['required', 'in:draft,published'],
        ];
    }
}

コントローラーの update メソッドにも適用します。

// 📁 app/Http/Controllers/PostController.php

public function update(UpdatePostRequest $request, Post $post) // ← 型を変更
{
    $post->update($request->only('title', 'body', 'status'));
    return redirect()->route('posts.show', $post)->with('success', '投稿を更新しました');
}

authorize() で認可を行う

authorize() は「このリクエストを実行する権限があるか」をチェックする場所です。ルートモデルバインディングと組み合わせると、「自分の投稿だけ編集できる」というチェックをここに書けます。

// 📁 app/Http/Requests/UpdatePostRequest.php

public function authorize(): bool
{
    // ルートの {post} パラメーターからモデルを取得
    $post = $this->route('post');

    // 現在のログインユーザーが投稿の作者か確認
    return $post->user_id === $this->user()->id;
}

authorize()false を返すと403エラーになります。


まとめ

  • php artisan make:request でFormRequestクラスを生成する
  • rules() にバリデーションルールを書く
  • messages() でエラーメッセージを日本語化できる
  • authorize() で認可ロジックも書ける
  • コントローラーの型を変えるだけでバリデーションが自動実行される

次回は依存性注入とサービスコンテナを学びます。