Do not overwrite "IDs" when updating names

When you have a chain of rules in the Validation and overwrite the name
with "setName()," it's impossible to get the messages from all rules in
the chain as an array because they all have the same name.

These changes will change that behavior by creating a more explicit
distinction between "IDs" and "names." The "IDs" will remain
unchangeable, while we can always overwrite the names. That means that
the array messages will look more similar to the chain, and it will be
possible to overwrite the messages from multiple rules in the same
chain.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2024-03-25 23:14:05 +01:00
parent 9322cd6375
commit 8573bc5d45
No known key found for this signature in database
GPG key ID: 221E9281655813A6
25 changed files with 102 additions and 77 deletions

View file

@ -43,7 +43,7 @@ final class Result
) {
$this->name = $rule->getName() ?? $name;
$this->template = $rule->getTemplate() ?? $template;
$this->id = $id ?? $this->name ?? lcfirst(substr((string) strrchr($rule::class, '\\'), 1));
$this->id = $id ?? lcfirst(substr((string) strrchr($rule::class, '\\'), 1));
$this->children = $children;
}

View file

@ -38,10 +38,13 @@ final class Key extends Wrapper
return $keyExistsResult;
}
$child = $this->rule->evaluate($input[$this->key]);
$child = $this->rule
->evaluate($input[$this->key])
->withId((string) $this->key);
return (new Result($child->isValid, $input, $this))
->withChildren($child)
->withId((string) $this->key)
->withNameIfMissing($this->rule->getName() ?? (string) $this->key);
}
}

View file

@ -30,7 +30,7 @@ final class KeyExists extends Standard
public function evaluate(mixed $input): Result
{
return new Result($this->hasKey($input), $input, $this, name: (string) $this->key);
return new Result($this->hasKey($input), $input, $this, name: (string) $this->key, id: (string) $this->key);
}
private function hasKey(mixed $input): bool

View file

@ -33,10 +33,13 @@ final class KeyOptional extends Wrapper
return $keyExistsResult->withInvertedMode();
}
$child = $this->rule->evaluate($input[$this->key]);
$child = $this->rule
->evaluate($input[$this->key])
->withId((string) $this->key);
return (new Result($child->isValid, $input, $this))
->withChildren($child)
->withId((string) $this->key)
->withNameIfMissing($this->rule->getName() ?? (string) $this->key);
}
}

View file

@ -35,10 +35,13 @@ final class Property extends Wrapper
return $propertyExistsResult;
}
$childResult = $this->rule->evaluate($this->extractPropertyValue($input, $this->propertyName));
$childResult = $this->rule
->evaluate($this->extractPropertyValue($input, $this->propertyName))
->withId($this->propertyName);
return (new Result($childResult->isValid, $input, $this))
->withChildren($childResult)
->withId($this->propertyName)
->withNameIfMissing($this->rule->getName() ?? $this->propertyName);
}
}

View file

@ -30,11 +30,17 @@ final class PropertyExists extends Standard
public function evaluate(mixed $input): Result
{
if (!is_object($input)) {
return Result::failed($input, $this)->withNameIfMissing($this->propertyName);
return Result::failed($input, $this)->withNameIfMissing($this->propertyName)->withId($this->propertyName);
}
$reflection = new ReflectionObject($input);
return new Result($reflection->hasProperty($this->propertyName), $input, $this, name: $this->propertyName);
return new Result(
$reflection->hasProperty($this->propertyName),
$input,
$this,
name: $this->propertyName,
id: $this->propertyName
);
}
}

View file

@ -35,10 +35,13 @@ final class PropertyOptional extends Wrapper
return $propertyExistsResult->withInvertedMode();
}
$childResult = $this->rule->evaluate($this->extractPropertyValue($input, $this->propertyName));
$childResult = $this->rule
->evaluate($this->extractPropertyValue($input, $this->propertyName))
->withId($this->propertyName);
return (new Result($childResult->isValid, $input, $this))
->withChildren($childResult)
->withId($this->propertyName)
->withNameIfMissing($this->rule->getName() ?? $this->propertyName);
}
}

View file

