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 708d759

Browse filesBrowse files
renan-tarantonicolas-grekas
authored andcommitted
[Validator] String normalization options for string-based validators
1 parent 29f81b0 commit 708d759
Copy full SHA for 708d759

29 files changed

+544
-3
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/CHANGELOG.md
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ CHANGELOG
88
* added UATP cards support to `CardSchemeValidator`
99
* added option `allowNull` to NotBlank constraint
1010
* added `Json` constraint
11-
11+
* added a new `normalizer` option to the string constraints and to the `NotBlank` constraint
12+
1213
4.2.0
1314
-----
1415

‎src/Symfony/Component/Validator/Constraints/Email.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/Email.php
+7-1Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Egulias\EmailValidator\EmailValidator as StrictEmailValidator;
1515
use Symfony\Component\Validator\Constraint;
16+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1617
use Symfony\Component\Validator\Exception\LogicException;
1718

1819
/**
@@ -73,6 +74,7 @@ class Email extends Constraint
7374
*/
7475
public $strict;
7576
public $mode;
77+
public $normalizer;
7678

7779
public function __construct($options = null)
7880
{
@@ -89,7 +91,7 @@ public function __construct($options = null)
8991
}
9092

9193
if (\is_array($options) && \array_key_exists('mode', $options) && !\in_array($options['mode'], self::$validationModes, true)) {
92-
throw new \InvalidArgumentException('The "mode" parameter value is not valid.');
94+
throw new InvalidArgumentException('The "mode" parameter value is not valid.');
9395
}
9496

9597
parent::__construct($options);
@@ -98,5 +100,9 @@ public function __construct($options = null)
98100
// throw new LogicException(sprintf('The "egulias/email-validator" component is required to use the "%s" constraint in strict mode.', __CLASS__));
99101
@trigger_error(sprintf('Using the "%s" constraint in strict mode without the "egulias/email-validator" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED);
100102
}
103+
104+
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
105+
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer)));
106+
}
101107
}
102108
}

‎src/Symfony/Component/Validator/Constraints/EmailValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/EmailValidator.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ public function validate($value, Constraint $constraint)
8181

8282
$value = (string) $value;
8383

84+
if (null !== $constraint->normalizer) {
85+
$value = ($constraint->normalizer)($value);
86+
}
87+
8488
if (null !== $constraint->strict) {
8589
@trigger_error(sprintf('The %s::$strict property is deprecated since Symfony 4.1. Use %s::mode="%s" instead.', Email::class, Email::class, Email::VALIDATION_MODE_STRICT), E_USER_DEPRECATED);
8690

‎src/Symfony/Component/Validator/Constraints/Ip.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/Ip.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Validator\Constraint;
1515
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
16+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1617

1718
/**
1819
* Validates that a value is a valid IP address.
@@ -72,6 +73,8 @@ class Ip extends Constraint
7273

7374
public $message = 'This is not a valid IP address.';
7475

76+
public $normalizer;
77+
7578
/**
7679
* {@inheritdoc}
7780
*/
@@ -82,5 +85,9 @@ public function __construct($options = null)
8285
if (!\in_array($this->version, self::$versions)) {
8386
throw new ConstraintDefinitionException(sprintf('The option "version" must be one of "%s"', implode('", "', self::$versions)));
8487
}
88+
89+
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
90+
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer)));
91+
}
8592
}
8693
}

‎src/Symfony/Component/Validator/Constraints/IpValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/IpValidator.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public function validate($value, Constraint $constraint)
4343

4444
$value = (string) $value;
4545

