Skip to content

Commit bd51db6

Browse files
committed
Added support for ULID
1 parent 8e3e6d3 commit bd51db6

11 files changed

+959
-672
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class MatcherTest extends TestCase
111111
* ``@*@`` || ``@wildcard@``
112112
* ``expr(expression)`` - **optional**, requires `symfony/expression-language: ^2.3|^3.0|^4.0|^5.0` to be present
113113
* ``@uuid@``
114+
* ``@ulid@``
114115
* ``@json@``
115116
* ``@string@||@integer@`` - string OR integer
116117

@@ -336,6 +337,18 @@ $matcher = new PHPMatcher();
336337
$matcher->match('9f4db639-0e87-4367-9beb-d64e3f42ae18', '@uuid@');
337338
```
338339

340+
### ULID matching
341+
342+
```php
343+
<?php
344+
345+
use Coduo\PHPMatcher\PHPMatcher;
346+
347+
$matcher = new PHPMatcher();
348+
349+
$matcher->match('01BX5ZZKBKACTAV9WEVGEMMVS0', '@ulid@');
350+
```
351+
339352
### Array matching
340353

341354
```php

src/Factory/MatcherFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ private function buildScalarMatchers(Parser $parser, Backtrace $backtrace) : Mat
8787
new Matcher\ScalarMatcher($backtrace),
8888
new Matcher\WildcardMatcher($backtrace),
8989
new Matcher\UuidMatcher($backtrace, $parser),
90+
new Matcher\UlidMatcher($backtrace, $parser),
9091
new Matcher\JsonObjectMatcher($backtrace, $parser),
9192
]
9293
);

src/Matcher/Pattern/RegexConverter.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Coduo\PHPMatcher\Matcher\Pattern;
66

77
use Coduo\PHPMatcher\Exception\UnknownTypeException;
8+
use Coduo\PHPMatcher\Matcher\UlidMatcher;
89
use Coduo\PHPMatcher\Matcher\UuidMatcher;
910

1011
final class RegexConverter
@@ -24,6 +25,8 @@ public function toRegex(TypePattern $typePattern) : string
2425
return '(\\-?[0-9]*[\\.|\\,][0-9]*)';
2526
case 'uuid':
2627
return '(' . UuidMatcher::UUID_PATTERN . ')';
28+
case 'ulid':
29+
return '(' . UlidMatcher::ULID_PATTERN . ')';
2730

2831
default:
2932
throw new UnknownTypeException($typePattern->getType());

src/Matcher/UlidMatcher.php

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Coduo\PHPMatcher\Matcher;
6+
7+
use Coduo\PHPMatcher\Backtrace;
8+
use Coduo\PHPMatcher\Parser;
9+
use Coduo\ToString\StringConverter;
10+
use Symfony\Component\Validator\Constraints\Ulid;
11+
12+
final class UlidMatcher extends Matcher
13+
{
14+
/**
15+
* @var string
16+
*/
17+
public const PATTERN = 'ulid';
18+
19+
/**
20+
* @var string
21+
*/
22+
public const ULID_PATTERN = '[0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz]{26}';
23+
24+
private Backtrace $backtrace;
25+
26+
private Parser $parser;
27+
28+
public function __construct(Backtrace $backtrace, Parser $parser)
29+
{
30+
$this->parser = $parser;
31+
$this->backtrace = $backtrace;
32+
}
33+
34+
public function match($value, $pattern) : bool
35+
{
36+
$this->backtrace->matcherEntrance(self::class, $value, $pattern);
37+
38+
if (!\is_string($value)) {
39+
$this->error = \sprintf(
40+
'%s "%s" is not a valid ULID: not a string.',
41+
\gettype($value),
42+
new StringConverter($value)
43+
);
44+
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);
45+
46+
return false;
47+
}
48+
49+
if (\strlen($value) !== strspn($value, '0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz')) {
50+
$this->error = \sprintf(
51+
'%s "%s" is not a valid ULID: invalid characters.',
52+
\gettype($value),
53+
new StringConverter($value)
54+
);
55+
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);
56+
57+
return false;
58+
}
59+
60+
if (26 < \strlen($value)) {
61+
$this->error = \sprintf(
62+
'%s "%s" is not a valid ULID: too long.',
63+
\gettype($value),
64+
new StringConverter($value)
65+
);
66+
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);
67+
68+
return false;
69+
}
70+
71+
if (26 > \strlen($value)) {
72+
$this->error = \sprintf(
73+
'%s "%s" is not a valid ULID: too short.',
74+
\gettype($value),
75+
new StringConverter($value)
76+
);
77+
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);
78+
79+
return false;
80+
}
81+
82+
// Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ'
83+
// Cf https://github.com/ulid/spec#overflow-errors-when-parsing-base32-strings
84+
if ($value[0] > '7') {
85+
$this->error = \sprintf(
86+
'%s "%s" is not a valid ULID: overflow.',
87+
\gettype($value),
88+
new StringConverter($value)
89+
);
90+
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);
91+
92+
return false;
93+
}
94+
95+
$this->backtrace->matcherSucceed(self::class, $value, $pattern);
96+
97+
return true;
98+
}
99+
100+
public function canMatch($pattern) : bool
101+
{
102+
if (!\is_string($pattern)) {
103+
$this->backtrace->matcherCanMatch(self::class, $pattern, false);
104+
105+
return false;
106+
}
107+
108+
$result = $this->parser->hasValidSyntax($pattern) && $this->parser->parse($pattern)->is(self::PATTERN);
109+
$this->backtrace->matcherCanMatch(self::class, $pattern, $result);
110+
111+
return $result;
112+
}
113+
}

0 commit comments

Comments
 (0)