Laravelによるバリデーションを組み込む方法
概論はここまでにして、実際にコードを交えてLaravelのバリデーションを体験していただきます。
入力画面やコントローラの作成
バリデーションのコードを紹介する前にまず、図1の画面とコントローラクラス、および、そのメソッドのルーティング登録を行いましょう。
入力画面はリスト1の内容です。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>入力画面</title> </head> <body> <h1>入力画面</h1> <form action="/firstlaravel/public/chap8/addData" method="post"> @csrf // ★ <label for="name"> 名前: <input type="text" name="name" id="name"> </label><br> <label for="height"> 身長: <input type="text" name="height" id="height"> </label><br> <label for="weight"> 体重: <input type="text" name="weight" id="weight"> </label><br> <label for="note"> コメント: <textarea name="note" id="note"></textarea> </label><br> <button type="submit">送信</button> </form> </body> </html>
HTMLの入力チェックはあえて含めないようにしています。なお、リスト1の★については、項末のNoteを参照してください。
次に、コントローラクラスです。これはリスト2の内容です。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class Chap8Controller extends Controller { public function showInput() // (1) { return view("chap8.input"); } public function addData(Request $request) // (2) { // (3) return "<h1>入力完了</h1>"; // (4) } }
ここではメソッドを2個記述しています。(1)がリスト1の入力画面を表示させるメソッドであり、(2)が入力画面の[送信]ボタンをクリックした時に呼び出されるメソッドです。(2)のメソッドに関しては、話を簡単にするために、特に処理を行わず、(4)のように画面に「入力完了」を表示させるだけにしています。この(3)の位置にバリデーション処理を追記していきます。その時に必要となるので、あらかじめ引数としてRequestオブジェクトをもらうようにしています。
この2メソッドをルーティング登録しましょう。web.phpにリスト3の2行を追記してください。
Route::get("/chap8/showInput", "Chap8Controller@showInput"); Route::post("/chap8/addData", "Chap8Controller@addData");
全ての追記が終了したら、次のURLにアクセスして図1の画面が表示されるか確認してください。
- http://localhost/firstlaravel/public/chap8/showInput
現状、何もバリデーションを含めていませんので、そのまま[送信]ボタンをクリックすると、画面に「入力完了」と表示されます。
Note:CSRF対策
Webの脆弱性を利用した攻撃のひとつとしてCSRFというのがあります。これは、クロスサイトリクエストフォージェリ(Cross-Site Request Forgeries)の頭文字を取ったものです。詳細は他媒体に譲りますが、これは本来拒否すべき他サイトからのリクエストを受信し、処理してしまう脆弱性のことです。Laravelには、デフォルトでこのCSRF対策が含まれており、formタグ内に@csrfディレクティブを記述することで実現できます。
Laravelのバリデーションはvalidate()メソッド
準備が整ったところで、リスト2の(3)にリスト4の太字のコードを追記していきましょう。これが、バリデーションのコードになります。
〜省略〜 public function addData(Request $request) { $request->validate([ // (1) "name" => "required", // (2) "height" => "required|numeric", // (3) "weight" => "required|numeric", // (4) ]); return "<h1>入力完了</h1>"; } }
Laravelでバリデーションを実行するには、リスト4の(1)のように、引数で渡されたRequestオブジェクトのvalidate()メソッドを実行するだけです。その際、引数として、(2)〜(4)のように、連想配列を渡します。連想配列には、キーとしてコントロールのname属性値、値としてバリデーションルール名を記載します。構文としてまとめると次のようになります。
$request->validate([ "name属性値" => "バリデーションルール名", : ]);
リスト4の(2)では、[名前]入力欄に必須チェックであるrequiredを指定しています。
[身長]入力欄である(3)と[体重]入力欄である(4)には、同じくrequiredだけでなく、数値かどうかのチェックを行うnumericも指定しています。このように複数のバリデーションを行う場合は「|」(パイプ)を記述して複数並べるか、次のように配列で指定します。
"height" => ["required", "numeric"]
なお、Laravelに標準で用意されているバルデーションルールはLaravelの公式ドキュメントで確認できます。また、詳細は割愛しますが、独自にルールを追加することもできます。
一通り、追記が終了したら、動作確認を行っておきましょう。図1の画面が表示された状態で、何も入力せずに[送信]ボタンをクリックしてください。これまで、画面に「入力完了」と表示されていたものが、リスト4の太字のコードを追記した途端、画面が遷移せずにもう一度図1が表示されてしまいます。この種明かしを次節で行なっていきましょう。
バリデーションメッセージの表示
コントローラにバリデーションのコードを追記した途端、画面遷移しなくなりました。これはどういうことでしょうか。その種明かしをしていきましょう。
バリデーションエラーの場合は入力画面表示URLへリダイレクト
入力画面から画面遷移しなくなったように見えますが、実は、これは遷移した先でもう一度入力画面に戻ってきているのです。その証拠に、図4のように各入力欄に正しい値を入力した上で[送信]ボタンをクリックした場合は、ちゃんと画面に「入力完了」と表示されます。
リスト4の(1)でvalidate()メソッドを実行した際、バリデーションエラーが見つかると、Laravelはそれ以降の処理を続行せずに、自動的に元の入力画面を表示するURLにリダイレクトする仕組みとなっています(図5)。
バリデーションメッセージはセッションに一時的に格納
とはいえ、このままでは何がどうエラーなのか全くわかりません。そこで、Laravelはリダイレクトすると同時に、バリデーションエラーメッセージをセッションに一時的に格納してくれます。これは、テンプレート変数$errorsでアクセスできます。入力画面では、このテンプレート変数を使って、該当メッセージを取り出して表示するコードを記載しておく必要があります。これが、リスト5になります。
〜省略〜 <h1>入力画面</h1> @if($errors->any()) // (1) <section style="border: 1px red solid"> <ul style="color: red"> @foreach($errors->all() as $error) // (2) <li>{{$error}}</li> @endforeach </ul> </section> @endif <form action="/firstlaravel/public/chap8/addData" method="post"> 〜省略〜
ここでは、h1タグとformタグの間にバリデーションメッセージを表示する領域としてsectionタグを配置しています。そしてバリデーションメッセージの有無で、このタグの部分全体の表示/非表示を切り替えています。その際、有効なのが(1)のany()メソッドです。
また、各々のメッセージは(2)のようにall()メソッドで取り出した配列をループさせることで取り出せます。
リスト5のコードを追記する前では、バリデーションエラーで戻ってきた際の画面が図1と同じ画面だったのに対し、追記した後では、図6のようにメッセージが表示されるようになります。
なお、このバリデーションメッセージはあくまで一時的にセッションに格納されているため、一度表示された瞬間にセッションから消えてしまいます(このような仕組みを「フラッシュメッセージ」といいます)。つまり、バリデーションメッセージが表示されるのは、バリデーションエラーが生じてリダイレクトされた時のみで、もう一度入力画面を表示させると、図1のようにメッセージのない入力画面となってしまいます。
個別のバリデーションメッセージ表示は@errorディレクティブ
図6、つまりリスト5のコードでは、バリデーションメッセージをまとめて表示させるような画面構成でした。これを、各入力欄の下に表示させるように、個別でバリデーションメッセージを表示させたい場合は、次のように@errorディレクティブを利用し、引数としてname属性を渡します。
<label for="height"> 身長: <input type="text" name="height" id="height"> </label> @error("height") <p>{{$message}}</p> @enderror
各々のバリデーションメッセージは$messageテンプレート変数で表示できます。
バリデーションメッセージのカスタマイズ
これで無事バリデーションを実装できるようになりましたが、図6を見てもわかるようにメッセージが英語のままです。これを日本語化するなど、メッセージをカスタマイズするにはどうすればいいのでしょうか。一番簡単なのは、これらバリデーションメッセージがまとめて記述されたresources/lang/en/validation.phpファイルがあるので、それを利用する方法です。このファイルパスにenとついていることからわかるように、これは英語用のメッセージファイルです。これを日本語化するには、resources/lang/に日本語を表すjaフォルダを作成し、同名のファイルを作成します。といっても、いちいち記述するのは面倒ですので、resources/lang/jaフォルダ内にvalidation.phpをコピーし、リスト6のように必要部分を書き換えることにしましょう。
<?php return [ 〜省略〜 "numeric" => ":attribute は数値で入力してください。", // (1) 〜省略〜 "required" => ":attribute の入力は必須です。", // (2) 〜省略〜 "attributes" => [ // (3) "name" => "名前", // (4) "height" => "身長", // (4) "weight" => "体重" // (4) ], ];
returnに続く連想配列に、バリデーションルール名がずらりと並んでいます。これらはアルファベット順になっていますので、numericとrequiredはすぐに見つかると思います。それを、リスト6の(1)や(2)のように書き換えてください。
ここで、:attributeがそのまま残っていますが、実は、この:attributeの部分にname属性値がそのまま挿入されるようになっています。するとバリデーションメッセージは、例えば次のように表示されてしまいます。
height の入力は必須です。
そこで、この:attributeの部分に独自の文字列を挿入できる仕組みがリスト6の(3)の部分です。オリジナルのvalidation.phpでは[]と空の連想配列となっていますが、ここに(4)のように、name属性値に対応する文字列を記述していきます。こうすることで、:attributeの部分にname属性値に応じて適切な文字列が挿入されるようになります。
最後に、このjaフォルダ中のファイルが適用されるように、アプリケーション全体の言語設定を日本語に変更しておきましょう。config/app.phpファイル中の次の部分を変更します。
'locale' => 'en',
これを、次のように日本語設定に変更してください。
'locale' => 'ja',
その上で、もう一度動作確認した画面が図7です。
無事、バリデーションメッセージが日本語化されています。
まとめ
今回は、入力チェックをLaravelに任せるバリデーション機能を紹介しました。
次回は、Laravelでデータベースを利用する方法を紹介します。