Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8101e63

Browse files
committed
Added DomainValidator
1 parent 519ba3c commit 8101e63

File tree

3 files changed

+269
-0
lines changed

3 files changed

+269
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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+
* @author Dmitrii Poddubnyi <[email protected]>
21+
*/
22+
class Domain extends Constraint
23+
{
24+
const INVALID_FORMAT_ERROR = '7057ffdb-0af4-4f7e-bd5e-e9acfa6d7a2d';
25+
26+
public $message = 'This value is not a valid domain';
27+
28+
public $requireTld = true;
29+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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+
/**
20+
* @author Dmitrii Poddubnyi <[email protected]>
21+
*/
22+
class DomainValidator extends ConstraintValidator
23+
{
24+
private const RESERVED = [
25+
'example',
26+
'invalid',
27+
'localhost',
28+
'test',
29+
];
30+
31+
public function validate($value, Constraint $constraint)
32+
{
33+
if (!$constraint instanceof Domain) {
34+
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Domain');
35+
}
36+
37+
if (null === $value || '' === $value) {
38+
return;
39+
}
40+
41+
if (!is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) {
42+
throw new UnexpectedValueException($value, 'string');
43+
}
44+
45+
$value = (string) $value;
46+
if ('' === $value) {
47+
return;
48+
}
49+
if (!$this->isValid($value) || ($constraint->requireTld && !$this->isTld($value))) {
50+
$this->context->buildViolation($constraint->message)
51+
->setParameter('{{ value }}', $this->formatValue($value))
52+
->setCode(Domain::INVALID_FORMAT_ERROR)
53+
->addViolation();
54+
}
55+
}
56+
57+
private function isValid(string $domain): bool
58+
{
59+
return false !== filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
60+
}
61+
62+
private function isTld(string $domain): bool
63+
{
64+
return (false !== strpos($domain, '.')) && (!$this->isReserved($domain));
65+
}
66+
67+
private function isReserved(string $domain): bool
68+
{
69+
$parts = explode('.', $domain);
70+
$domain = end($parts);
71+
$domain = strtolower($domain);
72+
73+
return \in_array($domain, self::RESERVED);
74+
}
75+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Domain;
15+
use Symfony\Component\Validator\Constraints\DomainValidator;
16+
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
17+
18+
/**
19+
* @author Dmitrii Poddubnyi <[email protected]>
20+
*/
21+
class DomainValidatorTest extends ConstraintValidatorTestCase
22+
{
23+
protected function createValidator()
24+
{
25+
return new DomainValidator();
26+
}
27+
28+
public function testNullIsValid()
29+
{
30+
$this->validator->validate(null, new Domain());
31+
32+
$this->assertNoViolation();
33+
}
34+
35+
public function testEmptyStringIsValid()
36+
{
37+
$this->validator->validate('', new Domain());
38+
39+
$this->assertNoViolation();
40+
}
41+
42+
/**
43+
* @expectedException \Symfony\Component\Validator\Exception\UnexpectedValueException
44+
*/
45+
public function testExpectsStringCompatibleType()
46+
{
47+
$this->validator->validate(new \stdClass(), new Domain());
48+
}
49+
50+
/**
51+
* @dataProvider getValidTldDomains
52+
*/
53+
public function testValidTldDomains_passValidation_ifTldRequired($domain)
54+
{
55+
$this->validator->validate($domain, new Domain());
56+
57+
$this->assertNoViolation();
58+
}
59+
60+
/**
61+
* @dataProvider getValidTldDomains
62+
*/
63+
public function testValidTldDomains_passValidation_ifTldNotRequired($domain)
64+
{
65+
$this->validator->validate($domain, new Domain(['requireTld' => false]));
66+
67+
$this->assertNoViolation();
68+
}
69+
70+
public function getValidTldDomains()
71+
{
72+
return [
73+
['symfony.com'],
74+
['example.co.uk'],
75+
['example.fr'],
76+
['example.com'],
77+
['xn--diseolatinoamericano-66b.com'],
78+
['xn--ggle-0nda.com'],
79+
['www.xn--simulateur-prt-2kb.fr'],
80+
[sprintf('%s.com', str_repeat('a', 20))],
81+
];
82+
}
83+
84+
/**
85+
* @dataProvider getInvalidDomains
86+
*/
87+
public function testInvalidDomains_throwException_ifTldRequired($domain)
88+
{
89+
$this->validator->validate($domain, new Domain([
90+
'message' => 'myMessage',
91+
]));
92+
93+
$this->buildViolation('myMessage')
94+
->setParameter('{{ value }}', '"'.$domain.'"')
95+
->setCode(Domain::INVALID_FORMAT_ERROR)
96+
->assertRaised();
97+
}
98+
99+
/**
100+
* @dataProvider getInvalidDomains
101+
*/
102+
public function testInvalidDomains_throwException_ifTldNotRequired($domain)
103+
{
104+
$this->validator->validate($domain, new Domain([
105+
'message' => 'myMessage',
106+
'requireTld' => false,
107+
]));
108+
109+
$this->buildViolation('myMessage')
110+
->setParameter('{{ value }}', '"'.$domain.'"')
111+
->setCode(Domain::INVALID_FORMAT_ERROR)
112+
->assertRaised();
113+
}
114+
115+
public function getInvalidDomains()
116+
{
117+
return [
118+
['acme..com'],
119+
['qq--.com'],
120+
['-example.com'],
121+
['example-.com'],
122+
[sprintf('%s.com', str_repeat('a', 300))],
123+
];
124+
}
125+
126+
/**
127+
* @dataProvider getReservedDomains
128+
*/
129+
public function testReservedDomains_passValidation_ifTldNotRequired($domain)
130+
{
131+
$this->validator->validate($domain, new Domain(['requireTld' => false]));
132+
133+
$this->assertNoViolation();
134+
}
135+
136+
/**
137+
* @dataProvider getReservedDomains
138+
*/
139+
public function testReservedDomains_throwException_ifTldRequired($domain)
140+
{
141+
$this->validator->validate($domain, new Domain([
142+
'message' => 'myMessage',
143+
'requireTld' => true,
144+
]));
145+
146+
$this->buildViolation('myMessage')
147+
->setParameter('{{ value }}', '"'.$domain.'"')
148+
->setCode(Domain::INVALID_FORMAT_ERROR)
149+
->assertRaised();
150+
}
151+
152+
public function getReservedDomains()
153+
{
154+
return [
155+
['example'],
156+
['foo.example'],
157+
['invalid'],
158+
['bar.invalid'],
159+
['localhost'],
160+
['lol.localhost'],
161+
['test'],
162+
['abc.test'],
163+
];
164+
}
165+
}

0 commit comments

Comments
 (0)