Skip to content

Commit

Permalink
[11.x] Fix nested rules custom attribute names (#51805)
Browse files Browse the repository at this point in the history
* Find wildcard custom attributes

* Remove whitespace

* Improve comment

* Add test for wildcard attribute names in nested arrays

* Move attribute matching logic

* Add test for translated attribute names

* Fix StyleCI issues

* More StyleCI

* More StyleCI

* formatting

---------

Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
owenandrews and taylorotwell authored Jun 17, 2024
1 parent c2776c3 commit 07e12d3
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 6 deletions.
40 changes: 34 additions & 6 deletions src/Illuminate/Validation/Concerns/FormatsMessages.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,15 @@ public function getDisplayableAttribute($attribute)
// The developer may dynamically specify the array of custom attributes on this
// validator instance. If the attribute exists in this array it is used over
// the other ways of pulling the attribute name for this given attributes.
if (isset($this->customAttributes[$name])) {
return $this->customAttributes[$name];
if ($inlineAttribute = $this->getAttributeFromLocalArray($name)) {
return $inlineAttribute;
}

// We allow for a developer to specify language lines for any attribute in this
// application, which allows flexibility for displaying a unique displayable
// version of the attribute name instead of the name used in an HTTP POST.
if ($line = $this->getAttributeFromTranslations($name)) {
return $line;
if ($translatedAttribute = $this->getAttributeFromTranslations($name)) {
return $translatedAttribute;
}
}

Expand All @@ -301,11 +301,39 @@ public function getDisplayableAttribute($attribute)
* Get the given attribute from the attribute translations.
*
* @param string $name
* @return string
* @return string|null
*/
protected function getAttributeFromTranslations($name)
{
return Arr::get($this->translator->get('validation.attributes'), $name);
return $this->getAttributeFromLocalArray(
$name, Arr::dot((array) $this->translator->get('validation.attributes'))
);
}

/**
* Get the custom name for an attribute if it exists in the given array.
*
* @param string $attribute
* @param array|null $source
* @return string|null
*/
protected function getAttributeFromLocalArray($attribute, $source = null)
{
$source = $source ?: $this->customAttributes;

if (isset($source[$attribute])) {
return $source[$attribute];
}

foreach (array_keys($source) as $sourceKey) {
if (str_contains($sourceKey, '*')) {
$pattern = str_replace('\*', '([^.]*)', preg_quote($sourceKey, '#'));

if (preg_match('#^'.$pattern.'\z#u', $attribute) === 1) {
return $source[$sourceKey];
}
}
}
}

/**
Expand Down
34 changes: 34 additions & 0 deletions tests/Validation/ValidationValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Illuminate\Translation\ArrayLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\DatabasePresenceVerifierInterface;
use Illuminate\Validation\Rule as ValidationRule;
use Illuminate\Validation\Rules\Exists;
use Illuminate\Validation\Rules\ProhibitedIf;
use Illuminate\Validation\Rules\Unique;
Expand Down Expand Up @@ -558,6 +559,39 @@ public function testAttributeNamesAreReplacedInArrays()
$this->assertSame('First name is required!', $v->messages()->first('names.0'));
}

public function testInlineAttributeNamesAreReplacedInArraysFromNestedRules()
{
$trans = $this->getIlluminateArrayTranslator();
$trans->addLines(['validation.required' => ':attribute is required!'], 'en');
$v = new Validator($trans, [
'users' => [['name' => 'Taylor']],
], [
'users.*' => ValidationRule::forEach(fn () => ['id' => 'required']),
], [], [
'users.*.id' => 'User ID',
]);
$this->assertFalse($v->passes());
$v->messages()->setFormat(':message');
$this->assertSame('User ID is required!', $v->messages()->first('users.0.id'));
}

public function testTranslatedAttributeNamesAreReplacedInArraysFromNestedRules()
{
$trans = $this->getIlluminateArrayTranslator();
$trans->addLines([
'validation.required' => ':attribute is required!',
'validation.attributes' => ['users.*.id' => 'User ID'],
], 'en');
$v = new Validator($trans, [
'users' => [['name' => 'Taylor']],
], [
'users.*' => ValidationRule::forEach(fn () => ['id' => 'required']),
]);
$this->assertFalse($v->passes());
$v->messages()->setFormat(':message');
$this->assertSame('User ID is required!', $v->messages()->first('users.0.id'));
}

public function testInputIsReplaced()
{
$trans = $this->getIlluminateArrayTranslator();
Expand Down

0 comments on commit 07e12d3

Please sign in to comment.