Skip to content

Commit 29a1538

Browse files
committed
Add UuidFilter
1 parent b666aeb commit 29a1538

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

src/Filter/UuidFilter.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace TraderInteractive\Filter;
4+
5+
use InvalidArgumentException;
6+
use TraderInteractive\Exceptions\FilterException;
7+
8+
final class UuidFilter
9+
{
10+
/**
11+
* @var string
12+
*/
13+
const FILTER_ALIAS = 'uuid';
14+
15+
/**
16+
* @var string
17+
*/
18+
const UUID_PATTERN_FORMAT = '^[0-9A-F]{8}-[0-9A-F]{4}-[%d][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$';
19+
20+
/**
21+
* @var string
22+
*/
23+
const FILTER_ERROR_FORMAT = "Value '%s' is not a valid UUID. Versions checked (%s)";
24+
25+
/**
26+
* @var array
27+
* @internal
28+
*/
29+
const VALID_UUID_VERSIONS = [1,4,7];
30+
31+
32+
/**
33+
* Filters a given string values to a valid UUID
34+
*
35+
* @param string|null $value The value to be filtered.
36+
* @param bool $allowNull Flag to allow value to be null.
37+
* @param array $versions List of specific UUID version to validate against.
38+
*
39+
* @return string|null
40+
*
41+
* @throws FilterException Thrown if value cannot be filtered as an UUID.
42+
*/
43+
public static function filter(
44+
string $value = null,
45+
bool $allowNull = false,
46+
array $versions = self::VALID_UUID_VERSIONS
47+
) {
48+
if (self::valueIsNullAndValid($allowNull, $value)) {
49+
return null;
50+
}
51+
52+
self::validateVersions($versions);
53+
foreach ($versions as $version) {
54+
$pattern = sprintf(self::UUID_PATTERN_FORMAT, $version);
55+
if (preg_match("/{$pattern}/i", $value)) {
56+
return $value;
57+
}
58+
}
59+
60+
throw new FilterException(
61+
sprintf(
62+
self::FILTER_ERROR_FORMAT,
63+
$value,
64+
implode(', ', $versions)
65+
)
66+
);
67+
}
68+
69+
private static function valueIsNullAndValid(bool $allowNull, string $value = null): bool
70+
{
71+
if ($allowNull === false && $value === null) {
72+
throw new FilterException('Value failed filtering, $allowNull is set to false');
73+
}
74+
75+
return $allowNull === true && $value === null;
76+
}
77+
78+
private static function validateVersions(array $versions)
79+
{
80+
foreach ($versions as $version) {
81+
if (!in_array($version, self::VALID_UUID_VERSIONS)) {
82+
throw new InvalidArgumentException("Filter does not support UUID v{$version}");
83+
}
84+
}
85+
}
86+
}

tests/Filter/UuidFilterTest.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
namespace Filter;
4+
5+
use InvalidArgumentException;
6+
use TraderInteractive\Exceptions\FilterException;
7+
use TraderInteractive\Filter\UuidFilter;
8+
use PHPUnit\Framework\TestCase;
9+
10+
/**
11+
* @coversDefaultClass \TraderInteractive\Filter\UuidFilter
12+
* @covers ::<private>
13+
*/
14+
final class UuidFilterTest extends TestCase
15+
{
16+
/**
17+
* @var string
18+
* @internal
19+
*/
20+
const UUID_V1 = '1a42403c-a29d-11ef-b864-0242ac120002';
21+
22+
/**
23+
* @var string
24+
* @internal
25+
*/
26+
const UUID_V4 = 'cc468b36-0b9d-4c93-b8e9-d5e949331ffb';
27+
28+
/**
29+
* @var string
30+
* @internal
31+
*/
32+
const UUID_V7 = '01932b4a-af2b-7093-af59-2fb2044d13d8';
33+
34+
/**
35+
* @test
36+
* @covers ::filter
37+
*/
38+
public function filterUuidV1()
39+
{
40+
$this->assertSame(self::UUID_V1, UuidFilter::filter(self::UUID_V1));
41+
}
42+
43+
/**
44+
* @test
45+
* @covers ::filter
46+
*/
47+
public function filterUuidV4()
48+
{
49+
$this->assertSame(self::UUID_V4, UuidFilter::filter(self::UUID_V4));
50+
}
51+
52+
/**
53+
* @test
54+
* @covers ::filter
55+
*/
56+
public function filterUuidV7()
57+
{
58+
$this->assertSame(self::UUID_V7, UuidFilter::filter(self::UUID_V7));
59+
}
60+
61+
/**
62+
* @test
63+
* @covers ::filter
64+
*/
65+
public function filterNullAllowedNullIsTrue()
66+
{
67+
$this->assertNull(UuidFilter::filter(null, true));
68+
}
69+
70+
/**
71+
* @test
72+
* @covers ::filter
73+
*/
74+
public function filterNullAllowedNullIsFalse()
75+
{
76+
$this->expectException(FilterException::class);
77+
UuidFilter::filter(null, false);
78+
}
79+
80+
/**
81+
* @test
82+
* @covers ::filter
83+
*/
84+
public function filterWithInvalidVersionSpecified()
85+
{
86+
$this->expectException(InvalidArgumentException::class);
87+
$this->expectExceptionMessage('Filter does not support UUID v0');
88+
UuidFilter::filter(self::UUID_V7, false, [0]);
89+
}
90+
91+
/**
92+
* @test
93+
* @covers ::filter
94+
*/
95+
public function filterValueDoesNotMatchGivenVersions()
96+
{
97+
$this->expectException(FilterException::class);
98+
$this->expectExceptionMessage(
99+
sprintf(
100+
UuidFilter::FILTER_ERROR_FORMAT,
101+
self::UUID_V4,
102+
implode(', ', [1,7])
103+
)
104+
);
105+
UuidFilter::filter(self::UUID_V4, false, [1,7]);
106+
}
107+
}

0 commit comments

Comments
 (0)