Verified Commit 774f29f6 authored by Dave Long's avatar Dave Long
Browse files

task: #3535734 Make block.settings.inline_block:* fully validatable

By: larowlan
By: heddn
By: penyaskito
By: smustgrave
By: bbrala
By: godotislate
(cherry picked from commit 1de50d63)
parent 1f5b3ee8
Loading
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -172,12 +172,20 @@ protected function validateNode(TypedDataInterface $data, $constraints = NULL, $
      $this->validateConstraints($value, $cache_key, $constraints);
    }

    // If the data is a list or complex data, validate the contained list items
    // or properties. However, do not recurse if the data is empty.
    if (
      // If the call is the root call or there are no constraints are given, we
      // recurse. These are calls that should go into the values and find the
      // relevant constraints per value.
      ($is_root_call === TRUE || $constraints_given === FALSE) &&

      // If the data is a list or complex data, validate the contained list
      // items or properties. However, do not recurse if the data is empty.
      ($data instanceof ListInterface || $data instanceof ComplexDataInterface) && !$data->isEmpty() &&

      // Next, we do not recurse if given constraints are validated against an
      // entity, since we should determine whether the entity matches the
      // constraints and not whether the entity validates.
    if (($data instanceof ListInterface || $data instanceof ComplexDataInterface) && !$data->isEmpty() && !($data instanceof EntityAdapter && $constraints_given)) {
      !($data instanceof EntityAdapter && $constraints_given)) {
      foreach ($data as $property) {
        $this->validateNode($property);
      }
+4 −0
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@ public function createInstance($plugin_id, array $configuration = []) {
    if (is_subclass_of($plugin_class, CompositeConstraintInterface::class)) {
      $composite_constraint_options = (array) $plugin_class::getCompositeOptionStatic();
      foreach ($composite_constraint_options as $option) {
        // Skip if no constraints are set in the configuration.
        if (!isset($configuration[$option])) {
          continue;
        }
        foreach ($configuration[$option] as $key => $value) {
          foreach ($value as $nested_constraint_id => $nested_constraint_configuration) {
            $configuration[$option][$key] = $this->createInstance($nested_constraint_id, $nested_constraint_configuration);
+31 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Validation\Plugin\Validation\Constraint;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Validation\Attribute\Constraint;
use Drupal\Core\Validation\CompositeConstraintInterface;
use Symfony\Component\Validator\Constraints\Collection;

/**
 * Checks that at least one of the given constraints is satisfied.
 *
 * Overrides the Symfony constraint to convert the array of constraint IDs to an
 * array of constraint objects and use them.
 */
#[Constraint(
  id: 'MappingCollection',
  label: new TranslatableMarkup('Validate mapping as a Collection', [], ['context' => 'Validation'])
)]
class MappingCollectionConstraint extends Collection implements CompositeConstraintInterface {

  /**
   * {@inheritdoc}
   */
  public static function getCompositeOptionStatic(): string {
    return 'fields';
  }

}
+38 −0
Original line number Diff line number Diff line
<?php

declare(strict_types = 1);

namespace Drupal\Core\Validation\Plugin\Validation\Constraint;

use Drupal\Core\Config\Schema\Mapping;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Collection;
use Symfony\Component\Validator\Constraints\CollectionValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

/**
 * Validates the MappingCollection constraint.
 */
class MappingCollectionConstraintValidator extends CollectionValidator {

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

    if (NULL === $value) {
      return;
    }

    if (!$this->context->getObject() instanceof Mapping) {
      throw new UnexpectedTypeException($this->context->getObject(), Mapping::class);
    }

    $value = $this->context->getObject()->getIterator();
    parent::validate($value, $constraint);
  }

}
+34 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Validation\Plugin\Validation\Constraint;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Validation\Attribute\Constraint;
use Drupal\Core\Validation\CompositeConstraintInterface;
use Symfony\Component\Validator\Attribute\HasNamedArguments;
use Symfony\Component\Validator\Constraints\Optional;

/**
 * Marks a field as optional in a Collection constraint.
 */
#[Constraint(
  id: 'Optional',
  label: new TranslatableMarkup('Mark a field as optional in a Collection constraint', [], ['context' => 'Validation'])
)]
class OptionalConstraint extends Optional implements CompositeConstraintInterface {

  #[HasNamedArguments]
  public function __construct(...$args) {
    parent::__construct(...$args);
  }

  /**
   * {@inheritdoc}
   */
  public static function getCompositeOptionStatic(): array|string {
    return 'constraints';
  }

}
Loading