8000 [Validator] Add `Ulid::VALIDATE_BASE_32` and `Ulid::VALIDATE_BASE_58`… · symfony/symfony@66e7a97 · GitHub
[go: up one dir, main page]

Skip to content

Commit 66e7a97

Browse files
[Validator] Add Ulid::VALIDATE_BASE_32 and Ulid::VALIDATE_BASE_58 to the Uuid constraint
1 parent 9ed27d0 commit 66e7a97

File tree

4 files changed

+71
-11
lines changed

4 files changed

+71
-11
lines changed

src/Symfony/Component/Validator/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Make `PasswordStrengthValidator::estimateStrength()` public
88
* Add the `Yaml` constraint for validating YAML content
9+
* Add `Ulid::FORMAT_BASE_32` and `Ulid::FORMAT_BASE_58` to the `Uuid` constraint
910

1011
7.1
1112
---

src/Symfony/Component/Validator/Constraints/Ulid.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,27 @@ class Ulid extends Constraint
3535
self::TOO_LARGE_ERROR => 'TOO_LARGE_ERROR',
3636
];
3737

38+
public const FORMAT_BASE_32 = 'base32';
39+
public const FORMAT_BASE_58 = 'base58';
40+
3841
public string $message = 'This is not a valid ULID.';
42+
public string $format = self::FORMAT_BASE_32;
3943

4044
/**
4145
* @param array<string,mixed>|null $options
4246
* @param string[]|null $groups
47+
* @param self::FORMAT_*|null $format
4348
*/
4449
public function __construct(
4550
?array $options = null,
4651
?string $message = null,
4752
?array $groups = null,
4853
mixed $payload = null,
54+
?string $format = null,
4955
) {
5056
parent::__construct($options, $groups, $payload);
5157

5258
$this->message = $message ?? $this->message;
59+
$this->format = $format ?? $this->format;
5360
}
5461
}

src/Symfony/Component/Validator/Constraints/UlidValidator.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,27 @@ public function validate(mixed $value, Constraint $constraint): void
3939
}
4040

4141
$value = (string) $value;
42+
$requiredLength = match ($constraint->format) {
43+
Ulid::FORMAT_BASE_32 => 26,
44+
Ulid::FORMAT_BASE_58 => 22,
45+
default => throw new \InvalidArgumentException(sprintf('The "%s" validation format is not supported.', $constraint->format)),
46+
};
4247

43-
if (26 !== \strlen($value)) {
48+
$requiredCharset = match ($constraint->format) {
49+
Ulid::FORMAT_BASE_32 => '0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz',
50+
Ulid::FORMAT_BASE_58 => '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
51+
};
52+
53+
if ($requiredLength !== \strlen($value)) {
4454
$this->context->buildViolation($constraint->message)
4555
->setParameter('{{ value }}', $this->formatValue($value))
46-
->setCode(26 > \strlen($value) ? Ulid::TOO_SHORT_ERROR : Ulid::TOO_LONG_ERROR)
56+
->setCode($requiredLength > \strlen($value) ? Ulid::TOO_SHORT_ERROR : Ulid::TOO_LONG_ERROR)
4757
->addViolation();
4858

4959
return;
5060
}
5161

52-
if (\strlen($value) !== strspn($value, '0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz')) {
62+
if (\strlen($value) !== strspn($value, $requiredCharset)) {
5363
$this->context->buildViolation($constraint->message)
5464
->setParameter('{{ value }}', $this->formatValue($value))
5565
->setCode(Ulid::INVALID_CHARACTERS_ERROR)
@@ -58,13 +68,15 @@ public function validate(mixed $value, Constraint $constraint): void
5868
return;
5969
}
6070

61-
// Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ'
62-
// Cf https://github.com/ulid/spec#overflow-errors-when-parsing-base32-strings
63-
if ($value[0] > '7') {
64-
$this->context->buildViolation($constraint->message)
65-
->setParameter('{{ value }}', $this->formatValue($value))
66-
->setCode(Ulid::TOO_LARGE_ERROR)
67-
->addViolation();
71+
if (Ulid::FORMAT_BASE_32 === $constraint->format) {
72+
// Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ'
73+
// Cf https://github.com/ulid/spec#overflow-errors-when-parsing-base32-strings
74+
if ($value[0] > '7') {
75+
$this->context->buildViolation($constraint->message)
76+
->setParameter('{{ value }}', $this->formatValue($value))
77+
->setCode(Ulid::TOO_LARGE_ERROR)
78+
->addViolation();
79+
}
6880
}
6981
}
7082
}

src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,28 @@ public function testExpectsStringCompatibleType()
4646
$this->validator->validate(new \stdClass(), new Ulid());
4747
}
4848

49+
public function testUnexpectedValidationFormat()
50+
{
51+
$this->expectException(\InvalidArgumentException::class);
52+
$this->expectExceptionMessage('The "invalid" validation format is not supported.');
53+
54+
$this->validator->validate('01ARZ3NDEKTSV4RRFFQ69G5FAV', new Ulid(format: 'invalid'));
55+
}
56+
4957
public function testValidUlid()
5058
{
5159
$this->validator->validate('01ARZ3NDEKTSV4RRFFQ69G5FAV', new Ulid());
5260

5361
$this->assertNoViolation();
5462
}
5563

64+
public function testValidUlidAsBase58()
65+
{
66+
$this->validator->validate('1CCD2w4mK2m455S2BAXFht', new Ulid(format: Ulid::FORMAT_BASE_58));
67+
68+
$this->assertNoViolation();
69+
}
70+
5671
/**
5772
* @dataProvider getInvalidUlids
5873
*/
@@ -70,7 +85,7 @@ public function testInvalidUlid(string $ulid, string $code)
7085
->assertRaised();
7186
}
7287

73-
public static function getInvalidUlids()
88+
public static function getInvalidUlids(): array
7489
{
7590
return [
7691
['01ARZ3NDEKTSV4RRFFQ69G5FA', Ulid::TOO_SHORT_ERROR],
@@ -81,6 +96,31 @@ public static function getInvalidUlids()
8196
];
8297
}
8398

99+
/**
100+
* @dataProvider getInvalidBase58Ulids
101+
*/
102+
public function testInvalidBase58Ulid(string $ulid, string $code)
103+
{
104+
$constraint = new Ulid(message: 'testMessage', format: Ulid::FORMAT_BASE_58);
105+
106+
$this->validator->validate($ulid, $constraint);
107+
108+
$this->buildViolation('testMessage')
109+
->setParameter('{{ value }}', '"'.$ulid.'"')
110+
->setCode($code)
111+
->assertRaised();
112+
}
113+
114+
public static function getInvalidBase58Ulids(): array
115+
{
116+
return [
117+
['1CCD2w4mK2m455S2BAXFh', Ulid::TOO_SHORT_ERROR],
118+
['1CCD2w4mK2m455S2BAXFhttt', Ulid::TOO_LONG_ERROR],
119+
['1CCD2w4mK2m455S2BAXFhO', Ulid::INVALID_CHARACTERS_ERROR],
120+
['not-even-ulid-like', Ulid::TOO_SHORT_ERROR],
121+
];
122+
}
123+
84124
public function testInvalidUlidNamed()
85125
{
86126
$constraint = new Ulid(message: 'testMessage');

0 commit comments

Comments
 (0)
0