Skip to content

Commit

Permalink
Merge 73f8215 into fe18728
Browse files Browse the repository at this point in the history
  • Loading branch information
Jelmer Schreuder committed Aug 24, 2016
2 parents fe18728 + 73f8215 commit 3683cff
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 18 deletions.
12 changes: 10 additions & 2 deletions docs/rules.md
Expand Up @@ -521,13 +521,21 @@ $v->validate(['link' => 'http://validator.particle-php.com'])->isValid(); // fal

## uuid

Validates that the value is a valid UUID. Currently only supports version 4.
Validates if the value is a valid UUID and of the given version. The version constant may be combined with other constants to allow multiple versions or the NIL UUID (all zeroes).

```php
use Particle\Validator\Rule\Uuid;
$v = new Validator;
$v->required('uuid')->uuid();

// Requires a UUID V4
$v->required('userId')->uuid(Uuid::UUID_V4);
$v->validate(['uuid' => '44c0ffee-988a-49dc-8bad-a55c0de2d1e4'])->isValid(); // true
$v->validate(['uuid' => '00000000-0000-0000-0000-000000000000'])->isValid(); // false

// Requires a UUID V4 or NIL UUID
$v->required('userId')->uuid(Uuid::UUID_V4 | Uuid::UUID_NIL);
$v->validate(['uuid' => '44c0ffee-988a-49dc-8bad-a55c0de2d1e4'])->isValid(); // true
$v->validate(['uuid' => '00000000-0000-0000-0000-000000000000'])->isValid(); // true
```

[back to the top](#included-validation-rules)
62 changes: 49 additions & 13 deletions src/Rule/Uuid.php
Expand Up @@ -8,8 +8,6 @@
*/
namespace Particle\Validator\Rule;

use Particle\Validator\Rule;

/**
* This rule is for validating if a the value is a valid UUIDv4.
*
Expand All @@ -23,17 +21,43 @@ class Uuid extends Regex
const INVALID_UUID = 'Uuid::INVALID_UUID';

/**
* UUID Version 4.
* UUID NIL & version binary masks
*/
const UUID_V4 = 4;
const UUID_VALID = 0b0000100;
const UUID_NIL = 0b0000001;
const UUID_V1 = 0b0000010;
const UUID_V2 = 0b0001000;
const UUID_V3 = 0b0010000;
const UUID_V4 = 0b0100000;
const UUID_V5 = 0b1000000;

/**
* An array of all validation regexes.
*
* @var array
*/
protected $regexes = [
4 => '~^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i', // UUIDv4 Format
self::UUID_VALID => '~^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$~i',
self::UUID_NIL => '~^[0]{8}-[0]{4}-[0]{4}-[0]{4}-[0]{12}$~i',
self::UUID_V1 => '~^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i',
self::UUID_V2 => '~^[0-9a-f]{8}-[0-9a-f]{4}-2[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i',
self::UUID_V3 => '~^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i',
self::UUID_V4 => '~^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i',
self::UUID_V5 => '~^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$~i',
];

/**
* An array of names for all the versions
*
* @var array
*/
protected $versionNames = [
self::UUID_NIL => 'NIL',
self::UUID_V1 => 'v1',
self::UUID_V2 => 'v2',
self::UUID_V3 => 'v3',
self::UUID_V4 => 'v4',
self::UUID_V5 => 'v5',
];

/**
Expand All @@ -42,7 +66,7 @@ class Uuid extends Regex
* @var array
*/
protected $messageTemplates = [
self::INVALID_UUID => '{{ name }} must be a valid UUID (v{{ version }})'
self::INVALID_UUID => '{{ name }} must be a valid UUID ({{ version }})'
];

/**
Expand All @@ -57,26 +81,31 @@ class Uuid extends Regex
*
* @param int $version
*/
public function __construct($version = self::UUID_V4)
public function __construct($version = self::UUID_VALID)
{
if (!array_key_exists($version, $this->regexes)) {
if ($version >= (self::UUID_V5 * 2) || $version < 0) {
throw new \InvalidArgumentException(
sprintf('Unknown UUID version "%s"', $version)
'Invalid UUID version mask given. Please choose one of the constants on the Uuid class.'
);
}

$this->version = $version;
$this->regex = $this->regexes[$version];
}

/**
* Validates if the value is a valid UUIDv4.
* Validates if the value is a valid UUID of an allowed version.
*
* @param string $value
* @return bool
*/
public function validate($value)
{
return $this->match($this->regex, $value, self::INVALID_UUID);
foreach ($this->regexes as $version => $regex) {
if (($version & $this->version) === $version && preg_match($regex, $value) > 0) {
return true;
}
}
return $this->error(self::INVALID_UUID);
}

/**
Expand All @@ -86,8 +115,15 @@ public function validate($value)
*/
protected function getMessageParameters()
{
$versions = [];
foreach (array_keys($this->regexes) as $version) {
if (($version & $this->version) === $version) {
$versions[] = $this->versionNames[$version];
}
}

return array_merge(parent::getMessageParameters(), [
'version' => $this->version
'version' => implode(', ', $versions)
]);
}
}
140 changes: 137 additions & 3 deletions tests/Rule/UuidTest.php
Expand Up @@ -16,6 +16,40 @@ protected function setUp()
$this->validator = new Validator();
}

