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',
],