Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 487f73e

Browse filesBrowse files
committed
[Validator] Add the HexColor constraint and validator
1 parent 9acb060 commit 487f73e
Copy full SHA for 487f73e

File tree

6 files changed

+241
-0
lines changed
Filter options

6 files changed

+241
-0
lines changed

‎src/Symfony/Component/Validator/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* added option `alpha3` to `Country` constraint
99
* allow to define a reusable set of constraints by extending the `Compound` constraint
1010
* added `Sequentially` constraint, to sequentially validate a set of constraints (any violation raised will prevent further validation of the nested constraints)
11+
* added the `HexColor` constraint and validator
1112

1213
5.0.0
1314
-----
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
16+
/**
17+
* @Annotation
18+
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
19+
*/
20+
final class HexColor extends Constraint
21+
{
22+
public const INVALID_FORMAT_ERROR = 'e8c5955b-9ee3-451e-9c12-4d18240805db';
23+
24+
/**
25+
* @see https://www.w3.org/TR/html52/sec-forms.html#color-state-typecolor
26+
*/
27+
public $html5 = true;
28+
29+
public $message = 'This value is not a valid hexadecimal color.';
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function getDefaultOption()
35+
{
36+
return 'html5';
37+
}
38+
}
+50Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
18+
19+
final class HexColorValidator extends ConstraintValidator
20+
{
21+
private const PATTERN_HTML5 = '/^#[0-9a-f]{6}$/i';
22+
private const PATTERN = '/^#[0-9a-f]{3}(?:[0-9a-f](?:[0-9a-f]{2}(?:[0-9a-f]{2})?)?)?$/i';
23+
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function validate($value, Constraint $constraint)
28+
{
29+
if (!$constraint instanceof HexColor) {
30+
throw new UnexpectedTypeException($constraint, HexColor::class);
31+
}
32+
33+
if (null === $value || '' === $value) {
34+
return;
35+
}
36+
37+
if (!\is_string($value) && !(\is_object($value) && method_exists($value, '__toString'))) {
38+
throw new UnexpectedValueException($value, 'string');
39+
}
40+
41+
$value = (string) $value;
42+
43+
if (!preg_match($constraint->html5 ? self::PATTERN_HTML5 : self::PATTERN, $value)) {
44+
$this->context->buildViolation($constraint->message)
45+
->setParameter('{{ value }}', $this->formatValue($value))
46+
->setCode(HexColor::INVALID_FORMAT_ERROR)
47+
->addViolation();
48+
}
49+
}
50+
}

‎src/Symfony/Component/Validator/Resources/translations/validators.en.xlf

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Resources/translations/validators.en.xlf
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@
370370
<source>This value is not a valid hostname.</source>
371371
<target>This value is not a valid hostname.</target>
372372
</trans-unit>
373+
<trans-unit id="96">
374+
<source>This value is not a valid hexadecimal color.</source>
375+
<target>This value is not a valid hexadecimal color.</target>
376+
</trans-unit>
373377
</body>
374378
</file>
375379
</xliff>

‎src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@
370370
<source>This value is not a valid hostname.</source>
371371
<target>Cette valeur n'est pas un nom d'hôte valide.</target>
372372
</trans-unit>
373+
<trans-unit id="96">
374+
<source>This value is not a valid hexadecimal color.</source>
375+
<target>Cette valeur n'est pas une couleur hexadécimale valide.</target>
376+
</trans-unit>
373377
</body>
374378
</file>
375379
</xliff>
+144Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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\Email;
15+
use Symfony\Component\Validator\Constraints\HexColor;
16+
use Symfony\Component\Validator\Constraints\HexColorValidator;
17+
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
18+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
19+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
20+
21+
final class HexColorValidatorTest extends ConstraintValidatorTestCase
22+
{
23+
protected function createValidator()
24+
{
25+
return new HexColorValidator();
26+
}
27+
28+
public function testUnexpectedType()
29+
{
30+
$this->expectException(UnexpectedTypeException::class);
31+
$this->expectExceptionMessage('Expected argument of type "Symfony\Component\Validator\Constraints\HexColor", "Symfony\Component\Validator\Constraints\Email" given');
32+
33+
$this->validator->validate(null, new Email());
34+
}
35+
36+
public function testUnexpectedValue()
37+
{
38+
$this->expectException(UnexpectedValueException::class);
39+
$this->expectExceptionMessage('Expected argument of type "string", "stdClass" given');
40+
41+
$this->validator->validate(new \stdClass(), new HexColor());
42+
}
43+
44+
public function testNullIsValid()
45+
{
46+
$this->validator->validate(null, new HexColor());
47+
48+
$this->assertNoViolation();
49+
}
50+
51+
public function testEmptyStringIsValid()
52+
{
53+
$this->validator->validate('', new HexColor());
54+
55+
$this->assertNoViolation();
56+
}
57+
58+
/**
59+
* @dataProvider getValidHexColors
60+
*/
61+
public function testValidHexColors($hexColor, bool $html5 = true)
62+
{
63+
$this->validator->validate($hexColor, new HexColor($html5));
64+
65+
$this->assertNoViolation();
66+
}
67+
68+
public function getValidHexColors()
69+
{
70+
// Valid for both patterns
71+
foreach ([
72+
'#000000',
73+
'#abcabc',
74+
'#BbBbBb',
75+
new class() {
76+
public function __toString(): string
77+
{
78+
return '#1Ee54d';
79+
}
80+
},
81+
] as $hexColor) {
82+
yield [$hexColor, true];
83+
yield [$hexColor, false];
84+
}
85+
86+
// Only valid with the generic pattern
87+
foreach ([
88+
'#abc',
89+
'#A000',
90+
'#1e98ccCC',
91+
] as $hexColor) {
92+
yield [$hexColor, false];
93+
}
94+
}
95+
96+
/**
97+
* @dataProvider getHexColorsWithInvalidFormat
98+
*/
99+
public function testHexColorsWithInvalidFormat($hexColor, bool $html5 = true)
100+
{
101+
$this->validator->validate($hexColor, new HexColor([
102+
'html5' => $html5,
103+
'message' => 'foo',
104+
]));
105+
106+
$this->buildViolation('foo')
107+
->setParameter('{{ value }}', '"'.(string) $hexColor.'"')
108+
->setCode(HexColor::INVALID_FORMAT_ERROR)
109+
->assertRaised();
110+
}
111+
112+
public function getHexColorsWithInvalidFormat()
113+
{
114+
// Invalid for both patterns
115+
foreach ([
116+
'#',
117+
'#A',
118+
'#A1',
119+
'000000',
120+
'#abcabg',
121+
' #ffffff',
122+
'#12345',
123+
new class() {
124+
public function __toString(): string
125+
{
126+
return '#010101 ';
127+
}
128+
},
129+
'#1e98ccCC9',
130+
] as $hexColor) {
131+
yield [$hexColor, true];
132+
yield [$hexColor, false];
133+
}
134+
135+
// Only invalid with the html5 pattern
136+
foreach ([
137+
'#abc',
138+
'#A000',
139+
'#1e98ccCC',
140+
] as $hexColor) {
141+
yield [$hexColor, true];
142+
}
143+
}
144+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.