php 向 Laravel 表单添加自定义验证错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22158580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Adding custom validation errors to Laravel form
提问by John Dorean
I have a basic form set up to allow a user to change their email address, and I'm doing the following validation on it before I change the email:
我设置了一个基本表单以允许用户更改他们的电子邮件地址,并且在更改电子邮件之前我正在对其进行以下验证:
// Set up the form validation
$validator = Validator::make(
Input::all(),
array(
'email' => 'email|unique:users',
'password' => 'required'
)
);
// If validation fails, redirect to the settings page and send the errors
if ($validator->fails())
{
return Redirect::route('settings')->withErrors($validator)->withInput();
}
This works fine, however after this basic validation I'd like to check if the user supplied a correct password. To do so, I'm doing the following with Laravel's basic authentication library:
这工作正常,但是在此基本验证之后,我想检查用户是否提供了正确的密码。为此,我正在使用 Laravel 的基本身份验证库执行以下操作:
// Find the user and validate their password
$user = Auth::user();
if (!Auth::validate(array('username' => $user->username, 'password' => Input::get('password'))))
{
die("failed to authenticate");
}
Rather than handling the logic to tell the user their password is incorrect myself, I'd rather just add a form error to the passwordinput so it shows up just like regular form validation. Something like so:
与其处理逻辑告诉用户他们自己的密码不正确,我宁愿在password输入中添加一个表单错误,以便它像常规表单验证一样显示。像这样:
if (!Auth::validate(array('username' => $user->username, 'password' => Input::get('password'))))
{
$validator->addError('password', 'That password is incorrect.');
return Redirect::route('settings')->withErrors($validator)->withInput();
}
That way, the incorrect password error will show next to my password input and look like proper form validation.
这样,不正确的密码错误将显示在我的密码输入旁边,看起来像正确的表单验证。
How can I do this?
我怎样才能做到这一点?
回答by Bastian Hofmann
See Darren Craig's answer.
见达伦克雷格的回答。
One way to implement it though.
实现它的一种方法。
// inside if(Auth::validate)
if(User::where('email', $email)->first())
{
$validator->getMessageBag()->add('password', 'Password wrong');
}
else
{
$validator->getMessageBag()->add('email', 'Email not found');
}
回答by JustAMartin
There is one problem with the accepted answer (and Laravel's Validator in general, in my opinion) - the validation process itself and validation status detection is merged into one method.
接受的答案有一个问题(在我看来,一般来说也是 Laravel 的验证器)——验证过程本身和验证状态检测合并为一种方法。
If you blindly render all validation messages from the bag, it's no big deal. But if you have some additional logic that detects if the validator has failed or not and does additional actions (such as feeding international text messages for current validated form fields), then you have a problem.
如果您盲目地从包中呈现所有验证消息,那没什么大不了的。但是如果你有一些额外的逻辑来检测验证器是否失败并执行额外的操作(例如为当前已验证的表单字段提供国际文本消息),那么你就有问题了。
Demonstration:
示范:
// 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???
Also,
还,
$v->getMessageBag()->add('some_field', 'some_translated_error_key');
yields the same results. Why? Because if you look into Laravel's Validator code, you will find the following:
产生相同的结果。为什么?因为如果你查看 Laravel 的 Validator 代码,你会发现以下内容:
public function fails()
{
return ! $this->passes();
}
public function passes()
{
$this->messages = new MessageBag;
As you can see, fails()method essentially clears away the bag losing all the messages you have appended, and thus making the validator assume that there are no errors.
如您所见,fails()方法基本上清除了丢失所有附加消息的包,从而使验证器假设没有错误。
There is no way to append errors to existing validator and make it fail. You can only create a new validator with custom errors like this:
无法将错误附加到现有验证器并使其失败。您只能创建一个带有自定义错误的新验证器,如下所示:
$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
If you don't like the idea of abusing requiredvalidation rule for custom appended errors, you can always extend Laravel Validator with custom rules. I added a generic failkeyrule and made it mandatory this way:
如果您不喜欢required为自定义附加错误滥用验证规则的想法,您可以随时使用自定义规则扩展 Laravel 验证器。我添加了一个通用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;
}
And I can use it like this:
我可以这样使用它:
$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
Of course, that's still a hacky way to work around the issue.
当然,这仍然是解决该问题的一种黑客方法。
Ideally, I would redesign the Validator to clearly separate its validation phase from status detection (separate methods for validate()and passes()or better isValid()) and also add convenience methods to manually fail specific field with specific rule. Although that also might be considered hacky, but still we have no other choice if we want to use Laravel validator not only with Laravel's own validation rules, but also our custom business logic rules.
理想情况下,我会重新设计 Validator 以将其验证阶段与状态检测清楚地分开(将validate()和passes()或更好的方法分开isValid()),并添加方便的方法以使用特定规则手动使特定字段失败。虽然这也可能被认为是 hacky,但是如果我们想将 Laravel 验证器不仅与 Laravel 自己的验证规则一起使用,而且还与我们自定义的业务逻辑规则一起使用,我们仍然别无选择。
回答by Pathros
Moreover, it could be helpful to add the following Redirect::back()function:
此外,添加以下Redirect::back()功能可能会有所帮助:
$validator->getMessageBag()->add('password', 'Password wrong');
return Redirect::back()->withErrors($validator)->withInput();
According to
根据
The Alpha
阿尔法
(http://heera.it/laravel-manually-invalidate-validation#.VVt7Wfl_NBc)
(http://heera.it/laravel-manually-invalidate-validation#.VVt7Wfl_NBc)
回答by zeros-and-ones
Alternate syntax:
替代语法:
$validator->errors()
->add('photos', 'At least one photo is required for a new listing.');
回答by TKoL
user Matt K said in a comment that laravel has since implemented validation hooks, which does exactly what we want:
用户 Matt K 在评论中说laravel 已经实现了验证钩子,这正是我们想要的:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
// this actually runs! even if the original validator succeeded!
}
回答by Darren Craig
I understand why you want this, however it's actually bad practice from a security point of view to return a message that indicates whether the username and/or the password is incorrect. It would allow a hacker to understand whether they got the username or password correct.
我理解你为什么想要这个,但是从安全的角度来看,返回一条指示用户名和/或密码是否不正确的消息实际上是不好的做法。它可以让黑客了解他们的用户名或密码是否正确。
It's better to return a generic message like 'Your credentials are incorrect', which you wouldn't want to be displayed next to your fields anyway.
最好返回诸如“您的凭据不正确”之类的通用消息,无论如何您都不希望将其显示在您的字段旁边。
回答by Guillermo Espert
I solved a similar problem with validation and custom validation. In my case, I need to verify that uploaded file with the form is a valid image and also the post data, so I need to run a validation test for the file and the validation tests for the post data. I was a problem when I tried to return back my custom validation data, only Laravel's validation errors was present. According to @JustAMartin post, I've been coded a solution that shows all errors.
我用验证和自定义验证解决了类似的问题。就我而言,我需要验证使用表单上传的文件是有效的图像以及发布数据,因此我需要对文件运行验证测试并对发布数据运行验证测试。当我尝试返回自定义验证数据时遇到了问题,只存在 Laravel 的验证错误。根据@JustAMartin 的帖子,我编写了一个显示所有错误的解决方案。
//Creem una instància del validador. A?ò ens permet manipular-lo
$validator = Validator::make($request->all(), [
'nomCompanyia' => 'required',
'urlCompanyia' => 'url'
]);
$imageError = false;
$imgOriginal = null;
$imgMitjana = null;
$imgXicoteta = null;
$fallaValidacio = !$validator->passes(); //-> Retorna true si cap error, false en cas contrari.
if($request->hasFile('logoCompanyia') && !$fallaValidacio)
{
$imatge = $request->file('logoCompanyia');
if($imatge->isValid() && $this->verificaExtensionsImatges($imatge->getClientOriginalExtension(), $imatge->guessExtension()))
{
$sPath = $imatge->store('images/companyies/', 'public');
$fullPathOriginal = public_path() . "/storage/" . $sPath;
$fpInfo = pathinfo($fullPathOriginal);
$imgOriginal = sprintf("%s.%s", $fpInfo['filename'], $fpInfo['extension']);
//Crear les miniatures
$mitjana = Image::make($fullPathOriginal)->widen(300, function ($constraint) {
$constraint->upsize();
});
$imgMitjana = sprintf("%s_300.%s", $fpInfo['filename'], $fpInfo['extension']);
$mitjana->save($fpInfo['dirname'] . '/' . $imgMitjana);
$xicoteta = Image::make($fullPathOriginal)->widen(100, function ($constraint) {
$constraint->upsize();
});
$imgXicoteta = sprintf("%s_100.%s", $fpInfo['filename'], $fpInfo['extension']);
$xicoteta->save($fpInfo['dirname'] . '/' . $imgXicoteta);
}
else
{
$imageError = true;
$validator->getMessageBag()->add('logoCompanyia', "Sembla que el fitxer d'imatge no és vàlid o està corrupte. Només s'accepten els formats: .jpg, .jpeg, .png, .gif");
}
}
else
{
$imageError = true;
$validator->getMessageBag()->add('logoCompanyia', "Sembla que el fitxer d'imatge no és vàlid o ha sigut rebutjat per el servidor si és massa gran.");
}
if($fallaValidacio || $imageError)
{
$data['mode'] = "nou";
$data['urlFormulari'] = "administracio/companyies/afegir";
$data['nomCompanyia'] = $request->nomCompanyia;
$data['idCompanyia'] = 0;
$data['urlCompanyia'] = $request->urlCompanyia;
$data['logoCompanyia'] = $request->logoCompanyia;
$data['errors'] = (object) $validator->errors();
return view($this->formulariTemplate, $data);
}
$companyia = new Companyies();
$companyia->nom = $request->nomCompanyia;
$companyia->url = $request->urlCompanyia;
$companyia->logo_original = $imgOriginal;
$companyia->logo_300 = $imgMitjana;
$companyia->logo_100 = $imgXicoteta;
$companyia->save();
As you can see I only makes one call to $validator->passes() and I store the result in a variable. When I call this method, all Laravel tests are maked. If they're passed or not result is stored in the variable, so you can test your variable later. That permits make the tests on the file to finally determine if all data is OK or not.
如您所见,我只对 $validator->passes() 进行了一次调用,并将结果存储在一个变量中。当我调用这个方法时,所有的 Laravel 测试都进行了。如果它们通过与否,结果存储在变量中,因此您可以稍后测试您的变量。这允许对文件进行测试以最终确定所有数据是否正常。
If there are errors, I redirect back with the view() helper, adding all data: input and errors. If there are not errors the normal behaviour for the method is continued.
如果有错误,我会使用 view() 助手重定向回来,添加所有数据:输入和错误。如果没有错误,该方法的正常行为将继续。
回答by António Almeida
If you are using ajax calls, don't forget to throw a ValidationException.
如果您使用 ajax 调用,请不要忘记抛出一个ValidationException.
if ($subscribed) {
$validator->errors()->add('email', __('Your email is already subscribed.'));
throw new ValidationException($validator);
}
回答by Lipa
$validator -> errors() -> add('attribute', 'value');
return redirect($request -> url())
-> withErrors($validator)
-> withInput();
In "value" You can pass anything.
在“值”中,您可以传递任何内容。

