Laravel5のフォームバリデーション

プログラマが最も面倒臭がるところです。実際実装していてあまりおもしろいところじゃない。
いちばんわかりやすいやり方は、入力されたPOST値のバリデーションはPOST値をうけるコントローラで行います。

バリデーションの実装

POST値をうけるコントローラの最初あたりでやるのがよいかと思います。save()とかする手前とか。

public function complete(Request $request) {
    // do to validate
    $this->validate($request, [
        'Email' => 'required|email',
        'Password' => 'required|min:4',
    ]);
    ....
}

$request->input(‘Email’),$request->input(‘Password’)が送信されてきた際には上記のコードでバリデーションができてしまいます。
具体的なバリデーションルールは、Laravel 5.4 バリデーションの「使用可能なバリデーションルール」にいっぱいのってます。

このバリデーションは、ValidatesRequestsトレイトで行っています。デフォルトでどのコントローラでも$this->validate()だけで利用可能になってます。このトレイトの実際はパスはここあたりにあるので、コード見てみるとよいでしょう。

vendor/laravel/framework/src/Illuminate/Foundation/Validation/ValidatesRequests.php

エラーメッセージを返す

バリデーションが通るとそのままコントローラの残りの部分が実行されますが、ひっかかったときは上記のコードのままだとただ戻されるだけ(実行されないだけ)になります。エラーメッセージをFrontに返したい場合はエラーを取得して返す必要があります。
バリデーションエラーは全部自動的にフラッシュデータとしてセッションへ保存されます。コントローラでエラーを取得してbladeのFront画面へ返してやるという作業になりますが、手順は簡単です。最初にuseで

use Illuminate\View\Middleware\ShareErrorsFromSession;

という感じでエラーを取得する準備をしてあげます。
それからbladeでエラーを出力します。入力フォームのあるbladeテンプレートに書いてあげます。コントローラで処理されたバリデーションがここに戻ってくるという仕組みです。

@if (count($errors) > 0)
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

foreachしてあげるとわかりますが、オブジェクトには0から順番にエラーが入ってきます。後はよしなに加工すればよいのですが、ここまで荒削りだと実際の制作ではあまり使えません。実際に入力フィールドの下部などにわかりやすく表示するには、

<input type....>
{{$errors->first('Email')}}
<input type....>
{{$errors->first('Password')}}

という感じで、firstメソッドを使います。

バリデーションをカスタマイズする

Laravelのバリデーションは本来requestクラスでやるのがよいようです。requestクラスはコントローラが実行される前よりも先に読み込まれるので、無駄な処理を走らせないという意味でも結構いい感じになります。
app/Http/Requests/*にクラスファイルがあります。デフォルトではRequest.phpが作成されています。これを使ってもいいし、これじゃないものを使ってもいいです。が、結局はFormRequestを継承しているだけなので、つまりは継承していればどのリクエストクラスを使ってもよいことになります。
ここではartisanで新規のリクエストクラスを作ってみます。

php artisan make:request StoreRequest

app/Http/Requests/StoreRequest.phpが作成されます。FormRequestを継承しているのとauthorize()とrules()関数があらかじめ雛形として書かれています。先にコントローラで実装した$this->validate()の中身はrules()メソッド内に書くことができます。またリクエストクラスに分離した場合、コントローラ側ではバリデーション結果の後の処理のみを行うことになります。
コントローラ側では、新しいリクエストクラスをuseして、引数にそのメソッド名を明示的に書いてあげる必要があります。

....
use App\Http\Requests\StoreRequest;
....
public function complete(StoreRequest $request) { ← StoreRequestを明示的に!
    // このバリデーション処理はリクエストでやる
    // $this->validate($request, [
    //  'Email' => 'required|email',
    //  'Password' => 'required|min:4',
    //]);
    ....
}

StoreRequest.phpのrules()の中にバリデーション処理を入れます。
またauthorize()の返り値はtrueにしておきましょう。(ちゃんとコードまだ見てないですが、trueにするとちゃんと動きます。)

public function authorize()
{
    return true;
}

public function rules()
{
    return [
        'Email' => 'required|unique:lavel_users|email',
        'Password' => 'required|min:4',
    ];

}

ここまででバリデーションをコントローラから切り離すことができました。

バリデーションの日本語化

バリデーションエラーは元々あるバリデーションのエラーメッセージを後から修正する方法と、元々のエラーメッセージを日本語化する方法があります。
ここでは日本語化するところからやります。
まずは日本語の方を優先的にレスポンスするようにconfig/app.phpのlocaleの値を変更します。

//config/app.php
....
'locale' => 'ja',
....
'fallback_locale' => 'ja',
....

これで日本語が優先されます。
エラーメッセージの日本語を作成します。その前にデフォルトの英語のエラーメッセージが設定されている箇所を確認します。

resources/lang/en/validation.php

連想配列でエラーメッセージが書かれています。これを、

resources/lang/ja/validation.php

に日本語版を作成してあげるということになります。なかなか優れものです。該当の項目を日本語にしてあげるだけでOKです。
gibhubにも日本語版のvalidation.phpがいっぱいありました。
:attributeが変数的なものになっていて該当のバリデーションの項目を表示します。デフォルトではバリデーションルールを設定した際の値が英語のまま入ってくるのでこの項目も日本語にしてあげます。
(ここで私はちょっとハマったのですが、validarionルールで設定した値(つまりFormのnameで指定した値)を設定することになっていました。ここ注意)

return [
    'Email' => 'required|unique:lavel_users|email',
    'Password' => 'required|min:4',
];

バリデーションルールが上記のような感じだと、

'attributes' => [
    'Email' => 'Emailアドレス',
    'Password' => 'パスワード',
],

EmailもPasswordも頭が大文字設定なのでattributesでも頭大文字で指定。

参考:
Laravel5でのValidationMessageを日本語化してみた
Laravelのデフォルトログイン処理でエラーメッセージを日本語にしたい

Ajaxでレスポンスする

昨今のモダンなUI実装という意味では実際に必要になってくるバリデーションはAjaxで返すのがいちばん無難な気がします。
AjaxでもってPOSTした際にJSONの返り値を得るには何もしなくていいっていうのがすごいですね。何かしないといけないと思って調べていたら何もしなくてよかったです。POSTするURIに対してajaxしてあげるだけで、バリデーションを設定した際のエラーがjsonで返ってきます。
上記の例では、complete()メソッドを実行するURLにajaxする感じです。POST値を空にすると以下のようなJSONフォーマットのレスポンスが返ってきます。(ステータスが422で返ってくるんですね。このステータスコードもなんか現代的です。)

{
    "readyState":4,
    "responseText":"{
        \"Email\":[\"validation.required\"],
        \"Password\":[\"validation.required\"]
    }",
    "responseJSON":{
        "Email":["validation.required"],
        "Password":["validation.required"]
    },
    "status":422,
    "statusText":"Unprocessable Entity"
}

各種マニュアルではエラーメッセージがJSONで返ってくるみたいなことになっていましたが、私の場合は、エラーメッセージではなくresponseTextとresponseJSONでもってひっかかったバリデーションの種別が返ってくるといった感じでした。
また成功時にはJSONではなく、完了画面の標準出力というかhttpの返り値がそのまま返ってきました。


Laravel 5.4 バリデーション
Laravel 5.1 入門記 その14(Form Request とメッセージのカスタマイズ編)
LaravelのformバリデートでAjax通信時のエラーを独自のフォーマットに変更する

Last update: 2017.06.06 (火)