46+
if (null !== $constraint->normalizer) {
47+
$value = ($constraint->normalizer)($value);
48+
}
49+
4650
switch ($constraint->version) {
4751
case Ip::V4:
4852
$flag = FILTER_FLAG_IPV4;

‎src/Symfony/Component/Validator/Constraints/Length.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/Length.php
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator\Constraints;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1516
use Symfony\Component\Validator\Exception\MissingOptionsException;
1617

1718
/**
@@ -39,6 +40,7 @@ class Length extends Constraint
3940
public $max;
4041
public $min;
4142
public $charset = 'UTF-8';
43+
public $normalizer;
4244

4345
public function __construct($options = null)
4446
{
@@ -54,5 +56,9 @@ public function __construct($options = null)
5456
if (null === $this->min && null === $this->max) {
5557
throw new MissingOptionsException(sprintf('Either option "min" or "max" must be given for constraint %s', __CLASS__), ['min', 'max']);
5658
}
59+
60+
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
61+
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer)));
62+
}
5763
}
5864
}

‎src/Symfony/Component/Validator/Constraints/LengthValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/LengthValidator.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public function validate($value, Constraint $constraint)
4040

4141
$stringValue = (string) $value;
4242

43+
if (null !== $constraint->normalizer) {
44+
$stringValue = ($constraint->normalizer)($stringValue);
45+
}
46+
4347
if (!$invalidCharset = !@mb_check_encoding($stringValue, $constraint->charset)) {
4448
$length = mb_strlen($stringValue, $constraint->charset);
4549
}

‎src/Symfony/Component/Validator/Constraints/NotBlank.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/NotBlank.php
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator\Constraints;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1516

1617
/**
1718
* @Annotation
@@ -30,4 +31,14 @@ class NotBlank extends Constraint
3031

3132
public $message = 'This value should not be blank.';
3233
public $allowNull = false;
34+
public $normalizer;
35+
36+
public function __construct($options = null)
37+
{
38+
parent::__construct($options);
39+
40+
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
41+
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer)));
42+
}
43+
}
3344
}

‎src/Symfony/Component/Validator/Constraints/NotBlankValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/NotBlankValidator.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ public function validate($value, Constraint $constraint)
3434
return;
3535
}
3636

37+
if (\is_string($value) && null !== $constraint->normalizer) {
38+
$value = ($constraint->normalizer)($value);
39+
}
40+
3741
if (false === $value || (empty($value) && '0' != $value)) {
3842
$this->context->buildViolation($constraint->message)
3943
->setParameter('{{ value }}', $this->formatValue($value))

‎src/Symfony/Component/Validator/Constraints/Regex.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/Regex.php
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator\Constraints;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1516

1617
/**
1718
* @Annotation
@@ -31,6 +32,16 @@ class Regex extends Constraint
3132
public $pattern;
3233
public $htmlPattern;
3334
public $match = true;
35+
public $normalizer;
36+
37+
public function __construct($options = null)
38+
{
39+
parent::__construct($options);
40+
41+
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
42+
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer)));
43+
}
44+
}
3445

3546
/**
3647
* {@inheritdoc}

‎src/Symfony/Component/Validator/Constraints/RegexValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/RegexValidator.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public function validate($value, Constraint $constraint)
4343

4444
$value = (string) $value;
4545

46+
if (null !== $constraint->normalizer) {
47+
$value = ($constraint->normalizer)($value);
48+
}
49+
4650
if ($constraint->match xor preg_match($constraint->pattern, $value)) {
4751
$this->context->buildViolation($constraint->message)
4852
->setParameter('{{ value }}', $this->formatValue($value))

‎src/Symfony/Component/Validator/Constraints/Url.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/Url.php
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator\Constraints;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1516

1617
/**
1718
* @Annotation
@@ -105,6 +106,7 @@ class Url extends Constraint
105106
*/
106107
public $checkDNS = self::CHECK_DNS_TYPE_NONE;
107108
public $relativeProtocol = false;
109+
public $normalizer;
108110

109111
public function __construct($options = null)
110112
{
@@ -118,5 +120,9 @@ public function __construct($options = null)
118120
}
119121

120122
parent::__construct($options);
123+
124+
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
125+
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer)));
126+
}
121127
}
122128
}

‎src/Symfony/Component/Validator/Constraints/UrlValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/UrlValidator.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ public function validate($value, Constraint $constraint)
6262
return;
6363
}
6464

65+
if (null !== $constraint->normalizer) {
66+
$value = ($constraint->normalizer)($value);
67+
}
68+
6569
$pattern = $constraint->relativeProtocol ? str_replace('(%s):', '(?:(%s):)?', static::PATTERN) : static::PATTERN;
6670
$pattern = sprintf($pattern, implode('|', $constraint->protocols));
6771

‎src/Symfony/Component/Validator/Constraints/Uuid.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/Uuid.php
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Validator\Constraints;
1313

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Exception\InvalidArgumentException;
1516

1617
/**
1718
* @Annotation
@@ -74,4 +75,15 @@ class Uuid extends Constraint
7475
self::V4_RANDOM,
7576
self::V5_SHA1,
7677
];
78+
79+
public $normalizer;
80+
81+
public function __construct($options = null)
82+
{
83+
parent::__construct($options);
84+
85+
if (null !== $this->normalizer && !\is_callable($this->normalizer)) {
86+
throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', \is_object($this->normalizer) ? \get_class($this->normalizer) : \gettype($this->normalizer)));
87+
}
88+
}
7789
}

‎src/Symfony/Component/Validator/Constraints/UuidValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/UuidValidator.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ public function validate($value, Constraint $constraint)
8181

8282
$value = (string) $value;
8383

84+
if (null !== $constraint->normalizer) {
85+
$value = ($constraint->normalizer)($value);
86+
}
87+
8488
if ($constraint->strict) {
8589
$this->validateStrict($value, $constraint);
8690

‎src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Tests/Constraints/EmailTest.php
+26-1Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,36 @@ public function testConstructorStrict()
3535
}
3636

3737
/**
38-
* @expectedException \InvalidArgumentException
38+
* @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException
3939
* @expectedExceptionMessage The "mode" parameter value is not valid.
4040
*/
4141
public function testUnknownModesTriggerException()
4242
{
4343
new Email(['mode' => 'Unknown Mode']);
4444
}
45+
46+
public function testNormalizerCanBeSet()
47+
{
48+
$email = new Email(['normalizer' => 'trim']);
49+
50+
$this->assertEquals('trim', $email->normalizer);
51+
}
52+
53+
/**
54+
* @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException
55+
* @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given).
56+
*/
57+
public function testInvalidNormalizerThrowsException()
58+
{
59+
new Email(['normalizer' => 'Unknown Callable']);
60+
}
61+
62+
/**
63+
* @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException
64+
* @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given).
65+
*/
66+
public function testInvalidNormalizerObjectThrowsException()
67+
{
68+
new Email(['normalizer' => new \stdClass()]);
69+
}
4570
}

‎src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,28 @@ public function getValidEmails()
9494
];
9595
}
9696

97+
/**
98+
* @dataProvider getValidEmailsWithWhitespaces
99+
*/
100+
public function testValidNormalizedEmails($email)
101+
{
102+
$this->validator->validate($email, new Email(['normalizer' => 'trim']));
103+
104+
$this->assertNoViolation();
105+
}
106+
107+
public function getValidEmailsWithWhitespaces()
108+
{
109+
return [
110+
["\x20example@example.co.uk\x20"],
111+
["\x09\x09example@example.co..uk\x09\x09"],
112+
["\x0A{}~!@!@£$%%^&*().!@£$%^&*()\x0A"],
113+
["\x0D\x0Dexample@example.co..uk\x0D\x0D"],
114+
["\x00example@-example.com"],
115+
["example@example.com\x0B\x0B"],
116+
];
117+
}
118+
97119
/**
98120
* @dataProvider getValidEmailsHtml5
99121
*/
+46Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Validator\Constraints\Ip;
16+
17+
/**
18+
* @author Renan Taranto <renantaranto@gmail.com>
19+
*/
20+
class IpTest extends TestCase
21+
{
22+
public function testNormalizerCanBeSet()
23+
{
24+
$ip = new Ip(['normalizer' => 'trim']);
25+
26+
$this->assertEquals('trim', $ip->normalizer);
27+
}
28+
29+
/**
30+
* @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException
31+
* @expectedExceptionMessage The "normalizer" option must be a valid callable ("string" given).
32+
*/
33+
public function testInvalidNormalizerThrowsException()
34+
{
35+
new Ip(['normalizer' => 'Unknown Callable']);
36+
}
37+
38+
/**
39+
* @expectedException \Symfony\Component\Validator\Exception\InvalidArgumentException
40+
* @expectedExceptionMessage The "normalizer" option must be a valid callable ("stdClass" given).
41+
*/
42+
public function testInvalidNormalizerObjectThrowsException()
43+
{
44+
new Ip(['normalizer' => new \stdClass()]);
45+
}
46+
}

0 commit comments

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