diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 85baf4340c129..1bbceef965b62 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Deprecate `Constraint::$errorNames`, use `Constraint::ERROR_NAMES` instead + * Supports PHP backed enumerations in constraint groups 6.0 --- diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php index ee1d68c78f50b..40c2e5153d176 100644 --- a/src/Symfony/Component/Validator/Constraint.php +++ b/src/Symfony/Component/Validator/Constraint.php @@ -103,11 +103,11 @@ public static function getErrorName(string $errorCode): string * getRequiredOptions() to return the names of these options. If any * option is not set here, an exception is thrown. * - * @param mixed $options The options (as associative array) - * or the value for the default - * option (any other type) - * @param string[] $groups An array of validation groups - * @param mixed $payload Domain-specific data attached to a constraint + * @param mixed $options The options (as associative array) + * or the value for the default + * option (any other type) + * @param array $groups An array of validation groups + * @param mixed $payload Domain-specific data attached to a constraint * * @throws InvalidOptionsException When you pass the names of non-existing * options @@ -197,7 +197,7 @@ protected function normalizeOptions(mixed $options): array public function __set(string $option, mixed $value) { if ('groups' === $option) { - $this->groups = (array) $value; + $this->groups = $this->normalizeGroups((array) $value); return; } @@ -205,6 +205,24 @@ public function __set(string $option, mixed $value) throw new InvalidOptionsException(sprintf('The option "%s" does not exist in constraint "%s".', $option, static::class), [$option]); } + /** + * @param array $groups + * + * @return array + */ + protected function normalizeGroups(array $groups): array + { + $normalized = []; + foreach ($groups as $group) { + if ($group instanceof \BackedEnum) { + $group = $group->value; + } + $normalized[] = $group; + } + + return $normalized; + } + /** * Returns the value of a lazily initialized option. * diff --git a/src/Symfony/Component/Validator/Tests/ConstraintTest.php b/src/Symfony/Component/Validator/Tests/ConstraintTest.php index 3d233c17815b7..4e09f409f8e40 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Validator\Exception\InvalidArgumentException; use Symfony\Component\Validator\Exception\InvalidOptionsException; use Symfony\Component\Validator\Exception\MissingOptionsException; +use Symfony\Component\Validator\Tests\Fixtures\BackedEnumA; use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint; use Symfony\Component\Validator\Tests\Fixtures\ConstraintA; use Symfony\Component\Validator\Tests\Fixtures\ConstraintB; @@ -133,6 +134,20 @@ public function testGroupsAreConvertedToArray() $this->assertEquals(['Foo'], $constraint->groups); } + public function testGroupsBackedEnumsAreConvertedToValue() + { + $constraint = new ConstraintA([], ['foo', BackedEnumA::READ]); + + $this->assertSame(['foo', 'read'], $constraint->groups); + } + + public function testOptionGroupsBackedEnumsAreConvertedToValue() + { + $constraint = new ConstraintA(['groups' => ['foo', BackedEnumA::READ]]); + + $this->assertSame(['foo', 'read'], $constraint->groups); + } + public function testAddDefaultGroupAddsGroup() { $constraint = new ConstraintA(['groups' => 'Default']); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanTest.php index 848db00204b93..999e2e308a78e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Validator\Constraints\GreaterThan; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Validator\Tests\Fixtures\BackedEnumA; class GreaterThanTest extends TestCase { @@ -38,6 +39,11 @@ public function testAttributes() self::assertSame('b', $cConstraint->propertyPath); self::assertSame('myMessage', $cConstraint->message); self::assertSame(['foo'], $cConstraint->groups); + + [$dConstraint] = $metadata->properties['d']->getConstraints(); + self::assertSame(4711, $dConstraint->value); + self::assertNull($dConstraint->propertyPath); + self::assertSame(['read', 'write'], $dConstraint->groups); } } @@ -51,4 +57,7 @@ class GreaterThanDummy #[GreaterThan(propertyPath: 'b', message: 'myMessage', groups: ['foo'])] private $c; + + #[GreaterThan(value: 4711, groups: [BackedEnumA::READ, 'write'])] + private $d; } diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/BackedEnumA.php b/src/Symfony/Component/Validator/Tests/Fixtures/BackedEnumA.php new file mode 100644 index 0000000000000..88a46a2cb2ab3 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/BackedEnumA.php @@ -0,0 +1,8 @@ +