【Laravel】バリデーションの作成
簡単な掲示板アプリケーションを作成するつもりでバリデーションを学習してみたいと思います。
【1】 基本のバリデーションを作成する
以下のような構成を想定しています。
Boardの仕様
・投稿のタイトル (subject)、
・メールアドレス(email)、
・本文 (message) をフィールドに持っており、タイトルと本文は必須。
タイトルは 10文字、本文は 50 文字の制限をつける。
テストなので、文字数制限は少なめにしています。
BoardController:Board モデルを操作するためのコントローラー。
以下のアクションを設定
・indexアクション:ユーザーが投稿作成を行うページ。
・addアクション:投稿データを送信する先。
・投稿内容をバリデートし、問題なければ index ページにリダイレクト、間違っていれば index ページに戻しエラーを表示する。
ひとまず、バリデーションが通っても通らなくても index ページを表示させるものを作成して、肉付けしていきます。
テンプレートは以前の「星・月・太陽ページ」で作成したものを流用します。
ルーティング
\routes\web.php に以下を追記。
1 2 |
Route::get('board', 'BoardController@index'); Route::post('board', 'BoardController@add'); |
以前にも思いましたが、POSTアクセス、GETアクセス両方を書くのが正しいのかが、やっぱりまだわかりません。
なんとなく違和感がありますね。
コントローラー
\app\Http\Controllers\BoardController.php は以下のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
class BoardController extends Controller { /** * フォーム画面 * */ public function index(Request $request) { $data = [ 'msg' => '投稿内容を入力してください', ]; return view('board.index', $data); } /** * バリデーション設定 * */ public function add(Request $request) { $data = [ 'msg' => '正しく入力されました!', ]; $validate_rule = [ 'subject' => 'required|max:10', 'email' => 'email', 'message' => 'required|max:50', ]; $this->validate($request, $validate_rule); return view('board.index', $data); } } |
indexページには『投稿内容を入力してください』というメッセージを設定(表示)し、入力が問題なく行われた場合に『正しく入力されました!』というメッセージが表示されるようにしています。
addアクションの
1 2 3 4 5 |
$validate_rule = [ 'subject' => 'required|max:10', 'email' => 'email', 'message' => 'required|max:50', ]; |
にて、ルールの設定を行い、
1 |
$this->validate($request, $validate_rule); |
が、バリデーションを実行している部分となります。
ひとつの項目に複数のルールを設定したい場合はパイプ記号「|」にて連結することで設定可能。
subject(件名)に対してはrequired(必須)とmax:10(上限10文字)を設定しています。
ビュー
\resources\views\board\index.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
@extends('layout.common') @section('title', '投稿のページ') @section('keywords', 'キーワード1,キーワード2,キーワード3') @section('description', '投稿ページの説明文です') @section('pageCss') <link href="/css/star/index.css" rel="stylesheet"> @endsection @include('layout.header') @section('content') <h2>このページは投稿ページです。</h2> <p>{{ $msg }}</p> <form action="/board" method="post"> {{ csrf_field() }} <table> <tr> <th>件名</th> <td><input type="text" name="subject"></td> </tr> <tr> <th>メールアドレス</th> <td><input type="text" name="email"></td> </tr> <tr> <th>メッセージ</th> <td><textarea name="message"></textarea></td> </tr> <tr> <td colspan="2"><input type="submit" value="送信"></td> </tr> </table> </form> @endsection @include('layout.submenu') @include('layout.footer') |
star.blade.php をコピーして書き換えています。
画面表示
フォーム3つにデータを入力して「送信」ボタンをクリックします。
上部に表示されているメセージが『投稿内容を入力してください』から『正しく入力されました!』になりましたが、ただそれだけです。
試しに再度フォーム画面を表示して、何も入力せずに「送信」ボタンをクリックしてみますと、ページ遷移も何もしません。
今のところは仕様通りの動きをしていますが、これでは何もわからないですし使い物になりませんが、徐々に理解を深めていきたいと思います。
【2】 エラーメッセージと値の保持
先程作成した基本形のバリデーションへ肉付けを行っていき、使えるものとしていきたいと思います。
以下の2点に関して、機能追加したいと思います。
1. エラーメッセージの表示(何がどう悪いのかを投稿者に伝える)
2. 再入力の際には、先に入力した内容をセットしておく(項目が100個あるフォームがすべてクリアされたりすると確実に誰も投稿しないw)
ビューの修正
まずは、エラーがある場合はその旨のメッセージをフォーム上部にまとめて表示させてみます。
indexの @section('content') を以下のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
@section('content') <h2>このページは投稿ページです。</h2> <p>{{ $msg }}</p> @if (count($errors) > 0) <div class="errormessagebox"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form action="/board" method="post"> {{ csrf_field() }} <table> <tr> <th>件名</th> <td><input type="text" name="subject" value="{{old('subject')}}"></td> </tr> <tr> <th>メールアドレス</th> <td><input type="text" name="email" value="{{old('email')}}"></td> </tr> <tr> <th>メッセージ</th> <td><textarea name="message">{{old('message')}}</textarea></td> </tr> <tr> <td colspan="2"><input type="submit" value="送信"></td> </tr> </table> </form> @endsection |
(結果)画面表示
各フォームの要件を満たさないようにデータ入力して「送信」ボタンをクリックします。
すると、、、
1. なにやら英語のメッセージが表示された
2. 入力した内容もそのまま表示された
と、上で挙げた、1、2にうまく対応できました。
なお、メッセージは上から、
「件名」は必須です
「メールアドレス」はemailの形式で入力してください
「メッセージ」は50文字以内で入力してください
となり、想定通り(仕様通り)のメッセージとなっていますね。
エラーメッセージ、送信内容を表示する仕組み
エラーメッセージ
エラーメッセージの表示処理は結構単純ですね。
if文で、 $errors という配列(オブジェクト?)をcount関数で判定しているだけです。
$errors に関しては、バリデーションが自動的に作成してくれる便利機能のようで、開発者が値に関して設定やらをする必要はなく、結果をまとめて作成してくれるとのこと。
素晴らしい。
$errors の内容はどうなっているのかを確認すると、以下のようになっていました。
(ビューの)if文の前に 簡単にデバッグができる魔法の言葉 {{ dump($errors) }} を書きます。
デバッグされましたが、(慣れていないので)よくわからんw
単純に var_dump() した内容も載っけておきます。
1 2 3 4 5 |
{ "subject":["The subject field is required."], "email":["The email must be a valid email address."], "message":["The message may not be greater than 50 characters."] } |
それぞれの項目に対応するエラー内容のメッセージがセットされています。
なるほどですね。
配列化されているので、 foreach でぐるぐる回して表示しているだけです。
bladeテンプレートでの foreachになっているので少し注意です。
送信内容
送信内容に関しては、単純に各フォームの value に値を設定するという方法で実現しています。
old() というメソッドを使用しているだけ。
old()メソッドは、引数に指定した入力項目の古い値(現在の値が設定される前の値)を返すという便利関数。
コントローラーでの作業は一切せず、ビューファイルへの記述だけで処理を行ってくれます。便利!
ひとまずここまで。
と思いましたがせっかくなので、項目ごとのエラーメッセージの取得方法も追加します。
【3】バリデーションエラーを項目ごとに表示する
ビュー
まとめて表示するのが出来ましたので、次は項目ごとに表示させてみたいと思います。
先と同じように、index.blade.php の @section('content') を以下のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
@section('content') <h2>このページは投稿ページです。</h2> <p>{{ $msg }}</p> <form action="/board" method="post"> {{ csrf_field() }} <table> @if ($errors->has('subject')) <tr> <th>ERROR</th> <td>{{$errors->first('subject')}}</td> </tr> @endif <tr> <th>件名</th> <td><input type="text" name="subject" value="{{old('subject')}}"></td> </tr> @if ($errors->has('email')) <tr> <th>ERROR</th> <td>{{$errors->first('email')}}</td> </tr> @endif <tr> <th>メールアドレス</th> <td><input type="text" name="email" value="{{old('email')}}"></td> </tr> @if ($errors->has('message')) <tr> <th>ERROR</th> <td>{{$errors->first('message')}}</td> </tr> @endif <tr> <th>メッセージ</th> <td><textarea name="message">{{old('message')}}</textarea></td> </tr> <tr> <td colspan="2"><input type="submit" value="送信"></td> </tr> </table> </form> @endsection |
各項目の上にテーブルタグを含んだ if文を挟み、firstメソッドでエラーメッセージを取り出して表示している構成です。
この状態でフォームに何も入力せずに送信ボタンを押すと、以下のようになります。
↑ 指定箇所に、エラーメッセージが表示されました
hasメソッド / firstメソッド
@ifディレクティブで $errors->has('subject') としていますが、この has はエラーが発生しているかをチェックするメソッドで、以下のように指定して実行できます。
1 |
$errors->has( 項目名 ) |
firstメソッドは指定した項目の最初のエラーメッセージを取得するものです。
以下のようにして利用します。
1 |
$errors->first( 項目名 ) |
これでエラーメッセージが取得できます。
今回の場合だと、$errors->first('subject') で件名フォームの「最初の」エラーが取得可能です。
「最初の」とわざわざカッコ書きしているのには理由があり、検証ルールが複数設定されている場合で、例えば2つのエラーが発生した場合でも「最初のエラーメッセージのみ」が取得されます。
getメソッド
1つの項目(フォーム)に検証ルールを複数設定し、発生した全てのエラーメッセージを取得したい場合は、getメソッドを利用すれば取得可能です。
getメソッドは以下のようにして利用します。
1 |
$変数 = $errors->get( 項目名 ); |
引数には取得したい項目名を指定します。
戻り値にはその項目で発生した全てのエラーメッセージが配列でまとめられます。配列で返るので、変数化する、foreachで順次表示する、などのように使用することが可能です。