book-2.0.x-dev/src/Plugin/Validation/Constraint/ExistsInConstraintValidator.php

src/Plugin/Validation/Constraint/ExistsInConstraintValidator.php
<?php

declare(strict_types=1);

namespace Drupal\book\Plugin\Validation\Constraint;

use Drupal\Core\Config\Schema\ArrayElement;
use Drupal\Core\TypedData\TypedDataInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

/**
 * Validates the ExistsIn constraint.
 */
class ExistsInConstraintValidator extends ConstraintValidator {

  /**
   * {@inheritdoc}
   */
  public function validate(mixed $value, Constraint $constraint): void {
    if (!$constraint instanceof ExistsInConstraint) {
      throw new UnexpectedTypeException($constraint, ExistsInConstraint::class);
    }

    $this_property = $this->context->getObject();
    assert($this_property instanceof TypedDataInterface);
    $choices_raw = self::find($constraint->selector, $this_property)->getValue();

    $choices = match($constraint->which) {
      'keys' => array_keys($choices_raw),
      'values' => array_values($choices_raw),
    };

    if (!in_array($value, $choices)) {
      $this->context->addViolation($constraint->message, [
        '@value' => $value,
        '@choices' => implode(', ', $choices),
      ]);
    }
  }

  /**
   * Resolves an expression that selects other typed data in the same root.
   *
   * The expression may contain the following special strings:
   * - '%parent', to reference the parent element.
   *
   * There may be nested configuration keys separated by dots or more complex
   * patterns like '%parent.name' which references the 'name' value of the
   * parent element.
   *
   * Example expressions:
   * - 'name.subkey', indicates a nested value of the current element.
   * - '%parent.name', will be replaced by the 'name' value of the parent.
   * - '%parent.%parent.foo', will be replaced by the 'foo' value of the
   *   parent's parent.
   *
   * @param string $expression
   *   Expression to be resolved.
   * @param \Drupal\Core\TypedData\TypedDataInterface $data
   *   Configuration data for the element.
   *
   * @return \Drupal\Core\TypedData\TypedDataInterface
   *   The selected typed data elsewhere in the same config object.
   *
   * @see \Drupal\Core\Config\Schema\TypeResolver::resolveExpression()
   */
  private static function find(string $expression, TypedDataInterface $data): TypedDataInterface {
    $parts = explode('.', $expression);
    // Process each value part, one at a time.
    while ($name = array_shift($parts)) {
      // Either go up a level.
      if ($name === '%parent') {
        if ($data->getRoot() === $data) {
          throw new \LogicException('Cannot get the parent of a config object (a root).');
        }
        $data = $data->getParent();
      }
      // Or go down a level.
      else {
        if (!$data instanceof ArrayElement) {
          throw new \LogicException(sprintf('This is not an array element, so cannot get `%s`.', $name));
        }
        if (!array_key_exists($name, $data->getElements())) {
          throw new \LogicException(sprintf('`%s` does not exist at `%s`.', $name, $data->getPropertyPath()));
        }
        $data = $data->getElements()[$name];
      }
    }
    return $data;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc