Skip to content

Commit d6efa82

Browse files
committed
[Validator] rewrite the feature to fit with the new way
1 parent ab1e712 commit d6efa82

21 files changed

+450
-671
lines changed

UPGRADE-4.4.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,9 @@ TwigBridge
6464

6565
* Deprecated to pass `$rootDir` and `$fileLinkFormatter` as 5th and 6th argument respectively to the
6666
`DebugCommand::__construct()` method, swap the variables position.
67+
68+
Validator
69+
---------
70+
71+
* Deprecated `All` in favor of `Each` constraint
72+
* Deprecated `AllValidator` in favor of `EachValidator` validator

UPGRADE-5.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,8 @@ Validator
442442
* The `symfony/intl` component is now required for using the `Bic`, `Country`, `Currency`, `Language` and `Locale` constraints
443443
* The `egulias/email-validator` component is now required for using the `Email` constraint in strict mode
444444
* The `symfony/expression-language` component is now required for using the `Expression` constraint
445+
* Removed `All`, use the `Each` constraint instead.
446+
* Removed `AllValidator`, use the `EachValidator` validator instead.
445447

446448
Workflow
447449
--------

src/Symfony/Component/Validator/CHANGELOG.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,17 @@ CHANGELOG
77
* added the `compared_value_path` parameter in violations when using any
88
comparison constraint with the `propertyPath` option.
99
* added support for checking an array of types in `TypeValidator`
10-
10+
* deprecated `All` in favor of `Each` constraint
11+
* deprecated `AllValidator` in favor of `EachValidator` validator
12+
* added `Each` constraint
13+
* added `EachValidator`
14+
* added `None` constraint
15+
* added `NoneValidator`
16+
* added `Some` constraint
17+
* added `SomeValidator`
18+
* added `Unique` contraint
19+
* added `AbstractComposite` constraint
20+
1121
4.3.0
1222
-----
1323

@@ -23,16 +33,6 @@ CHANGELOG
2333
* added `PositiveOrZero` constraint
2434
* added `Negative` constraint
2535
* added `NegativeOrZero` constraint
26-
* added `AbstractComposite` constraint
27-
* deprecate `All` constraint
28-
* deprecate `AllValidator`
29-
* added `Each` constraint
30-
* added `EachValidator`
31-
* added `None` constraint
32-
* added `NoneValidator`
33-
* added `Some` constraint
34-
* added `SomeValidator`
35-
* added `Unique` contraint
3636

3737
4.2.0
3838
-----

