Skip to content
95 changes: 42 additions & 53 deletions src/Illuminate/Validation/Concerns/ReplacesAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,10 @@ protected function replaceMissingUnless($message, $attribute, $rule, $parameters
*/
protected function replaceMissingWith($message, $attribute, $rule, $parameters)
{
return str_replace(
[':values', ':VALUES', ':Values'],
[
implode(' / ', $this->getAttributeList($parameters)),
Str::upper(implode(' / ', $this->getAttributeList($parameters))),
implode(' / ', array_map(Str::ucfirst(...), $this->getAttributeList($parameters))),
],
$message
return $this->replaceWhileKeepingCase(
$message,
['values' => $this->getAttributeList($parameters)],
['values' => ' / '],
);
}

Expand Down Expand Up @@ -295,14 +291,10 @@ protected function replaceIn($message, $attribute, $rule, $parameters)
$parameter = $this->getDisplayableValue($attribute, $parameter);
}

return str_replace(
[':values', ':VALUES', ':Values'],
[
implode(', ', $parameters),
Str::upper(implode(', ', $parameters)),
implode(', ', array_map(Str::ucfirst(...), $parameters)),
],
return $this->replaceWhileKeepingCase(
$message,
['values' => $parameters],
['values' => ', '],
);
}

Expand Down Expand Up @@ -431,14 +423,10 @@ protected function replacePresentUnless($message, $attribute, $rule, $parameters
*/
protected function replacePresentWith($message, $attribute, $rule, $parameters)
{
return str_replace(
[':values', ':VALUES', ':Values'],
[
implode(' / ', $this->getAttributeList($parameters)),
Str::upper(implode(' / ', $this->getAttributeList($parameters))),
implode(' / ', array_map(Str::ucfirst(...), $this->getAttributeList($parameters))),
],
return $this->replaceWhileKeepingCase(
$message,
['values' => $this->getAttributeList($parameters)],
['values' => ' / '],
);
}

Expand Down Expand Up @@ -467,14 +455,10 @@ protected function replacePresentWithAll($message, $attribute, $rule, $parameter
*/
protected function replaceRequiredWith($message, $attribute, $rule, $parameters)
{
return str_replace(
[':values', ':VALUES', ':Values'],
[
implode(' / ', $this->getAttributeList($parameters)),
Str::upper(implode(' / ', $this->getAttributeList($parameters))),
implode(' / ', array_map(Str::ucfirst(...), $this->getAttributeList($parameters))),
],
return $this->replaceWhileKeepingCase(
$message,
['values' => $this->getAttributeList($parameters)],
['values' => ' / '],
);
}

Expand Down Expand Up @@ -657,17 +641,10 @@ protected function replaceRequiredUnless($message, $attribute, $rule, $parameter
$values[] = $this->getDisplayableValue($parameters[0], $value);
}

return str_replace(
[':other', ':OTHER', ':Other', ':values', ':VALUES', ':Values'],
[
$other,
Str::upper($other),
Str::ucfirst($other),
implode(', ', $values),
Str::upper(implode(', ', $values)),
implode(', ', array_map(Str::ucfirst(...), $values)),
],
$message
return $this->replaceWhileKeepingCase(
$message,
['other' => $other, 'values' => $values],
['values' => ', '],
);
}

Expand Down Expand Up @@ -738,14 +715,10 @@ protected function replaceProhibitedUnless($message, $attribute, $rule, $paramet
*/
protected function replaceProhibits($message, $attribute, $rule, $parameters)
{
return str_replace(
[':other', ':OTHER', ':Other'],
[
implode(' / ', $this->getAttributeList($parameters)),
Str::upper(implode(' / ', $this->getAttributeList($parameters))),
implode(' / ', array_map(Str::ucfirst(...), $this->getAttributeList($parameters))),
],
$message
return $this->replaceWhileKeepingCase(
$message,
['other' => $this->getAttributeList($parameters)],
['other' => ' / '],
);
}

Expand Down Expand Up @@ -935,20 +908,36 @@ protected function replaceDoesntContain($message, $attribute, $rule, $parameters
* Replace the given string while maintaining different casing variants.
*
* @param array<string, string> $mapping
* @param array<string, string> $wordSeparators
*/
private function replaceWhileKeepingCase(string $message, array $mapping): string
private function replaceWhileKeepingCase(string $message, array $mapping, array $wordSeparators = []): string
{
$fn = [Str::lower(...), Str::upper(...), Str::ucfirst(...)];
$fn = [
Str::lower(...),
Str::upper(...),
//fn (string $placeholder, ?string $parameter = null) => ucwords($parameter ?? $placeholder, $parameter !== null ? ($wordSeparators[$placeholder] ?? ' ') : ' '),
];

$ucwordsReplacement = fn (string $parameter, string $placeholder) => array_key_exists($placeholder, $wordSeparators)
? ucwords($parameter, $wordSeparators[$placeholder])
: ucfirst($parameter);

$cases = array_reduce(
array_keys($mapping),
fn (array $carry, string $placeholder) => [...$carry, ...array_map(fn (callable $fn) => ':'.$fn($placeholder), $fn)],
fn (array $carry, string $placeholder) => [...$carry, ...array_map(fn (callable $fn) => ':'.$fn($placeholder), [...$fn, ucfirst(...)])],
[],
);

$replacements = array_reduce(
array_values($mapping),
fn (array $carry, string $parameter) => [...$carry, ...array_map(fn (callable $fn) => $fn($parameter), $fn)],
array_keys($mapping),
fn (array $carry, string $placeholder) => [...$carry, ...array_map(function (callable $fn) use ($placeholder, $mapping, $wordSeparators) {
$parameter = $mapping[$placeholder];
if (is_array($parameter) && array_is_list($parameter) && array_key_exists($placeholder, $wordSeparators)) {
$parameter = implode($wordSeparators[$placeholder], $parameter);
}

return $fn($parameter, $placeholder);
}, [...$fn, $ucwordsReplacement])],
[],
);

Expand Down
18 changes: 9 additions & 9 deletions tests/Validation/ValidationValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -816,12 +816,12 @@ public function testDisplayableValuesAreReplaced()
// in:foo,bar,...
$trans = $this->getIlluminateArrayTranslator();
$trans->addLines(['validation.in' => ':attribute must be included in :values.'], 'en');
$trans->addLines(['validation.values.type.5' => 'Short'], 'en');
$trans->addLines(['validation.values.type.300' => 'Long'], 'en');
$trans->addLines(['validation.values.type.5' => 'short'], 'en');
$trans->addLines(['validation.values.type.300' => 'long'], 'en');
$v = new Validator($trans, ['type' => '4'], ['type' => 'in:5,300']);
$this->assertFalse($v->passes());
$v->messages()->setFormat(':message');
$this->assertSame('type must be included in Short, Long.', $v->messages()->first('type'));
$this->assertSame('type must be included in short, long.', $v->messages()->first('type'));

// date_equals:tomorrow
$trans = $this->getIlluminateArrayTranslator();
Expand All @@ -837,30 +837,30 @@ public function testDisplayableValuesAreReplaced()
$trans->addLines(['validation.in' => ':attribute must be included in :values.'], 'en');
$customValues = [
'type' => [
'5' => 'Short',
'300' => 'Long',
'5' => 'short',
'300' => 'long',
],
];
$v = new Validator($trans, ['type' => '4'], ['type' => 'in:5,300']);
$v->addCustomValues($customValues);
$this->assertFalse($v->passes());
$v->messages()->setFormat(':message');
$this->assertSame('type must be included in Short, Long.', $v->messages()->first('type'));
$this->assertSame('type must be included in short, long.', $v->messages()->first('type'));

// set custom values by setter
$trans = $this->getIlluminateArrayTranslator();
$trans->addLines(['validation.in' => ':attribute must be included in :values.'], 'en');
$customValues = [
'type' => [
'5' => 'Short',
'300' => 'Long',
'5' => 'short',
'300' => 'long',
],
];
$v = new Validator($trans, ['type' => '4'], ['type' => 'in:5,300']);
$v->setValueNames($customValues);
$this->assertFalse($v->passes());
$v->messages()->setFormat(':message');
$this->assertSame('type must be included in Short, Long.', $v->messages()->first('type'));
$this->assertSame('type must be included in short, long.', $v->messages()->first('type'));
}

public function testDisplayableAttributesAreReplacedInCustomReplacers()
Expand Down
Loading