You are here

public function InstallableRequirement::validate in Markdown 8.2

Validates the requirement.

Return value

\Symfony\Component\Validator\ConstraintViolationListInterface A list of constraint violations. If the list is empty, validation succeeded.

File

src/Annotation/InstallableRequirement.php, line 210

Class

InstallableRequirement
Markdown Requirement Annotation.

Namespace

Drupal\markdown\Annotation

Code

public function validate() {
  $object = $this
    ->getObject();
  if (isset($this->name)) {
    foreach ($this->constraints as $name => &$constraint) {
      if ($name !== 'Version') {
        continue;
      }
      if (!is_array($constraint)) {
        $constraint = [
          'value' => $constraint,
        ];
      }
      if (!isset($constraint['name'])) {
        $constraint['name'] = $this->name;
      }
    }
  }
  if (!isset($this->value)) {
    if ($this->callback) {
      if ($object) {
        $callback = [
          $object,
          ltrim($this->callback, ':'),
        ];
        $this->value = call_user_func_array($callback, $this->arguments);
      }
      else {
        $this->value = call_user_func_array($this->callback, $this->arguments);
      }
      if (!$this->constraints) {
        $this->constraints = [
          'NotNull' => [],
        ];
      }
    }
    else {
      $this->value = $object ? [
        $this
          ->getId(),
      ] : [];
      if (!$this->constraints) {
        $this->constraints = [
          'Count' => [
            'min' => 1,
            'max' => 1,
          ],
        ];
      }
    }
  }

  // If returned value is typed data, add the conditions to its definition.
  if (($value = $this->value) instanceof TypedDataInterface) {
    $typed = $this->value;
    $definition = $typed
      ->getDataDefinition();
    foreach ($this->constraints as $name => $options) {
      $definition
        ->addConstraint($name, $options);
    }
  }
  elseif (is_array($value) || $value instanceof \Traversable) {

    // Don't use config based types. Bug in earlier versions of core.
    // @see https://www.drupal.org/project/drupal/issues/1928868.
    $valueType = is_scalar(current($value)) ? gettype(current($value)) : 'string';
    $itemDefinition = \Drupal::typedDataManager()
      ->createDataDefinition($valueType);
    $definition = new ListDataDefinition([], $itemDefinition);
    $definition
      ->setConstraints($this->constraints);
    $typed = ItemList::createInstance($definition);
    $typed
      ->setValue($value);
  }
  else {
    $valueType = is_scalar($value) ? gettype($value) : 'string';
    $definition = DataDefinition::create($valueType)
      ->setConstraints($this->constraints);
    switch ($valueType) {
      case 'boolean':
        $typed = BooleanData::createInstance($definition);
        break;
      case 'float':
        $typed = FloatData::createInstance($definition);
        break;
      case 'integer':
        $typed = IntegerData::createInstance($definition);
        break;
      case 'string':
      default:
        $typed = StringData::createInstance($definition);
        $value = (string) $value;
        break;
    }
    $typed
      ->setValue($value);
  }

  // Attempt to validate the requirement constraints.
  try {
    return $typed
      ->validate();
  } catch (PluginNotFoundException $exception) {

    // See if a global was set in markdown_requirements().
    // @todo This is currently only needed because its bundled with the
    //   markdown module; remove when moved to a standalone upstream project
    //   https://www.drupal.org/project/installable_plugins
    global $_markdown_requirements;
    $message = $exception
      ->getMessage();
    $violationList = new ConstraintViolationList();

    // The exception to this exception is when it is attempting to find
    // constraints provided by this module, which may not yet be installed.
    // In this case, the constraints must be validated manually.
    // @see markdown_requirements()
    // @todo This is currently only needed because its bundled with the
    //   markdown module; remove when moved to a standalone upstream project
    //   https://www.drupal.org/project/installable_plugins
    $markdownConstraints = [
      'Installed',
      'Exists',
      'Version',
    ];
    if ($_markdown_requirements === 'install' && preg_match('/(?:Plugin ID |The )\\s*[\'"]([^\'"]+)[\'"]\\s*(?:was not found|plugin does not exist)/i', $message, $matches) && in_array($matches[1], $markdownConstraints)) {
      $pluginId = $matches[1];
      if (($class = '\\Drupal\\markdown\\Plugin\\Validation\\Constraint\\' . $pluginId) && class_exists($class)) {
        $value = $typed
          ->getValue();
        $context = new ExecutionContext($typed
          ->getTypedDataManager()
          ->getValidator(), $value, new DrupalTranslator());
        foreach ($this->constraints as $name => $options) {
          if ($name === $pluginId) {

            /** @var \Symfony\Component\Validator\Constraint $constraint */
            $constraint = new $class($options);
            if (($validatorClass = $constraint
              ->validatedBy()) && class_exists($validatorClass)) {

              /** @var \Symfony\Component\Validator\ConstraintValidatorInterface $constraintValidator */
              $constraintValidator = new $validatorClass();
              $constraintValidator
                ->initialize($context);
              $constraintValidator
                ->validate($value, $constraint);
            }
          }
        }
        $violationList
          ->addAll($context
          ->getViolations());
        return $violationList;
      }
    }

    // Add the exception message to the violations list.
    $violationList
      ->add(new ConstraintViolation($message, '', [], '', '', ''));
    return $violationList;
  }
}