diff --git a/src/Symfony/Tests/Fixtures/DummyValidatedEntityWithGroupSequence.php b/src/Symfony/Tests/Fixtures/DummyValidatedEntityWithGroupSequence.php index 354207b6eb4..3e6c9f75bfa 100644 --- a/src/Symfony/Tests/Fixtures/DummyValidatedEntityWithGroupSequence.php +++ b/src/Symfony/Tests/Fixtures/DummyValidatedEntityWithGroupSequence.php @@ -20,7 +20,7 @@ * * @author Baptiste Meyer */ -#[Assert\GroupSequence(['dummy', 'DummyValidatedEntityWithGroupSequence'])] +#[Assert\GroupSequence(['dummy', 'DummyValidatedEntityWithGroupSequence', ['dummy2'], new Assert\GroupSequence(['dummy3'])])] class DummyValidatedEntityWithGroupSequence { /** @@ -73,6 +73,18 @@ class DummyValidatedEntityWithGroupSequence #[Assert\NotNull(groups: ['dummy'])] public $dummyGroup; + /** + * @var string A dummy group + */ + #[Assert\NotNull(groups: ['dummy2'])] + public $dummyGroup2; + + /** + * @var string A dummy group + */ + #[Assert\NotNull(groups: ['dummy3'])] + public $dummyGroup3; + /** * @var string A dummy url */ diff --git a/src/Symfony/Tests/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php b/src/Symfony/Tests/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php index 7b2b6031ac3..29b04694979 100644 --- a/src/Symfony/Tests/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php +++ b/src/Symfony/Tests/Validator/Metadata/Property/ValidatorPropertyMetadataFactoryTest.php @@ -142,13 +142,14 @@ public function testCreateWithPropertyWithoutConstraints(): void $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata); } - public function testCreateWithPropertyWithRequiredConstraintsAndGroupSequence(): void + #[DataProvider('createWithPropertyWithRequiredConstraintsAndGroupSequenceDataProvider')] + public function testCreateWithPropertyWithRequiredConstraintsAndGroupSequence(string $propertyName): void { $propertyMetadata = (new ApiProperty())->withDescription('A dummy group')->withReadable(true)->withWritable(true); $expectedPropertyMetadata = $propertyMetadata->withRequired(true); $decoratedPropertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class); - $decoratedPropertyMetadataFactory->create(DummyValidatedEntityWithGroupSequence::class, 'dummyGroup', [])->willReturn($propertyMetadata)->shouldBeCalled(); + $decoratedPropertyMetadataFactory->create(DummyValidatedEntityWithGroupSequence::class, $propertyName, [])->willReturn($propertyMetadata)->shouldBeCalled(); $validatorClassMetadata = new ClassMetadata(DummyValidatedEntityWithGroupSequence::class); (new AttributeLoader())->loadClassMetadata($validatorClassMetadata); @@ -161,11 +162,21 @@ public function testCreateWithPropertyWithRequiredConstraintsAndGroupSequence(): $decoratedPropertyMetadataFactory->reveal(), [] ); - $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntityWithGroupSequence::class, 'dummyGroup'); + $resultedPropertyMetadata = $validatorPropertyMetadataFactory->create(DummyValidatedEntityWithGroupSequence::class, $propertyName); $this->assertEquals($expectedPropertyMetadata, $resultedPropertyMetadata); } + /** + * @return iterable + */ + public static function createWithPropertyWithRequiredConstraintsAndGroupSequenceDataProvider(): iterable + { + yield ['dummyGroup']; + yield ['dummyGroup2']; + yield ['dummyGroup3']; + } + public function testCreateWithPropertyWithRightValidationGroupsAndRequiredConstraints(): void { $propertyMetadata = (new ApiProperty())->withDescription('A dummy group')->withReadable(true)->withWritable(true); diff --git a/src/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php b/src/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php index ddfa7991f39..3fdc024188e 100644 --- a/src/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php +++ b/src/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php @@ -149,12 +149,14 @@ public function create(string $resourceClass, string $property, array $options = /** * Returns the list of validation groups. + * + * @return array */ private function getValidationGroups(ValidatorClassMetadataInterface $classMetadata, array $options): array { if (isset($options['validation_groups'])) { if ($options['validation_groups'] instanceof GroupSequence) { - return $options['validation_groups']->groups; + return $this->getGroupSequenceValidationGroups($options['validation_groups']); } if (!\is_callable($options['validation_groups'])) { @@ -163,7 +165,7 @@ private function getValidationGroups(ValidatorClassMetadataInterface $classMetad } if ($classMetadata->hasGroupSequence()) { - return $classMetadata->getGroupSequence()->groups; + return $this->getGroupSequenceValidationGroups($classMetadata->getGroupSequence()); } if (!method_exists($classMetadata, 'getDefaultGroup')) { @@ -173,6 +175,25 @@ private function getValidationGroups(ValidatorClassMetadataInterface $classMetad return [$classMetadata->getDefaultGroup()]; } + /** + * @return array + */ + private function getGroupSequenceValidationGroups(GroupSequence $groupSequence): array + { + $groups = []; + foreach ($groupSequence->groups as $subGroup) { + if (\is_array($subGroup)) { + $groups[] = $subGroup; + } elseif ($subGroup instanceof GroupSequence) { + $groups[] = $this->getGroupSequenceValidationGroups($subGroup); + } else { + $groups[] = [$subGroup]; + } + } + + return array_merge([], ...$groups); + } + /** * Tests if the property is required because of its validation groups. */