経緯
Laravel のバリデーションルールの same 等は他のフィールド名を受け取る事ができ、配列にも対応している。
このようなカスタムバリデーションルールを作ろうと思ったがなかなか情報が見つからずに苦労したのでまとめる。
あるデータ内の2つの値の合計が41になる事を検証したい事がよくあると思うので1本記事では例として実装する。
配列に対応していない版
AppServiceProvider::boot 内で Validator ファサードの extend メソッドを使ってルールを登録する。
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Validator;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extend('sum41', function ($attribute, $value, $parameters, $validator) {
return $value + ($validator->getData())[$parameters[0]] === 41;
});
}
}
rule:param1[,...] のようにルールに渡した引数は、extend メソッドのクロージャの第3引数で配列として受け取れる。
第4引数は \Illuminate\Validation\Validator のインスタンスで、getData メソッドを使えば全体のデータが取得できる。
よって param1 に他のフィールドのキーを指定しているなら
($validator->getData())[$parameters[0]]
でそのフィールドの値が取得できる。
実際にルールを使ってみる。
>>> $data = ['data1' => 10, 'data2' => 31];
>>> $rules = ['data1' => 'required', 'data2' => 'sum41:data1'];
>>> Validator::make($data, $rules)->validate()
=> [
"data1" => 10,
"data2" => 31,
]
>>> $data2 = ['data1' => 10, 'data2' => 30];
>>> Validator::make($data2, $rules)->validate()
Illuminate/Validation/ValidationException with message 'The given data was invalid.'
データが一件の時は問題なく動いているように見えるが、配列に対して使おうとすると *.data1 をそのままキーとして認識するため Notice: Undefined index が発生する。
>>> $data = [['data1' => 10, 'data2' => 31], ['data1' => 20, 'data2' => 21]];
>>> $rules = ['*.data1' => 'required', '*.data2' => 'sum41:*.data1'];
>>> Validator::make($data, $rules)->validate()
PHP Notice: Undefined index: *.data1 in /***/app/Providers/AppServiceProvider.php on line 14
配列に対応
調べた所、パラメータの * を配列のインデックスに変換するためには extend の代わりに extendDependent メソッドを使ってルールを登録すれば良い事が分かった。(この情報がなかなか見つからなかった)
これだけで $parameters 配列に自動的に 0.data1 のような値が入ってくれる。
また、 $validator->getData() は
array:2 [
0 => array:2 [
"data1" => 10
"data2" => 31
]
1 => array:2 [
"data1" => 20
"data2" => 21
]
]
このような構造になっているので
Arr::get($validator->getData(), $parameters[0])
で目的の値が取得できる。
最終的に以下のようになった。
<?php
namespace App\Providers;
use Arr;
use Illuminate\Support\ServiceProvider;
use Validator;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extendDependent('sum41', function ($attribute, $value, $parameters, $validator) {
return $value + Arr::get($validator->getData(), $parameters[0]) === 41;
});
}
}
>>> $data = [['data1' => 10, 'data2' => 31], ['data1' => 20, 'data2' => 21]];
>>> $rules = ['*.data1' => 'required', '*.data2' => 'sum41:*.data1'];
>>> Validator::make($data, $rules)->validate()
=> [
[
"data1" => 10,
"data2" => 31,
],
[
"data1" => 20,
"data2" => 21,
],
]
別の方法
一度しか使わないルールを検証時にその場で記述したい場合は、\Illuminate\Validation\Validator::addDependentExtension でもルールの登録ができる。
$validator = Validator::make($data, $rules);
$validator->addDependentExtension('sum41', function($attribute, $value, $parameters, $validator) {
return $value + Arr::get($validator->getData(), $parameters[0]) === 41;
});
$validator->validate();
-
ない ↩