日記

日々のことと、Python/Django/PHP/Laravel/nodejs などソフトウェア開発のことを書き綴ります

Laravel 5.1 入門記 その14(Form Request とメッセージのカスタマイズ編)

今回は Eloquent からはちょっと離れて、Request とメッセージリソースのことを。

Validation - Laravel - The PHP Framework For Web Artisans

Localization - Laravel - The PHP Framework For Web Artisans

オフィシャルドキュメント的には、明確にココというページが無いけど上記の2ページを主に参考に。

Request を使ったバリデーション

気が付いたら入力値のバリデーションについて、いままで記事にしていなかった模様。

Laravel にも他の Web フレームワークと同様に宣言的なバリデーションが用意されてます。Controller にバリデーションも定義できるけど、王道的には Request クラスを作って実装するのが良いらしい。簡単に入力値パラメータに対してバリデーションルールを定義すると、こんな感じです。

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class UserEditRequest extends Request
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'login_id' => 'required|between:3,16|unique:users,login_id',
            'password' => 'required|between:8,32|confirmed',
        ];
    }

}

これはユーザ情報のログインIDとパスワードの入力に対してバリデーションを設定した例で、Request のバリデーションルールは rules メソッド連想配列を定義します。連想配列のキーがフォームの入力パラメータ名です。

このように定義した Request を Controller 側で使用する場合は、以下の様に引数できっちりクラス名を指定して受け取ります。

    public function editUser(UserEditRequest $request)
    {
        // バリデーション後の処理
    }

コントローラ側に Request インスタンスがインジェクションされてパラメータが渡ってくる時には、バリデーションが行われた後になり、コントローラ側では特に入力値のバリデーションは意識せずに実装することができます。 きっちりコンポーネントを分けずに大きめのロジックを実装していくと、コントローラクラスの実装は巨大で見通しが悪く、メンテナンスしにくいものになりがちですが、入力値のバリデーションくらいは Request に分けた上で、宣言的バリデーションのフレームワークを活用して実装していきたいものですね。

バリデーションルールの種類について

    public function rules()
    {
        return [
            'login_id' => 'required|between:3,16|unique:users,login_id',
            'password' => 'required|between:8,32|confirmed',
        ];
    }

上記のサンプルコードで使っていたバリデーションルールの定義は、全て最初から Laravel に組み込まれているルールです。Laravel で用意されているバリデーションルールはドキュメントに記載されているので、下記のページを参照してください。自分で頑張る前に、一通り目を通すことをオススメします。

http://laravel.com/docs/5.1/validation#available-validation-rules

サンプルで使っているコードを簡単に解説します。

required

入力値が存在することをチェックします。

between

入力値の文字数が指定した文字数の範囲にあることをチェックします。 サンプルコードの例だとそれぞれ、3〜16文字と8〜32文字の範囲の文字数であることのチェックとなります。

unique

テーブル上でユニークな値が設定されていることをチェックします。unique の定義に書いたパラメータから SQL を発行して テーブル名,カラム名 で勝手に調べてくれます。ただ、この例では自分自身に保存されているログインIDも引っかかってしまうので、ちょっと工夫が必要で、以下のように Request に編集中のユーザ自身の ID を渡してあげて、それを unique のルールに設定したりする必要があります。

    public function rules()
    {
        $id = ($this->has('id')) ? ',' . $this->input('id') : '';
        return [
            'login_id' => 'required|between:3,16|unique:users,login_id'.$id,
            'password' => 'between:8,32|cms_user_password|confirmed',
        ];
    }

unique はクセがあるので、オフィシャルドキュメントを読んでから使うのをオススメします。

confirmed

パスワード入力の「確認欄」に対応するバリデーションルールで暗黙的に password と password_confirmation フィールドに同じ値が入力されていることをチェックします

バリデーションエラーのメッセージをカスタマイズ

Laravel は開発が英語で行われていて、当然デフォルトのバリデーションエラーメッセージは英語。

エラーメッセージは resources/lang/en/validation.php に書かれています。ディレクトリを見ても想像つきますが、日本語のエラーメッセージファイルは resource/lang/ja/validation.php を作って書いていきます。 Laravel 5.1 のファイルに関しては、ララ帳の人が翻訳版を作ってくれているので、それを使うと良いと思います。

Laravel 5.1 日本語エラーメッセージファイル | ララ帳

実案件でも使わせてもらいました。感謝。 この日本語のファイル利用に合わせて、config/app.php の locale を 'ja' に変更すると、日本語のリソースファイルを優先的に使用してくれます。

エラーメッセージの定義を見ると The :attribute field is required. と書かれています。途中 attribute: という部分があり、ここにはパラメータの論理的な名前を入れるためのシンタックスです。この attribute は、validation.php の終わりにある 'attributes' の連想配列にパラメータ名 => 論理名の対で定義が必要です。

ただ、やり方だとエンドユーザに見える画面と管理側の画面で、フィールド名を変えたい時に対応しにくい。そのため Request クラスに attribute を設定する方法もあり、以下の様にします。

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class UserEditRequest extends Request
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'login_id' => 'required|between:3,16|unique:users,login_id',
            'password' => 'required|between:8,32|confirmed',
        ];
    }

    public function attributes() {
        return [
            'login_id' => 'ユーザID',
            'password' => 'パスワード',
        ];
    }
}

attributes メソッドを作り、そのメソッド連想配列でパラメータ名と論理名を返せば OK。フィールドの名前だけではなく、Request クラス上でバリデーションエラーのメッセージを変更することもできます。

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class UserEditRequest extends Request
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'login_id' => 'required|between:3,16|unique:users,login_id',
            'password' => 'required|between:8,32|confirmed',
        ];
    }

    public function attributes() {
        return [
            'login_id' => 'ユーザID',
            'password' => 'パスワード',
        ];
    }

    public function messages() {
        return [
            'login_id.unique' => '指定のログインIDは既に使われています',
        ];
    }
}

この例では login_id が unique バリデーションに引っかかってエラーが出たときに使用するメッセージを login_id.unique として定義してます。login_id.required とすれば必須チェックで引っかかった時のメッセージを定義できるし、required だけで定義すればフィールド関係なしに required のバリデーションエラーメッセージを置き換えできます。

最初、使っていた時にうまいメッセージ変更の方法が分からなかったけど、この実装方法を理解した時点から、一気に色々実装しやすくなった気がします。バリデーションルールは自分で拡張できるし便利。この辺りを理解して実装するかで、Laravel の利用価値や、楽できる度合いが随分と変わってくると思う。特に Ajax な通信でバリデーションをするときには、レスポンスの加工はしにくいから、ちゃんと Laravel のやり方を理解して使うことは重要そう。

ちなみにカスタムバリデーションルールは、↓のドキュメントに載ってるので、それを見れば大体作れると思う。

http://laravel.com/docs/5.1/validation#custom-validation-rules

HTMLへのエラーメッセージのレンダリングを考えて見たらやってないけど、まぁいいか…。 Laravel 5になって、HTML Form のコンポーネントは本体から外れてしまったので、色々書きにくいのだよね。

とりあえず、今回はこれで終了。