51
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel の FormRequest で sometimes を使いたい時は withValidator メソッド経由が良さ気

Last updated at Posted at 2017-07-03

Laravel 5.4 での話。

FormRequest を用いている時、特定のフィールドの Validate Rule を、そのフィールド自身の値以外を用いて適用するかどうか等を決定したいときがある。

そんな時に、どうしたら都合が良いだろうか考えてみたメモ。

まず結論

laravel formrequest sometimes とかで検索すると、 getValidatorInstance メソッドを使う例が出てくるけど、 多分 withValidator メソッドを使った方がいいよ。(主に test が書けるという理由で。)

Validator::sometimes

https://laravel.com/docs/5.4/validation#conditionally-adding-rules にあるように、何らかの条件を付与して、 Rule を適用するべきかどうかを判定することが出来る。

$v->sometimes('reason', 'required|max:500', function ($input) {
    return $input->games >= 100;
});

上記 URL に記載のある、この例だと、"games の値が 100 以上ならば、 reason を必須として、最大500文字以内とする"という条件となる。

games の値が 100 より小さい場合は、 reason は必須とならない。

Controller の中とかで、 Validator を用意して操作するぶんには、まぁ、これでも大丈夫。

FormRequest

https://laravel.com/docs/5.4/validation#form-request-validation のやつ。

Controller の Action で DI して使う便利なやつ。

rules メソッドで必要な KEY と対応する rule を定義するだけで使える。

    public function rules()
    {
        return [
            'email' => [
                'required',
                'email',
            ],
        ];
    }

と書いておくと、 email フィールドは必須かつ、 email 書式である、という条件で Validator が動いてくれる。

Controller の中とかで Validator を用意しなくて良いのでかなり見通しが良くなる。

それだけでも使う価値があると思う。(し、 unit test も少し楽になる。)

FormRequest + Validator::sometimes を使いたい

FormRequest を使って、先ほどの例の games の値によって reason に条件を付与したい場合どうしたら良いか。

ダメなやつ

    public function rules()
    {
        return [
            'reason' => [
                'sometimes',
                'required',
                'max:500',
            ],
        ];
    }

当然、これだと、 reason に値が存在する場合は必須かつ 500 文字以内となってしまう。

実現できるけどイマイチなやつ

https://stackoverflow.com/questions/30300119/how-to-use-sometimes-rule-in-laravel-5-request-class とか、 laravel formrequest sometimes で検索すると出てくる。

FormRequest を extends した自前の Request Class で getValidatorInstance を Override し、その中で sometimes メソッドを使う。

例えば、 app/Http/Requests/Some/Path/StoreRequest.php の中で、以下のように書く。

    protected function getValidatorInstance()
    {
        $validator = parent::getValidatorInstance();

        $validator->sometimes('reason', 'required|max:500', function ($input) {
            return $input->games >= 500;
        });

        return $validator;
    }

これは期待する通りに動く。

ただし、 parent::getValidatorInstance() してるので、 test を書く時に悲しい気持ちになる(はず)。

今のところ良さそうなやつ

FormRequest を extends した自前の Request Class で withValidator メソッドを使う。

https://laravel.com/docs/5.4/validation の 「Adding After Hooks To Form Requests」に良さそうな事が書いてある。

This method receives the fully constructed validator, allowing you to call any of its methods before the validation rules are actually evaluated:

つまり、 rules を評価する前の状態の Validator を受け取れるので、お好きにどうぞってことだと思う。

after フックはわかり易い例として、他にも Validator への"追加的措置"が必要ならココに書くのが良いんやないかな。

例えば、 app/Http/Requests/Some/Path/StoreRequest.php の中で、以下のように書く。

    public function withValidator(\Illuminate\Contracts\Validation\Validator $validator)
    {
        $validator->sometimes('reason', 'required|max:500', function ($input) {
            return $input->games >= 500;
        });
    }

こうすると parent:: も使わないので、 test しやすい!

51
43
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?