diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php index c8ff90e..fb1150b 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php @@ -37,6 +37,60 @@ public function validate($value, Constraint $constraint) { $value = $typed_data->get($name)->getValue(); } } - return parent::validate($value, $constraint); + + // Start to validate. The only difference from parent::validate() is + // code checks $value before checks $constraint->choices here. We do this + // to make sure $value is checked firstly. + if (null === $value) { + return; + } + + if (!$constraint->choices && !$constraint->callback) { + throw new ConstraintDefinitionException('Either "choices" or "callback" must be specified on constraint Choice'); + } + + if ($constraint->multiple && !is_array($value)) { + throw new UnexpectedTypeException($value, 'array'); + } + + if ($constraint->callback) { + if (is_callable(array($this->context->getClassName(), $constraint->callback))) { + $choices = call_user_func(array($this->context->getClassName(), $constraint->callback)); + } + elseif (is_callable($constraint->callback)) { + $choices = call_user_func($constraint->callback); + } + else { + throw new ConstraintDefinitionException('The Choice constraint expects a valid callback'); + } + } + else { + $choices = $constraint->choices; + } + + if ($constraint->multiple) { + foreach ($value as $_value) { + if (!in_array($_value, $choices, $constraint->strict)) { + $this->context->addViolation($constraint->multipleMessage, array('{{ value }}' => $_value)); + } + } + + $count = count($value); + + if ($constraint->min !== null && $count < $constraint->min) { + $this->context->addViolation($constraint->minMessage, array('{{ limit }}' => $constraint->min), null, (int) $constraint->min); + + return; + } + + if ($constraint->max !== null && $count > $constraint->max) { + $this->context->addViolation($constraint->maxMessage, array('{{ limit }}' => $constraint->max), null, (int) $constraint->max); + + return; + } + } + elseif (!in_array($value, $choices, $constraint->strict)) { + $this->context->addViolation($constraint->message, array('{{ value }}' => $value)); + } } }