Skip to content

Commit 3ed6f30

Browse files
authored
fix(symfony): fix resolving groups in ValidationGroupsExtractorTrait when GroupSequence (#7272)
1 parent 0e712d9 commit 3ed6f30

File tree

4 files changed

+51
-70
lines changed

4 files changed

+51
-70
lines changed

src/Symfony/Validator/Metadata/Property/ValidatorPropertyMetadataFactory.php

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
use ApiPlatform\Metadata\ApiProperty;
1818
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
1919
use ApiPlatform\Symfony\Validator\Metadata\Property\Restriction\PropertySchemaRestrictionMetadataInterface;
20-
use ApiPlatform\Symfony\Validator\ValidationGroupsExtractorTrait;
21-
use Psr\Container\ContainerInterface;
2220
use Symfony\Component\Validator\Constraint;
2321
use Symfony\Component\Validator\Constraints\Bic;
2422
use Symfony\Component\Validator\Constraints\CardScheme;
@@ -28,6 +26,7 @@
2826
use Symfony\Component\Validator\Constraints\DateTime;
2927
use Symfony\Component\Validator\Constraints\Email;
3028
use Symfony\Component\Validator\Constraints\File;
29+
use Symfony\Component\Validator\Constraints\GroupSequence;
3130
use Symfony\Component\Validator\Constraints\Iban;
3231
use Symfony\Component\Validator\Constraints\Image;
3332
use Symfony\Component\Validator\Constraints\Isbn;
@@ -49,10 +48,6 @@
4948
*/
5049
final class ValidatorPropertyMetadataFactory implements PropertyMetadataFactoryInterface
5150
{
52-
use ValidationGroupsExtractorTrait {
53-
getValidationGroups as extractValidationGroups;
54-
}
55-
5651
/**
5752
* @var string[] A list of constraint classes making the entity required
5853
*/
@@ -78,13 +73,8 @@ final class ValidatorPropertyMetadataFactory implements PropertyMetadataFactoryI
7873
/**
7974
* @param PropertySchemaRestrictionMetadataInterface[] $restrictionsMetadata
8075
*/
81-
public function __construct(
82-
private readonly ValidatorMetadataFactoryInterface $validatorMetadataFactory,
83-
private readonly PropertyMetadataFactoryInterface $decorated,
84-
private readonly iterable $restrictionsMetadata = [],
85-
?ContainerInterface $container = null,
86-
) {
87-
$this->container = $container;
76+
public function __construct(private readonly ValidatorMetadataFactoryInterface $validatorMetadataFactory, private readonly PropertyMetadataFactoryInterface $decorated, private readonly iterable $restrictionsMetadata = [])
77+
{
8878
}
8979

9080
/**
@@ -162,8 +152,14 @@ public function create(string $resourceClass, string $property, array $options =
162152
*/
163153
private function getValidationGroups(ValidatorClassMetadataInterface $classMetadata, array $options): array
164154
{
165-
if (null !== ($groups = $this->extractValidationGroups($options['validation_groups'] ?? null))) {
166-
return $groups;
155+
if (isset($options['validation_groups'])) {
156+
if ($options['validation_groups'] instanceof GroupSequence) {
157+
return $options['validation_groups']->groups;
158+
}
159+
160+
if (!\is_callable($options['validation_groups'])) {
161+
return $options['validation_groups'];
162+
}
167163
}
168164

169165
if (!method_exists($classMetadata, 'getDefaultGroup')) {

src/Symfony/Validator/ValidationGroupsExtractorTrait.php

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/Symfony/Validator/Validator.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ApiPlatform\Validator\Exception\ValidationException;
1717
use ApiPlatform\Validator\ValidatorInterface;
1818
use Psr\Container\ContainerInterface;
19+
use Symfony\Component\Validator\Constraints\GroupSequence;
1920
use Symfony\Component\Validator\Validator\ValidatorInterface as SymfonyValidatorInterface;
2021

2122
/**
@@ -25,19 +26,34 @@
2526
*/
2627
final class Validator implements ValidatorInterface
2728
{
28-
use ValidationGroupsExtractorTrait;
29-
30-
public function __construct(private readonly SymfonyValidatorInterface $validator, ?ContainerInterface $container = null)
29+
public function __construct(private readonly SymfonyValidatorInterface $validator, private readonly ?ContainerInterface $container = null)
3130
{
32-
$this->container = $container;
3331
}
3432

3533
/**
3634
* {@inheritdoc}
3735
*/
3836
public function validate(object $data, array $context = []): void
3937
{
40-
$violations = $this->validator->validate($data, null, $this->getValidationGroups($context['groups'] ?? null, $data));
38+
if (null !== $validationGroups = $context['groups'] ?? null) {
39+
if (
40+
$this->container
41+
&& \is_string($validationGroups)
42+
&& $this->container->has($validationGroups)
43+
&& ($service = $this->container->get($validationGroups))
44+
&& \is_callable($service)
45+
) {
46+
$validationGroups = $service($data);
47+
} elseif (\is_callable($validationGroups)) {
48+
$validationGroups = $validationGroups($data);
49+
}
50+
51+
if (!$validationGroups instanceof GroupSequence) {
52+
$validationGroups = (array) $validationGroups;
53+
}
54+
}
55+
56+
$violations = $this->validator->validate($data, null, $validationGroups);
4157
if (0 !== \count($violations)) {
4258
throw new ValidationException($violations);
4359
}

tests/Symfony/Validator/ValidatorTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PHPUnit\Framework\TestCase;
2121
use Prophecy\PhpUnit\ProphecyTrait;
2222
use Psr\Container\ContainerInterface;
23+
use Symfony\Component\Validator\Constraints\GroupSequence;
2324
use Symfony\Component\Validator\ConstraintViolation;
2425
use Symfony\Component\Validator\ConstraintViolationList;
2526
use Symfony\Component\Validator\ConstraintViolationListInterface;
@@ -119,4 +120,22 @@ public function testValidatorWithScalarGroup(): void
119120
$validator = new Validator($symfonyValidator, $containerProphecy->reveal());
120121
$validator->validate(new DummyEntity(), ['groups' => 'foo']);
121122
}
123+
124+
public function testValidatorWithGroupSequence(): void
125+
{
126+
$data = new DummyEntity();
127+
$expectedValidationGroups = new GroupSequence(['foo', 'bar']);
128+
129+
$constraintViolationListProphecy = $this->prophesize(ConstraintViolationListInterface::class);
130+
$constraintViolationListProphecy->count()->willReturn(0);
131+
132+
$symfonyValidatorProphecy = $this->prophesize(SymfonyValidatorInterface::class);
133+
$symfonyValidatorProphecy->validate($data, null, $expectedValidationGroups)->willreturn($constraintViolationListProphecy->reveal())->shouldBeCalled();
134+
$symfonyValidator = $symfonyValidatorProphecy->reveal();
135+
136+
$containerProphecy = $this->prophesize(ContainerInterface::class);
137+
138+
$validator = new Validator($symfonyValidator, $containerProphecy->reveal());
139+
$validator->validate(new DummyEntity(), ['groups' => $expectedValidationGroups]);
140+
}
122141
}

0 commit comments

Comments
 (0)