我们正在构建一个需要精确性的apiendpoint。我们希望对POST/PUT到服务器的参数实施严格的验证。
如果api用户发送了一个不受支持的key=value
对(例如,我们允许参数[first\u name,last\u name],并且用户包含一个不受支持的参数[country]),我们希望验证失败。
已尝试构建名为允许的\u属性
(用作允许的\u属性:attr1、attr2、
)的自定义验证器,但要使其在$validationRules
数组中可用,必须将其应用于嵌套/子属性列表的父级(…因为我们的自定义验证器无法访问正在验证的属性)。
Validator::extend('allowed_attributes', 'App\Validators\AllowedAttributesValidator@validate');
这就给其他验证器带来了问题,我们必须预测父/子结构及其周围的代码,包括额外的验证后错误键和错误消息字符串的清理。
tl;dr:非常脏,不是一个干净的实现。
$validationRules = [
'parent' => 'allowed_attributes:first_name,last_name',
'parent.first_name' => 'required|string|max:40',
'parent.last_name' => 'required|string|max:40'
];
$isValid = Validator::make(['parent' => $request], $validationRules);
var_dump("Validation results: " . ($isValid ? "passed" : "failed"));
关于如何在laravel中更干净地实现这一点,而不需要使用父/子关系来访问所有$request属性列表(在自定义验证器中),有什么想法/建议吗?
它应该适用于具有此自定义验证器的简单键/值对:
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
不包含
,我们正在处理一个顶级参数,我们只需检查它是否存在于传递给规则的允许的属性列表中
这里的关键是将其应用于验证规则,如下所示(请注意第一条验证规则):
$validationRules = [
'parent.*' => 'allowed_attributes:first_name,last_name',
'parent.first_name' => 'required|string|max:40',
'parent.last_name' => 'required|string|max:40'
];
父对象*
规则将对“父”对象的每个键应用自定义验证器。
只是不要在对象中包装您的请求,而是使用与上述相同的概念,并使用
*
应用allowed_attributes
规则:
$validationRules = [
'*' => 'allowed_attributes:first_name,last_name',
'first_name' => 'required|string|max:40',
'last_name' => 'required|string|max:40'
];
这将把规则应用于所有当前的顶级输入请求字段。
注意:请记住,在规则数组中放入规则时,laravel验证会受到规则顺序的影响。例如,移动
父对象*
规则将在父级上触发该规则。名字和父项。姓氏;相反,将其保留为第一条规则不会触发对
first\u name
和last\u name
的验证。
这意味着您最终可以从
allowed_attributes
规则的参数列表中删除具有进一步验证逻辑的属性。
例如,如果您希望只需要first_name和last_name并禁止
父
对象中的任何其他字段,您可以使用以下规则:
$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上看到一个错误,但您无法判断是哪个字段导致了问题!
我更喜欢发布一个新的答案,因为这个方法与之前的方法不同,而且更干净。因此,我宁愿将这两种方法分开,而不是在同一个答案中混为一谈。
自上次回答以来,我深入研究了验证名称空间的源代码,发现最简单的方法是扩展Validator类,以重新实现passs()
函数,同时检查所需内容。
此实现还可以正确地处理单个数组/对象字段的特定错误消息,而不产生任何影响,并且应该与通常的错误消息转换完全兼容。
你应该首先在你的app文件夹中创建一个Validator类(我把它放在app/Validation/Validator.php
)并实现如下passs方法:
<?php
namespace App\Validation;
use Illuminate\Support\Arr;
use Illuminate\Validation\Validator as BaseValidator;
class Validator extends BaseValidator
{
/**
* Determine if the data passes the validation rules.
*
* @return bool
*/
public function passes()
{
// Perform the usual rules validation, but at this step ignore the
// return value as we still have to validate the allowance of the fields
// The error messages count will be recalculated later and returned.
parent::passes();
// Compute the difference between the request data as a dot notation
// array and the attributes which have a rule in the current validator instance
$extraAttributes = array_diff_key(
Arr::dot($this->data),
$this->rules
);
// We'll spin through each key that hasn't been stripped in the
// previous filtering. Most likely the fields will be top level
// forbidden values or array/object values, as they get mapped with
// indexes other than asterisks (the key will differ from the rule
// and won't match at earlier stage).
// We have to do a deeper check if a rule with that array/object
// structure has been specified.
foreach ($extraAttributes as $attribute => $value) {
if (empty($this->getExplicitKeys($attribute))) {
$this->addFailure($attribute, 'forbidden_attribute', ['value' => $value]);
}
}
return $this->messages->isEmpty();
}
}
这将基本上扩展默认的Validator类,以添加对Pass方法的其他检查。检查通过转换为点符号(以支持数组/对象验证)的输入属性和至少分配了一个规则的属性之间的键计算数组差异。
然后,您错过的最后一步是在服务提供程序的引导方法中绑定新的Validator类。要做到这一点,您可以重写绑定到IoC容器中的类的解析程序:
// Do not forget the class import at the top of the file!
use App\Validation\Validator;
// ...
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->app->make('validator')
->resolver(function ($translator, $data, $rules, $messages, $attributes) {
return new Validator($translator, $data, $rules, $messages, $attributes);
});
}
// ...
您不必做任何特定的事情来使用此功能。只需像往常一样调用valester
方法:
$this->validate(request(), [
'first_name' => 'required|string|max:40',
'last_name' => 'required|string|max:40'
]);
要自定义错误消息,您只需在lang文件中添加一个翻译键,该键等于forbidden_attribute
(您可以在addFailure
方法调用的自定义Validator类中自定义错误键名称)。
示例:resources/lang/en/validation。php
<?php
return [
// ...
'forbidden_attribute' => 'The :attribute key is not allowed in the request body.',
// ...
];
注:此实现仅在Laravel 5.3中进行了测试。
我正在尝试使用“语言”中的验证属性 我有这个: 要显示错误,请执行以下操作: 以及控制器中的验证: $messages数组: 有人能告诉我我做错了什么吗。我希望:attribute name在attributes数组(语言)中被替换为“nice name”。 谢谢 编辑: 我注意到问题是我从来没有为我的Laravel项目设置默认语言。当我设置语言为'NL'上面的代码工作。但是,当我设置我的语言时,
晚上好,我正在尝试在下面的场景中使用Hibernate验证器:
字段的属性似乎不起作用。 在HTML5中有没有其他属性可以帮助我设置字段值的最小长度?
假设我有以下课程: 是否可以通过“MyProduct”类验证“code”属性?比如:
问题内容: 我有一个laravel 模型,该模型在和上具有唯一的验证规则。在我的存储库中,当我更新模型时,我将重新验证字段,以使所需的规则验证没有问题: 测试失败 有没有办法优雅地解决这个问题? 问题答案: 将当前正在更新的实例的追加到验证器。 传递实例的来忽略唯一的验证器。 在验证器中,使用参数来检测您是否正在 更新 或 创建 资源。 如果进行更新,则强制唯一规则忽略给定的id: 如果创建,请照
As we learned earlier in the book, the validate method on a Model is called before set and save, and is passed the model attributes updated with the values from these methods. By default, where we def