Laravel Tips集 ~Validationの便利技大全~
Laravel Validation Tips チートシート
バリデーションルールやフォームリクエストのカスタマイズ方法、エラーメッセージの改善など、バリデーションに関するさまざまなテクニックをまとめました。
1. インラインバリデーション
通常はカスタムクラスで定義するバリデーションルールも、クロージャを利用してインラインで記述できます。
※メールアドレスの末尾が @example.com
でなければエラーとする例
<?php
request()->validate([
'email' => [
'required',
'email',
function ($attribute, $value, $fail) {
if (substr($value, -12) !== '@example.com') {
$fail($attribute, 'The email must belong to example.com domain');
}
},
],
]);
2. ネストされた配列のバリデーション
Laravel 9 以降では、Rule::forEach()
を利用することで、ネストされた配列内の各要素に対して個別のバリデーションルールを定義できます。
<?php
use App\Rules\HasPermission;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'companies.*.id' => Rule::forEach(function (string|null $value, string $attribute) {
return [
Rule::exists(Company::class, 'id'),
new HasPermission('manage-company', $value),
];
}),
]);
3. 最初の失敗で停止する
フォームリクエストクラスのプロパティに stopOnFirstFailure
を true に設定すると、最初のバリデーションエラーで残りのチェックをスキップできます。
<?php
/**
* Indicates if the validator should stop on the first rule failure.
*
* @var bool
*/
protected $stopOnFirstFailure = true;
4. bail ルール
フィールドごとに「bail」を指定することで、最初のルールに失敗した時点で以降のルールチェックを中断します。
<?php
$request->validate([
'title' => 'bail|required|unique:posts|max:255',
'body' => 'required',
]);
5. バリデーション済み入力の抽出
リクエストでバリデーション済みの値を、safe()
メソッドを利用して簡単に取得できます。
※必要なキーだけ抽出や除外が可能
<?php
$validated = $request->safe()->only(['name', 'email']);
$validated = $request->safe()->except(['name', 'email']);
$validated = $request->safe()->all();
6. 条件付きルールの追加
動的なフォームの場合、ある入力値がチェックされている場合のみ特定のバリデーションを適用したい時は、exclude_if
ルールを使います。
<?php
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($data, [
'has_appointment' => 'required|boolean',
'appointment_date' => 'exclude_if:has_appointment,false|required|date',
'doctor_name' => 'exclude_if:has_appointment,false|required|string',
]);
7. 正規化処理(Normalize Validated Data)
フォームリクエストの passedValidation
フックを利用することで、バリデーション後にデータを整形できます。
※例:名前を先頭大文字に変換
<?php
protected function passedValidation(): void
{
$this->replace([
'name' => ucwords(strtolower($this->name)),
]);
}
8. 日付バリデーションの簡潔な記述
バリデーションルールで「today」「tomorrow」などの文字列を利用できるため、日付の条件が読みやすくなります。
<?php
$rules = [
'start_date' => 'required|date|after:tomorrow',
'end_date' => 'required|date|after_or_equal:start_date',
'past_date' => 'required|date|before:yesterday',
'deadline' => 'required|date|before_or_equal:today',
];
9. 入力の除外(Exclude Validated Input)
特定のフィールドをバリデーション済み配列から除外したい場合は、exclude
ルールを利用します。
<?php
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
'captcha' => 'required|exclude',
]);
dd($validated); // 'title' と 'body' のみが含まれる
}
10. 実在するメールアドレスのチェック
dns
ルールを利用して、存在するメールサーバーのあるメールアドレスかどうかチェックできます。
※テスト環境では freeEmail() を利用することを推奨
<?php
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'email' => 'required|email:dns'
]);
}
11. 配列のエラーメッセージ改善
配列の各アイテムでエラーが発生した場合、:index
や :position
プレースホルダを利用して、具体的な位置を示すエラーメッセージを表示できます。
<?php
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'photos.*.description' => 'required',
], [
'photos.*.description.required' => 'Please describe photo #:position.',
]);
12. Required If Accepted ルール
あるチェックボックスが選択されている場合のみ、別のフィールドを必須にするために、required_if_accepted
ルールを利用できます。
<?php
$validator = Validator::make($data, [
'subscribe_to_newsletter' => 'boolean',
'email' => 'required_if_accepted:subscribe_to_newsletter|email',
]);
13. 画像のサイズ検証
画像ファイルの幅、高さ、アスペクト比などを検証する場合、dimensions
ルールを利用して簡潔に定義できます。
<?php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
Validator::make($data, [
'avatar' => [
'required',
Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
],
]);
14. prohibitedIf ルール
条件に応じて、特定のフィールドに値が入っていること自体を禁止する場合は、prohibitedIf
ルールを利用します。
<?php
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
// 管理者の場合、role_id の入力を禁止する
Validator::make($request->all(), [
'role_id' => Rule::prohibitedIf($request->user()->is_admin),
]);
15. sometimes ルール
フィールドが存在する場合のみバリデーションを行い、存在しない場合はスキップするには、sometimes
ルールを使用します。
<?php
$validator = Validator::make($data, [
'email' => ['sometimes', 'email'],
]);
16. distinct ルール
配列内に重複する値がないかチェックするには、distinct
ルールを利用します。厳密な比較(型も考慮)も可能です。
<?php
use Illuminate\Support\Facades\Validator;
$posts = [
['title' => 'First Post'],
['title' => 'Second Post'],
['title' => 'First Post'], // 重複あり
['title' => 'Third Post'],
];
Validator::make($posts, ['*.title' => 'distinct:strict'])->fails(); // true
17. 現在のパスワード確認
アカウント削除などの際、ユーザーに現在のパスワードの確認を求める場合、current_password
ルールを利用するとシンプルです。
<?php
public function destroy(Request $request): RedirectResponse
{
$request->validate([
'password' => ['required', 'current_password:web'],
]);
// アカウント削除処理...
return to_route('home');
}
18. 条件付きバリデーション
特定の条件下でのみルールを適用したい場合、Validator インスタンスの sometimes
メソッドで柔軟に設定できます。
<?php
use Illuminate\Support\Fluent;
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'email' => 'required|email',
'games' => 'required|numeric',
]);
// games の数が 100 以上なら reason フィールドに必須・最大 500 文字のルールを適用
$validator->sometimes('reason', 'required|max:500', function (Fluent $input) {
return $input->games >= 100;
});
19. デフォルトのパスワードルールのカスタマイズ
Laravel のデフォルトパスワードルールを、環境に応じてカスタマイズすることで、コード全体で一貫性を保つことができます。
<?php
use Illuminate\Validation\Rules\Password;
public function boot(): void
{
Password::defaults(function () {
$rule = Password::min(8);
return $this->app->isProduction()
? $rule->mixedCase()->uncompromised()
: $rule;
});
}
// 利用例
'password' => ['required', Password::defaults()]
元記事
Discussion