Skip to content

Commit bb7baa2

Browse files
committed
Fix incorrect string handling of callbacks #26
Fix incorrect scoping of callbacks preventing access to rule properties via $this
1 parent 06af1b5 commit bb7baa2

6 files changed

+87
-3
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
Change Log
22
==========
33

4+
2024-03-21
5+
----------
6+
7+
* fix callback strings as error messages (#26 thanks to [jakewhiteley](https://github.com/jakewhiteley)
8+
* fix bug in callback binding in Callback rule, not setting scope to the rule instance
9+
410
2024-03-02
511
----------
612

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,11 @@ $validation = $validator->validate($_POST, [
372372
]);
373373
```
374374

375-
You can set a custom message by returning a string instead of false:
375+
You can set a custom message by returning a string instead of false. To allow for message translation, instead of
376+
a literal string; return a message key instead and add this to the message bag on the Factory.
377+
378+
> Note: returning a message string will be removed in a future version, requiring only boolean responses.
379+
> Instead, set the message string directly before returning true/false via `$this->message = "";`.
376380
377381
```php
378382
$validation = $validator->validate($_POST, [

src/MessageBag.php

+11
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,15 @@ public function has(string $key, string $lang = null): bool
6161
{
6262
return isset($this->messages[$lang ?? $this->defaultLang][$key]);
6363
}
64+
65+
public function hasAnyOf(array $keys, string $lang = null): bool
66+
{
67+
foreach ($keys as $key) {
68+
if ($this->has($key, $lang)) {
69+
return true;
70+
}
71+
}
72+
73+
return false;
74+
}
6475
}

src/Rules/Callback.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function check(mixed $value): bool
2828
throw new InvalidArgumentException(sprintf('Callback rule for "%s" is not callable.', $this->attribute->key()));
2929
}
3030

31-
$callback = $callback->bindTo($this);
31+
$callback = $callback->bindTo($this, $this);
3232
$invalidMessage = $callback($value);
3333

3434
if (is_string($invalidMessage)) {

src/Validation.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Closure;
66
use Somnambulist\Components\Validation\Exceptions\RuleException;
7+
use Somnambulist\Components\Validation\Rules\Callback;
78
use Somnambulist\Components\Validation\Rules\Contracts\ModifyValue;
89
use Somnambulist\Components\Validation\Rules\Required;
910

@@ -361,7 +362,11 @@ protected function resolveMessage(Attribute $attribute, Rule $rule, mixed $value
361362
array_splice($messageKeys, 3, 0, $primaryAttributeKey);
362363
}
363364

364-
$message->setMessage($this->messages->firstOf($messageKeys, $this->lang));
365+
$message->setMessage(
366+
$this->messages->hasAnyOf($messageKeys, $this->lang)
367+
?
368+
$this->messages->firstOf($messageKeys, $this->lang) : $message->key()
369+
);
365370

366371
// Replace key indexes
367372
$keyIndexes = $attribute->indexes();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Somnambulist\Components\Validation\Tests\Issues;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Somnambulist\Components\Validation\Factory;
7+
8+
class GH26HandlingCallbackErrorMessagesTest extends TestCase
9+
{
10+
/**
11+
* @link https://github.com/somnambulist-tech/validation/issues/26
12+
*/
13+
public function testReturningMessageStringsProducesErrorMessage()
14+
{
15+
$testData = [
16+
'name' => 'John Doe',
17+
'custom' => 'foo',
18+
];
19+
20+
$validation = (new Factory)->validate($testData, [
21+
'name' => 'required',
22+
'custom' => [
23+
'required',
24+
function ($value) {
25+
if ($value !== 'bar') {
26+
return ':attribute should be bar';
27+
}
28+
29+
return true;
30+
},
31+
],
32+
]);
33+
34+
$this->assertEquals('custom should be bar', $validation->errors()->first('custom'));
35+
}
36+
37+
public function testCanSetMessageIdentityViaCallback()
38+
{
39+
$testData = [
40+
'name' => 'John Doe',
41+
'custom' => 'foo',
42+
];
43+
44+
$validation = (new Factory)->validate($testData, [
45+
'name' => 'required',
46+
'custom' => [
47+
'required',
48+
function ($value) {
49+
$this->message = ':attribute should be bar';
50+
51+
return $value === 'bar';
52+
},
53+
],
54+
]);
55+
56+
$this->assertEquals('custom should be bar', $validation->errors()->first('custom'));
57+
}
58+
}

0 commit comments

Comments
 (0)