Skip to content

Commit

Permalink
Added support for ULID
Browse files Browse the repository at this point in the history
  • Loading branch information
WengerK committed May 19, 2021
1 parent 8e3e6d3 commit e14b90b
Show file tree
Hide file tree
Showing 11 changed files with 968 additions and 672 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class MatcherTest extends TestCase
* ``@*@`` || ``@wildcard@``
* ``expr(expression)`` - **optional**, requires `symfony/expression-language: ^2.3|^3.0|^4.0|^5.0` to be present
* ``@uuid@``
* ``@ulid@``
* ``@json@``
* ``@string@||@integer@`` - string OR integer

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

### ULID matching

```php
<?php

use Coduo\PHPMatcher\PHPMatcher;

$matcher = new PHPMatcher();

$matcher->match('01BX5ZZKBKACTAV9WEVGEMMVS0', '@ulid@');
```

### Array matching

```php
Expand Down
1 change: 1 addition & 0 deletions src/Factory/MatcherFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ private function buildScalarMatchers(Parser $parser, Backtrace $backtrace) : Mat
new Matcher\ScalarMatcher($backtrace),
new Matcher\WildcardMatcher($backtrace),
new Matcher\UuidMatcher($backtrace, $parser),
new Matcher\UlidMatcher($backtrace, $parser),
new Matcher\JsonObjectMatcher($backtrace, $parser),
]
);
Expand Down
3 changes: 3 additions & 0 deletions src/Matcher/Pattern/RegexConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Coduo\PHPMatcher\Matcher\Pattern;

use Coduo\PHPMatcher\Exception\UnknownTypeException;
use Coduo\PHPMatcher\Matcher\UlidMatcher;
use Coduo\PHPMatcher\Matcher\UuidMatcher;

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

default:
throw new UnknownTypeException($typePattern->getType());
Expand Down
117 changes: 117 additions & 0 deletions src/Matcher/UlidMatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

declare(strict_types=1);

namespace Coduo\PHPMatcher\Matcher;

use Coduo\PHPMatcher\Backtrace;
use Coduo\PHPMatcher\Parser;
use Coduo\ToString\StringConverter;
use Symfony\Component\Validator\Constraints\Ulid;

final class UlidMatcher extends Matcher
{
/**
* @var string
*/
public const PATTERN = 'ulid';

/**
* ULID validation pattern highly inspired by the Symfony Uid Component.
*
* @see https://github.com/symfony/uid/blob/8311a3f6e14c21960e7955452fe52a462d58ad2b/Ulid.php#L41-L52
*
* @var string
*/
public const ULID_PATTERN = '[01234567]{1}[0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz]{25}';

private Backtrace $backtrace;

private Parser $parser;

public function __construct(Backtrace $backtrace, Parser $parser)
{
$this->parser = $parser;
$this->backtrace = $backtrace;
}

public function match($value, $pattern) : bool
{
$this->backtrace->matcherEntrance(self::class, $value, $pattern);

if (!\is_string($value)) {
$this->error = \sprintf(
'%s "%s" is not a valid ULID: not a string.',
\gettype($value),
new StringConverter($value)
);
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);

return false;
}

if (\strlen($value) !== \strspn($value, '0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz')) {
$this->error = \sprintf(
'%s "%s" is not a valid ULID: invalid characters.',
\gettype($value),
new StringConverter($value)
);
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);

return false;
}

if (26 < \strlen($value)) {
$this->error = \sprintf(
'%s "%s" is not a valid ULID: too long.',
\gettype($value),
new StringConverter($value)
);
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);

return false;
}

if (26 > \strlen($value)) {
$this->error = \sprintf(
'%s "%s" is not a valid ULID: too short.',
\gettype($value),
new StringConverter($value)
);
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);

return false;
}

// Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ'
// Cf https://github.com/ulid/spec#overflow-errors-when-parsing-base32-strings
if ($value[0] > '7') {
$this->error = \sprintf(
'%s "%s" is not a valid ULID: overflow.',
\gettype($value),
new StringConverter($value)
);
$this->backtrace->matcherFailed(self::class, $value, $pattern, $this->error);

return false;
}

$this->backtrace->matcherSucceed(self::class, $value, $pattern);

return true;
}

public function canMatch($pattern) : bool
{
if (!\is_string($pattern)) {
$this->backtrace->matcherCanMatch(self::class, $pattern, false);

return false;
}

$result = $this->parser->hasValidSyntax($pattern) && $this->parser->parse($pattern)->is(self::PATTERN);
$this->backtrace->matcherCanMatch(self::class, $pattern, $result);

return $result;
}
}
Loading

0 comments on commit e14b90b

Please sign in to comment.