8000 feature #38322 [Validator] Add Ulid constraint and validator (Laurent… · symfony/symfony@e159dff · GitHub
[go: up one dir, main page]

Skip to content

Commit e159dff

Browse files
committed
feature #38322 [Validator] Add Ulid constraint and validator (Laurent Clouet)
This PR was squashed before being merged into the 5.2-dev branch. Discussion ---------- [Validator] Add Ulid constraint and validator | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #38152 | License | MIT ULID constraint and validator as mentioned in ticket #38103 I checked for it ulid specifications https://github.com/ulid/spec Commits ------- e36fd55 [Validator] Add Ulid constraint and validator
2 parents 3113fce + e36fd55 commit e159dff

File tree

4 files changed

+189
-0
lines changed

4 files changed

+189
-0
lines changed

src/Symfony/Component/Validator/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ CHANGELOG
3030
*/
3131
```
3232
* added the `Isin` constraint and validator
33+
* added the `ULID` constraint and validator
3334

3435
5.1.0
3536
-----
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Constraints;
13+
14+
use Symfony\Component\Validator\Constraint;
15+
16+
/**
17+
* @Annotation
18+
*
19+
* @author Laurent Clouet <laurent35240@gmail.com>
20+
*/
21+
class Ulid extends Constraint
22+
{
23+
const TOO_SHORT_ERROR = '7b44804e-37d5-4df4-9bdd-b738d4a45bb4';
24+
const TOO_LONG_ERROR = '9608249f-6da1-4d53-889e-9864b58c4d37';
25+
const INVALID_CHARACTERS_ERROR = 'e4155739-5135-4258-9c81-ae7b44b5311e';
26+
const TOO_LARGE_ERROR = 'df8cfb9a-ce6d-4a69-ae5a-eea7ab6f278b';
27+
28+
protected static $errorNames = [
29+
self::TOO_SHORT_ERROR => 'TOO_SHORT_ERROR',
30+
self::TOO_LONG_ERROR => 'TOO_LONG_ERROR',
31+
self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR',
32+
self::TOO_LARGE_ERROR => 'TOO_LARGE_ERROR',
33+
];
34+
35+
public $message = 'This is not a valid ULID.';
36+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Constraints;
13+
14+
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\ConstraintValidator;
16+
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
17+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
18+
19+
/**
20+
* Validates whether the value is a valid ULID (Universally Unique Lexicographically Sortable Identifier).
21+
* Cf https://github.com/ulid/spec for ULID specifications.
22+
*
23+
* @author Laurent Clouet <laurent35240@gmail.com>
24+
*/
25+
class UlidValidator extends ConstraintValidator
26+
{
27+
/**
28+
* {@inheritdoc}
29+
*/
30+
public function validate($value, Constraint $constraint)
31+
{
32+
if (!$constraint instanceof Ulid) {
33+
throw new UnexpectedTypeException($constraint, Ulid::class);
34+
}
35+
36+
if (null === $value || '' === $value) {
37+
return;
38+
}
39+
40+
if (!is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) {
41+
throw new UnexpectedValueException($value, 'string');
42+
}
43+
44+
$value = (string) $value;
45+
46+
if (26 !== \strlen($value)) {
47+
$this->context->buildViolation($constraint->message)
48+
->setParameter('{{ value }}', $this->formatValue($value))
49+
->setCode(26 > \strlen($value) ? Ulid::TOO_SHORT_ERROR : Ulid::TOO_LONG_ERROR)
50+
->addViolation();
51+
}
52+
53+
if (\strlen($value) !== strspn($value, '0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz')) {
54+
$this->context->buildViolation($constraint->message)
55+
->setParameter('{{ value }}', $this->formatValue($value))
56+
->setCode(Ulid::INVALID_CHARACTERS_ERROR)
57+
->addViolation();
58+
}
59+
60+
// Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ'
61+
// Cf https://github.com/ulid/spec#overflow-errors-when-parsing-base32-strings
62+
if ($value[0] > '7') {
63+
$this->context->buildViolation($constraint->message)
64+
->setParameter('{{ value }}', $this->formatValue($value))
65+
->setCode(Ulid::TOO_LARGE_ERROR)
66+
->addViolation();
67+
}
68+
}
69+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Tests\Constraints;
13+
14+
use stdClass;
15+
use Symfony\Component\Validator\Constraints\Ulid;
16+
use Symfony\Component\Validator\Constraints\UlidValidator;
17+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
18+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
19+
20+
/**
21+
* @author Laurent Clouet <laurent35240@gmail.com>
22+
*/
23+
class UlidValidatorTest extends ConstraintValidatorTestCase
24+
{
25+
protected function createValidator()
26+
{
27+
return new UlidValidator();
28+
}
29+
30+
public function testNullIsValid()
31+
{
32+
$this->validator->validate(null, new Ulid());
33+
34+
$this->assertNoViolation();
35+
}
36+
37+
public function testEmptyStringIsValid()
38+
{
39+
$this->validator->validate('', new Ulid());
40+
41+
$this->assertNoViolation();
42+
}
43+
44+
public function testExpectsStringCompatibleType()
45+
{
46+
$this->expectException(UnexpectedValueException::class);
47+
$this->validator->validate(new stdClass(), new Ulid());
48+
}
49+
50+
public function testValidUlid()
51+
{
52+
$this->validator->validate('01ARZ3NDEKTSV4RRFFQ69G5FAV', new Ulid());
53+
54+
$this->assertNoViolation();
55+
}
56+
57+
/**
58+
* @dataProvider getInvalidUlids
59+
*/
60+
public function testInvalidUlid(string $ulid, string $code)
61+
{
62+
$constraint = new Ulid([
63+
'message' => 'testMessage',
64+
]);
65+
66+
$this->validator->validate($ulid, $constraint);
67+
68+
$this->buildViolation('testMessage')
69+
->setParameter('{{ value }}', '"'.$ulid.'"')
70+
->setCode($code)
71+
->assertRaised();
72+
}
73+
74+
public function getInvalidUlids()
75+
{
76+
return [
77+
['01ARZ3NDEKTSV4RRFFQ69G5FA', Ulid::TOO_SHORT_ERROR],
78+
['01ARZ3NDEKTSV4RRFFQ69G5FAVA', Ulid::TOO_LONG_ERROR],
79+
['01ARZ3NDEKTSV4RRFFQ69G5FAO', Ulid::INVALID_CHARACTERS_ERROR],
80+
['Z1ARZ3NDEKTSV4RRFFQ69G5FAV', Ulid::TOO_LARGE_ERROR],
81+
];
82+
}
83+
}

0 commit comments

Comments
 (0)
0