LoginSignup
0
0

【laravel】required_ifをANDで繋げるような振る舞いがしたい

Last updated at Posted at 2024-05-02

前置き

laravelのバリデーションでは条件を簡便に書くことができる
これ自体は便利なのだが、複雑なことをやろうとすると若干物足りないことがある。

やりたいこと

0と1の値を持つラジオボタンが2項目ぶん、項目AとBとして用意されており、その直下にテキストエリアが項目Cとして用意されている。

<input name="radioa" value="0" type="radio" checked>
<input name="radioa" value="1" type="radio">

<input name="radiob" value="0" type="radio" checked>
<input name="radiob" value="1" type="radio">

<textarea name="textc"></textarea>

このラジオボタンの両方が1の場合のみ、テキストエリアが空欄かどうかのチェックをしたい。

required_ifを使う(失敗)

このようなとき、laravelのバリデーションの機能を使おうとすると大抵はrequired_ifが思い浮かぶ。
片方のラジオボタンだけ見るのなら、radioaが1のときtextcの内容を確認したいので、

'textc' => 'required_if:radioa,1',

とすればいいが、
これに加えてradiobも見たいとなると

'textc' => 'required_if:radioa,1|required_if:radiob,1|emoji',

これではradioaかradiobのどちらかが1のときにrequiredのチェックが走ってしまいうまくいかない、つまりOR条件になってしまう。
条件をつなぐパイプ(|)を&に変えたらどうだろうかなどと考えたがだめだった。(それはそう)

クロージャで対処(成功)

いろいろ調べたが、required_ifだけではandのような挙動をもたせることはできないようなので、おとなしくクロージャを使うことにした

'textc' => [
    // required_ifではORになり要件を満たせないのでクロージャを使う
    function ($attribute, $value, $fail) use ($request) {
        // 入力データの取得
        $input_data = $request->all();
        // radioaとradiobがどちらも1の場合
        if ($input_data['radioa'] === '1' && $input_data['radiob'] === '1') {
            // textcが空欄か
            if (empty($input_data['textc'])) {
                $fail('エラーメッセージ');
            }
        }
    },
    // 上記以外にも条件があれば続けて書く
    'max:1000',
],

FromRequestを継承している場合はuse以降は不要で、$this->all()で読み出せる。

こういう特殊な条件はだいたいそのフォーム固有のことが多いのでクロージャでの対応でもまぁ問題ないと思われ。
もしあちこちで使うならばRulesに定義して読み出すほうが簡潔で綺麗。

0
0
0

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
0
0