Include "__root__" when getting message as an array

When converting an object into an array, we exclude the message root
message from it. Since we're using a convention to template those
messages as an array, we could also use the same convention to return
those messages.

While working on it, I noticed that the name "__self__" wasn't
reflecting what that really meant, so I renamed it "__root__" because it
better reflects the meaning of those messages/templates.

Signed-off-by: Henrique Moody <henriquemoody@gmail.com>
This commit is contained in:
Henrique Moody 2024-03-25 22:32:08 +01:00
parent d1f108dc87
commit fefe905e0b
No known key found for this signature in database
GPG key ID: 221E9281655813A6
14 changed files with 84 additions and 29 deletions

View file

@ -100,6 +100,12 @@ final class StandardFormatter implements Formatter
$messages[$child->id] = current($messages[$child->id]);
}
if (count($messages) > 1) {
$self = ['__root__' => $this->renderer->render($this->getTemplated($result, $selectedTemplates))];
return $self + $messages;
}
return $messages;
}
@ -110,8 +116,8 @@ final class StandardFormatter implements Formatter
return $result;
}
if (!isset($templates[$result->id]) && isset($templates['__self__'])) {
return $result->withTemplate($templates['__self__']);
if (!isset($templates[$result->id]) && isset($templates['__root__'])) {
return $result->withTemplate($templates['__root__']);
}
if (!isset($templates[$result->id])) {
@ -141,7 +147,7 @@ final class StandardFormatter implements Formatter
return false;
}
return isset($templates['__self__']) || isset($templates[$result->id]);
return isset($templates['__root__']) || isset($templates[$result->id]);
}
/**

View file

@ -75,7 +75,7 @@ final class Validator extends Standard
$templates = $this->templates;
if (count($templates) === 0 && $this->getTemplate() != null) {
$templates = ['__self__' => $this->getTemplate()];
$templates = ['__root__' => $this->getTemplate()];
}
throw new ValidationException(

View file

@ -15,4 +15,7 @@
<file>tests/</file>
<rule ref="Respect" />
<rule ref="Generic.Files.LineLength.TooLong">
<exclude-pattern>tests/integration/</exclude-pattern>
</rule>
</ruleset>

View file

@ -39,13 +39,16 @@ exceptionMessages(static function (): void {
?>
--EXPECT--
[
'__root__' => 'All of the required rules must pass for `["mysql": ["host": 42, "schema": 42], "postgresql": ["user": 42, "password": 42]]`',
'mysql' => [
'__root__' => 'All of the required rules must pass for mysql',
'host' => 'host must be of type string',
'user' => 'user must be present',
'password' => 'password must be present',
'schema' => 'schema must be of type string',
],
'postgresql' => [
'__root__' => 'All of the required rules must pass for postgresql',
'host' => 'host must be present',
'user' => 'user must be of type string',
'password' => 'password must be of type string',

View file

@ -26,6 +26,7 @@ exceptionMessages(static function (): void {
?>
--EXPECT--
[
'__root__' => 'All of the required rules must pass for `["username": "u", "birthdate": "Not a date", "password": ""]`',
'username' => 'The length of username must be between 2 and 32',
'birthdate' => 'birthdate must be a valid date/time',
'password' => 'password must not be empty',

View file

@ -50,13 +50,16 @@ exceptionMessages(
?>
--EXPECT--
[
'__root__' => 'All of the required rules must pass for `["mysql": ["host": 42, "schema": 42], "postgresql": ["user": 42, "password": 42]]`',
'mysql' => [
'__root__' => 'All of the required rules must pass for mysql',
'host' => '`host` should be a MySQL host',
'user' => 'Value should be a MySQL username',
'password' => 'password must be present',
'schema' => 'schema must be of type string',
],
'postgresql' => [
'__root__' => 'All of the required rules must pass for postgresql',
'host' => 'host must be present',
'user' => 'user must be of type string',
'password' => 'password must be of type string',

View file

@ -30,24 +30,31 @@ exceptionMessages(static function () use ($cars): void {
--EXPECT--
[
'each' => [
'__root__' => 'Each item in `[["manufacturer": "Honda", "model": "Accord"], ["manufacturer": "Toyota", "model": "Rav4"], ["manufacturer": "Fo ... ]` must be valid',
'oneOf.3' => [
'__root__' => 'Only one of these rules must pass for `["manufacturer": "Ford", "model": "not real"]`',
'allOf.1' => [
'__root__' => 'All of the required rules must pass for `["manufacturer": "Ford", "model": "not real"]`',
'manufacturer' => 'manufacturer must equal "Honda"',
'model' => 'model must be in `["Accord", "Fit"]`',
],
'allOf.2' => [
'__root__' => 'All of the required rules must pass for `["manufacturer": "Ford", "model": "not real"]`',
'manufacturer' => 'manufacturer must equal "Toyota"',
'model' => 'model must be in `["Rav4", "Camry"]`',
],
'allOf.3' => 'model must be in `["F150", "Bronco"]`',
],
'oneOf.4' => [
'__root__' => 'Only one of these rules must pass for `["manufacturer": "Honda", "model": "not valid"]`',
'allOf.1' => 'model must be in `["Accord", "Fit"]`',
'allOf.2' => [
'__root__' => 'All of the required rules must pass for `["manufacturer": "Honda", "model": "not valid"]`',
'manufacturer' => 'manufacturer must equal "Toyota"',
'model' => 'model must be in `["Rav4", "Camry"]`',
],
'allOf.3' => [
'__root__' => 'All of the required rules must pass for `["manufacturer": "Honda", "model": "not valid"]`',
'manufacturer' => 'manufacturer must equal "Ford"',
'model' => 'model must be in `["F150", "Bronco"]`',
],

View file

@ -21,6 +21,7 @@ exceptionMessages(
?>
--EXPECT--
[
'__root__' => 'All of the required rules must pass for "really messed up screen#name"',
'alnum' => '"really messed up screen#name" must contain only letters and digits',
'noWhitespace' => '"really messed up screen#name" cannot contain spaces',
'length' => '"really messed up screen#name" must not have more than 15 chars',

View file

@ -13,6 +13,7 @@ exceptionMessages(
?>
--EXPECT--
[
'__root__' => 'All of the required rules must pass for "really messed up screen#name"',
'alnum' => '"really messed up screen#name" must contain only letters (a-z) and digits (0-9)',
'noWhitespace' => '"really messed up screen#name" must not contain whitespace',
'length' => 'The length of "really messed up screen#name" must be between 1 and 15',

View file

@ -16,7 +16,7 @@ run([
v::allOf(v::stringType(), v::uppercase()),
5,
[
'__self__' => 'Two things are wrong',
'__root__' => 'Two things are wrong',
'stringType' => 'Template for "stringType"',
'uppercase' => 'Template for "uppercase"',
],
@ -31,6 +31,7 @@ Two rules
- "2" must be of type integer
- "2" must be negative
[
'__root__' => 'All of the required rules must pass for "2"',
'intType' => '"2" must be of type integer',
'negative' => '"2" must be negative',
]
@ -42,6 +43,7 @@ Wrapped by "not"
- 3 must not be of type integer
- 3 must not be positive
[
'__root__' => 'These rules must not pass for 3',
'intType' => '3 must not be of type integer',
'positive' => '3 must not be positive',
]
@ -69,6 +71,8 @@ Template for "stringType"
- Template for "stringType"
- Template for "uppercase"
[
'__root__' => 'Two things are wrong',
'stringType' => 'Template for "stringType"',
'uppercase' => 'Template for "uppercase"',
]

View file

@ -48,7 +48,7 @@ run([
v::each(v::intType()),
$default, [
'each' => [
'__self__' => 'Here a sequence of items that did not pass the validation',
'__root__' => 'Here a sequence of items that did not pass the validation',
'intType.1' => 'First item should have been an integer',
'intType.2' => 'Second item should have been an integer',
'intType.3' => 'Third item should have been an integer',
@ -59,7 +59,7 @@ run([
v::each(v::intType()->setName('Wrapped'))->setName('Wrapper'),
$default, [
'Wrapped' => [
'__self__' => 'Here a sequence of items that did not pass the validation',
'__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',
@ -93,6 +93,7 @@ Default
- "b" must be of type integer
- "c" must be of type integer
[
'__root__' => 'Each item in `["a", "b", "c"]` must be valid',
'intType.1' => '"a" must be of type integer',
'intType.2' => '"b" must be of type integer',
'intType.3' => '"c" must be of type integer',
@ -106,6 +107,7 @@ Negative
- 2 must not be of type integer
- 3 must not be of type integer
[
'__root__' => 'Each item in `[1, 2, 3]` must not validate',
'intType.1' => '1 must not be of type integer',
'intType.2' => '2 must not be of type integer',
'intType.3' => '3 must not be of type integer',
@ -135,6 +137,7 @@ Wrapped must be of type integer
- 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',
@ -148,6 +151,7 @@ Wrapped must not be of type integer
- 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',
@ -161,6 +165,7 @@ Wrapper must be of type integer
- 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',
@ -174,6 +179,7 @@ Wrapper must not be of type integer
- 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',
@ -187,6 +193,7 @@ Not must not be of type integer
- 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',
@ -232,6 +239,7 @@ First item should have been an integer
- Second item should have been an integer
- Third item should have been an integer
[
'__root__' => 'Here a sequence of items that did not pass the validation',
'intType.1' => 'First item should have been an integer',
'intType.2' => 'Second item should have been an integer',
'intType.3' => 'Third item should have been an integer',
@ -245,7 +253,9 @@ First item should have been an integer
- Second item should have been an integer
- Third item should have been an 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',
]

View file

@ -32,6 +32,7 @@ trait ArrayProvider
'with single-level children, without templates' => [
self::singleLevelChildrenMessage(),
[
'__root__' => '__parent_original__',
'1st' => '__1st_original__',
'2nd' => '__2nd_original__',
'3rd' => '__3rd_original__',
@ -40,12 +41,13 @@ trait ArrayProvider
'with single-level children, with templates' => [
self::singleLevelChildrenMessage(),
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
'3rd' => '3rd custom',
],
[
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
'3rd' => '3rd custom',
@ -54,7 +56,7 @@ trait ArrayProvider
'with single-level children, with partial templates' => [
self::singleLevelChildrenMessage(),
[
'__root__' => '__parent_original__',
'1st' => '1st custom',
'2nd' => '__2nd_original__',
'3rd' => '3rd custom',
@ -72,7 +74,7 @@ trait ArrayProvider
'with single-nested child, without templates' => [
self::multiLevelChildrenWithSingleNestedChildMessage(),
[
'__root__' => '__parent_original__',
'1st' => '__1st_original__',
'2nd' => '__2nd_1st_original__',
'3rd' => '__3rd_original__',
@ -81,12 +83,13 @@ trait ArrayProvider
'with single-nested child, with templates' => [
self::multiLevelChildrenWithSingleNestedChildMessage(),
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd > 1st custom',
'3rd' => '3rd custom',
],
[
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'2nd_1st' => '2nd > 1st custom',
@ -97,12 +100,13 @@ trait ArrayProvider
'with single-nested child, with partial templates' => [
self::multiLevelChildrenWithSingleNestedChildMessage(),
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '__2nd_1st_original__',
'3rd' => '3rd custom',
],
[
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'2nd_2nd' => '2nd > 2nd not shown',
@ -113,11 +117,13 @@ trait ArrayProvider
'with single-nested child, with overwritten templates' => [
self::multiLevelChildrenWithSingleNestedChildMessage(),
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
'3rd' => '3rd custom',
],
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
'3rd' => '3rd custom',
@ -126,8 +132,10 @@ trait ArrayProvider
'with multi-nested children, without templates' => [
self::multiLevelChildrenWithMultiNestedChildrenMessage(),
[
'__root__' => '__parent_original__',
'1st' => '__1st_original__',
'2nd' => [
'__root__' => '__2nd_original__',
'2nd_1st' => '__2nd_1st_original__',
'2nd_2nd' => '__2nd_2nd_original__',
],
@ -137,16 +145,20 @@ trait ArrayProvider
'with multi-nested children, with templates' => [
self::multiLevelChildrenWithMultiNestedChildrenMessage(),
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'__root__' => '2nd custom',
'2nd_1st' => '2nd > 1st custom',
'2nd_2nd' => '2nd > 2nd custom',
],
'3rd' => '3rd custom',
],
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'__root__' => '2nd custom',
'2nd_1st' => '2nd > 1st custom',
'2nd_2nd' => '2nd > 2nd custom',
],
@ -156,27 +168,28 @@ trait ArrayProvider
'with multi-nested children, with partial templates' => [
self::multiLevelChildrenWithMultiNestedChildrenMessage(),
[
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'__root__' => '__2nd_original__',
'2nd_1st' => '__2nd_1st_original__',
'2nd_2nd' => '2nd > 2nd custom',
],
'3rd' => '3rd custom',
],
[
'parent' => [
'__self__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'2nd_2nd' => '2nd > 2nd custom',
],
'3rd' => '3rd custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'2nd_2nd' => '2nd > 2nd custom',
],
'3rd' => '3rd custom',
],
],
'with children with the same id, without templates' => [
self::singleLevelChildrenWithSameId(),
[
'__root__' => '__parent_original__',
'child.1' => '__1st_original__',
'child.2' => '__2nd_original__',
'child.3' => '__3rd_original__',
@ -185,11 +198,13 @@ trait ArrayProvider
'with children with the same id, with templates' => [
self::singleLevelChildrenWithSameId(),
[
'__root__' => 'Parent custom',
'child.1' => '1st custom',
'child.2' => '2nd custom',
'child.3' => '3rd custom',
],
[
'__root__' => 'Parent custom',
'child.1' => '1st custom',
'child.2' => '2nd custom',
'child.3' => '3rd custom',
@ -198,6 +213,7 @@ trait ArrayProvider
'with children with the same id, with partial templates' => [
self::singleLevelChildrenWithSameId(),
[
'__root__' => '__parent_original__',
'child.1' => '1st custom',
'child.2' => '2nd custom',
'child.3' => '__3rd_original__',

View file

@ -48,7 +48,7 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
'3rd' => '3rd custom',
@ -96,7 +96,7 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'2nd_1st' => '2nd > 1st custom',
@ -115,7 +115,7 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'2nd_2nd' => '2nd > 2nd not shown',
@ -134,7 +134,7 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
'3rd' => '3rd custom',
@ -164,10 +164,10 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'__self__' => '2nd custom',
'__root__' => '2nd custom',
'2nd_1st' => '2nd > 1st custom',
'2nd_2nd' => '2nd > 2nd custom',
],
@ -187,7 +187,7 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => [
'2nd_2nd' => '2nd > 2nd custom',
@ -206,7 +206,7 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
'3rd' => '3rd custom',
@ -232,7 +232,7 @@ trait FullProvider
MESSAGE,
[
'parent' => [
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'child.1' => '1st custom',
'child.2' => '2nd custom',
'child.3' => '3rd custom',

View file

@ -49,7 +49,7 @@ trait MainProvider
->build(),
'Parent custom',
[
'__self__' => 'Parent custom',
'__root__' => 'Parent custom',
'1st' => '1st custom',
'2nd' => '2nd custom',
],