Skip to content

Commit

Permalink
Introduced StructValidator to unpack validation errors for structs
Browse files Browse the repository at this point in the history
  • Loading branch information
Steveb-p committed Nov 14, 2024
1 parent d35f7b4 commit c9b9cac
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 8 deletions.
3 changes: 2 additions & 1 deletion src/bundle/Core/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ services:

Ibexa\Contracts\Core\Validation\StructValidator:
decorates: 'validator'
decoration_priority: -10
# Decorator priority is higher than debug.validator to ensure profiler receives struct errors
decoration_priority: 500
arguments:
$inner: '@.inner'
2 changes: 2 additions & 0 deletions src/contracts/Validation/AbstractValidationStructWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

/**
* @template T of object
*
* @implements \Ibexa\Contracts\Core\Validation\ValidatorStructWrapperInterface<T>
*/
abstract class AbstractValidationStructWrapper implements ValidatorStructWrapperInterface
{
Expand Down
4 changes: 3 additions & 1 deletion src/contracts/Validation/StructValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,17 @@ public function validate($value, $constraints = null, $groups = null): Constrain
$prefix = ltrim($value->getStructName(), '$') . '.';
foreach ($result as $error) {
$path = $error->getPropertyPath();
$root = $error->getRoot();
if (str_starts_with($path, $prefix)) {
$path = substr($path, strlen($prefix));
$root = $value->getStruct();
}

$unwrappedError = new ConstraintViolation(
$error->getMessage(),
$error->getMessageTemplate(),
$error->getParameters(),
$error->getRoot(),
$root,
$path,
$error->getInvalidValue(),
$error->getPlural(),
Expand Down
8 changes: 8 additions & 0 deletions src/contracts/Validation/ValidatorStructWrapperInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
*/
namespace Ibexa\Contracts\Core\Validation;

/**
* @template T of object
*/
interface ValidatorStructWrapperInterface
{
public function getStructName(): string;

/**
* @phpstan-return T
*/
public function getStruct(): object;
}
18 changes: 12 additions & 6 deletions tests/lib/Validation/StructValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,35 +71,41 @@ public function testAssertValidStructWithInvalidStruct(): void

$error = $errors->get(0);
self::assertSame($initialError, $error);
self::assertEquals('validation error', $error->getMessage());
self::assertEquals('struct.property', $error->getPropertyPath());
self::assertSame('validation error', $error->getMessage());
self::assertSame('struct.property', $error->getPropertyPath());
}

public function testAssertValidStructWithInvalidWrapperStruct(): void
{
$initialError = $this->createExampleConstraintViolation();
$initialErrors = $this->createExampleConstraintViolationList($initialError);

$struct = $this->createMock(ValidatorStructWrapperInterface::class);
$struct->expects(self::once())
$wrapper = $this->createMock(ValidatorStructWrapperInterface::class);
$wrapper->expects(self::once())
->method('getStructName')
->willReturn('$struct');

$struct = new stdClass();
$wrapper->expects(self::once())
->method('getStruct')
->willReturn($struct);

$this->validator
->method('validate')
->with(
$struct,
$wrapper,
null,
['Default', 'group']
)->willReturn($initialErrors);

$errors = $this->structValidator->validate($struct, null, ['Default', 'group']);
$errors = $this->structValidator->validate($wrapper, null, ['Default', 'group']);
self::assertNotSame($initialErrors, $errors);
self::assertCount(1, $errors);

$error = $errors->get(0);
self::assertNotSame($error, $initialError);
self::assertSame('validation error', $error->getMessage());
self::assertSame($struct, $error->getRoot());
self::assertSame('property', $error->getPropertyPath());
}

Expand Down

0 comments on commit c9b9cac

Please sign in to comment.