From 8573bc5d45a20e88517d33b7eb338aa6e6413608 Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Mon, 25 Mar 2024 23:14:05 +0100 Subject: [PATCH] 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 --- library/Result.php | 2 +- library/Rules/Key.php | 5 +- library/Rules/KeyExists.php | 2 +- library/Rules/KeyOptional.php | 5 +- library/Rules/Property.php | 5 +- library/Rules/PropertyExists.php | 10 +++- library/Rules/PropertyOptional.php | 5 +- tests/integration/issue-1244.phpt | 2 +- tests/integration/issue-1333.phpt | 17 +++++++ tests/integration/rules/betweenExclusive.phpt | 2 +- tests/integration/rules/consecutive.phpt | 11 +++-- tests/integration/rules/each.phpt | 49 +++++++++---------- tests/integration/rules/hetu.phpt | 3 +- tests/integration/rules/iterableType.phpt | 3 +- tests/integration/rules/key.phpt | 7 ++- tests/integration/rules/keyExists.phpt | 3 +- tests/integration/rules/keyOptional.phpt | 5 +- tests/integration/rules/lazy.phpt | 11 ++--- tests/integration/rules/length.phpt | 2 +- tests/integration/rules/max.phpt | 8 +-- tests/integration/rules/min.phpt | 3 +- tests/integration/rules/phone.phpt | 4 +- tests/integration/rules/property.phpt | 7 ++- tests/integration/rules/propertyExists.phpt | 3 +- tests/integration/rules/propertyOptional.phpt | 5 +- 25 files changed, 102 insertions(+), 77 deletions(-) create mode 100644 tests/integration/issue-1333.phpt diff --git a/library/Result.php b/library/Result.php index 158630933..e10cb026e 100644 --- a/library/Result.php +++ b/library/Result.php @@ -43,7 +43,7 @@ public function __construct( ) { $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; } diff --git a/library/Rules/Key.php b/library/Rules/Key.php index 8acac3e6d..3cfcdea7d 100644 --- a/library/Rules/Key.php +++ b/library/Rules/Key.php @@ -38,10 +38,13 @@ public function evaluate(mixed $input): Result 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); } } diff --git a/library/Rules/KeyExists.php b/library/Rules/KeyExists.php index 527b03969..82888e39e 100644 --- a/library/Rules/KeyExists.php +++ b/library/Rules/KeyExists.php @@ -30,7 +30,7 @@ public function __construct( 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 diff --git a/library/Rules/KeyOptional.php b/library/Rules/KeyOptional.php index 0af856b7a..777883653 100644 --- a/library/Rules/KeyOptional.php +++ b/library/Rules/KeyOptional.php @@ -33,10 +33,13 @@ public function evaluate(mixed $input): Result 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); } } diff --git a/library/Rules/Property.php b/library/Rules/Property.php index 388057363..feb5e6c44 100644 --- a/library/Rules/Property.php +++ b/library/Rules/Property.php @@ -35,10 +35,13 @@ public function evaluate(mixed $input): Result 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); } } diff --git a/library/Rules/PropertyExists.php b/library/Rules/PropertyExists.php index 5496b0103..b517df961 100644 --- a/library/Rules/PropertyExists.php +++ b/library/Rules/PropertyExists.php @@ -30,11 +30,17 @@ public function __construct( 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 + ); } } diff --git a/library/Rules/PropertyOptional.php b/library/Rules/PropertyOptional.php index 90a5a6c08..7e853b37e 100644 --- a/library/Rules/PropertyOptional.php +++ b/library/Rules/PropertyOptional.php @@ -35,10 +35,13 @@ public function evaluate(mixed $input): Result 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); } } diff --git a/tests/integration/issue-1244.phpt b/tests/integration/issue-1244.phpt index 49ebb0577..f2bd0be41 100644 --- a/tests/integration/issue-1244.phpt +++ b/tests/integration/issue-1244.phpt @@ -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', ] diff --git a/tests/integration/issue-1333.phpt b/tests/integration/issue-1333.phpt new file mode 100644 index 000000000..acece34ce --- /dev/null +++ b/tests/integration/issue-1333.phpt @@ -0,0 +1,17 @@ +--FILE-- + 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', +] diff --git a/tests/integration/rules/betweenExclusive.phpt b/tests/integration/rules/betweenExclusive.phpt index 3c5f8f8f9..6eec65bad 100644 --- a/tests/integration/rules/betweenExclusive.phpt +++ b/tests/integration/rules/betweenExclusive.phpt @@ -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', ] diff --git a/tests/integration/rules/consecutive.phpt b/tests/integration/rules/consecutive.phpt index 3114674aa..bb71f6111 100644 --- a/tests/integration/rules/consecutive.phpt +++ b/tests/integration/rules/consecutive.phpt @@ -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', ] + diff --git a/tests/integration/rules/each.phpt b/tests/integration/rules/each.phpt index 4cf24af54..494f59f07 100644 --- a/tests/integration/rules/each.phpt +++ b/tests/integration/rules/each.phpt @@ -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', ] - diff --git a/tests/integration/rules/hetu.phpt b/tests/integration/rules/hetu.phpt index ced816d04..f4ae4d55d 100644 --- a/tests/integration/rules/hetu.phpt +++ b/tests/integration/rules/hetu.phpt @@ -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', ] - diff --git a/tests/integration/rules/iterableType.phpt b/tests/integration/rules/iterableType.phpt index a200170d5..b77e889ba 100644 --- a/tests/integration/rules/iterableType.phpt +++ b/tests/integration/rules/iterableType.phpt @@ -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', ] - diff --git a/tests/integration/rules/key.phpt b/tests/integration/rules/key.phpt index 3645b3486..ecd00e1bf 100644 --- a/tests/integration/rules/key.phpt +++ b/tests/integration/rules/key.phpt @@ -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', ] - diff --git a/tests/integration/rules/keyExists.phpt b/tests/integration/rules/keyExists.phpt index aba5ebe74..18a7b69fd 100644 --- a/tests/integration/rules/keyExists.phpt +++ b/tests/integration/rules/keyExists.phpt @@ -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`', ] - diff --git a/tests/integration/rules/keyOptional.phpt b/tests/integration/rules/keyOptional.phpt index ba0915b8c..7a20e4ffa 100644 --- a/tests/integration/rules/keyOptional.phpt +++ b/tests/integration/rules/keyOptional.phpt @@ -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', ] - diff --git a/tests/integration/rules/lazy.phpt b/tests/integration/rules/lazy.phpt index 90d36f9a8..5c933089f 100644 --- a/tests/integration/rules/lazy.phpt +++ b/tests/integration/rules/lazy.phpt @@ -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', ] - diff --git a/tests/integration/rules/length.phpt b/tests/integration/rules/length.phpt index 9569b6855..323b35bac 100644 --- a/tests/integration/rules/length.phpt +++ b/tests/integration/rules/length.phpt @@ -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', ] diff --git a/tests/integration/rules/max.phpt b/tests/integration/rules/max.phpt index 61852cebc..2c2a88fc2 100644 --- a/tests/integration/rules/max.phpt +++ b/tests/integration/rules/max.phpt @@ -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 diff --git a/tests/integration/rules/min.phpt b/tests/integration/rules/min.phpt index 783796175..6129c07d4 100644 --- a/tests/integration/rules/min.phpt +++ b/tests/integration/rules/min.phpt @@ -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', ] - diff --git a/tests/integration/rules/phone.phpt b/tests/integration/rules/phone.phpt index 906d28c08..40ef9ba43 100644 --- a/tests/integration/rules/phone.phpt +++ b/tests/integration/rules/phone.phpt @@ -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', ] diff --git a/tests/integration/rules/property.phpt b/tests/integration/rules/property.phpt index 4f5548307..95f66119d 100644 --- a/tests/integration/rules/property.phpt +++ b/tests/integration/rules/property.phpt @@ -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', ] - diff --git a/tests/integration/rules/propertyExists.phpt b/tests/integration/rules/propertyExists.phpt index b7e93e661..b2c7fbec9 100644 --- a/tests/integration/rules/propertyExists.phpt +++ b/tests/integration/rules/propertyExists.phpt @@ -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`', ] - diff --git a/tests/integration/rules/propertyOptional.phpt b/tests/integration/rules/propertyOptional.phpt index d24b5eb3c..293d1fbcc 100644 --- a/tests/integration/rules/propertyOptional.phpt +++ b/tests/integration/rules/propertyOptional.phpt @@ -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', ] -