🔎

Laravel 配列のバリデーションで、ちょっと留意しておきたい点

2021/07/16に公開

Laravel 8.50で Validator::excludeUnvalidatedArrayKeys(); なる機能が追加されました。この機能を見がてら、Laravel で配列をバリデーションする際に、少し留意しておきたい点も確認してみます。

参考:GitHub [8.x] Add Validator::excludeArrays() to exclude .... #37943
参考:本家ドキュメント

現在、Laravel では、コントローラや FormRequest でバリデーションする際、
validate() 又は validated() メソッドを使って、バリデーションを通ったデータ(列挙した項目のみ)が返ってきますね。

まぁ、それは私でも知っている内容ですが、配列の場合は、そうではなかったんですね。
配列と言っても、幾つかタイプがあると思いますが、例えば次のような場合、

(コントローラを想定)

    $input = [
        'user' => [
            'name' => 'taro',
            'admin' => true,
        ],
    ];

    $data = validator()->validate($input, [
        'user' => ['required', 'array'],
        'user.name' => ['required'],
    ]);

    dd($data);

dd($data); の結果は、

array:1 ["user" => array:2 ["name" => "taro"
    "admin" => true
  ]
]

'admin' の方は、バリデーションしてないのに、$data に含まれてしまっているんですね。これはちょっと嬉しくないです。

ではどういう対策があるかと言うと、'array'にオプションで項目を指定して、以下のようにしてやれば OK となります。(項目複数あったらカンマ区切り)

    $data = validator()->validate($input, [
        'user' => ['required', 'array:name'], // ここ
        'user.name' => ['required'],
    ]);

こうすれば、'admin' などという項目が飛んできたら、バリデーションエラーになります。

一方、ワイルドカードを使うタイプの話で以下のような場合、

    $input = [
        'users' => [
            1 => [
                'name' => 'taro',
                'admin' => true,
            ],
            2 => [
                'name' => 'jiro',
                'admin' => true,
            ],
        ],
    ];

    $data = validator()->validate($input, [
        'users' => ['required', 'array'],
        'users.*.name' => ['required'],
    ]);

    dd($data);

dd($data); の結果は、

array:1 ["users" => array:2 [1 => array:2 ["name" => "taro"
      "admin" => true
    ]
    2 => array:2 ["name" => "jiro"
      "admin" => true
    ]
  ]
]

'admin' が入ってしまっています。今回は、キーは添え字(数字)なので、先の方法そのままではうまく行きません。

こちらの場合は、Ver. 8.50 で追加された機能を利用すれば、

AppServiceProvider

use Illuminate\Support\Facades\Validator;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Validator::excludeUnvalidatedArrayKeys();

今度は下記のように含まれなくなります。

array:1 ["users" => array:2 [1 => array:1 ["name" => "taro"
    ]
    2 => array:1 ["name" => "jiro"
    ]
  ]
]

この機能が有効なのは、こちらのワイルドカードを使ったバリデーションの時のみですね。 Ver.8.51 で修正され、ワイルドカードのタイプのみならず、最初に紹介したタイプでも有効です。

雑感

もしかしたら、リリースが来年2月に伸びた Ver.9 で、この機能の挙動がデフォルトになるかも知れません。まぁ、Ver.9 のリリースは伸びましたが、新機能は随時追加されていますね(breaking change でない限り)。

間違い等ありましたらコメントお願いします。

Discussion