Laravelで複数カラムのvalidation

LaravelのValidationは便利。

http://laravel.com/docs/4.2/validation#basic-usage にある例を引用すると

$validator = Validator::make(
    array(
        'name' => 'Dayle',
        'password' => 'lamepassword',
        'email' => 'email@example.com'
    ),
    array(
        'name' => 'required',
        'password' => 'required|min:8',
        'email' => 'required|email|unique:users'
    )
);

こんな感じで、第1引数にvalidateしたい配列を、第2引数にvalidationのruleを渡すとvalidationができる。

modelのvalidationをしたい時は、formなりpostのdataなりで受け取ったデータに対してvalidationをかければいいので、例えばこんな感じになる。

    $rules =     array(
        'name' => 'required',
        'password' => 'required|min:8',
        'email' => 'required|email|unique:users'
    );

    $validator = Validator::make(Input::all(), $rules);

validationは元々色々用意されているけど、これは拡張できる。

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

アプリケーションによって色々な仕様があるので、独自にvalidationを簡単に拡張できて手軽に使えるのは便利だと思う。

ただ、カラムごとにvalidationする形になっているので、複数のカラムに条件がまたがる場合のvalidationが書けない。(と思っていた)

(そもそも設計が良くないのかもしれないが)こういう場合にcontrollerとかにvalidation的なことを書くと辛くなってくるのでなるべくmodelとかに収めておきたい。

で、書けないと思っていたわけだが、実は書ける。良いやり方かどうかは知らない。

validationの拡張の仕方は2種類ある。

1つはクロージャを使う方法、もう1つはクラスを使う方法。

Validator::extendを使う点は同じだが、前者は第2引数に直接クロージャで関数を渡す。(例はさっきのページから引用)

Validator::extend('foo', function($attribute, $value, $parameters)
{
    return $value == 'foo';
});

後者は第2引数に呼び出すクラス名を渡す。

Validator::extend('foo', 'FooValidator@validate');

validatorで使うクラスを新たに追加した場合は、それをresolverに登録してあげる必要がある。それが以下のところ。

Validator::resolver(function($translator, $data, $rules, $messages)
{
    return new CustomValidator($translator, $data, $rules, $messages);
});

ここで、この$dataには全てのカラムの情報が入っているので、この情報を使うことで、他のカラムの情報も使ってvalidationができる。

これはIlluminate\Validation\Validatorを継承しているクラスでは、$this->dataとしてアクセスできる。

例などは以下のあたりを参考に