-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[Validator] Added 'Any' validator #11586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Validator\Constraints; | ||
|
||
use Symfony\Component\Validator\Constraint; | ||
|
||
/** | ||
* @Annotation | ||
* @Target({"PROPERTY", "METHOD", "ANNOTATION", "CLASS"}) | ||
* | ||
* @author Cas Leentfaar <info@casleentfaar.com> | ||
*/ | ||
class Any extends Composite | ||
{ | ||
/** | ||
* @var string | ||
*/ | ||
public $message = 'None of the contraints found the value to be valid'; | ||
|
||
/** | ||
* @var Constraint[] | ||
*/ | ||
public $constraints = array(); | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function __construct($options = null) | ||
{ | ||
parent::__construct($options); | ||
|
||
$this->message = array_key_exists('message', $options) ? $options['message'] : $this->message; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getDefaultOption() | ||
{ | ||
return 'constraints'; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getRequiredOptions() | ||
{ | ||
return array( | ||
'constraints', | ||
); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function getCompositeOption() | ||
{ | ||
return 'constraints'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Validator\Constraints; | ||
|
||
use Symfony\Component\Validator\Constraint; | ||
use Symfony\Component\Validator\ConstraintValidator; | ||
use Symfony\Component\Validator\Context\ExecutionContext; | ||
use Symfony\Component\Validator\Context\ExecutionContextInterface; | ||
use Symfony\Component\Validator\Exception\UnexpectedTypeException; | ||
|
||
/** | ||
* @author Cas Leentfaar <info@casleentfaar.com> | ||
*/ | ||
class AnyValidator extends ConstraintValidator | ||
{ | ||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function validate($value, Constraint $constraint) | ||
{ | ||
if (!$constraint instanceof Any) { | ||
throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\Any'); | ||
} | ||
|
||
if (null === $value) { | ||
return; | ||
} | ||
|
||
$context = $this->context; | ||
$group = $context->getGroup(); | ||
|
||
if (!$context instanceof ExecutionContext) { | ||
throw new \LogicException('Don\'t know how to deal with this when we need to create separate contexts later'); | ||
} | ||
|
||
foreach ($constraint->constraints as $subConstraint) { | ||
$subContext = new ExecutionContext( | ||
$context->getValidator(), | ||
$context->getRoot(), | ||
$context->getTranslator(), | ||
$context->getTranslationDomain() | ||
); | ||
if ($context instanceof ExecutionContextInterface) { | ||
$subContext->getValidator()->validate($value, $subConstraint); | ||
} else { | ||
// 2.4 API | ||
$subContext->validateValue($value, $subConstraint); | ||
} | ||
$violations = $subContext->getViolations(); | ||
if ($violations && $violations->count() === 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. given that you use the same context for all constraints, this will not work if the first constraint fails and the second one does not fail (as there will be a violation for the first one). Thus, it also fails if another constraint already recorded a violation on the field outside the Any constraint. The only way to do this cleanly is to use a separate context to validate each constraint (and you can stop iterating over constraint as soon as one of the is reported as valid). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for all the feedback (so quick too!) I will get on this tonight. As a side note, do you happen to know of a way to create a separate context without having to inject the required translator and validator services through my own validator/constraint? |
||
return; | ||
} | ||
} | ||
|
||
if ($this->context instanceof ExecutionContextInterface) { | ||
$this->context->buildViolation($constraint->message) | ||
->setParameter('{{ value }}', $value) | ||
->setInvalidValue($value) | ||
->addViolation(); | ||
} else { | ||
// 2.4 API | ||
$this->context->addViolation( | ||
$constraint->message, | ||
array('{{ value }}' => $value), | ||
$value | ||
); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Validator\Tests\Constraints; | ||
|
||
use Symfony\Component\Validator\Constraints\All; | ||
use Symfony\Component\Validator\Constraints\Any; | ||
use Symfony\Component\Validator\Constraints\Valid; | ||
|
||
/** | ||
* @author Cas Leentfaar <info@casleentfaar.com> | ||
*/ | ||
class AnyTest extends \PHPUnit_Framework_TestCase | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you should use the AbstractConstraintValidatorTest to provide a test against each API version There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, will get it fixed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, my comment is for AnyValidatorTest |
||
{ | ||
/** | ||
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException | ||
*/ | ||
public function testRejectNonConstraints() | ||
{ | ||
new All(array( | ||
'foo', | ||
)); | ||
} | ||
|
||
/** | ||
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException | ||
*/ | ||
public function testRejectValidConstraint() | ||
{ | ||
new Any(array( | ||
new Valid(), | ||
)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Validator\Tests\Constraints; | ||
|
||
use Symfony\Component\Validator\Constraints\Any; | ||
use Symfony\Component\Validator\Constraints\AnyValidator; | ||
use Symfony\Component\Validator\Constraints\NotNull; | ||
use Symfony\Component\Validator\Constraints\Range; | ||
use Symfony\Component\Validator\Validation; | ||
|
||
class AnyValidatorTest extends AbstractConstraintValidatorTest | ||
{ | ||
protected function getApiVersion() | ||
{ | ||
return Validation::API_VERSION_2_5; | ||
} | ||
|
||
protected function createValidator() | ||
{ | ||
return new AnyValidator(); | ||
} | ||
|
||
public function testNullIsValid() | ||
{ | ||
$this->validator->validate(null, new Any(new Range(array('min' => 4)))); | ||
|
||
$this->assertNoViolation(); | ||
} | ||
|
||
public function testWalkSingleConstraint() | ||
{ | ||
$value = 5; | ||
$constraint = new Range(array('min' => 4)); | ||
|
||
$this->validator->validate($value, new Any($constraint)); | ||
|
||
$this->assertNoViolation(); | ||
} | ||
|
||
public function testWalkMultipleConstraints() | ||
{ | ||
$value = 1; | ||
$constraint1 = new Range(array('min' => 4)); | ||
$constraint2 = new NotNull(); | ||
$constraints = array($constraint1, $constraint2); | ||
|
||
$this->validator->validate($value, new Any($constraints)); | ||
|
||
$this->assertNoViolation(); | ||
} | ||
|
||
public function testNoConstraintValidated() | ||
{ | ||
$value = 1; | ||
$constraint1 = new Range(array('min' => 4)); | ||
$constraint2 = new NotNull(); | ||
$constraints = array($constraint1, $constraint2); | ||
$any = new Any($constraints); | ||
|
||
$this->validator->validate($value, $any); | ||
|
||
$this->assertViolation($any->message); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We never put such checks in Symfony
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you clarify this? I just checked some validators and they all do this in their validate()-method, am I missing something here?
E.g., the
CountryValidator
:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, I forgot we added it in March