diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ec95138..c0dff8d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## 2.1.1 under development -- no changes in this release. +- Bug #748: Fix hook processing for nested objects that implement `PostValidationHookInterface` when `Nested` rule with + specified rules is used (@DAGpro) ## 2.1.0 September 12, 2024 diff --git a/src/Rule/NestedHandler.php b/src/Rule/NestedHandler.php index 0c754ca9..75ac7566 100644 --- a/src/Rule/NestedHandler.php +++ b/src/Rule/NestedHandler.php @@ -8,6 +8,7 @@ use Yiisoft\Strings\StringHelper; use Yiisoft\Validator\DataSet\ObjectDataSet; use Yiisoft\Validator\Exception\UnexpectedRuleException; +use Yiisoft\Validator\PostValidationHookInterface; use Yiisoft\Validator\Result; use Yiisoft\Validator\RuleHandlerInterface; use Yiisoft\Validator\RuleInterface; @@ -112,6 +113,10 @@ public function validate(mixed $value, RuleInterface $rule, ValidationContext $c } } + if ($value instanceof PostValidationHookInterface) { + $value->processValidationResult($compoundResult); + } + return $compoundResult; } } diff --git a/tests/Rule/NestedTest.php b/tests/Rule/NestedTest.php index 2bf5b2f9..cba3175a 100644 --- a/tests/Rule/NestedTest.php +++ b/tests/Rule/NestedTest.php @@ -12,12 +12,13 @@ use Yiisoft\Validator\DataSetInterface; use Yiisoft\Validator\Error; use Yiisoft\Validator\Helper\RulesDumper; +use Yiisoft\Validator\PostValidationHookInterface; use Yiisoft\Validator\Result; -use Yiisoft\Validator\Rule\FilledAtLeast; use Yiisoft\Validator\Rule\BooleanValue; use Yiisoft\Validator\Rule\Callback; use Yiisoft\Validator\Rule\Count; use Yiisoft\Validator\Rule\Each; +use Yiisoft\Validator\Rule\FilledAtLeast; use Yiisoft\Validator\Rule\In; use Yiisoft\Validator\Rule\Integer; use Yiisoft\Validator\Rule\Length; @@ -26,6 +27,7 @@ use Yiisoft\Validator\Rule\Number; use Yiisoft\Validator\Rule\Regex; use Yiisoft\Validator\Rule\Required; +use Yiisoft\Validator\Rule\StringValue; use Yiisoft\Validator\RuleInterface; use Yiisoft\Validator\RulesProviderInterface; use Yiisoft\Validator\Tests\Rule\Base\DifferentRuleInHandlerTestTrait; @@ -36,6 +38,7 @@ use Yiisoft\Validator\Tests\Support\Data\EachNestedObjects\Foo; use Yiisoft\Validator\Tests\Support\Data\InheritAttributesObject\InheritAttributesObject; use Yiisoft\Validator\Tests\Support\Data\IteratorWithBooleanKey; +use Yiisoft\Validator\Tests\Support\Data\NestedHookProvider\NestedObjectWithPostValidationHook; use Yiisoft\Validator\Tests\Support\Data\ObjectWithDifferentPropertyVisibility; use Yiisoft\Validator\Tests\Support\Data\ObjectWithNestedObject; use Yiisoft\Validator\Tests\Support\Helper\OptionsHelper; @@ -860,6 +863,65 @@ public function testWithOtherNestedAndEach( $this->assertSame($expectedErrorMessagesIndexedByPath, $result->getErrorMessagesIndexedByPath()); } + public function testNestedPostValidationHook(): void + { + $object = new class () implements PostValidationHookInterface { + #[Required] + #[StringValue] + #[Length(min: 6)] + public string $name = ''; + + #[Nested(NestedObjectWithPostValidationHook::class)] + public NestedObjectWithPostValidationHook $nested; + + public ?Result $validationResult = null; + + public function __construct() + { + $this->nested = new NestedObjectWithPostValidationHook(); + } + + public function processValidationResult(Result $result): void + { + $this->validationResult = $result; + } + }; + + (new Validator())->validate($object); + + $this->assertInstanceOf(Result::class, $object->validationResult); + $this->assertInstanceOf(Result::class, $object->nested->validationResult); + $this->assertInstanceOf(Result::class, $object->nested->secondNested->validationResult); + $this->assertSame( + [ + 'name', + 'nested.firstString', + 'nested.firstArray.0', + 'nested.firstArray.1', + 'nested.secondNested.secondInt', + 'nested.secondNested.secondString', + ], + array_keys($object->validationResult->getFirstErrorMessagesIndexedByPath()) + ); + $this->assertSame( + [ + 'firstString', + 'firstArray.0', + 'firstArray.1', + 'secondNested.secondInt', + 'secondNested.secondString', + ], + array_keys($object->nested->validationResult->getFirstErrorMessagesIndexedByPath()) + ); + $this->assertSame( + [ + 'secondInt', + 'secondString', + ], + array_keys($object->nested->secondNested->validationResult->getFirstErrorMessagesIndexedByPath()) + ); + } + public function dataValidationPassed(): array { return [ diff --git a/tests/Support/Data/NestedHookProvider/NestedObjectWithPostValidationHook.php b/tests/Support/Data/NestedHookProvider/NestedObjectWithPostValidationHook.php new file mode 100644 index 00000000..423d23c6 --- /dev/null +++ b/tests/Support/Data/NestedHookProvider/NestedObjectWithPostValidationHook.php @@ -0,0 +1,48 @@ +secondNested = new SecondNestedObjectWithPostValidationHook(); + } + + public function processValidationResult(Result $result): void + { + $this->validationResult = $result; + } +} diff --git a/tests/Support/Data/NestedHookProvider/SecondNestedObjectWithPostValidationHook.php b/tests/Support/Data/NestedHookProvider/SecondNestedObjectWithPostValidationHook.php new file mode 100644 index 00000000..cad2e9bc --- /dev/null +++ b/tests/Support/Data/NestedHookProvider/SecondNestedObjectWithPostValidationHook.php @@ -0,0 +1,32 @@ +validationResult = $result; + } +}