From be4c7d74ae4435fb6ad7fb66dda0a27f78db3321 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 7 Aug 2024 10:39:45 +0200 Subject: [PATCH] [Validator] Add support for RFC4122 format in the `Ulid` constraint --- .../Component/Validator/Constraints/Ulid.php | 9 +++-- .../Validator/Constraints/UlidValidator.php | 11 ++++++ .../Validator/Tests/Constraints/UlidTest.php | 3 +- .../Tests/Constraints/UlidValidatorTest.php | 37 +++++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Ulid.php b/src/Symfony/Component/Validator/Constraints/Ulid.php index d4d0a0a1de569..b73757c137a67 100644 --- a/src/Symfony/Component/Validator/Constraints/Ulid.php +++ b/src/Symfony/Component/Validator/Constraints/Ulid.php @@ -26,18 +26,21 @@ class Ulid extends Constraint { public const TOO_SHORT_ERROR = '7b44804e-37d5-4df4-9bdd-b738d4a45bb4'; public const TOO_LONG_ERROR = '9608249f-6da1-4d53-889e-9864b58c4d37'; - public const INVALID_CHARACTERS_ERROR = 'e4155739-5135-4258-9c81-ae7b44b5311e'; public const TOO_LARGE_ERROR = 'df8cfb9a-ce6d-4a69-ae5a-eea7ab6f278b'; + public const INVALID_CHARACTERS_ERROR = 'e4155739-5135-4258-9c81-ae7b44b5311e'; + public const INVALID_FORMAT_ERROR = '34d5cdd7-5aac-4ba0-b9a2-b45e0bab3e2e'; protected const ERROR_NAMES = [ self::TOO_SHORT_ERROR => 'TOO_SHORT_ERROR', self::TOO_LONG_ERROR => 'TOO_LONG_ERROR', - self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR', self::TOO_LARGE_ERROR => 'TOO_LARGE_ERROR', + self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR', + self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR', ]; public const FORMAT_BASE_32 = 'base32'; public const FORMAT_BASE_58 = 'base58'; + public const FORMAT_RFC_4122 = 'rfc4122'; public string $message = 'This is not a valid ULID.'; public string $format = self::FORMAT_BASE_32; @@ -59,7 +62,7 @@ public function __construct( $this->message = $message ?? $this->message; $this->format = $format ?? $this->format; - if (!\in_array($this->format, [self::FORMAT_BASE_32, self::FORMAT_BASE_58], true)) { + if (!\in_array($this->format, [self::FORMAT_BASE_32, self::FORMAT_BASE_58, self::FORMAT_RFC_4122], true)) { throw new ConstraintDefinitionException(\sprintf('The "%s" validation format is not supported.', $format)); } } diff --git a/src/Symfony/Component/Validator/Constraints/UlidValidator.php b/src/Symfony/Component/Validator/Constraints/UlidValidator.php index e4133d2dc16e4..ae49ad34bb1d2 100644 --- a/src/Symfony/Component/Validator/Constraints/UlidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UlidValidator.php @@ -43,6 +43,7 @@ public function validate(mixed $value, Constraint $constraint): void [$requiredLength, $requiredCharset] = match ($constraint->format) { Ulid::FORMAT_BASE_32 => [26, '0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz'], Ulid::FORMAT_BASE_58 => [22, '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'], + Ulid::FORMAT_RFC_4122 => [36, '0123456789ABCDEFabcdef-'], }; if ($requiredLength !== \strlen($value)) { @@ -81,6 +82,16 @@ public function validate(mixed $value, Constraint $constraint): void ->setCode(Ulid::TOO_LARGE_ERROR) ->addViolation(); } + } elseif (Ulid::FORMAT_RFC_4122 === $constraint->format) { + if (!preg_match('/^[^-]{8}-[^-]{4}-[^-]{4}-[^-]{4}-[^-]{12}$/', $value)) { + $this->context->buildViolation($constraint->message) + ->setParameters([ + '{{ value }}' => $this->formatValue($value), + '{{ format }}' => $constraint->format, + ]) + ->setCode(Ulid::INVALID_FORMAT_ERROR) + ->addViolation(); + } } } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UlidTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UlidTest.php index bb12ef0e90298..86cc322662736 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UlidTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UlidTest.php @@ -28,6 +28,7 @@ public function testAttributes() [$bConstraint] = $metadata->properties['b']->getConstraints(); self::assertSame('myMessage', $bConstraint->message); self::assertSame(['Default', 'UlidDummy'], $bConstraint->groups); + self::assertSame(Ulid::FORMAT_BASE_58, $bConstraint->format); [$cConstraint] = $metadata->properties['c']->getConstraints(); self::assertSame(['my_group'], $cConstraint->groups); @@ -48,7 +49,7 @@ class UlidDummy #[Ulid] private $a; - #[Ulid(message: 'myMessage')] + #[Ulid(message: 'myMessage', format: Ulid::FORMAT_BASE_58)] private $b; #[Ulid(groups: ['my_group'], payload: 'some attached data')] diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php index 7d2be16e208d5..0b7a698e02867 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php @@ -60,6 +60,13 @@ public function testValidUlidAsBase58() $this->assertNoViolation(); } + public function testValidUlidAsRfc4122() + { + $this->validator->validate('01912bf3-feff-fa6c-00f2-90d2f2e00564', new Ulid(format: Ulid::FORMAT_RFC_4122)); + + $this->assertNoViolation(); + } + /** * @dataProvider getInvalidUlids */ @@ -119,6 +126,36 @@ public static function getInvalidBase58Ulids(): array ]; } + /** + * @dataProvider getInvalidRfc4122Ulids + */ + public function testInvalidInvalid4122Ulid(string $ulid, string $code) + { + $constraint = new Ulid(message: 'testMessage', format: Ulid::FORMAT_RFC_4122); + + $this->validator->validate($ulid, $constraint); + + $this->buildViolation('testMessage') + ->setParameters([ + '{{ value }}' => '"'.$ulid.'"', + '{{ format }}' => Ulid::FORMAT_RFC_4122, + ]) + ->setCode($code) + ->assertRaised(); + } + + public static function getInvalidRfc4122Ulids(): array + { + return [ + ['01912bf3-f5b7-e55d', Ulid::TOO_SHORT_ERROR], + ['01912bf3-f5b7-e55d-d21f-5ef032cd8e29999999', Ulid::TOO_LONG_ERROR], + ['01912bf3-f5b7-e55d-d21f-5ef032cd8eZZ', Ulid::INVALID_CHARACTERS_ERROR], + ['not-even-ulid-like', Ulid::TOO_SHORT_ERROR], + ['01912bf30feff0fa6c000f2090d2f2e00564', Ulid::INVALID_FORMAT_ERROR], + ['019-2bf3-fe-f-fa-c-00-2-90d2f-e00564', Ulid::INVALID_FORMAT_ERROR], + ]; + } + public function testInvalidUlidNamed() { $constraint = new Ulid(message: 'testMessage');