Skip to content

Commit a8da712

Browse files
crynoboneStyleCIBottaylorotwell
authored
Fix attribute name used on Validator instance within certain rule classes (#54845)
* Fix attribute name used on `Validator` instance within File rule class Signed-off-by: Mior Muhammad Zaki <[email protected]> * wip Signed-off-by: Mior Muhammad Zaki <[email protected]> * wip Signed-off-by: Mior Muhammad Zaki <[email protected]> * wip Signed-off-by: Mior Muhammad Zaki <[email protected]> * Apply fixes from StyleCI * wip Signed-off-by: Mior Muhammad Zaki <[email protected]> * use static variable --------- Signed-off-by: Mior Muhammad Zaki <[email protected]> Co-authored-by: StyleCI Bot <[email protected]> Co-authored-by: Taylor Otwell <[email protected]>
1 parent fd9681f commit a8da712

File tree

4 files changed

+180
-13
lines changed

4 files changed

+180
-13
lines changed

src/Illuminate/Validation/Validator.php

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -307,11 +307,11 @@ class Validator implements ValidatorContract
307307
protected $defaultNumericRules = ['Numeric', 'Integer', 'Decimal'];
308308

309309
/**
310-
* The current placeholder for dots in rule keys.
310+
* The current random hash for the validator.
311311
*
312312
* @var string
313313
*/
314-
protected $dotPlaceholder;
314+
protected static $placeholderHash;
315315

316316
/**
317317
* The exception to throw upon failure.
@@ -344,7 +344,9 @@ public function __construct(
344344
array $messages = [],
345345
array $attributes = [],
346346
) {
347-
$this->dotPlaceholder = Str::random();
347+
if (! isset(static::$placeholderHash)) {
348+
static::$placeholderHash = Str::random();
349+
}
348350

349351
$this->initialRules = $rules;
350352
$this->translator = $translator;
@@ -372,7 +374,7 @@ public function parseData(array $data)
372374

373375
$key = str_replace(
374376
['.', '*'],
375-
[$this->dotPlaceholder, '__asterisk__'],
377+
['__dot__'.static::$placeholderHash, '__asterisk__'.static::$placeholderHash],
376378
$key
377379
);
378380

@@ -410,7 +412,7 @@ protected function replacePlaceholders($data)
410412
protected function replacePlaceholderInString(string $value)
411413
{
412414
return str_replace(
413-
[$this->dotPlaceholder, '__asterisk__'],
415+
['__dot__'.static::$placeholderHash, '__asterisk__'.static::$placeholderHash],
414416
['.', '*'],
415417
$value
416418
);
@@ -425,7 +427,7 @@ protected function replacePlaceholderInString(string $value)
425427
protected function replaceDotPlaceholderInParameters(array $parameters)
426428
{
427429
return array_map(function ($field) {
428-
return str_replace($this->dotPlaceholder, '.', $field);
430+
return str_replace('__dot__'.static::$placeholderHash, '.', $field);
429431
}, $parameters);
430432
}
431433

@@ -746,7 +748,7 @@ protected function getPrimaryAttribute($attribute)
746748
protected function replaceDotInParameters(array $parameters)
747749
{
748750
return array_map(function ($field) {
749-
return str_replace('\.', $this->dotPlaceholder, $field);
751+
return str_replace('\.', '__dot__'.static::$placeholderHash, $field);
750752
}, $parameters);
751753
}
752754

@@ -872,11 +874,24 @@ protected function hasNotFailedPreviousRuleIfPresenceRule($rule, $attribute)
872874
*/
873875
protected function validateUsingCustomRule($attribute, $value, $rule)
874876
{
875-
$attribute = $this->replacePlaceholderInString($attribute);
877+
$originalAttribute = $this->replacePlaceholderInString($attribute);
878+
879+
$attribute = match (true) {
880+
$rule instanceof Rules\Email => $attribute,
881+
$rule instanceof Rules\File => $attribute,
882+
$rule instanceof Rules\Password => $attribute,
883+
default => $originalAttribute,
884+
};
876885

877886
$value = is_array($value) ? $this->replacePlaceholders($value) : $value;
878887

879888
if ($rule instanceof ValidatorAwareRule) {
889+
if ($attribute !== $originalAttribute) {
890+
$this->addCustomAttributes([
891+
$attribute => $this->customAttributes[$originalAttribute] ?? $originalAttribute,
892+
]);
893+
}
894+
880895
$rule->setValidator($this);
881896
}
882897

@@ -889,14 +904,14 @@ protected function validateUsingCustomRule($attribute, $value, $rule)
889904
get_class($rule->invokable()) :
890905
get_class($rule);
891906

892-
$this->failedRules[$attribute][$ruleClass] = [];
907+
$this->failedRules[$originalAttribute][$ruleClass] = [];
893908

894-
$messages = $this->getFromLocalArray($attribute, $ruleClass) ?? $rule->message();
909+
$messages = $this->getFromLocalArray($originalAttribute, $ruleClass) ?? $rule->message();
895910

896911
$messages = $messages ? (array) $messages : [$ruleClass];
897912

898913
foreach ($messages as $key => $message) {
899-
$key = is_string($key) ? $key : $attribute;
914+
$key = is_string($key) ? $key : $originalAttribute;
900915

901916
$this->messages->add($key, $this->makeReplacements(
902917
$message, $key, $ruleClass, []
@@ -1189,7 +1204,7 @@ public function getRulesWithoutPlaceholders()
11891204
{
11901205
return (new Collection($this->rules))
11911206
->mapWithKeys(fn ($value, $key) => [
1192-
str_replace($this->dotPlaceholder, '\\.', $key) => $value,
1207+
str_replace('__dot__'.static::$placeholderHash, '\\.', $key) => $value,
11931208
])
11941209
->all();
11951210
}
@@ -1203,7 +1218,7 @@ public function getRulesWithoutPlaceholders()
12031218
public function setRules(array $rules)
12041219
{
12051220
$rules = (new Collection($rules))->mapWithKeys(function ($value, $key) {
1206-
return [str_replace('\.', $this->dotPlaceholder, $key) => $value];
1221+
return [str_replace('\.', '__dot__'.static::$placeholderHash, $key) => $value];
12071222
})->toArray();
12081223

12091224
$this->initialRules = $rules;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Integration\Validation\Rules;
4+
5+
use Illuminate\Support\Facades\Validator;
6+
use Illuminate\Validation\Rules\Email;
7+
use Orchestra\Testbench\TestCase;
8+
use PHPUnit\Framework\Attributes\TestWith;
9+
10+
class EmailValidationTest extends TestCase
11+
{
12+
#[TestWith(['0'])]
13+
#[TestWith(['.'])]
14+
#[TestWith(['*'])]
15+
#[TestWith(['__asterisk__'])]
16+
public function test_it_can_validate_attribute_as_array(string $attribute)
17+
{
18+
$validator = Validator::make([
19+
'emails' => [
20+
$attribute => '[email protected]',
21+
],
22+
], [
23+
'emails.*' => ['required', Email::default()->rfcCompliant()],
24+
]);
25+
26+
$this->assertTrue($validator->passes());
27+
}
28+
29+
#[TestWith(['0'])]
30+
#[TestWith(['.'])]
31+
#[TestWith(['*'])]
32+
#[TestWith(['__asterisk__'])]
33+
public function test_it_can_validate_attribute_as_array_when_validation_should_fails(string $attribute)
34+
{
35+
$validator = Validator::make([
36+
'emails' => [
37+
$attribute => 'taylor[at]laravel.com',
38+
],
39+
], [
40+
'emails.*' => ['required', Email::default()->rfcCompliant()],
41+
]);
42+
43+
$this->assertFalse($validator->passes());
44+
45+
$this->assertSame([
46+
0 => __('validation.email', ['attribute' => sprintf('emails.%s', str_replace('_', ' ', $attribute))]),
47+
], $validator->messages()->all());
48+
}
49+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Integration\Validation\Rules;
4+
5+
use Illuminate\Http\UploadedFile;
6+
use Illuminate\Support\Facades\Validator;
7+
use Illuminate\Validation\Rules\File;
8+
use Orchestra\Testbench\TestCase;
9+
use PHPUnit\Framework\Attributes\TestWith;
10+
11+
class FileValidationTest extends TestCase
12+
{
13+
#[TestWith(['0'])]
14+
#[TestWith(['.'])]
15+
#[TestWith(['*'])]
16+
#[TestWith(['__asterisk__'])]
17+
public function test_it_can_validate_attribute_as_array(string $attribute)
18+
{
19+
$file = UploadedFile::fake()->create('laravel.png', 1, 'image/png');
20+
21+
$validator = Validator::make([
22+
'files' => [
23+
$attribute => $file,
24+
],
25+
], [
26+
'files.*' => ['required', File::types(['image/png', 'image/jpeg'])],
27+
]);
28+
29+
$this->assertTrue($validator->passes());
30+
}
31+
32+
#[TestWith(['0'])]
33+
#[TestWith(['.'])]
34+
#[TestWith(['*'])]
35+
#[TestWith(['__asterisk__'])]
36+
public function test_it_can_validate_attribute_as_array_when_validation_should_fails(string $attribute)
37+
{
38+
$file = UploadedFile::fake()->create('laravel.php', 1, 'image/php');
39+
40+
$validator = Validator::make([
41+
'files' => [
42+
$attribute => $file,
43+
],
44+
], [
45+
'files.*' => ['required', File::types($mimes = ['image/png', 'image/jpeg'])],
46+
]);
47+
48+
$this->assertFalse($validator->passes());
49+
50+
$this->assertSame([
51+
0 => __('validation.mimetypes', ['attribute' => sprintf('files.%s', str_replace('_', ' ', $attribute)), 'values' => implode(', ', $mimes)]),
52+
], $validator->messages()->all());
53+
}
54+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Integration\Validation\Rules;
4+
5+
use Illuminate\Support\Facades\Validator;
6+
use Illuminate\Validation\Rules\Password;
7+
use Orchestra\Testbench\TestCase;
8+
use PHPUnit\Framework\Attributes\TestWith;
9+
10+
class PasswordValidationTest extends TestCase
11+
{
12+
#[TestWith(['0'])]
13+
#[TestWith(['.'])]
14+
#[TestWith(['*'])]
15+
#[TestWith(['__asterisk__'])]
16+
public function test_it_can_validate_attribute_as_array(string $attribute)
17+
{
18+
$validator = Validator::make([
19+
'passwords' => [
20+
$attribute => 'secret',
21+
],
22+
], [
23+
'passwords.*' => ['required', Password::default()->min(6)],
24+
]);
25+
26+
$this->assertTrue($validator->passes());
27+
}
28+
29+
#[TestWith(['0'])]
30+
#[TestWith(['.'])]
31+
#[TestWith(['*'])]
32+
#[TestWith(['__asterisk__'])]
33+
public function test_it_can_validate_attribute_as_array_when_validation_should_fails(string $attribute)
34+
{
35+
$validator = Validator::make([
36+
'passwords' => [
37+
$attribute => 'secret',
38+
],
39+
], [
40+
'passwords.*' => ['required', Password::default()->min(8)],
41+
]);
42+
43+
$this->assertFalse($validator->passes());
44+
45+
$this->assertSame([
46+
0 => sprintf('The passwords.%s field must be at least 8 characters.', str_replace('_', ' ', $attribute)),
47+
], $validator->messages()->all());
48+
}
49+
}

0 commit comments

Comments
 (0)