diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ab9341..1a74576 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Change Log ========== +2024-03-21 +---------- + + * fix callback strings as error messages (#26 thanks to [jakewhiteley](https://github.com/jakewhiteley) + * fix bug in callback binding in Callback rule, not setting scope to the rule instance + 2024-03-02 ---------- diff --git a/README.md b/README.md index 6c6532a..68b5f6a 100644 --- a/README.md +++ b/README.md @@ -372,7 +372,11 @@ $validation = $validator->validate($_POST, [ ]); ``` -You can set a custom message by returning a string instead of false: +You can set a custom message by returning a string instead of false. To allow for message translation, instead of +a literal string; return a message key instead and add this to the message bag on the Factory. + +> Note: returning a message string will be removed in a future version, requiring only boolean responses. +> Instead, set the message string directly before returning true/false via `$this->message = "";`. ```php $validation = $validator->validate($_POST, [ diff --git a/src/MessageBag.php b/src/MessageBag.php index 2209bfd..5628ea0 100644 --- a/src/MessageBag.php +++ b/src/MessageBag.php @@ -61,4 +61,15 @@ public function has(string $key, string $lang = null): bool { return isset($this->messages[$lang ?? $this->defaultLang][$key]); } + + public function hasAnyOf(array $keys, string $lang = null): bool + { + foreach ($keys as $key) { + if ($this->has($key, $lang)) { + return true; + } + } + + return false; + } } diff --git a/src/Rules/Callback.php b/src/Rules/Callback.php index 29809fc..fc8078b 100644 --- a/src/Rules/Callback.php +++ b/src/Rules/Callback.php @@ -28,7 +28,7 @@ public function check(mixed $value): bool throw new InvalidArgumentException(sprintf('Callback rule for "%s" is not callable.', $this->attribute->key())); } - $callback = $callback->bindTo($this); + $callback = $callback->bindTo($this, $this); $invalidMessage = $callback($value); if (is_string($invalidMessage)) { diff --git a/src/Validation.php b/src/Validation.php index f9c63d6..473cb7a 100644 --- a/src/Validation.php +++ b/src/Validation.php @@ -4,6 +4,7 @@ use Closure; use Somnambulist\Components\Validation\Exceptions\RuleException; +use Somnambulist\Components\Validation\Rules\Callback; use Somnambulist\Components\Validation\Rules\Contracts\ModifyValue; use Somnambulist\Components\Validation\Rules\Required; @@ -361,7 +362,11 @@ protected function resolveMessage(Attribute $attribute, Rule $rule, mixed $value array_splice($messageKeys, 3, 0, $primaryAttributeKey); } - $message->setMessage($this->messages->firstOf($messageKeys, $this->lang)); + $message->setMessage( + $this->messages->hasAnyOf($messageKeys, $this->lang) + ? + $this->messages->firstOf($messageKeys, $this->lang) : $message->key() + ); // Replace key indexes $keyIndexes = $attribute->indexes(); diff --git a/tests/Issues/GH26HandlingCallbackErrorMessagesTest.php b/tests/Issues/GH26HandlingCallbackErrorMessagesTest.php new file mode 100644 index 0000000..de7d519 --- /dev/null +++ b/tests/Issues/GH26HandlingCallbackErrorMessagesTest.php @@ -0,0 +1,58 @@ + 'John Doe', + 'custom' => 'foo', + ]; + + $validation = (new Factory)->validate($testData, [ + 'name' => 'required', + 'custom' => [ + 'required', + function ($value) { + if ($value !== 'bar') { + return ':attribute should be bar'; + } + + return true; + }, + ], + ]); + + $this->assertEquals('custom should be bar', $validation->errors()->first('custom')); + } + + public function testCanSetMessageIdentityViaCallback() + { + $testData = [ + 'name' => 'John Doe', + 'custom' => 'foo', + ]; + + $validation = (new Factory)->validate($testData, [ + 'name' => 'required', + 'custom' => [ + 'required', + function ($value) { + $this->message = ':attribute should be bar'; + + return $value === 'bar'; + }, + ], + ]); + + $this->assertEquals('custom should be bar', $validation->errors()->first('custom')); + } +}