function ComponentValidator::validateDefinition

Same name in this branch
  1. 10 core/lib/Drupal/Core/Theme/Component/ComponentValidator.php \Drupal\Core\Theme\Component\ComponentValidator::validateDefinition()
Same name in other branches
  1. 11.x core/modules/sdc/src/Component/ComponentValidator.php \Drupal\sdc\Component\ComponentValidator::validateDefinition()
  2. 11.x core/lib/Drupal/Core/Theme/Component/ComponentValidator.php \Drupal\Core\Theme\Component\ComponentValidator::validateDefinition()

Validates the component metadata file.

A valid component metadata file can be validated against the metadata-author.schema.json, plus the ability of classes and interfaces in the `type` property.

Parameters

array $definition: The definition to validate.

bool $enforce_schemas: TRUE if schema definitions are mandatory.

Return value

bool TRUE if the component is valid.

Throws

\Drupal\sdc\Exception\InvalidComponentException

File

core/modules/sdc/src/Component/ComponentValidator.php, line 57

Class

ComponentValidator
Validates a component based on its definition and the component schema.

Namespace

Drupal\sdc\Component

Code

public function validateDefinition(array $definition, bool $enforce_schemas) : bool {
    // First ensure there are no name collisions between props and slots.
    $prop_names = array_keys($definition['props']['properties'] ?? []);
    $slot_names = array_keys($definition['slots'] ?? []);
    $collisions = array_intersect($prop_names, $slot_names);
    if ($collisions) {
        $message = sprintf('The component "%s" declared [%s] both as a prop and as a slot. Make sure to use different names.', $definition['id'], implode(', ', $collisions));
        throw new InvalidComponentException($message);
    }
    // If the validator isn't set, then the validation library is not installed.
    if (!$this->validator) {
        return TRUE;
    }
    // Detect the props with a type class, and validate that the class exists.
    $schema = $definition['props'] ?? NULL;
    if (!$schema) {
        if ($enforce_schemas) {
            throw new InvalidComponentException(sprintf('The component "%s" does not provide schema information. Schema definitions are mandatory for components declared in modules. For components declared in themes, schema definitions are only mandatory if the "enforce_prop_schemas" key is set to "true" in the theme info file.', $definition['id']));
        }
        return TRUE;
    }
    // If there are no props, force casting to object instead of array.
    if (($schema['properties'] ?? NULL) === []) {
        $schema['properties'] = new \stdClass();
    }
    $classes_per_prop = $this->getClassProps($schema);
    $missing_class_errors = [];
    foreach ($classes_per_prop as $prop_name => $class_types) {
        // For each possible type, check if it is a class.
        $missing_classes = array_filter($class_types, static fn(string $class) => !class_exists($class) && !interface_exists($class));
        $missing_class_errors = [
            $missing_class_errors,
            array_map(static fn(string $class) => sprintf('Unable to find class/interface "%s" specified in the prop "%s" for the component "%s".', $class, $prop_name, $definition['id']), $missing_classes),
        ];
    }
    // Remove the non JSON Schema types for validation down below.
    $definition['props'] = $this->nullifyClassPropsSchema($schema, $classes_per_prop);
    $definition_object = Validator::arrayToObjectRecursive($definition);
    $this->validator
        ->validate($definition_object, (object) [
        '$ref' => 'file://' . dirname(__DIR__) . '/metadata-full.schema.json',
    ]);
    if (empty($missing_class_errors) && $this->validator
        ->isValid()) {
        return TRUE;
    }
    $message_parts = array_map(static fn(array $error): string => sprintf("[%s] %s", $error['property'], $error['message']), $this->validator
        ->getErrors());
    $message_parts = [
        $message_parts,
        $missing_class_errors,
    ];
    $message = implode("/n", $message_parts);
    // Throw the exception with the error message.
    throw new InvalidComponentException($message);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.