src/Symfony/Component/Validator/Constraints/AbstractComposite.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* @author Marc Morales Valldepérez <marcmorales83@gmail.com>
2121
* @author Marc Morera Merino <yuhu@mmoreram.com>
2222
*/
23-
abstract class AbstractComposite extends Constraint
23+
abstract class AbstractComposite extends Composite
2424
{
2525
/**
2626
* @var array
@@ -36,12 +36,7 @@ public function __construct($options = null)
3636
{
3737
parent::__construct($options);
3838

39-
if (!\is_array($this->constraints)) {
40-
$this->constraints = [$this->constraints];
41-
}
42-
43-
// We consider explicid groups are defined if are not default one
44-
$areExplicitGroupsDefined = ($this->groups != [self::DEFAULT_GROUP]);
39+
$this->constraints = (array) $this->constraints;
4540

4641
// Each constraint contained
4742
foreach ($this->constraints as $constraint) {
@@ -53,10 +48,10 @@ public function __construct($options = null)
5348
throw new ConstraintDefinitionException(sprintf('The constraint Valid cannot be nested inside constraint %s. You can only declare the Valid constraint directly on a field or method.', __CLASS__));
5449
}
5550

56-
// If explicid groups are defined
57-
if ($areExplicitGroupsDefined) {
51+
// If explicit groups are defined
52+
if ($this->groups != [self::DEFAULT_GROUP]) {
5853
/*
59-
* If constraint has explicid groups defined
54+
* If constraint has explicit groups defined
6055
*
6156
* In that case, the groups of the nested constraint need to be
6257
* a subset of the groups of the outer constraint.
@@ -90,7 +85,6 @@ public function __construct($options = null)
9085
*
9186
* @param string $group
9287
*
93-
* @api
9488
*/
9589
public function addImplicitGroupName($group)
9690
{
@@ -116,4 +110,12 @@ public function getRequiredOptions()
116110
{
117111
return ['constraints'];
118112
}
113+
114+
/**
115+
* {@inheritdoc}
116+
*/
117+
protected function getCompositeOption()
118+
{
119+
return 'constraints';
120+
}
119121
}

src/Symfony/Component/Validator/Constraints/EachValidator.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
use Symfony\Component\Validator\Constraint;
1515
use Symfony\Component\Validator\ConstraintValidator;
1616
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
17+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
1718

1819
/**
1920
* @author Marc Morera Merino <yuhu@mmoreram.com>
2021
* @author Marc Morales Valldepérez <marcmorales83@gmail.com>
22+
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
2123
*/
2224
class EachValidator extends ConstraintValidator
2325
{
@@ -26,20 +28,22 @@ class EachValidator extends ConstraintValidator
2628
*/
2729
public function validate($value, Constraint $constraint)
2830
{
31+
if (!$constraint instanceof Each) {
32+
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Each');
33+
}
34+
2935
if (null === $value) {
3036
return;
3137
}
3238

33-
if (!\is_array($value) && !$value instanceof \Traversable) {
34-
throw new UnexpectedTypeException($value, 'array or Traversable');
39+
if (!is_iterable($value)) {
40+
throw new UnexpectedValueException($value, 'iterable');
3541
}
3642

37-
$group = $this->context->getGroup();
43+
$validator = $this->context->getValidator()->inContext($this->context);
3844

3945
foreach ($value as $key => $element) {
40-
foreach ($constraint->constraints as $constr) {
41-
$this->context->validateValue($element, $constr, '['.$key.']', $group);
42-
}
46+
$validator->atPath('['.$key.']')->validate($element, $constraint->constraints);
4347
}
4448
}
4549
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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\Exception\MissingOptionsException;
15+
16+
/**
17+
* @Annotation
18+
*
19+
* @author Marc Morera Merino <yuhu@mmoreram.com>
20+
* @author Marc Morales Valldepérez <marcmorales83@gmail.com>
21+
*/
22+
class Exactly extends AbstractComposite
23+
{
24+
/**
25+
* @var string
26+
*
27+
* Message for notice Exactly Violation
28+
*/
29+
public $exactlyMessage = 'Exactly {{ limit }} element of this collection should pass validation.|Exactly {{ limit }} elements of this collection should pass validation';
30+
31+
/**
32+
* @var int
33+
*
34+
* Exactly number of Success expected
35+
*/
36+
public $exactly;
37+
38+
/**
39+
* {@inheritdoc}
40+
*/
41+
public function __construct($options = null)
42+
{
43+
parent::__construct($options);
44+
if (null === $this->exactly) {
45+
throw new MissingOptionsException('The "exactly" option cannot be null', ['exactly']);
46+
}
47+
}
48+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
/**
20+
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
21+
*/
22+
class ExactlyValidator extends ConstraintValidator
23+
{
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function validate($value, Constraint $constraint)
28+
{
29+
if (null === $value) {
30+
return;
31+
}
32+
33+
if (!$constraint instanceof Exactly) {
34+
throw new UnexpectedTypeException($constraint, Exactly::class);
35+
}
36+
37+
if (!is_iterable($value)) {
38+
throw new UnexpectedValueException($value, 'array or Traversable');
39+
}
40+
41+
$totalIterations = \count($value) * \count($constraint->constraints);
42+
43+
44+
$validator = $this->context->getValidator()->inContext($this->context);
45+
46+
foreach ($value as $key => $element) {
47+
$validator->atPath('['.$key.']')->validate($element, $constraint->constraints);
48+
}
49+
50+
$constraintsSuccess = $totalIterations - (int) $this->context->getViolations()->count();
51+
$violations = $this->context->getViolations();
52+
// We clear all violations as just current Validator should add real Violations
53+
foreach ($this->context->getViolations() as $key => $violation) {
54+
$violations->remove($key);
55+
}
56+
57+
if (isset($constraint->exactly) && $constraintsSuccess != $constraint->exactly) {
58+
$this->context->buildViolation($constraint->exactlyMessage)
59+
->setParameter('{{ limit }}', $constraint->exactly)
60+
->addViolation();
61+
}
62+
}
63+
}

src/Symfony/Component/Validator/Constraints/None.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,5 @@
1919
*/
2020
class None extends AbstractComposite
2121
{
22-
/**
23-
* @var string
24-
*
25-
* Message for notice Violation
26-
*/
2722
public $message = 'None of this collection should pass validation.';
2823
}

src/Symfony/Component/Validator/Constraints/NoneValidator.php

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
use Symfony\Component\Validator\Constraint;
1515
use Symfony\Component\Validator\ConstraintValidator;
1616
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
17+
use Symfony\Component\Validator\Exception\UnexpectedValueException;
1718

1819
/**
1920
* @author Marc Morera Merino <yuhu@mmoreram.com>
2021
* @author Marc Morales Valldepérez <marcmorales83@gmail.com>
22+
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
2123
*/
2224
class NoneValidator extends ConstraintValidator
2325
{
@@ -30,24 +32,30 @@ public function validate($value, Constraint $constraint)
3032
return;
3133
}
3234

33-
if (!\is_array($value) && !$value instanceof \Traversable) {
34-
throw new UnexpectedTypeException($value, 'array or Traversable');
35+
if (!$constraint instanceof None) {
36+
throw new UnexpectedTypeException($constraint, None::class);
3537
}
3638

37-
$group = $this->context->getGroup();
39+
if (!is_iterable($value)) {
40+
throw new UnexpectedValueException($value, 'array or Traversable');
41+
}
42+
43+
$validator = $this->context->getValidator()->inContext($this->context);
3844

3945
$totalIterations = \count($value) * \count($constraint->constraints);
4046

4147
foreach ($value as $key => $element) {
42-
foreach ($constraint->constraints as $constr) {
43-
$this->context->validateValue($element, $constr, '['.$key.']', $group);
44-
}
48+
$validator->atPath('['.$key.']')->validate($element, $constraint->constraints);
4549
}
4650

4751
$constraintsSuccess = $totalIterations - (int) $this->context->getViolations()->count();
4852

4953
//We clear all violations as just current Validator should add real Violations
50-
$this->context->clearViolations();
54+
$violations = $this->context->getViolations();
55+
// We clear all violations as just current Validator should add real Violations
56+
foreach ($this->context->getViolations() as $key => $violation) {
57+
$violations->remove($key);
58+
}
5159

5260
if ($constraintsSuccess > 0) {
5361
$this->context->addViolation($constraint->message);

src/Symfony/Component/Validator/Constraints/Some.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,21 @@ class Some extends AbstractComposite
4545
/**
4646
* @var int
4747
*
48-
* Min number of Succeds expected
48+
* Min number of Success expected
4949
*/
5050
public $min;
5151

5252
/**
5353
* @var int
5454
*
55-
* Max number of Succeds expected
55+
* Max number of Success expected
5656
*/
5757
public $max;
5858

5959
/**
6060
* @var int
6161
*
62-
* Exactly number of Succeds expected
62+
* Exactly number of Success expected
6363
*/
6464
public $exactly;
6565

@@ -69,17 +69,16 @@ class Some extends AbstractComposite
6969
public function __construct($options = null)
7070
{
7171
parent::__construct($options);
72-
73-
if ((isset($this->min) || isset($this->max)) && isset($this->exactly)) {
74-
throw new MissingOptionsException(sprintf('"min" or "max" and "exactly" must not be given at the same time: %s', __CLASS__), ['min', 'max', 'exactly']);
72+
if ((null !== $this->min || null !== $this->max) && null !== $this->exactly) {
73+
throw new MissingOptionsException('The "exactly" option cannot be used with "min" or "max" at the same time.', ['min', 'max', 'exactly']);
7574
}
7675

77-
if (!isset($this->min) && !isset($this->exactly)) {
76+
if (null === $this->min && null === $this->min) {
7877
$this->min = 1;
7978
}
8079

8180
if (isset($this->max) && ($this->min > $this->max)) {
82-
throw new MissingOptionsException(sprintf('"min" must not be given great than "max": %s', __CLASS__), ['min', 'max']);
81+
throw new MissingOptionsException('The "min" option must not be greater than "max".', ['min', 'max']);
8382
}
8483
}
8584
}

0 commit comments

Comments
 (0)