接受的答案存在一个问题(在我看来,通常是 Laravel 的验证器) - 验证过程本身和验证状态检测合并为一种方法。
如果你盲目地渲染包中的所有验证消息,那没什么大不了的。但是,如果您有一些额外的逻辑来检测验证器是否失败并执行其他操作(例如为当前已验证的表单字段提供国际文本消息),那么您就有问题了。
演示:
// let's create an empty validator, assuming that we have no any errors yet
$v = Validator::make([], []);
// add an error
$v->errors()->add('some_field', 'some_translated_error_key');
$fails = $v->fails(); // false!!! why???
$failedMessages = $v->failed(); // 0 failed messages!!! why???
还有,
$v->getMessageBag()->add('some_field', 'some_translated_error_key');
产生相同的结果。为什么?因为如果你查看 Laravel 的 Validator 代码,你会发现以下内容:
public function fails()
{
return ! $this->passes();
}
public function passes()
{
$this->messages = new MessageBag;
如您所见,fails() 方法本质上清除了丢失您附加的所有消息的包,从而使验证器假定没有错误。
无法将错误附加到现有验证器并使其失败。您只能创建一个带有自定义错误的新验证器,如下所示:
$v = Validator::make(['some_field' => null],
['some_field' => 'Required:some_translated_error_key']);
$fails = $v->fails(); // true
$failedMessages = $v->failed(); // has error for `required` rule
如果你不喜欢滥用 required 验证规则来处理自定义附加错误,你可以随时使用自定义规则扩展 Laravel Validator。我添加了一个通用的failkey 规则并以这种方式强制执行:
// in custom Validator constructor: our enforced failure validator
array_push($this->implicitRules, "Failkey");
...
/**
* Allows to fail every passed field with custom key left as a message
* which should later be picked up by controller
* and resolved with correct message namespaces in validate or failValidation methods
*
* @param $attribute
* @param $value
* @param $parameters
*
* @return bool
*/
public function validateFailkey($attribute, $value, $parameters)
{
return false; // always fails
}
protected function replaceFailkey($message, $attribute, $rule, $parameters)
{
$errMsgKey = $parameters[0];
// $parameters[0] is the message key of the failure
if(array_key_exists($errMsgKey, $this->customMessages)){
$msg = $this->customMessages[$parameters[0]];
}
// fallback to default, if exists
elseif(array_key_exists($errMsgKey, $this->fallbackMessages)){
return $this->fallbackMessages[$parameters[0]];
}
else {
$msg = $this->translator->trans("validation.{$errMsgKey}");
}
// do the replacement again, if possible
$msg = str_replace(':attribute', "`" . $this->getAttribute($attribute)
. "`", $msg);
return $msg;
}
我可以这样使用它:
$v = Validator::make(['some_field' => null],
['some_field' => 'failkey:some_translated_error_key']);
$fails = $v->fails(); // true
$failedMessages = $v->failed(); // has error for `Failkey` rule
当然,这仍然是解决该问题的一种老套方法。
理想情况下,我会重新设计验证器,以清楚地将其验证阶段与状态检测分开(validate() 和passes() 或更好的isValid() 的单独方法),并添加方便的方法来手动使特定字段与特定规则失败。虽然这也可能被认为是 hacky,但如果我们想使用 Laravel 验证器,不仅要使用 Laravel 自己的验证规则,还要使用我们自定义的业务逻辑规则。