它应该适用于使用此自定义验证器的简单键/值对:
Validator::extendImplicit('allowed_attributes', function ($attribute, $value, $parameters, $validator) {
// If the attribute to validate request top level
if (strpos($attribute, '.') === false) {
return in_array($attribute, $parameters);
}
// If the attribute under validation is an array
if (is_array($value)) {
return empty(array_diff_key($value, array_flip($parameters)));
}
// If the attribute under validation is an object
foreach ($parameters as $parameter) {
if (substr_compare($attribute, $parameter, -strlen($parameter)) === 0) {
return true;
}
}
return false;
});
验证器逻辑非常简单:
- 如果
$attribute 不包含.,我们正在处理顶级参数,我们只需要检查它是否存在于我们传递给规则的allowed_attributes 列表中。
- 如果
$attribute 的值是一个数组,我们将输入键与allowed_attributes 列表进行比较,并检查是否还有任何属性键。如果是这样,我们的请求有一个我们没有预料到的额外密钥,所以我们返回false。
- 否则
$attribute 的值是一个对象,我们必须检查我们期望的每个参数(同样,allowed_attributes 列表)是否是当前属性的最后一段(因为 laravel 给了我们完整的点符号$attribute 中的属性)。
这里的关键是将它应用到验证规则应该是这样的(注意第一个验证规则):
$validationRules = [
'parent.*' => 'allowed_attributes:first_name,last_name',
'parent.first_name' => 'required|string|max:40',
'parent.last_name' => 'required|string|max:40'
];
parent.* 规则会将自定义验证器应用于“父”对象的每个键。
回答你的问题
只是不要将您的请求包装在对象中,而是使用与上述相同的概念并将allowed_attributes 规则与* 一起应用:
$validationRules = [
'*' => 'allowed_attributes:first_name,last_name',
'first_name' => 'required|string|max:40',
'last_name' => 'required|string|max:40'
];
这会将规则应用于所有当前顶级输入请求字段。
注意:请记住,laravel 验证受规则顺序的影响,因为它们被放入规则数组中。
例如,将parent.* 规则移到底部将触发parent.first_name 和parent.last_name 上的该规则;相反,将其作为第一条规则不会触发first_name 和last_name 的验证。
这意味着您最终可以从allowed_attributes 规则的参数列表中删除具有进一步验证逻辑的属性。
例如,如果您只想要求 first_name 和 last_name 并禁止 parent 对象中的任何其他字段,则可以使用以下规则:
$validationRules = [
// This will be triggered for all the request fields except first_name and last_name
'parent.*' => 'allowed_attributes',
'parent.first_name' => 'required|string|max:40',
'parent.last_name' => 'required|string|max:40'
];
但是,以下不会按预期工作:
$validationRules = [
'parent.first_name' => 'required|string|max:40',
'parent.last_name' => 'required|string|max:40',
// This, instead would be triggered on all fields, also on first_name and last_name
// If you put this rule as last, you MUST specify the allowed fields.
'parent.*' => 'allowed_attributes',
];
数组小问题
据我所知,根据 Laravel 的验证逻辑,如果您要验证一个对象数组,这个自定义验证器会起作用,但是您会得到的错误消息是数组项上的通用信息,而不是键上的不允许的数组项。
例如,您允许在请求中包含一个 products 字段,每个字段都有一个 id:
$validationRules = [
'products.*' => 'allowed_attributes:id',
];
如果您验证这样的请求:
{
"products": [{
"id": 3
}, {
"id": 17,
"price": 3.49
}]
}
您将在产品 2 上收到错误,但您无法确定是哪个字段导致了问题!