Skip to content

Commit

Permalink
Fix hook processing for nested objects when Nested is used (#748)
Browse files Browse the repository at this point in the history
Co-authored-by: Sergei Predvoditelev <[email protected]>
Co-authored-by: Alexander Makarov <[email protected]>
Co-authored-by: Alexey Rogachev <[email protected]>
  • Loading branch information
4 people authored Oct 2, 2024
1 parent 3c66920 commit 22d6572
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions src/Rule/NestedHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -112,6 +113,10 @@ public function validate(mixed $value, RuleInterface $rule, ValidationContext $c
}
}

if ($value instanceof PostValidationHookInterface) {
$value->processValidationResult($compoundResult);
}

return $compoundResult;
}
}
64 changes: 63 additions & 1 deletion tests/Rule/NestedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Tests\Support\Data\NestedHookProvider;

use Yiisoft\Validator\PostValidationHookInterface;
use Yiisoft\Validator\Result;
use Yiisoft\Validator\Rule\Each;
use Yiisoft\Validator\Rule\Length;
use Yiisoft\Validator\Rule\Nested;
use Yiisoft\Validator\Rule\Required;
use Yiisoft\Validator\Rule\StringValue;

class NestedObjectWithPostValidationHook implements PostValidationHookInterface
{
#[Required]
#[StringValue]
#[Length(min: 6)]
public string $firstString = 'short';

#[Each(
[
new StringValue(),
new Length(min: 6),
]
)]
public array $firstArray = [
'short',
'short',
'long string',
];

#[Nested(SecondNestedObjectWithPostValidationHook::class)]
public SecondNestedObjectWithPostValidationHook $secondNested;

public ?Result $validationResult = null;

public function __construct()
{
$this->secondNested = new SecondNestedObjectWithPostValidationHook();
}

public function processValidationResult(Result $result): void
{
$this->validationResult = $result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Validator\Tests\Support\Data\NestedHookProvider;

use Yiisoft\Validator\PostValidationHookInterface;
use Yiisoft\Validator\Result;
use Yiisoft\Validator\Rule\Integer;
use Yiisoft\Validator\Rule\Length;
use Yiisoft\Validator\Rule\Required;
use Yiisoft\Validator\Rule\StringValue;

class SecondNestedObjectWithPostValidationHook implements PostValidationHookInterface
{
#[Required]
#[Integer(min: 5, max: 10)]
public int $secondInt = 15;
#[StringValue]
#[Length(min: 10)]
public string $secondString = 'short';
public ?Result $validationResult = null;

public function __construct()
{
}

public function processValidationResult(Result $result): void
{
$this->validationResult = $result;
}
}

0 comments on commit 22d6572

Please sign in to comment.