11.

Laravel バリデーション完全ガイド(validate / Form Request / カスタムルール / ローカライズ)

編集
この記事の要点
  • Laravel のバリデーションは $request->validate([...]) が最短。失敗時は自動で 422 か直前ページへ戻る
  • 大規模プロジェクトでは Form Request クラスphp artisan make:request StoreUserRequest)にルールを分離
  • 標準ルールが豊富: required / email / unique:users,email / confirmed / regex:/.../ / exists:users,id
  • カスタムルールphp artisan make:rule Uppercase または Rule::make() クロージャ
  • エラーメッセージは resources/lang/{ja|en}/validation.php でローカライズ。属性名は attributes キーで日本語化

バリデーションの基本: $request->validate()

Laravel で最も簡単なバリデーション方法。コントローラ内で $request->validate() を呼ぶだけで、失敗時は自動的にリダイレクト(HTML)or 422 JSON 応答(API)を返します。

// app/Http/Controllers/UserController.php
public function store(Request $request)
{
    $validated = $request->validate([
        'name'     => 'required|string|max:255',
        'email'    => 'required|email|unique:users,email',
        'password' => 'required|min:8|confirmed',
        'age'      => 'nullable|integer|min:0|max:150',
    ]);

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

失敗時は Illuminate\Validation\ValidationException がスローされ、Laravel が以下を自動処理します:

  • HTML リクエスト → 直前ページへリダイレクト + $errors をセッションに格納
  • JSON / Ajax リクエスト → HTTP 422 + エラー JSON を返却

Form Request クラスで分離する

コントローラが肥大化したら Form Request に分離するのがベストプラクティス:

php artisan make:request StoreUserRequest
# → app/Http/Requests/StoreUserRequest.php
// app/Http/Requests/StoreUserRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('create', User::class);
    }

    public function rules(): array
    {
        return [
            'name'     => ['required', 'string', 'max:255'],
            'email'    => ['required', 'email', 'unique:users,email'],
            'password' => ['required', 'min:8', 'confirmed'],
        ];
    }

    public function messages(): array
    {
        return [
            'email.unique' => 'このメールアドレスは既に登録されています。',
        ];
    }

    public function attributes(): array
    {
        return [
            'name'  => '氏名',
            'email' => 'メールアドレス',
        ];
    }
}

コントローラ側は型ヒントするだけで自動的にバリデーションが実行されます:

public function store(StoreUserRequest $request)
{
    // ここに到達した時点でバリデーション済
    User::create($request->validated());
    return redirect()->route('users.index');
}

主要バリデーションルール一覧

ルール説明
required必須項目required
nullablenull 許容(他ルールをスキップ)nullable|integer
string / integer / numeric型チェックinteger|min:1
min / max長さ・値の範囲min:8|max:255
emailメール形式email:rfc,dns
unique:table,columnDB に重複なしunique:users,email
exists:table,columnDB に存在するexists:roles,id
confirmed{field}_confirmation と一致password+password_confirmation
regex:/pattern/正規表現regex:/^[A-Z]+$/
in:a,b,c列挙値in:admin,user,guest
date / date_format:Y-m-d日付date_format:Y-m-d H:i
image / mimes:jpg,pngファイル種別image|mimes:jpg,png|max:2048

Validator::make() を直接使う

Request 以外(コマンド、ジョブ、Livewire 等)でバリデーションしたいときは Validator ファサードを使います:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($data, [
    'name'  => 'required|max:255',
    'email' => 'required|email',
]);

if ($validator->fails()) {
    return response()->json([
        'errors' => $validator->errors(),
    ], 422);
}

$validated = $validator->validated();

カスタムルール

標準ルールで足りない場合はカスタムルールを作ります:

php artisan make:rule Uppercase
// app/Rules/Uppercase.php
namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class Uppercase implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (strtoupper($value) !== $value) {
            $fail('The :attribute must be uppercase.');
        }
    }
}

// 使い方
$request->validate([
    'code' => ['required', new Uppercase],
]);

1 行で済むならクロージャでも OK:

$request->validate([
    'title' => [
        'required',
        function (string $attribute, mixed $value, Closure $fail) {
            if (str_contains($value, 'NG')) {
                $fail("{$attribute} に NG ワードが含まれています。");
            }
        },
    ],
]);

エラーメッセージのローカライズ

日本語化は resources/lang/ja/validation.php を配置:

# Laravel 標準の日本語訳パッケージを使う
composer require askdkc/breezejp --dev
php artisan breezejp

# または手動で resources/lang/ja/ を作成
// resources/lang/ja/validation.php
return [
    'required' => ':attribute は必須項目です。',
    'email'    => ':attribute は正しいメールアドレス形式で入力してください。',
    'min'      => [
        'string'  => ':attribute は :min 文字以上で入力してください。',
        'numeric' => ':attribute は :min 以上の数値で入力してください。',
    ],
    'unique'   => ':attribute は既に使用されています。',

    'attributes' => [
        'name'     => '氏名',
        'email'    => 'メールアドレス',
        'password' => 'パスワード',
    ],
];

// config/app.php
'locale' => 'ja',

Blade テンプレートでのエラー表示

@csrf
@error('name') {{ $message }} @enderror
{{-- 全エラーをまとめて表示 --}} @if ($errors->any())
    @foreach ($errors->all() as $error)
  • {{ $error }}
  • @endforeach
@endif

FAQ

Q: API で JSON エラーを返したい
A: Accept: application/json ヘッダ付きならデフォルトで JSON 応答。または app/Exceptions/Handler.phprender() をカスタマイズ。

Q: unique:users,email で更新時に自分自身を除外したい
A: Rule::unique('users', 'email')->ignore($this->route('user')) を使います。

Q: ネストした配列をバリデーションしたい
A: 'items.*.name' => 'required' のようにドット記法 + ワイルドカードでアクセス可能です。

編集
Post Share
子ページ
  1. 入力データの保持
  2. 必須チェック
  3. 文字列の長さチェック
  4. 存在チェック
  5. 一意チェック
  6. 日本語化
同階層のページ
  1. インストールと設定
  2. クイックスタート & チュートリアル(初心者向け)
  3. クイックスタート & チュートリアル(中級者向け)
  4. ルーティング
  5. Bladeテンプレート(ビュー/レイアウト)
  6. コントローラー
  7. マイグレーションとテーブル定義
  8. データベースの設定
  9. Eloquentモデル (ORM)
  10. SQLとクエリビルダー
  11. バリデーション
  12. .envファイルの設定値へのアクセス
  13. 動作環境による分岐処理
  14. configフォルダ配下の設定値へのアクセス
  15. assetヘルパーを利用したpublicフォルダへのアクセス
  16. storageフォルダへのアクセス
  17. アプリケーション名の変更
  18. メンテナンス
  19. ログイン画面(認証システム)の作成
  20. ログインの必須化
  21. ログインユーザー情報の取得
  22. ルートの認証化
  23. 本番サーバーへのデプロイ方法
  24. 多言語化
  25. csrf_field
  26. ファイルのダウンロード
  27. CSVのアップロードおよび読み込み(maatwebsite/excel)
  28. ページタイトルの設定
  29. コマンド一覧
  30. エラー一覧
  31. SQLの実行ログ出力方法
  32. キャッシュのクリア
  33. Selectの結果の最初もしくは最後に任意の値を追加する方法
  34. ajaxでPOST通信する際の注意点
  35. ソーシャルログインの実装
  36. セッション情報の確認
  37. ログイン、ユーザー登録、パスワードリセット後のリダイレクト先の変更方法
  38. redirectやreturn viewにメッセージを付与する方法
  39. クッキー(cookie)の設定と取得
  40. クラスの再読み込み
  41. csrfの有効時間を変更する方法
  42. ViewComposerを用いてviewに共通の値を付与する方法
  43. View::shareを用いて共通の値を各ビューに渡す方法
  44. ミドルウェアを用いた処理の共通化
  45. Middleware内でAuth::check()などを使用する方法
  46. Controller以外でリダイレクトする方法
  47. セッションの値の取得/保存/更新/削除
  48. $requestの値を変更する方法
  49. 常時SSL化
  50. ページング(ページネーション)をする方法
  51. vue.jsとの連携
  52. Vue.jsと連携するSPA実行環境構築
  53. .envの値をvue.jsで参照する方法
  54. vue.jsを本番環境にリリースする方法
  55. could not find driver(Windows, MySQL編)