第 1 点:就像我在问题下的评论中提到的那样,您想要实现的目标可能会以更简单的方式完成。
第 2 点:由于您不想更改已经编写好的代码,->messages()
那么您可以执行以下操作。我将列出这些步骤并提供示例代码。
- 我们需要重写 Laravel 的验证器、(验证)工厂和 ValidationService 提供者类。
- 在
App\Services
文件夹中,您可以创建两个类Validator
和ValidationFactory
- 在
App\Providers
创建一个类ValidationServiceProvider
- 进入
config/app.php
文件并providers
替换 Illuminate\Validation\ValidationServiceProvider::class
为App\Providers\ValidationServiceProvider::class
Validator
类看起来像这样:
namespace App\Services;
use Illuminate\Support\MessageBag;
use Illuminate\Validation\ValidationRuleParser;
use Illuminate\Contracts\Translation\Translator;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Illuminate\Contracts\Validation\Rule as RuleContract;
class Validator extends \Illuminate\Validation\Validator
{
/**
* @var MessageBag $all_messages
*/
protected $all_messages;
public function __construct(Translator $translator, array $data, array $rules, array $messages = [], array $customAttributes = [])
{
parent::__construct($translator, $data, $rules, $messages, $customAttributes);
$this->all_messages = new MessageBag;
$this->getAllFormattedMessages();
}
public function makeAllRulesMessages($attribute, $rule, $parameters)
{
$this->all_messages->add($attribute, $this->makeReplacements(
$this->getMessage($attribute, $rule), $attribute, $rule, $parameters
));
}
public function messages(bool $validated_rules_messages = false)
{
return $validated_rules_messages
? $this->validatedMessages()
: $this->all_messages;
}
/**
* This is here in case the true validated messages are needed
*
* @return MessageBag
*/
public function validatedMessages()
{
return parent::messages();
}
public function getAllFormattedMessages()
{
// We'll spin through each rule and add all messages to it.
foreach ($this->rules as $attribute => $rules) {
$attribute = str_replace('\.', '->', $attribute);
foreach ($rules as $rule) {
// First we will get the correct keys for the given attribute in case the field is nested in
// an array. Then we determine if the given rule accepts other field names as parameters.
// If so, we will replace any asterisks found in the parameters with the correct keys.
[$rule, $parameters] = ValidationRuleParser::parse($rule);
if (($keys = $this->getExplicitKeys($attribute)) &&
$this->dependsOnOtherFields($rule)) {
$parameters = $this->replaceAsterisksInParameters($parameters, $keys);
}
$value = $this->getValue($attribute);
if ($value instanceof UploadedFile && $this->hasRule($attribute, array_merge($this->fileRules, $this->implicitRules))
) {
$this->makeAllRulesMessages($attribute, 'uploaded', []);
} elseif ($rule instanceof RuleContract) {
$this->makeCustomRuleMessage($attribute, $rule);
} else {
$this->makeAllRulesMessages($attribute, $rule, $parameters);
}
}
}
}
/**
* @param $attribute
* @param \Illuminate\Contracts\Validation\Rule $rule $rule
*/
public function makeCustomRuleMessage($attribute, $rule)
{
$this->failedRules[$attribute][get_class($rule)] = [];
$messages = (array)$rule->message();
foreach ($messages as $message) {
$this->all_messages->add($attribute, $this->makeReplacements(
$message, $attribute, get_class($rule), []
));
}
}
}
这个类总结起来做一件事,把所有通过规则的消息都放到$all_messages
类的属性中。它扩展并允许基本验证类运行,并简单地覆盖messages()
方法以使所有收集的规则可供使用。
ValidationFactory
覆盖Illuminate\Validation\Factory
,它看起来像这样:
namespace App\Services;
use Illuminate\Validation\Factory;
class ValidationFactory extends Factory
{
/**
* Resolve a new Validator instance.
*
* @param array $data
* @param array $rules
* @param array $messages
* @param array $customAttributes
* @return \Illuminate\Validation\Validator
*/
protected function resolve(array $data, array $rules, array $messages, array $customAttributes)
{
if (is_null($this->resolver)) {
return new \App\Services\Validator($this->translator, $data, $rules, $messages, $customAttributes);
}
return call_user_func($this->resolver, $this->translator, $data, $rules, $messages, $customAttributes);
}
}
这个类只做一件事,resolve()
通过使用我们自定义类的实例来覆盖这个类中的方法\App\Services\Validator
。
ValidationServiceProvider
扩展Illuminate\Validation\ValidationServiceProvider
和覆盖registerValidationFactory()
方法,它看起来像这样:
namespace App\Providers;
use App\Services\ValidationFactory;
use Illuminate\Validation\ValidationServiceProvider as BaseValidationServiceProvider;
class ValidationServiceProvider extends BaseValidationServiceProvider
{
protected function registerValidationFactory()
{
$this->app->singleton('validator', function ($app) {
$validator = new ValidationFactory($app['translator'], $app);
// The validation presence verifier is responsible for determining the existence of
// values in a given data collection which is typically a relational database or
// other persistent data stores. It is used to check for "uniqueness" as well.
if (isset($app['db'], $app['validation.presence'])) {
$validator->setPresenceVerifier($app['validation.presence']);
}
return $validator;
});
}
}
上面的类所做的也是指示提供者App\Services\ValidationFactory
在应用程序需要时使用我们的。
我们完成了。即使我们的验证规则之一失败,也会显示所有验证消息。
注意事项
为了实现这一点,我们需要进行大量更改和覆盖。除了非常关键之外,这可能表明应用程序的设计看起来有问题。
Laravel 验证实现可能会在未来的版本中更改,因此可能会成为维护这些更改的问题。
我无法确定覆盖 Laravel 的默认验证实现是否会发生其他副作用,或者是否所有规则都返回正确的消息。
通常您只想将失败的验证消息返回给用户,而不是所有可能的失败。