diff --git a/library/Message/StandardFormatter.php b/library/Message/StandardFormatter.php index 1cb705af..7c93a7bb 100644 --- a/library/Message/StandardFormatter.php +++ b/library/Message/StandardFormatter.php @@ -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]); } /** diff --git a/library/Validator.php b/library/Validator.php index e6dfd773..f96fb8ae 100644 --- a/library/Validator.php +++ b/library/Validator.php @@ -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( diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 15934dc3..c53ced14 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -15,4 +15,7 @@ tests/ + + tests/integration/ + diff --git a/tests/integration/get_messages.phpt b/tests/integration/get_messages.phpt index 2ac98d43..94d09d0e 100644 --- a/tests/integration/get_messages.phpt +++ b/tests/integration/get_messages.phpt @@ -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', diff --git a/tests/integration/get_messages_should_include_all_validation_messages_in_a_chain.phpt b/tests/integration/get_messages_should_include_all_validation_messages_in_a_chain.phpt index c0c8ba64..796ee532 100644 --- a/tests/integration/get_messages_should_include_all_validation_messages_in_a_chain.phpt +++ b/tests/integration/get_messages_should_include_all_validation_messages_in_a_chain.phpt @@ -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', diff --git a/tests/integration/get_messages_with_replacements.phpt b/tests/integration/get_messages_with_replacements.phpt index a21c0fe9..8352c6e9 100644 --- a/tests/integration/get_messages_with_replacements.phpt +++ b/tests/integration/get_messages_with_replacements.phpt @@ -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', diff --git a/tests/integration/issue-1348.phpt b/tests/integration/issue-1348.phpt index 96fb813c..fa1434e5 100644 --- a/tests/integration/issue-1348.phpt +++ b/tests/integration/issue-1348.phpt @@ -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"]`', ], diff --git a/tests/integration/readme/custom_messages.phpt b/tests/integration/readme/custom_messages.phpt index b7ace79d..bc0686fc 100644 --- a/tests/integration/readme/custom_messages.phpt +++ b/tests/integration/readme/custom_messages.phpt @@ -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', diff --git a/tests/integration/readme/getting_messages_as_an_array.phpt b/tests/integration/readme/getting_messages_as_an_array.phpt index e3ea2096..6b806238 100644 --- a/tests/integration/readme/getting_messages_as_an_array.phpt +++ b/tests/integration/readme/getting_messages_as_an_array.phpt @@ -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', diff --git a/tests/integration/rules/allOf.phpt b/tests/integration/rules/allOf.phpt index d236e527..1f956adb 100644 --- a/tests/integration/rules/allOf.phpt +++ b/tests/integration/rules/allOf.phpt @@ -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"', ] + diff --git a/tests/integration/rules/each.phpt b/tests/integration/rules/each.phpt index 4547f03d..4cf24af5 100644 --- a/tests/integration/rules/each.phpt +++ b/tests/integration/rules/each.phpt @@ -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', ] + diff --git a/tests/unit/Message/StandardFormatter/ArrayProvider.php b/tests/unit/Message/StandardFormatter/ArrayProvider.php index 739f2651..695faa91 100644 --- a/tests/unit/Message/StandardFormatter/ArrayProvider.php +++ b/tests/unit/Message/StandardFormatter/ArrayProvider.php @@ -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__', diff --git a/tests/unit/Message/StandardFormatter/FullProvider.php b/tests/unit/Message/StandardFormatter/FullProvider.php index 9f6ec74a..c1fdbbdd 100644 --- a/tests/unit/Message/StandardFormatter/FullProvider.php +++ b/tests/unit/Message/StandardFormatter/FullProvider.php @@ -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', diff --git a/tests/unit/Message/StandardFormatter/MainProvider.php b/tests/unit/Message/StandardFormatter/MainProvider.php index 18ad0d07..13047b22 100644 --- a/tests/unit/Message/StandardFormatter/MainProvider.php +++ b/tests/unit/Message/StandardFormatter/MainProvider.php @@ -49,7 +49,7 @@ trait MainProvider ->build(), 'Parent custom', [ - '__self__' => 'Parent custom', + '__root__' => 'Parent custom', '1st' => '1st custom', '2nd' => '2nd custom', ],