From cae175856bc0968a7bbbb8d00ffb472ab072c639 Mon Sep 17 00:00:00 2001 From: Tomas Date: Tue, 16 Mar 2021 12:47:57 +0200 Subject: [PATCH] Handle composite validator constraints when generating property metadata --- .../ValidatorPropertyMetadataFactory.php | 9 +++-- .../ValidatorPropertyMetadataFactoryTest.php | 33 +++++++++++++++++++ .../DummySequentiallyValidatedEntity.php | 29 ++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 tests/Fixtures/DummySequentiallyValidatedEntity.php diff --git a/src/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php b/src/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php index 438f20d1a2d..1f1706597a6 100644 --- a/src/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php +++ b/src/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php @@ -30,6 +30,7 @@ use Symfony\Component\Validator\Constraints\Issn; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotNull; +use Symfony\Component\Validator\Constraints\Sequentially; use Symfony\Component\Validator\Constraints\Time; use Symfony\Component\Validator\Constraints\Url; use Symfony\Component\Validator\Constraints\Uuid; @@ -170,11 +171,15 @@ private function getPropertyConstraints( } foreach ($validatorPropertyMetadata->findConstraints($validationGroup) as $propertyConstraint) { - $constraints[] = $propertyConstraint; + if ($propertyConstraint instanceof Sequentially) { + $constraints[] = $propertyConstraint->getNestedContraints(); + } else { + $constraints[] = [$propertyConstraint]; + } } } - return $constraints; + return array_merge([], ...$constraints); } /** diff --git a/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php b/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php index 819493540f3..a530266467b 100644 --- a/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php +++ b/tests/Bridge/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php @@ -20,11 +20,13 @@ use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Property\PropertyMetadata; use ApiPlatform\Core\Tests\Fixtures\DummyIriWithValidationEntity; +use ApiPlatform\Core\Tests\Fixtures\DummySequentiallyValidatedEntity; use ApiPlatform\Core\Tests\Fixtures\DummyValidatedEntity; use ApiPlatform\Core\Tests\ProphecyTrait; use Doctrine\Common\Annotations\AnnotationReader; use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraints\Sequentially; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader; @@ -335,4 +337,35 @@ public function testCreateWithPropertyFormatRestriction(): void $this->assertEquals($format, $schema['format']); } } + + public function testCreateWithSequentiallyConstraint(): void + { + if (!class_exists(Sequentially::class)) { + $this->markTestSkipped(); + } + + $validatorClassMetadata = new ClassMetadata(DummySequentiallyValidatedEntity::class); + (new AnnotationLoader(new AnnotationReader()))->loadClassMetadata($validatorClassMetadata); + + $validatorMetadataFactory = $this->prophesize(MetadataFactoryInterface::class); + $validatorMetadataFactory->getMetadataFor(DummySequentiallyValidatedEntity::class) + ->willReturn($validatorClassMetadata) + ->shouldBeCalled(); + + $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class); + $decoratedPropertyMetadataFactory->create(DummySequentiallyValidatedEntity::class, 'dummy', [])->willReturn( + new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING)) + )->shouldBeCalled(); + $validationPropertyMetadataFactory = new ValidatorPropertyMetadataFactory( + $validatorMetadataFactory->reveal(), + $decoratedPropertyMetadataFactory->reveal(), + [new PropertySchemaLengthRestriction(), new PropertySchemaRegexRestriction()] + ); + $schema = $validationPropertyMetadataFactory->create(DummySequentiallyValidatedEntity::class, 'dummy')->getSchema(); + + $this->assertNotNull($schema); + $this->assertArrayHasKey('minLength', $schema); + $this->assertArrayHasKey('maxLength', $schema); + $this->assertArrayHasKey('pattern', $schema); + } } diff --git a/tests/Fixtures/DummySequentiallyValidatedEntity.php b/tests/Fixtures/DummySequentiallyValidatedEntity.php new file mode 100644 index 00000000000..aa4937d0b7f --- /dev/null +++ b/tests/Fixtures/DummySequentiallyValidatedEntity.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Fixtures; + +use Symfony\Component\Validator\Constraints as Assert; + +class DummySequentiallyValidatedEntity +{ + /** + * @var string + * + * @Assert\Sequentially({ + * @Assert\Length(min=1, max=32), + * @Assert\Regex(pattern="/^[a-z]$/") + * }) + */ + public $dummy; +}