タイトル: 必須チェック
SEOタイトル: Laravel バリデーション required (必須チェック) 完全ガイド
この本文には実行可能なタグ等が含まれるため、安全のため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>"name" => "required"</code> がベース</li><li>条件付き必須: <code>required_if</code> / <code>required_unless</code> / <code>required_with</code> / <code>required_without</code></li><li><code>sometimes</code> で<strong>キーが存在する時だけ</strong>バリデーション</li><li>empty 判定: <code>""</code> / null / <code>[]</code> / UploadedFile なし が「必須未入力」</li><li>クライアント JS バリデーション併用 + サーバ側必須チェックの<strong>二段構え</strong>が安全</li></ul></td></tr></table>
<h2>required の基本</h2>
<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($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);
}</code></pre>
<h2>required の判定基準</h2>
<p>Laravel が「未入力」と判定するのは次のすべて:</p>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>値</th><th>required で fail する?</th></tr></thead>
<tbody>
<tr><td>null</td><td>fail</td></tr>
<tr><td>空文字 <code>""</code></td><td>fail</td></tr>
<tr><td>空配列 <code>[]</code></td><td>fail</td></tr>
<tr><td>未送信 (キー無し)</td><td>fail</td></tr>
<tr><td>UploadedFile でパス無し</td><td>fail</td></tr>
<tr><td>"0" (文字列ゼロ)</td><td>pass</td></tr>
<tr><td>0 (数値ゼロ)</td><td>pass</td></tr>
<tr><td>false</td><td>pass</td></tr>
<tr><td>" " (空白のみ)</td><td>pass (空文字ではない)</td></tr>
</tbody>
</table>
<p><strong>空白のみは pass する</strong>ので、フォームで「未入力扱い」にしたいなら独自ルールが必要:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 解決法 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</code></pre>
<h2>条件付き必須</h2>
<h3>required_if (他フィールドが特定値のとき必須)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 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</code></pre>
<h3>required_unless (他フィールドが特定値でなければ必須)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// status が 'draft' でなければ title が必須
$rules = [
'status' => 'required|in:draft,published',
'title' => 'required_unless:status,draft|string|max:255',
];</code></pre>
<h3>required_with / required_without</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 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',</code></pre>
<h3>required_array_keys (配列の必須キー指定)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// address 配列に prefecture と city が必須
'address' => 'required|array|required_array_keys:prefecture,city',
'address.prefecture' => 'required|string',
'address.city' => 'required|string',</code></pre>
<h2>sometimes: キーが存在する時だけバリデーション</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 通常 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';
});</code></pre>
<h2>nullable: 任意項目で null を許可</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// nullable 無しで integer | null → fail (null は integer ではない)
// nullable 付ければ null を許可
$rules = [
'phone' => 'nullable|string|max:20',
'birthdate' => 'nullable|date',
'company_id' => 'nullable|integer|exists:companies,id',
];</code></pre>
<h2>Form Request クラスで整理</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 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');
}</code></pre>
<h2>required_array_keys と配列要素のバリデーション</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 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</code></pre>
<h2>カスタムメッセージ・属性名</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">$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 は必須項目です。',</code></pre>
<h2>JS バリデーションとの併用</h2>
<p>クライアント JS で即時フィードバック、サーバで最終検証の<strong>二段構え</strong>が王道。サーバ側を省略してはいけません (DevTools で簡単に回避できる):</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><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></code></pre>
<h2>エラー表示</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">{{-- 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."]
}
}</code></pre>
<h2>FAQ</h2>
<p><strong>Q: <code>required</code> と <code>present</code> の違いは?</strong><br />
A: <code>present</code> はキーが存在することだけチェック (値が空文字でも OK)。<code>required</code> は値が「空でない」ことまで要求。</p>
<p><strong>Q: チェックボックスの必須はどう書く?</strong><br />
A: 未チェックは送信されない (キー無し) ので <code>required|accepted</code>。<code>accepted</code> は値が yes / on / 1 / true / "1" のいずれかなら pass。</p>
<p><strong>Q: ファイルアップロードの必須は?</strong><br />
A: <code>'avatar' => 'required|file|image|max:2048'</code>。アップロード失敗 (サイズ超過等) も自動で fail します。</p>