@ -11,5 +11,5 @@ exceptionMessages(static fn () => v::key('firstname', v::notBlank()->setName('Fi
?>
--EXPECTF--
[
'First Name' => 'First Name must be present',
'firstname' => 'First Name must be present',
]

View file

@ -0,0 +1,17 @@
--FILE--
<?php
declare(strict_types=1);
use Respect\Validation\Validator as v;
require 'vendor/autoload.php';
exceptionMessages(static fn() => v::noWhitespace()->email()->setName('User Email')->assert('not email'));
?>
--EXPECT--
[
'__root__' => 'All of the required rules must pass for User Email',
'noWhitespace' => 'User Email must not contain whitespace',
'email' => 'User Email must be valid email',
]

View file

@ -44,6 +44,6 @@ With name
Range must be greater than 1 and less than 10
- Range must be greater than 1 and less than 10
[
'Range' => 'Range must be greater than 1 and less than 10',
'betweenExclusive' => 'Range must be greater than 1 and less than 10',
]

View file

@ -83,7 +83,7 @@ With wrapped name, default
Wrapped must evaluate to `true`
- Wrapped must evaluate to `true`
[
'Wrapped' => 'Wrapped must evaluate to `true`',
'trueVal' => 'Wrapped must evaluate to `true`',
]
With wrapper name, default
@ -91,7 +91,7 @@ With wrapper name, default
Wrapper must evaluate to `true`
- Wrapper must evaluate to `true`
[
'Wrapper' => 'Wrapper must evaluate to `true`',
'trueVal' => 'Wrapper must evaluate to `true`',
]
With the name set in the wrapped rule of an inverted failing rule
@ -99,7 +99,7 @@ With the name set in the wrapped rule of an inverted failing rule
Wrapped must not evaluate to `true`
- Wrapped must not evaluate to `true`
[
'Wrapped' => 'Wrapped must not evaluate to `true`',
'trueVal' => 'Wrapped must not evaluate to `true`',
]
With the name set in an inverted failing rule
@ -107,7 +107,7 @@ With the name set in an inverted failing rule
Not must not evaluate to `true`
- Not must not evaluate to `true`
[
'Not' => 'Not must not evaluate to `true`',
'trueVal' => 'Not must not evaluate to `true`',
]
With the name set in the "consecutive" that has an inverted failing rule
@ -115,7 +115,7 @@ With the name set in the "consecutive" that has an inverted failing rule
Wrapper must not evaluate to `true`
- Wrapper must not evaluate to `true`
[
'Wrapper' => 'Wrapper must not evaluate to `true`',
'trueVal' => 'Wrapper must not evaluate to `true`',
]
With template
@ -141,3 +141,4 @@ subdivisionCode must be a subdivision code of Brazil
[
'subdivisionCode' => 'subdivisionCode must be a subdivision code of Brazil',
]

View file

@ -138,9 +138,9 @@ Wrapped must be of type integer
- Wrapped must be of type integer
[
'__root__' => 'Each item in Wrapped must be valid',
'Wrapped.1' => 'Wrapped must be of type integer',
'Wrapped.2' => 'Wrapped must be of type integer',
'Wrapped.3' => 'Wrapped must be of type integer',
'intType.1' => 'Wrapped must be of type integer',
'intType.2' => 'Wrapped must be of type integer',
'intType.3' => 'Wrapped must be of type integer',
]
With name, negative
@ -152,9 +152,9 @@ Wrapped must not be of type integer
- Wrapped must not be of type integer
[
'__root__' => 'Each item in Wrapped must not validate',
'Wrapped.1' => 'Wrapped must not be of type integer',
'Wrapped.2' => 'Wrapped must not be of type integer',
'Wrapped.3' => 'Wrapped must not be of type integer',
'intType.1' => 'Wrapped must not be of type integer',
'intType.2' => 'Wrapped must not be of type integer',
'intType.3' => 'Wrapped must not be of type integer',
]
With wrapper name, default
@ -166,9 +166,9 @@ Wrapper must be of type integer
- Wrapper must be of type integer
[
'__root__' => 'Each item in Wrapper must be valid',
'Wrapper.1' => 'Wrapper must be of type integer',
'Wrapper.2' => 'Wrapper must be of type integer',
'Wrapper.3' => 'Wrapper must be of type integer',
'intType.1' => 'Wrapper must be of type integer',
'intType.2' => 'Wrapper must be of type integer',
'intType.3' => 'Wrapper must be of type integer',
]
With wrapper name, negative
@ -180,9 +180,9 @@ Wrapper must not be of type integer
- Wrapper must not be of type integer
[
'__root__' => 'Each item in Wrapper must not validate',
'Wrapper.1' => 'Wrapper must not be of type integer',
'Wrapper.2' => 'Wrapper must not be of type integer',
'Wrapper.3' => 'Wrapper must not be of type integer',
'intType.1' => 'Wrapper must not be of type integer',
'intType.2' => 'Wrapper must not be of type integer',
'intType.3' => 'Wrapper must not be of type integer',
]
With Not name, negative
@ -194,9 +194,9 @@ Not must not be of type integer
- Not must not be of type integer
[
'__root__' => 'Each item in Not must not validate',
'Not.1' => 'Not must not be of type integer',
'Not.2' => 'Not must not be of type integer',
'Not.3' => 'Not must not be of type integer',
'intType.1' => 'Not must not be of type integer',
'intType.2' => 'Not must not be of type integer',
'intType.3' => 'Not must not be of type integer',
]
With template, non-iterable
@ -247,15 +247,14 @@ First item should have been an integer
With array template and name, default
⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺
First item should have been an integer
- Here a sequence of items that did not pass the validation
- First item should have been an integer
- Second item should have been an integer
- Third item should have been an integer
Wrapped must be of type integer
- Each item in Wrapped must be valid
- Wrapped must be of type integer
- Wrapped must be of type integer
- Wrapped must be of type integer
[
'__root__' => 'Here a sequence of items that did not pass the validation',
'Wrapped.1' => 'First item should have been an integer',
'Wrapped.2' => 'Second item should have been an integer',
'Wrapped.3' => 'Third item should have been an integer',
'__root__' => 'Each item in Wrapped must be valid',
'intType.1' => 'Wrapped must be of type integer',
'intType.2' => 'Wrapped must be of type integer',
'intType.3' => 'Wrapped must be of type integer',
]

View file

@ -44,6 +44,5 @@ With name
Hetu must be a valid Finnish personal identity code
- Hetu must be a valid Finnish personal identity code
[
'Hetu' => 'Hetu must be a valid Finnish personal identity code',
'hetu' => 'Hetu must be a valid Finnish personal identity code',
]

View file

@ -44,6 +44,5 @@ With name
Options must be of type iterable
- Options must be of type iterable
[
'Options' => 'Options must be of type iterable',
'iterableType' => 'Options must be of type iterable',
]

View file

@ -90,7 +90,7 @@ With wrapped name, missing key
Wrapped must be present
- Wrapped must be present
[
'Wrapped' => 'Wrapped must be present',
'foo' => 'Wrapped must be present',
]
With wrapped name, default
@ -98,7 +98,7 @@ With wrapped name, default
Wrapped must be of type integer
- Wrapped must be of type integer
[
'Wrapped' => 'Wrapped must be of type integer',
'foo' => 'Wrapped must be of type integer',
]
With wrapped name, negative
@ -106,7 +106,7 @@ With wrapped name, negative
Wrapped must not be of type integer
- Wrapped must not be of type integer
[
'Wrapped' => 'Wrapped must not be of type integer',
'foo' => 'Wrapped must not be of type integer',
]
With wrapper name, default
@ -156,4 +156,3 @@ No off-key key
[
'foo' => 'No off-key key',
]

View file

@ -36,7 +36,7 @@ Custom name
Custom name must be present
- Custom name must be present
[
'Custom name' => 'Custom name must be present',
'foo' => 'Custom name must be present',
]
Custom template
@ -46,4 +46,3 @@ Custom template for `foo`
[
'foo' => 'Custom template for `foo`',
]

View file

@ -73,7 +73,7 @@ With wrapped name, default
Wrapped must be of type integer
- Wrapped must be of type integer
[
'Wrapped' => 'Wrapped must be of type integer',
'foo' => 'Wrapped must be of type integer',
]
With wrapped name, negative
@ -81,7 +81,7 @@ With wrapped name, negative
Wrapped must not be of type integer
- Wrapped must not be of type integer
[
'Wrapped' => 'Wrapped must not be of type integer',
'foo' => 'Wrapped must not be of type integer',
]
With wrapper name, default
@ -123,4 +123,3 @@ No off-key key
[
'foo' => 'No off-key key',
]

View file

@ -59,7 +59,7 @@ With created name, default
Created must be of type integer
- Created must be of type integer
[
'Created' => 'Created must be of type integer',
'intType' => 'Created must be of type integer',
]
With wrapper name, default
@ -67,7 +67,7 @@ With wrapper name, default
Wrapper must be of type integer
- Wrapper must be of type integer
[
'Wrapper' => 'Wrapper must be of type integer',
'intType' => 'Wrapper must be of type integer',
]
With created name, negative
@ -75,7 +75,7 @@ With created name, negative
Created must not be of type integer
- Created must not be of type integer
[
'Created' => 'Created must not be of type integer',
'intType' => 'Created must not be of type integer',
]
With wrapper name, negative
@ -83,7 +83,7 @@ With wrapper name, negative
Wrapped must not be of type integer
- Wrapped must not be of type integer
[
'Wrapped' => 'Wrapped must not be of type integer',
'intType' => 'Wrapped must not be of type integer',
]
With not name, negative
@ -91,7 +91,7 @@ With not name, negative
Not must not be of type integer
- Not must not be of type integer
[
'Not' => 'Not must not be of type integer',
'intType' => 'Not must not be of type integer',
]
With template, default
@ -101,4 +101,3 @@ Lazy lizards lounging like lords in the local lagoon
[
'intType' => 'Lazy lizards lounging like lords in the local lagoon',
]

View file

@ -53,5 +53,5 @@ With wrapper name
The length of Cactus must equal 3
- The length of Cactus must equal 3
[
'Cactus' => 'The length of Cactus must equal 3',
'length' => 'The length of Cactus must equal 3',
]

View file

@ -64,7 +64,7 @@ With wrapped name, default
The maximum of Wrapped must be negative
- The maximum of Wrapped must be negative
[
'Wrapped' => 'The maximum of Wrapped must be negative',
'max' => 'The maximum of Wrapped must be negative',
]
With wrapper name, default
@ -72,7 +72,7 @@ With wrapper name, default
The maximum of Wrapper must be negative
- The maximum of Wrapper must be negative
[
'Wrapper' => 'The maximum of Wrapper must be negative',
'max' => 'The maximum of Wrapper must be negative',
]
With wrapped name, negative
@ -80,7 +80,7 @@ With wrapped name, negative
The maximum of Wrapped must not be negative
- The maximum of Wrapped must not be negative
[
'Wrapped' => 'The maximum of Wrapped must not be negative',
'max' => 'The maximum of Wrapped must not be negative',
]
With wrapper name, negative
@ -88,7 +88,7 @@ With wrapper name, negative
The maximum of Wrapper must not be negative
- The maximum of Wrapper must not be negative
[
'Wrapper' => 'The maximum of Wrapper must not be negative',
'max' => 'The maximum of Wrapper must not be negative',
]
With template, default

View file

@ -44,6 +44,5 @@ With name
The minimum from Options must equal 1
- The minimum from Options must equal 1
[
'Options' => 'The minimum from Options must equal 1',
'min' => 'The minimum from Options must equal 1',
]

View file

@ -45,7 +45,7 @@ Default with name
Phone must be a valid telephone number
- Phone must be a valid telephone number
[
'Phone' => 'Phone must be a valid telephone number',
'phone' => 'Phone must be a valid telephone number',
]
Country-specific with name
@ -53,5 +53,5 @@ Country-specific with name
Phone must be a valid telephone number for country United States
- Phone must be a valid telephone number for country United States
[
'Phone' => 'Phone must be a valid telephone number for country United States',
'phone' => 'Phone must be a valid telephone number for country United States',
]

View file

@ -98,7 +98,7 @@ With wrapped name, missing property
Wrapped must be present
- Wrapped must be present
[
'Wrapped' => 'Wrapped must be present',
'foo' => 'Wrapped must be present',
]
With wrapped name, default
@ -106,7 +106,7 @@ With wrapped name, default
Wrapped must be of type integer
- Wrapped must be of type integer
[
'Wrapped' => 'Wrapped must be of type integer',
'foo' => 'Wrapped must be of type integer',
]
With wrapped name, negative
@ -114,7 +114,7 @@ With wrapped name, negative
Wrapped must not be of type integer
- Wrapped must not be of type integer
[
'Wrapped' => 'Wrapped must not be of type integer',
'foo' => 'Wrapped must not be of type integer',
]
With wrapper name, default
@ -164,4 +164,3 @@ Not a prompt prospect of a particularly primitive property
[
'foo' => 'Not a prompt prospect of a particularly primitive property',
]

View file

@ -36,7 +36,7 @@ Custom name
Custom name must be present
- Custom name must be present
[
'Custom name' => 'Custom name must be present',
'foo' => 'Custom name must be present',
]
Custom template
@ -46,4 +46,3 @@ Custom template for `foo`
[
'foo' => 'Custom template for `foo`',
]

View file

@ -81,7 +81,7 @@ With wrapped name, default
Wrapped must be of type integer
- Wrapped must be of type integer
[
'Wrapped' => 'Wrapped must be of type integer',
'foo' => 'Wrapped must be of type integer',
]
With wrapped name, negative
@ -89,7 +89,7 @@ With wrapped name, negative
Wrapped must not be of type integer
- Wrapped must not be of type integer
[
'Wrapped' => 'Wrapped must not be of type integer',
'foo' => 'Wrapped must not be of type integer',
]
With wrapper name, default
@ -131,4 +131,3 @@ Not proving prudent property planning promotes prosperity
[
'foo' => 'Not proving prudent property planning promotes prosperity',
]