Created
July 11, 2016 14:40
-
-
Save joesexton00/08ffebe4dd667676f19223410201a7b6 to your computer and use it in GitHub Desktop.
Logical Or Validation Constraint
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Constraint to validate any of the constraints added to it. | |
* At least one constraint must pass validation. | |
* | |
* @Annotation | |
* @Target({"PROPERTY", "METHOD", "ANNOTATION"}) | |
*/ | |
class LogicalOr extends Composite | |
{ | |
public $message = 'This value is not valid.'; | |
public $constraints = array(); | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getDefaultOption() | |
{ | |
return 'constraints'; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getRequiredOptions() | |
{ | |
return array('constraints'); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function validatedBy() | |
{ | |
return 'logical_or_validator'; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
protected function getCompositeOption() | |
{ | |
return 'constraints'; | |
} | |
} | |
/** | |
* Validates that at least one of the LogicalOr->constraints validation constraints are met. | |
*/ | |
class LogicalOrValidator extends ConstraintValidator | |
{ | |
/** | |
* Changing the type hint on this property prevents deprecation notices. | |
* | |
* @see https://github.com/symfony/symfony/issues/11049#issuecomment-49328345 | |
* | |
* @var ExecutionContextInterface | |
*/ | |
protected $context; | |
/** | |
* @var ConstraintValidatorFactoryInterface | |
*/ | |
private $constraintValidatorFactory; | |
/** | |
* @param ConstraintValidatorFactoryInterface $constraintValidatorFactory | |
*/ | |
public function __construct(ConstraintValidatorFactoryInterface $constraintValidatorFactory) | |
{ | |
$this->constraintValidatorFactory = $constraintValidatorFactory; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function validate($value, Constraint $constraint) | |
{ | |
if (!$constraint instanceof LogicalOr) { | |
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Any'); | |
} | |
if (null === $value || '' === $value) { | |
return; | |
} | |
if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) { | |
throw new UnexpectedTypeException($value, 'string'); | |
} | |
$isValid = false; | |
$constraintViolations = $this->context->getViolations(); | |
foreach ($constraint->constraints as $childConstraint) { | |
if (!$childConstraint instanceof Constraint) { | |
continue; | |
} | |
$preValidationViolationCount = count($constraintViolations); | |
$validator = $this->constraintValidatorFactory->getInstance($childConstraint); | |
$validator->initialize($this->context); | |
$validator->validate($value, $childConstraint); | |
// If a violation was not added after validation of any constraint then the "Any" constraint is met. | |
if ($preValidationViolationCount === count($constraintViolations)) { | |
$isValid = true; | |
break; | |
} | |
} | |
foreach ($constraintViolations as $key => $violation) { | |
$constraintViolations->remove($key); | |
} | |
if (!$isValid) { | |
$this->context->buildViolation($constraint->message) | |
->setParameter('{{ value }}', $this->formatValue($value)) | |
->addViolation(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment