diff --git a/src/Illuminate/Validation/InvokableValidationRule.php b/src/Illuminate/Validation/InvokableValidationRule.php index 621198fa0c75..8ca83f0a5a80 100644 --- a/src/Illuminate/Validation/InvokableValidationRule.php +++ b/src/Illuminate/Validation/InvokableValidationRule.php @@ -103,6 +103,16 @@ public function passes($attribute, $value) return ! $this->failed; } + /** + * Get the underlying invokable rule. + * + * @return \Illuminate\Contracts\Validation\InvokableRule + */ + public function invokable() + { + return $this->invokable; + } + /** * Get the validation error messages. * diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 32c3a3ce3160..74e360bccd54 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -810,17 +810,21 @@ protected function validateUsingCustomRule($attribute, $value, $rule) } if (! $rule->passes($attribute, $value)) { - $this->failedRules[$attribute][get_class($rule)] = []; + $ruleClass = $rule instanceof InvokableValidationRule ? + get_class($rule->invokable()) : + get_class($rule); - $messages = $this->getFromLocalArray($attribute, get_class($rule)) ?? $rule->message(); + $this->failedRules[$attribute][$ruleClass] = []; - $messages = $messages ? (array) $messages : [get_class($rule)]; + $messages = $this->getFromLocalArray($attribute, $ruleClass) ?? $rule->message(); + + $messages = $messages ? (array) $messages : [$ruleClass]; foreach ($messages as $key => $message) { $key = is_string($key) ? $key : $attribute; $this->messages->add($key, $this->makeReplacements( - $message, $key, get_class($rule), [] + $message, $key, $ruleClass, [] )); } } diff --git a/tests/Validation/ValidationInvokableRuleTest.php b/tests/Validation/ValidationInvokableRuleTest.php index 46df5023b2a2..a87faf077268 100644 --- a/tests/Validation/ValidationInvokableRuleTest.php +++ b/tests/Validation/ValidationInvokableRuleTest.php @@ -7,6 +7,7 @@ use Illuminate\Contracts\Validation\ValidatorAwareRule; use Illuminate\Translation\ArrayLoader; use Illuminate\Translation\Translator; +use Illuminate\Validation\InvokableValidationRule; use Illuminate\Validation\Validator; use PHPUnit\Framework\TestCase; @@ -333,6 +334,85 @@ public function __invoke($attribute, $value, $fail) ], $validator->messages()->messages()); } + public function testExplicitRuleCanUseInlineValidationMessages() + { + $trans = $this->getIlluminateArrayTranslator(); + $rule = new class() implements InvokableRule + { + public $implicit = false; + + public function __invoke($attribute, $value, $fail) + { + $fail('xxxx'); + } + }; + + $validator = new Validator($trans, ['foo' => 'bar'], ['foo' => $rule], [$rule::class => ':attribute custom.']); + + $this->assertFalse($validator->passes()); + $this->assertSame([ + 'foo' => [ + 'foo custom.', + ], + ], $validator->messages()->messages()); + + $validator = new Validator($trans, ['foo' => 'bar'], ['foo' => $rule], ['foo.'.$rule::class => ':attribute custom with key.']); + + $this->assertFalse($validator->passes()); + $this->assertSame([ + 'foo' => [ + 'foo custom with key.', + ], + ], $validator->messages()->messages()); + } + + public function testImplicitRuleCanUseInlineValidationMessages() + { + $trans = $this->getIlluminateArrayTranslator(); + $rule = new class() implements InvokableRule + { + public $implicit = true; + + public function __invoke($attribute, $value, $fail) + { + $fail('xxxx'); + } + }; + + $validator = new Validator($trans, ['foo' => ''], ['foo' => $rule], [$rule::class => ':attribute custom.']); + + $this->assertFalse($validator->passes()); + $this->assertSame([ + 'foo' => [ + 'foo custom.', + ], + ], $validator->messages()->messages()); + + $validator = new Validator($trans, ['foo' => ''], ['foo' => $rule], ['foo.'.$rule::class => ':attribute custom with key.']); + + $this->assertFalse($validator->passes()); + $this->assertSame([ + 'foo' => [ + 'foo custom with key.', + ], + ], $validator->messages()->messages()); + } + + public function testItCanReturnInvokableRule() + { + $rule = new class() implements InvokableRule + { + public function __invoke($attribute, $value, $fail) + { + $fail('xxxx'); + } + }; + + $invokableValidationRule = InvokableValidationRule::make($rule); + + $this->assertSame($rule, $invokableValidationRule->invokable()); + } + private function getIlluminateArrayTranslator() { return new Translator(