Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9.x] Added support for index and position placeholders in array validation messages #41123

Merged
merged 10 commits into from
Feb 24, 2022
33 changes: 33 additions & 0 deletions src/Illuminate/Validation/Concerns/FormatsMessages.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ public function makeReplacements($message, $attribute, $rule, $parameters)

$message = $this->replaceInputPlaceholder($message, $attribute);

$message = $this->replaceIndexPlaceholder($message, $attribute);

$message = $this->replacePositionPlaceholder($message, $attribute);

if (isset($this->replacers[Str::snake($rule)])) {
return $this->callReplacer($message, $attribute, Str::snake($rule), $parameters, $this);
} elseif (method_exists($this, $replacer = "replace{$rule}")) {
Expand Down Expand Up @@ -307,6 +311,35 @@ protected function replaceAttributePlaceholder($message, $value)
);
}

/**
* Replace the :index placeholder in the given message.
*
* @param string $message
* @param string $attribute
* @return string
*/
protected function replaceIndexPlaceholder($message, $attribute)
{
$index = explode('.', $attribute);

return str_ireplace(':index', $index[1] ?? 0, $message);
}

/**
* Replace the :pos placeholder in the given message.
*
* @param string $message
* @param string $attribute
* @return string
*/
protected function replacePositionPlaceholder($message, $attribute)
{
$index = explode('.', $attribute);
$i = ($index[1] ?? 0) + 1;

return str_ireplace(':pos', $i, $message);
}

/**
* Replace the :input placeholder in the given message.
*
Expand Down
64 changes: 64 additions & 0 deletions tests/Validation/ValidationValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,70 @@ public function testDisplayableAttributesAreReplacedInCustomReplacers()
new Validator($trans, ['firstname' => 'Bob', 'lastname' => 'Smith'], ['lastname' => 'alliteration:firstname']);
}

public function testIndexValuesAreReplaced()
{
$trans = $this->getIlluminateArrayTranslator();

$v = new Validator($trans, ['name' => ''], ['name' => 'required'], ['name.required' => 'Name :index is required.']);
$this->assertFalse($v->passes());
$this->assertSame('Name 0 is required.', $v->messages()->first('name'));

$v = new Validator($trans, ['input' => [['name' => '']]], ['input.*.name' => 'required'], ['input.*.name.required' => 'Name :index is required.']);
$this->assertFalse($v->passes());
$this->assertSame('Name 0 is required.', $v->messages()->first('input.*.name'));
$v = new Validator($trans, ['input' => [['name' => '']]], ['input.*.name' => 'required'], ['input.*.name.required' => ':Attribute :index is required.']);
$v->setAttributeNames([
'input.*.name' => 'name',
]);
$this->assertFalse($v->passes());
$this->assertSame('Name 0 is required.', $v->messages()->first('input.*.name'));

$v = new Validator($trans, ['input' => [['name' => 'Bob'], ['name' => ''], ['name' => 'Jane']]], ['input.*.name' => 'required'], ['input.*.name.required' => 'Name :index is required.']);
$this->assertFalse($v->passes());
$this->assertSame('Name 1 is required.', $v->messages()->first('input.*.name'));
$v = new Validator($trans, ['input' => [['name' => 'Bob'], ['name' => ''], ['name' => 'Jane']]], ['input.*.name' => 'required'], ['input.*.name.required' => ':Attribute :index is required.']);
$v->setAttributeNames([
'input.*.name' => 'name',
]);
$this->assertFalse($v->passes());
$this->assertSame('Name 1 is required.', $v->messages()->first('input.*.name'));

$v = new Validator($trans, ['input' => [['name' => 'Bob'], ['name' => 'Jane']]], ['input.*.name' => 'required'], ['input.*.name.required' => 'Name :index is required.']);
$this->assertTrue($v->passes());
}

public function testPositionValuesAreReplaced()
{
$trans = $this->getIlluminateArrayTranslator();

$v = new Validator($trans, ['name' => ''], ['name' => 'required'], ['name.required' => 'Name :pos is required.']);
$this->assertFalse($v->passes());
$this->assertSame('Name 1 is required.', $v->messages()->first('name'));

$v = new Validator($trans, ['input' => [['name' => '']]], ['input.*.name' => 'required'], ['input.*.name.required' => 'Name :pos is required.']);
$this->assertFalse($v->passes());
$this->assertSame('Name 1 is required.', $v->messages()->first('input.*.name'));
$v = new Validator($trans, ['input' => [['name' => '']]], ['input.*.name' => 'required'], ['input.*.name.required' => ':Attribute :pos is required.']);
$v->setAttributeNames([
'input.*.name' => 'name',
]);
$this->assertFalse($v->passes());
$this->assertSame('Name 1 is required.', $v->messages()->first('input.*.name'));

$v = new Validator($trans, ['input' => [['name' => 'Bob'], ['name' => ''], ['name' => 'Jane']]], ['input.*.name' => 'required'], ['input.*.name.required' => 'Name :pos is required.']);
$this->assertFalse($v->passes());
$this->assertSame('Name 2 is required.', $v->messages()->first('input.*.name'));
$v = new Validator($trans, ['input' => [['name' => 'Bob'], ['name' => ''], ['name' => 'Jane']]], ['input.*.name' => 'required'], ['input.*.name.required' => ':Attribute :pos is required.']);
$v->setAttributeNames([
'input.*.name' => 'name',
]);
$this->assertFalse($v->passes());
$this->assertSame('Name 2 is required.', $v->messages()->first('input.*.name'));

$v = new Validator($trans, ['input' => [['name' => 'Bob'], ['name' => 'Jane']]], ['input.*.name' => 'required'], ['input.*.name.required' => 'Name :pos is required.']);
$this->assertTrue($v->passes());
}

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