You are here

public function AllowedValuesConstraintValidator::validate in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php \Drupal\Core\Validation\Plugin\Validation\Constraint\AllowedValuesConstraintValidator::validate()

File

core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraintValidator.php, line 50

Class

AllowedValuesConstraintValidator
Validates the AllowedValues constraint.

Namespace

Drupal\Core\Validation\Plugin\Validation\Constraint

Code

public function validate($value, Constraint $constraint) {
  $typed_data = $this
    ->getTypedData();
  if ($typed_data instanceof OptionsProviderInterface) {
    $allowed_values = $typed_data
      ->getSettableValues($this->currentUser);
    $constraint->choices = $allowed_values;

    // If the data is complex, we have to validate its main property.
    if ($typed_data instanceof ComplexDataInterface) {
      $name = $typed_data
        ->getDataDefinition()
        ->getMainPropertyName();
      if (!isset($name)) {
        throw new \LogicException('Cannot validate allowed values for complex data without a main property.');
      }
      $typed_data = $typed_data
        ->get($name);
      $value = $typed_data
        ->getValue();
    }
  }

  // The parent implementation ignores values that are not set, but makes
  // sure some choices are available firstly. However, we want to support
  // empty choices for undefined values; for instance, if a term reference
  // field points to an empty vocabulary.
  if (!isset($value)) {
    return;
  }

  // Get the value with the proper datatype in order to make strict
  // comparisons using in_array().
  if (!$typed_data instanceof PrimitiveInterface) {
    throw new \LogicException('The data type must be a PrimitiveInterface at this point.');
  }
  $value = $typed_data
    ->getCastedValue();

  // In a better world where typed data just returns typed values, we could
  // set a constraint callback to use the OptionsProviderInterface.
  // This is not possible right now though because we do the typecasting
  // further down.
  if ($constraint->callback) {
    if (!\is_callable($choices = [
      $this->context
        ->getObject(),
      $constraint->callback,
    ]) && !\is_callable($choices = [
      $this->context
        ->getClassName(),
      $constraint->callback,
    ]) && !\is_callable($choices = $constraint->callback)) {
      throw new ConstraintDefinitionException('The AllowedValuesConstraint constraint expects a valid callback');
    }
    $allowed_values = \call_user_func($choices);
    $constraint->choices = $allowed_values;

    // parent::validate() does not need to invoke the callback again.
    $constraint->callback = NULL;
  }

  // Force the choices to be the same type as the value.
  $type = gettype($value);
  foreach ($constraint->choices as &$choice) {
    settype($choice, $type);
  }
  parent::validate($value, $constraint);
}