public function correctUUIDNIL()
{
return array(
array('00000000-0000-0000-0000-000000000000'),
);
}

public function correctUUIDv1()
{
return array(
array('5c3d167e-6011-11e6-8b77-86f30ca893d3'),
array('885e561e-6011-11e6-8b77-86f30ca893d3'),
array('9293b566-6011-11e6-8b77-86f30ca893d3'),
);
}

public function correctUUIDv2()
{
return array(
array('5c3d167e-6011-21e6-8b77-86f30ca893d3'),
array('885e561e-6011-21e6-bb77-86f30ca893d3'),
array('9293b566-6011-21e6-ab77-86f30ca893d3'),
);
}

public function correctUUIDv3()
{
return array(
array('5C3d167e-6011-31e6-8b77-86f30ca893d3'),
array('885e561e-6011-31E6-bb77-86f30ca893d3'),
array('9293b566-6011-31e6-9b77-86f30ca893d3'),
);
}

public function correctUUIDv4()
{
return array(
Expand All @@ -25,6 +59,20 @@ public function correctUUIDv4()
);
}

public function correctUUIDv5()
{
return array(
array('44c0ffee-988a-59dc-8bad-a55c0de2d1e4'),
array('de305d54-75b4-531b-adb2-eb6b9e546014'),
array('00000000-0000-5000-8000-000000000000'),
);
}

public function correctUUIDNILv4v5()
{
return array_merge($this->correctUUIDNIL(), $this->correctUUIDv4(), $this->correctUUIDv5());
}

public function incorrectUUIDv4()
{
return array(
Expand All @@ -39,6 +87,58 @@ public function incorrectUUIDv4()
);
}

public function incorrectVersionsProvider()
{
return [
[4],
[Uuid::UUID_V5 * 2],
];
}

/**
* @dataProvider correctUUIDNIL
*/
public function testReturnsTrueWhenMatchesUuidNIL($uuid)
{
$this->validator->required('guid')->uuid(Uuid::UUID_NIL);
$result = $this->validator->validate(['guid' => $uuid]);
$this->assertTrue($result->isValid());
$this->assertEquals([], $result->getMessages());
}

/**
* @dataProvider correctUUIDv1
*/
public function testReturnsTrueWhenMatchesUuidV1($uuid)
{
$this->validator->required('guid')->uuid(Uuid::UUID_V1);
$result = $this->validator->validate(['guid' => $uuid]);
$this->assertTrue($result->isValid());
$this->assertEquals([], $result->getMessages());
}

/**
* @dataProvider correctUUIDv2
*/
public function testReturnsTrueWhenMatchesUuidV2($uuid)
{
$this->validator->required('guid')->uuid(Uuid::UUID_V2);
$result = $this->validator->validate(['guid' => $uuid]);
$this->assertTrue($result->isValid());
$this->assertEquals([], $result->getMessages());
}

/**
* @dataProvider correctUUIDv3
*/
public function testReturnsTrueWhenMatchesUuidV3($uuid)
{
$this->validator->required('guid')->uuid(Uuid::UUID_V3);
$result = $this->validator->validate(['guid' => $uuid]);
$this->assertTrue($result->isValid());
$this->assertEquals([], $result->getMessages());
}

/**
* @dataProvider correctUUIDv4
*/
Expand All @@ -50,6 +150,28 @@ public function testReturnsTrueWhenMatchesUuidV4($uuid)
$this->assertEquals([], $result->getMessages());
}

/**
* @dataProvider correctUUIDv5
*/
public function testReturnsTrueWhenMatchesUuidV5($uuid)
{
$this->validator->required('guid')->uuid(Uuid::UUID_V5);
$result = $this->validator->validate(['guid' => $uuid]);
$this->assertTrue($result->isValid());
$this->assertEquals([], $result->getMessages());
}

/**
* @dataProvider correctUUIDNILv4v5
*/
public function testReturnsTrueWhenMatchingMultipleUuidVersions($uuid)
{
$this->validator->required('guid')->uuid(Uuid::UUID_NIL | Uuid::UUID_V4 | Uuid::UUID_V5);
$result = $this->validator->validate(['guid' => $uuid]);
$this->assertTrue($result->isValid());
$this->assertEquals([], $result->getMessages());
}

/**
* @dataProvider incorrectUUIDv4
*/
Expand All @@ -68,9 +190,21 @@ public function testReturnsFalseOnNoMatch($uuid)
$this->assertEquals($expected, $result->getMessages());
}

public function testThrowsExceptionOnUnknownVersion()
/**
* @dataProvider incorrectVersionsProvider
*/
public function testThrowsExceptionOnUnknownVersion($version)
{
$this->setExpectedException(
'\InvalidArgumentException',
'Invalid UUID version mask given. Please choose one of the constants on the Uuid class.'
);
$this->validator->required('guid')->uuid(Uuid::UUID_V5 * 2);
}

public function testThrowsExceptionOnNegativeVersion()
{
$this->setExpectedException('\InvalidArgumentException', 'Unknown UUID version "2"');
$this->validator->required('guid')->uuid(2);
$this->setExpectedException('\InvalidArgumentException', 'Invalid UUID version mask given.');
$this->validator->required('guid')->uuid(-1);
}
}

0 comments on commit 3683cff

Please sign in to comment.