
バリデーションとは
入力されたデータが、条件や形式と合っているかチェックするものです。

「バリデーション」という言葉を知らなくても、画像のようなエラーメッセージを見たことはあるかと思います。このように正しく入力しないと進めないのは、バリデーションと呼ばれる入力チェックが行われているからなんです。
バリデーションを書いてみよう
記述場所はコントローラー・フォームリクエストの2通りありますが、当記事ではコントローラーに記述する方法について見ていきます。
コントローラーの記述方法も2通りあります。
・validateメソッドを使用
・Validatorファサードを使用
validateメソッドは手軽ですが応用があまり効きません。Validatorファサードは少し記述が増えますが、エラー時のリダイレクト先を指定など独自の処理を行うことが可能です。
validateメソッドで書く
validateメソッドのエラー時は、自動でリクエスト元(入力ページ)にリダイレクトします。
validateメソッドを使用した書き方は、2通りあります。
// パイプ区切り
$request->validate([
'email' => 'required|email|unique:users',
'name' => 'required',
]);
// 配列
$request->validate([
'email' => ['required', 'email', 'unique:users'],
'name' => ['required'],
]);
例では、「required(必須入力)」「email(メールアドレスのフォーマットかどうか)」「unique:users(usersテーブルに登録済みではないか)」をチェックしています。
どちらの書き方も同じように動きますが、正規表現でパイプ「 | 」を使用するときは配列で書く必要があります。下の例では、正規表現「/^(090|080|070)-\d{4}-\d{4}$/」で携帯の電話番号かどうかをチェックしています。
// パイプ区切り(エラーになる)
$request->validate([
'tel' => 'required|regex:/^(090|080|070)-\d{4}-\d{4}$/'],
]);
// 配列
$request->validate([
'tel' => ['required','regex:/^(090|080|070)-\d{4}-\d{4}$/'],
]);
Validatorファサードで書く
$validator = Validator::make($request->all(), [
'email' => 'required|email|unique:users',
'name' => 'required',
]);
if ($validator->fails()) {
return redirect("/input")
->withErrors($validator)
->withInput();
}
例はパイプ区切りで記述していますが、配列でも大丈夫です。
Validationファサードは、リダイレクト先を指定する必要があります。また、エラーメッセージを表示するにはwithErrorsでエラーを渡す必要があります。withInputは入力済みの値を渡し、リダイレクト先のviewで {{ old(‘email’) }} で取得することができます。
エラーメッセージを表示させよう
エラーメッセージの表示
foreachで発生しているエラーすべてを表示します。
// すべてのエラーメッセージを表示
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
error(‘ ’)で特定のエラーだけ表示することが可能です。
// 特定のエラーメッセージを表示
<label for="title">Post Title</label>
<input id="title" type="text" name="title" class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
エラーメッセージのカスタマイズ
エラーメッセージは、何も指定しなければ validation.php の内容が表示されます。そのため、すべての箇所共通でメッセージを変えたい場合は validation.php の内容を変更すればOKです。
// resources/lang/ja/validation.php
'distinct' => ':attributeには異なった値を指定してください。',
'email' => '有効なメールアドレスを指定してください。',
'ends_with' => ':attributeには、:valuesのどれかで終わる値を指定してください。',
特定の箇所だけメッセージを変えたいような場合はコントローラー内で記述します。
// validateメソッドの場合
$request->validate([
'email' => ['required', 'email', 'unique:users'],
],
[
'email.required' => 'メールアドレスの入力は必須です',
'email.email' => 'メールアドレスの形式が正しくありません',
'email.unique' => '既に登録されているメールアドレスです',
]);
// Validatorファサードの場合
$validator = Validator::make($request->all(), [
'email' => 'required|email|unique:users',
'name' => 'required',
],
[
'email.required' => 'メールアドレスの入力は必須です',
'email.email' => 'メールアドレスの形式が正しくありません',
'email.unique' => '既に登録されているメールアドレスです',
]);
if ($validator->fails()) {
return redirect("/input")
->withErrors($validator)
->withInput();
}
ルールごとにメッセージをカスタマイズできます。uniqueのメッセージだけカスタマイズしたい場合は、uniqueだけ記述すればrequiredとemailはデフォルトのメッセージを表示できます。
開発中に直面した問題
バリデーションエラー時に無限ループ
Cメソッド内でBのバリデーションに失敗した際、無限ループが起こってしまいました。
public function A(Request $request) {
}
public function B(Request $request) {
// Aのバリデーション →エラー時はGETでAに戻る
}
public function C(Request $request) {
// Bのバリデーション →エラー時はGETでBに戻る
}

原因は、CでバリデーションエラーになったときにBにAの値を渡せていなかったため、Bでも必ずバリデーションエラーになり無限ループ…という状態でした。
そこで、$_SERVER[‘REQUEST_METHOD’] を用いてブラウザからのリクエストがGETかPOSTかを判別し、GETの場合はAのバリデーションを行わないようにすることで解決しました。
public function A(Request $request) {
}
public function B(Request $request) {
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// Aのバリデーション
else {
// バリデーションは行わない
}
}
public function C(Request $request) {
// Bのバリデーション
}
バリデーションエラー時にThe payload is invalid.エラー

// 修正前
// app/Http/Controllers/AuthController.php
public function input(Request $request) {
$encrypt_email = $request->input('email'); // バリデーションエラー時はnull
$decrypt_email = Crypt::decryptString($encrypt_email);
// nullの値を復号化(decrypt)しようとしてるためエラー発生
// 省略
}
public function confirm(Request $request) {
$validator = Validator::make($request->all(), [
// 省略
]);
if ($validator->fails()) {
return redirect('/input')
->withErrors($validator)
->withInput();
}
// 省略
}
confirmメソッドからinputメソッドにリダイレクトした際、$encrypt_emailがnullのため暗号化できないよというエラーでした。
こちらも同じくGET/POSTで条件分岐を行いました。
リダイレクト先にパラメーターで$encrypt_emailを持たせ、バリデーションエラー時はパラメーターの値を取るようにすることで解決しました。
// 修正後
// app/Http/Controllers/AuthController.php
public function input(Request $request) {
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$encrypt_email = $request->input('email');
$decrypt_email = Crypt::decryptString($encrypt_email);
} else {
$encrypt_email = $request->query('e'); // バリデーションエラー時はパラメーターで値を取得
$decrypt_email = Crypt::decryptString($encrypt_email);
}
// 省略
}
public function confirm(Request $request) {
$encrypt_email = $request->input('email');
$validator = Validator::make($request->all(), [
// 省略
]);
if ($validator->fails()) {
return redirect('/input?e=$encrypt_email') // パラメーターで$encrypt_emailを渡す
->withErrors($validator)
->withInput();
}
// 省略
}
さいごに
エラーの解決、そんなに難しいことはしていないですが苦戦しました。。
(途中諦めて全部if文で書こうとしました。笑)
バリデーションは苦手意識がありましたが、今回ちゃんと学び、エラーも乗り越えたことで克服できた気がします!