8000 [Validator] Added new validator for UUIDs · symfony/symfony@6ffa383 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6ffa383

Browse files
committed
[Validator] Added new validator for UUIDs
1 parent 0788896 commit 6ffa383

File tree

3 files changed

+237
-0
lines changed

3 files changed

+237
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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\C 10000 onstraint;
15+
16+
/**
17+
* @Annotation
18+
*
19+
* @author Colin O'Dell <colinodell@gmail.com>
20+
*/
21+
class Uuid extends Constraint
22+
{
23+
// Possible versions defined by RFC 4122
24+
const V1_MAC = 1;
25+
const V2_DCE = 2;
26+
const V3_MD5 = 3;
27+
const V4_RANDOM = 4;
28+
const V4_SHA1 = 5;
29+
30+
// Message to display when validation fails
31+
public $message = 'This is not a valid UUID.';
32+
33+
// Array of allowed versions (see version constants above)
34+
// All UUID versions are allowed by default
35+
public $versions = array(
36+
self::V1_MAC,
37+
self::V2_DCE,
38+
self::V3_MD5,
39+
self::V4_RANDOM,
40+
self::V4_SHA1
41+
);
42+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
18+
/**
19+
* Validates whether the value is a valid UUID per RFC 4122.
20+
*
21+
* @author Colin O'Dell <colinodell@gmail.com>
22+
*
23+
* @see http://tools.ietf.org/html/rfc4122
24+
* @see https://en.wikipedia.org/wiki/Universally_unique_identifier
25+
*/
26+
class UuidValidator extends ConstraintValidator
27+
{
28+
// Regular expression which verifies allowed characters and the proper format
29+
const PATTERN = '/^[a-f0-9]{8}-[a-f0-9]{4}-[%s][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i';
30+
// Properly-formatted UUIDs contain 32 hex digits, separated by 4 dashes
31+
const UUID_LENGTH = 36;
32+
33+
/**
34+
* {@inheritDoc}
35+
*/
36+
public function validate($value, Constraint $constraint)
37+
{
38+
if (null === $value || '' === $value) {
39+
return;
40+
}
41+
42+
if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) {
43+
throw new UnexpectedTypeException($value, 'string');
44+
}
45+
46+
$value = (string) $value;
47+
48+
$pattern = sprintf(static::PATTERN, implode('', $constraint->versions));
49+
50+
if (strlen($value) !== static::UUID_LENGTH || !preg_match($pattern, $value)) {
51+
$this->context->addViolation($constraint->message, array('{{ value }}' => $value));
52+
}
53+
}
54+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
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 Symfony\Component\Validator\Constraints\Uuid;
15+
use Symfony\Component\Validator\Constraints\UuidValidator;
16+
17+
/**
18+
* @author Colin O'Dell <colinodell@gmail.com>
19+
*/
20+
class UuidValidatorTest extends \PHPUnit_Framework_TestCase
21+
{
22+
protected $context;
23+
protected $validator;
24+
25+
protected function setUp()
26+
{
27+
$this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false);
28+
$this->validator = new UuidValidator();
29+
$this->validator->initialize($this->context);
30+
}
31+
32+
protected function tearDown()
33+
{
34+
$this->context = null;
35+
$this->validator = null;
36+
}
37+
38+
public function testNullIsValid()
39+
{
40+
$this->context->expects($this->never())
41+
->method('addViolation');
42+
43+
$this->validator->validate(null, new Uuid());
44+
}
45+
46+
public function testEmptyStringIsValid()
47+
{
48+
$this->context->expects($this->never())
49+
->method('addViolation');
50+
51+
$this->validator->validate('', new Uuid());
52+
}
53+
54+
/**
55+
* @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException
56+
*/
57+
public function testExpectsStringCompatibleType()
58+
{
59+
$this->validator->validate(new \stdClass(), new Uuid());
60+
}
61+
62+
/**
63+
* @dataProvider getValidUuids
64+
*/
65+
public function testValidUuids($uuid)
66+
{
67+
$this->context->expects($this->never())
68+
->method('addViolation');
69+
70+
$this->validator->validate($uuid, new Uuid());
71+
}
72+
73+
public function getValidUuids()
74+
{
75+
return array(
76+
array('216fff40-98d9-11e3-a5e2-0800200c9a66'), // Version 1 UUID in lowercase
77+
array('216FFF40-98D9-11E3-A5E2-0800200C9A66'), // Version 1 UUID in UPPERCASE
78+
array('456daefb-5aa6-41b5-8dbc-068b05a8b201'), // Version 4 UUID in lowercase
79+
array('456DAEFb-5AA6-41B5-8DBC-068B05A8B201'), // Version 4 UUID in UPPERCASE
80+
);
81+
}
82+
83+
/**
84+
* @dataProvider getInvalidUuids
85+
*/
86+
public function testInvalidUuids($uuid)
87+
{
88+
$constraint = new Uuid(array(
89+
'message' => 'testMessage'
90+
));
91+
92+
$this->context->expects($this->once())
93+
->method('addViolation')
94+
->with('testMessage', array(
95+
'{{ value }}' => $uuid,
96+
));
97+
98+
$this->validator->validate($uuid, $constraint);
99+
}
100+
101+
public function getInvalidUuids()
102+
{
103+
return array(
104+
array('216fff40-98d9-11e3-a5e2-0800200c9a6'), // Too few characters
105+
array('216fff40-98d9-11e3-a5e2-0800200c9a666'), // Too many characters
106+
array('V16fff40-98d9-11e3-a5e2-0800200c9a66'), // Invalid character 'V'
107+
array('216fff40-98d9-11e3-a5e20800-200c9a66'), // Invalid dash position
108+
array('216fff4098d911e3a5e20800200c9a66'), // Missing dashes
109+
);
110+
}
111+
112+
/**
113+
* @dataProvider getValidUuids
114+
*/
115+
public function testVersionConstraintIsValid($uuid)
116+
{
117+
$this->context->expects($this->never())
118+
->method('addViolation');
119+
120+
$constraint = new Uuid(array(
121+
'versions' => array(Uuid::V1_MAC, Uuid::V4_RANDOM)
122+
));
123+
124+
$this->validator->validate($uuid, $constraint);
125+
}
126+
127+
/**
128+
* @dataProvider getValidUuids
129+
*/
130+
public function testVersionConstraintIsInvalid($uuid)
131+
{
132+
$constraint = new Uuid(array(
133+
'versions' => array(Uuid::V2_DCE, Uuid::V3_MD5)
134+
));
135+
136+
$this->context->expects($this->once())
137+
->method('addViolation');
138+
139+
$this->validator->validate($uuid, $constraint);
140+
}
141+
}

0 commit comments

Comments
 (0)
0