ChoiceValidator.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Validator\Constraints;
  11. use Symfony\Component\Validator\Constraint;
  12. use Symfony\Component\Validator\ConstraintValidator;
  13. use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
  14. use Symfony\Component\Validator\Exception\UnexpectedTypeException;
  15. use Symfony\Component\Validator\Exception\UnexpectedValueException;
  16. /**
  17. * ChoiceValidator validates that the value is one of the expected values.
  18. *
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. * @author Florian Eckerstorfer <florian@eckerstorfer.org>
  21. * @author Bernhard Schussek <bschussek@gmail.com>
  22. */
  23. class ChoiceValidator extends ConstraintValidator
  24. {
  25. /**
  26. * {@inheritdoc}
  27. */
  28. public function validate($value, Constraint $constraint)
  29. {
  30. if (!$constraint instanceof Choice) {
  31. throw new UnexpectedTypeException($constraint, Choice::class);
  32. }
  33. if (!\is_array($constraint->choices) && !$constraint->callback) {
  34. throw new ConstraintDefinitionException('Either "choices" or "callback" must be specified on constraint Choice.');
  35. }
  36. if (null === $value) {
  37. return;
  38. }
  39. if ($constraint->multiple && !\is_array($value)) {
  40. throw new UnexpectedValueException($value, 'array');
  41. }
  42. if ($constraint->callback) {
  43. if (!\is_callable($choices = [$this->context->getObject(), $constraint->callback])
  44. && !\is_callable($choices = [$this->context->getClassName(), $constraint->callback])
  45. && !\is_callable($choices = $constraint->callback)
  46. ) {
  47. throw new ConstraintDefinitionException('The Choice constraint expects a valid callback.');
  48. }
  49. $choices = $choices();
  50. } else {
  51. $choices = $constraint->choices;
  52. }
  53. if (true !== $constraint->strict) {
  54. throw new \RuntimeException('The "strict" option of the Choice constraint should not be used.');
  55. }
  56. if ($constraint->multiple) {
  57. foreach ($value as $_value) {
  58. if (!\in_array($_value, $choices, true)) {
  59. $this->context->buildViolation($constraint->multipleMessage)
  60. ->setParameter('{{ value }}', $this->formatValue($_value))
  61. ->setParameter('{{ choices }}', $this->formatValues($choices))
  62. ->setCode(Choice::NO_SUCH_CHOICE_ERROR)
  63. ->setInvalidValue($_value)
  64. ->addViolation();
  65. return;
  66. }
  67. }
  68. $count = \count($value);
  69. if (null !== $constraint->min && $count < $constraint->min) {
  70. $this->context->buildViolation($constraint->minMessage)
  71. ->setParameter('{{ limit }}', $constraint->min)
  72. ->setPlural((int) $constraint->min)
  73. ->setCode(Choice::TOO_FEW_ERROR)
  74. ->addViolation();
  75. return;
  76. }
  77. if (null !== $constraint->max && $count > $constraint->max) {
  78. $this->context->buildViolation($constraint->maxMessage)
  79. ->setParameter('{{ limit }}', $constraint->max)
  80. ->setPlural((int) $constraint->max)
  81. ->setCode(Choice::TOO_MANY_ERROR)
  82. ->addViolation();
  83. return;
  84. }
  85. } elseif (!\in_array($value, $choices, true)) {
  86. $this->context->buildViolation($constraint->message)
  87. ->setParameter('{{ value }}', $this->formatValue($value))
  88. ->setParameter('{{ choices }}', $this->formatValues($choices))
  89. ->setCode(Choice::NO_SUCH_CHOICE_ERROR)
  90. ->addViolation();
  91. }
  92. }
  93. }