diff --git a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php index abd5ba154a5c..f070a30de609 100644 --- a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php @@ -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' => ' / '], ); } @@ -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' => ', '], ); } @@ -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' => ' / '], ); } @@ -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' => ' / '], ); } @@ -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' => ', '], ); } @@ -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' => ' / '], ); } @@ -935,20 +908,36 @@ protected function replaceDoesntContain($message, $attribute, $rule, $parameters * Replace the given string while maintaining different casing variants. * * @param array $mapping + * @param array $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])], [], ); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index b6ec5ac6722f..3289c50784a9 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -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(); @@ -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()