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

タイトル: 必須チェック
SEOタイトル: Laravel バリデーション required (必須チェック) 完全ガイド

この記事の要点
  • Laravel の必須チェックは "name" => "required" がベース
  • 条件付き必須: required_if / required_unless / required_with / required_without
  • sometimesキーが存在する時だけバリデーション
  • empty 判定: "" / null / [] / UploadedFile なし が「必須未入力」
  • クライアント JS バリデーション併用 + サーバ側必須チェックの二段構えが安全

required の基本

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'name'     => 'required|string|max:255',
    'email'    => 'required|email',
    'password' => 'required|min:8',
    'age'      => 'required|integer|min:0',
]);

if ($validator->fails()) {
    return back()->withErrors($validator)->withInput();
}

// Controller の簡易記法
public function store(Request $request)
{
    $validated = $request->validate([
        'name'  => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
    ]);
    User::create($validated);
}

required の判定基準

Laravel が「未入力」と判定するのは次のすべて:

required で fail する?
nullfail
空文字 ""fail
空配列 []fail
未送信 (キー無し)fail
UploadedFile でパス無しfail
"0" (文字列ゼロ)pass
0 (数値ゼロ)pass
falsepass
" " (空白のみ)pass (空文字ではない)

空白のみは pass するので、フォームで「未入力扱い」にしたいなら独自ルールが必要:

// 解決法 A: prepareForValidation で trim
class StoreUserRequest extends FormRequest
{
    protected function prepareForValidation(): void
    {
        $this->merge([
            'name' => trim($this->input('name', '')),
        ]);
    }

    public function rules(): array
    {
        return ['name' => 'required|string'];  // trim 済みなので空白だけは required で fail
    }
}

// 解決法 B: グローバルミドルウェアの TrimStrings (Laravel 標準で有効)
// app/Http/Kernel.php に \Illuminate\Foundation\Http\Middleware\TrimStrings::class

条件付き必須

required_if (他フィールドが特定値のとき必須)

// payment_method = 'card' のとき card_number 必須
$rules = [
    'payment_method' => 'required|in:card,bank,cash',
    'card_number'    => 'required_if:payment_method,card|digits:16',
    'bank_code'      => 'required_if:payment_method,bank|digits:4',
];

// 複数値
'card_number' => 'required_if:payment_method,card,credit',  // card OR credit

required_unless (他フィールドが特定値でなければ必須)

// status が 'draft' でなければ title が必須
$rules = [
    'status' => 'required|in:draft,published',
    'title'  => 'required_unless:status,draft|string|max:255',
];

required_with / required_without

// other_name が入っていれば other_email も必須
'other_email' => 'required_with:other_name|email',

// すべて指定する場合
'other_email' => 'required_with_all:other_name,other_age|email',

// other_name が無ければ default_name 必須
'default_name' => 'required_without:other_name',

// すべて無ければ
'fallback' => 'required_without_all:a,b,c',

required_array_keys (配列の必須キー指定)

// address 配列に prefecture と city が必須
'address' => 'required|array|required_array_keys:prefecture,city',
'address.prefecture' => 'required|string',
'address.city'       => 'required|string',

sometimes: キーが存在する時だけバリデーション

// 通常 required: キーが無いと fail
// sometimes: キーが無いとスキップ、あれば検証

$rules = [
    'name'  => 'sometimes|required|string',  // 送られてきた時だけ必須
    'email' => 'sometimes|email',
];

// 用途: PATCH (部分更新)
public function update(Request $request, User $user)
{
    $validated = $request->validate([
        'name'  => 'sometimes|required|string|max:255',
        'email' => 'sometimes|required|email|unique:users,email,' . $user->id,
        'phone' => 'sometimes|nullable|string',
    ]);
    $user->update($validated);
}

// Validator::sometimes() でクロージャ条件
$v = Validator::make($data, ['credit_limit' => 'numeric']);
$v->sometimes('credit_limit', 'required|min:0', function ($input) {
    return $input->payment_method === 'credit';
});

nullable: 任意項目で null を許可

// nullable 無しで integer | null → fail (null は integer ではない)
// nullable 付ければ null を許可

$rules = [
    'phone'      => 'nullable|string|max:20',
    'birthdate'  => 'nullable|date',
    'company_id' => 'nullable|integer|exists:companies,id',
];

Form Request クラスで整理

// php artisan make:request StoreUserRequest

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|string|min:8|confirmed',
            'role'           => 'required|in:admin,user',
            'company_id'     => 'required_if:role,user|exists:companies,id',
            'profile.bio'    => 'nullable|string|max:1000',
            'profile.avatar' => 'nullable|image|max:2048',
        ];
    }

    public function messages(): array
    {
        return [
            'name.required'    => 'お名前は必須です',
            'email.required'   => 'メールアドレスは必須です',
            'email.email'      => '有効なメールアドレスを入力してください',
            'email.unique'     => 'このメールアドレスは既に使用されています',
            'password.min'     => 'パスワードは:min文字以上で入力してください',
            'password.confirmed' => 'パスワードが一致しません',
        ];
    }

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

// Controller では型ヒントするだけ
public function store(StoreUserRequest $request)
{
    User::create($request->validated());
    return redirect()->route('users.index');
}

required_array_keys と配列要素のバリデーション

// items が配列で各要素に name と price が必須
$rules = [
    'items'         => 'required|array|min:1',
    'items.*.name'  => 'required|string|max:255',
    'items.*.price' => 'required|integer|min:0',
    'items.*.tags'  => 'nullable|array',
    'items.*.tags.*' => 'string|max:20',
];

// 送信例
// items[0][name]=A&items[0][price]=100&items[1][name]=B&items[1][price]=200

カスタムメッセージ・属性名

$request->validate(
    [
        'name'  => 'required|string|max:255',
        'email' => 'required|email',
    ],
    [
        'name.required'  => ':attribute を入力してください',
        'email.required' => ':attribute を入力してください',
        'email.email'    => '正しい :attribute 形式で入力してください',
    ],
    [
        'name'  => 'お名前',
        'email' => 'メールアドレス',
    ]
);

// グローバルメッセージは resources/lang/ja/validation.php
// 'required' => ':attribute は必須項目です。',

JS バリデーションとの併用

クライアント JS で即時フィードバック、サーバで最終検証の二段構えが王道。サーバ側を省略してはいけません (DevTools で簡単に回避できる):

<form action="/users" method="POST">
    @csrf
    <input type="text" name="name" required minlength="1" maxlength="255">
    <input type="email" name="email" required>
    <input type="password" name="password" required minlength="8">
    <button type="submit">送信</button>
</form>

エラー表示

{{-- Blade --}}
@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

{{-- フィールド別 --}}
<input type="text" name="name" value="{{ old('name') }}"
       class="@error('name') is-invalid @enderror">
@error('name')
    <div class="text-danger">{{ $message }}</div>
@enderror

{{-- API レスポンス (validate() が自動で 422 JSON 返す) --}}
{
    "message": "The given data was invalid.",
    "errors": {
        "name": ["The name field is required."],
        "email": ["The email field is required."]
    }
}

FAQ

Q: requiredpresent の違いは?
A: present はキーが存在することだけチェック (値が空文字でも OK)。required は値が「空でない」ことまで要求。

Q: チェックボックスの必須はどう書く?
A: 未チェックは送信されない (キー無し) ので required|acceptedaccepted は値が yes / on / 1 / true / "1" のいずれかなら pass。

Q: ファイルアップロードの必須は?
A: 'avatar' => 'required|file|image|max:2048'。アップロード失敗 (サイズ超過等) も自動で fail します。