Verified Commit 73fbc455 authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

Issue #3516359 by larowlan, smustgrave, longwave, lauriii, wim leers,...

Issue #3516359 by larowlan, smustgrave, longwave, lauriii, wim leers, mstrelan: ComponentValidator ignores the set validator and creates a new one

(cherry picked from commit 914ecc3f)
(cherry picked from commit a99e6d35)
(cherry picked from commit ae15b7f4)
parent 709e987e
Loading
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ public function validateDefinition(array $definition, bool $enforce_schemas): bo
    );

    $definition_object = Validator::arrayToObjectRecursive($definition);
    $this->validator->reset();
    $this->validator->validate(
      $definition_object,
      (object) ['$ref' => 'file://' . dirname(__DIR__, 5) . '/assets/schemas/v1/metadata-full.schema.json']
@@ -166,15 +167,15 @@ public function validateProps(array $context, Component $component): bool {
    ] = $this->validateClassProps($schema, $props_raw, $component_id);
    $schema = Validator::arrayToObjectRecursive($schema);
    $props = Validator::arrayToObjectRecursive($props_raw);
    $validator = new Validator();
    $validator->validate($props, $schema, Constraint::CHECK_MODE_TYPE_CAST);
    $validator->getErrors();
    if ($validator->isValid()) {
    $this->validator->reset();
    $this->validator->validate($props, $schema, Constraint::CHECK_MODE_TYPE_CAST);
    $this->validator->getErrors();
    if ($this->validator->isValid()) {
      return TRUE;
    }
    // Dismiss type errors if the prop received a render array.
    $errors = array_filter(
      $validator->getErrors(),
      $this->validator->getErrors(),
      function (array $error) use ($context): bool {
        if (($error['constraint'] ?? '') !== 'type') {
          return TRUE;
+55 −0
Original line number Diff line number Diff line
@@ -4,10 +4,15 @@

namespace Drupal\Tests\Core\Theme\Component;

use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Theme\Component\ComponentValidator;
use Drupal\Core\Render\Component\Exception\InvalidComponentException;
use Drupal\Core\Plugin\Component;
use JsonSchema\Constraints\Factory;
use JsonSchema\Constraints\FormatConstraint;
use JsonSchema\Entity\JsonPointer;
use JsonSchema\Validator;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Yaml;

@@ -149,6 +154,33 @@ public static function dataProviderValidatePropsValid(): array {
    ];
  }

  /**
   * Tests we can use a custom validator to validate props.
   */
  public function testCustomValidator(): void {
    $component = new Component(
      ['app_root' => '/fake/path/root'],
      'sdc_test:my-cta',
      static::loadComponentDefinitionFromFs('my-cta'),
    );
    $component_validator = new ComponentValidator();
    // A validator with a constraint factory that uses a custom constraint for
    // checking format.
    $component_validator->setValidator(new Validator((new Factory())->setConstraintClass('format', UrlHelperFormatConstraint::class)));
    self::assertTrue(
      $component_validator->validateProps([
        'text' => 'Can Pica',
        // This is a valid URI but for v5.2 of justinrainbow/json-schema it
        // does not pass validation without a custom constraint for format.
        // We pass a custom factory and it should be used.
        'href' => 'entity:node/1',
        'target' => '_blank',
        'attributes' => new Attribute(['key' => 'value']),
      ], $component),
      'The valid component props threw an error.'
    );
  }

  /**
   * Tests that invalid props are handled properly.
   *
@@ -232,3 +264,26 @@ private static function loadComponentDefinitionFromFs(string $component_name): a
  }

}

/**
 * Defines a custom format constraint for json-schema.
 */
class UrlHelperFormatConstraint extends FormatConstraint {

  /**
   * {@inheritdoc}
   */
  public function check(&$element, $schema = NULL, ?JsonPointer $path = NULL, $i = NULL): void {
    if (!isset($schema->format) || $this->factory->getConfig(self::CHECK_MODE_DISABLE_FORMAT)) {
      return;
    }
    if ($schema->format === 'uri') {
      if (\is_string($element) && !UrlHelper::isValid($element)) {
        $this->addError($path, 'Invalid URL format', 'format', ['format' => $schema->format]);
      }
      return;
    }
    parent::check($element, $schema, $path, $i);
  }

}