この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:13
ページ更新者:guest
更新日時:2026-06-11 07:07:02

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

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li>Laravel のバリデーションは <code>$request->validate([...])</code> が最短。失敗時は自動で 422 か直前ページへ戻る</li><li>大規模プロジェクトでは <strong>Form Request クラス</strong>(<code>php artisan make:request StoreUserRequest</code>)にルールを分離</li><li>標準ルールが豊富: <code>required</code> / <code>email</code> / <code>unique:users,email</code> / <code>confirmed</code> / <code>regex:/.../</code> / <code>exists:users,id</code></li><li><strong>カスタムルール</strong>は <code>php artisan make:rule Uppercase</code> または <code>Rule::make()</code> クロージャ</li><li>エラーメッセージは <code>resources/lang/{ja|en}/validation.php</code> でローカライズ。属性名は <code>attributes</code> キーで日本語化</li></ul></td></tr></table>
<h2>バリデーションの基本: $request->validate()</h2>

<p>Laravel で最も簡単なバリデーション方法。コントローラ内で <code>$request->validate()</code> を呼ぶだけで、失敗時は自動的にリダイレクト(HTML)or 422 JSON 応答(API)を返します。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// app/Http/Controllers/UserController.php
public function store(Request $request)
{
    $validated = $request->validate([
        &apos;name&apos;     => &apos;required|string|max:255&apos;,
        &apos;email&apos;    => &apos;required|email|unique:users,email&apos;,
        &apos;password&apos; => &apos;required|min:8|confirmed&apos;,
        &apos;age&apos;      => &apos;nullable|integer|min:0|max:150&apos;,
    ]);

    User::create($validated);
    return redirect()->route(&apos;users.index&apos;);
}</code></pre>
<p>失敗時は <code>Illuminate\Validation\ValidationException</code> がスローされ、Laravel が以下を自動処理します:</p>

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

<h2>Form Request クラスで分離する</h2>

<p>コントローラが肥大化したら Form Request に分離するのがベストプラクティス:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash">php artisan make:request StoreUserRequest
# → app/Http/Requests/StoreUserRequest.php</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-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(&apos;create&apos;, User::class);
    }

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

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

    public function attributes(): array
    {
        return [
            &apos;name&apos;  => &apos;氏名&apos;,
            &apos;email&apos; => &apos;メールアドレス&apos;,
        ];
    }
}</code></pre>
<p>コントローラ側は型ヒントするだけで自動的にバリデーションが実行されます:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">public function store(StoreUserRequest $request)
{
    // ここに到達した時点でバリデーション済
    User::create($request->validated());
    return redirect()->route(&apos;users.index&apos;);
}</code></pre>
<h2>主要バリデーションルール一覧</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>ルール</th><th>説明</th><th>例</th></tr></thead>
<tbody>
<tr><td><code>required</code></td><td>必須項目</td><td><code>required</code></td></tr>
<tr><td><code>nullable</code></td><td>null 許容(他ルールをスキップ)</td><td><code>nullable|integer</code></td></tr>
<tr><td><code>string</code> / <code>integer</code> / <code>numeric</code></td><td>型チェック</td><td><code>integer|min:1</code></td></tr>
<tr><td><code>min</code> / <code>max</code></td><td>長さ・値の範囲</td><td><code>min:8|max:255</code></td></tr>
<tr><td><code>email</code></td><td>メール形式</td><td><code>email:rfc,dns</code></td></tr>
<tr><td><code>unique:table,column</code></td><td>DB に重複なし</td><td><code>unique:users,email</code></td></tr>
<tr><td><code>exists:table,column</code></td><td>DB に存在する</td><td><code>exists:roles,id</code></td></tr>
<tr><td><code>confirmed</code></td><td><code>{field}_confirmation</code> と一致</td><td><code>password</code>+<code>password_confirmation</code></td></tr>
<tr><td><code>regex:/pattern/</code></td><td>正規表現</td><td><code>regex:/^[A-Z]+$/</code></td></tr>
<tr><td><code>in:a,b,c</code></td><td>列挙値</td><td><code>in:admin,user,guest</code></td></tr>
<tr><td><code>date</code> / <code>date_format:Y-m-d</code></td><td>日付</td><td><code>date_format:Y-m-d H:i</code></td></tr>
<tr><td><code>image</code> / <code>mimes:jpg,png</code></td><td>ファイル種別</td><td><code>image|mimes:jpg,png|max:2048</code></td></tr>
</tbody>
</table>

<h2>Validator::make() を直接使う</h2>

<p>Request 以外(コマンド、ジョブ、Livewire 等)でバリデーションしたいときは <code>Validator</code> ファサードを使います:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">use Illuminate\Support\Facades\Validator;

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

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

$validated = $validator->validated();</code></pre>
<h2>カスタムルール</h2>

<p>標準ルールで足りない場合はカスタムルールを作ります:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash">php artisan make:rule Uppercase</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 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(&apos;The :attribute must be uppercase.&apos;);
        }
    }
}

// 使い方
$request->validate([
    &apos;code&apos; => [&apos;required&apos;, new Uppercase],
]);</code></pre>
<p>1 行で済むならクロージャでも OK:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$request->validate([
    &apos;title&apos; => [
        &apos;required&apos;,
        function (string $attribute, mixed $value, Closure $fail) {
            if (str_contains($value, &apos;NG&apos;)) {
                $fail("{$attribute} に NG ワードが含まれています。");
            }
        },
    ],
]);</code></pre>
<h2>エラーメッセージのローカライズ</h2>

<p>日本語化は <code>resources/lang/ja/validation.php</code> を配置:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash"># Laravel 標準の日本語訳パッケージを使う
composer require askdkc/breezejp --dev
php artisan breezejp

# または手動で resources/lang/ja/ を作成</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// resources/lang/ja/validation.php
return [
    &apos;required&apos; => &apos;:attribute は必須項目です。&apos;,
    &apos;email&apos;    => &apos;:attribute は正しいメールアドレス形式で入力してください。&apos;,
    &apos;min&apos;      => [
        &apos;string&apos;  => &apos;:attribute は :min 文字以上で入力してください。&apos;,
        &apos;numeric&apos; => &apos;:attribute は :min 以上の数値で入力してください。&apos;,
    ],
    &apos;unique&apos;   => &apos;:attribute は既に使用されています。&apos;,

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

// config/app.php
&apos;locale&apos; => &apos;ja&apos;,</code></pre>
<h2>Blade テンプレートでのエラー表示</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-blade"><form method="POST" action="{{ route(&apos;users.store&apos;) }}">
    @csrf
    <div>
        <label>氏名</label>
        <input type="text" name="name" value="{{ old(&apos;name&apos;) }}" />
        @error(&apos;name&apos;)
            <span style="color:red">{{ $message }}</span>
        @enderror
    </div>

    {{-- 全エラーをまとめて表示 --}}
    @if ($errors->any())
        <ul style="color:red">
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    @endif

    <button>登録</button>
</form></code></pre>
<h2>FAQ</h2>

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

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

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