Commit c6393087 authored by Mateu Aguiló Bosch's avatar Mateu Aguiló Bosch
Browse files

Issue #3295123 by e0ipso: Optimize finding one component

parent fb06a8af
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -4,13 +4,14 @@
  "name": "Card",
  "status": "BETA",
  "componentType": "organism",
  "variants": ["light"],
  "variants": [
    "light"
  ],
  "schemas": {
    "props": {
      "type": "object",
      "required": [
        "header",
        "children"
        "header"
      ],
      "properties": {
        "header": {
+49 −33
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ class ComponentDiscovery {
  private static $directoryIteratorFlags = \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_SELF | \FilesystemIterator::SKIP_DOTS;

  /**
   * Cached component information.
   * Cached component information keyed by component ID.
   *
   * @var \Drupal\cl_components\Component\Component[]|null
   */
@@ -75,14 +75,16 @@ class ComponentDiscovery {
    $components = $this->findAll();
    $filtered = array_filter(
      $components,
      fn(Component $component) => $component->getMetadata()->getComponentType() === ComponentMetadata::COMPONENT_TYPE_ORGANISM
      fn(Component $component) => $component->getMetadata()
          ->getComponentType() === ComponentMetadata::COMPONENT_TYPE_ORGANISM
    );
    if (!$no_wip) {
      return $filtered;
    }
    return array_filter(
      $filtered,
      fn(Component $component) => $component->getMetadata()->getStatus() !== ComponentMetadata::COMPONENT_STATUS_WIP
      fn(Component $component) => $component->getMetadata()
          ->getStatus() !== ComponentMetadata::COMPONENT_STATUS_WIP
    );
  }

@@ -94,47 +96,49 @@ class ComponentDiscovery {
   */
  public function findAll(): array {
    if (isset($this->components)) {
      return $this->components;
      return array_values($this->components);
    }
    $components_by_key = fn(array $data) => array_reduce(
      $data,
      static fn(array $all, Component $c) => [...$all, $c->getId() => $c],
      []
    );
    $cache_ids = $this->cache->get('all-cache-ids');
    if ($cache_ids && is_array($cache_ids->data)) {
      $cache_entries = $this->cache->getMultiple($cache_ids->data);
      $components = array_map(
      // Get the data of the cache properties.
      $cache_data = array_map(
        fn(object $item) => $item->data,
        $cache_entries
      );
      $this->components = array_values($components);
      return $this->components;
    }
    $unflattened = array_map(function (string $path) {
      try {
        $directory_iterator = new \RecursiveDirectoryIterator($path, static::$directoryIteratorFlags);
      }
      catch (\UnexpectedValueException $exception) {
        watchdog_exception('cl_components', $exception);
        return [];
      }
      $components = array_map(
        [$this, 'createComponent'],
        $this->discoverComponentPaths($directory_iterator, [])
      // Ensure cache data deserializes to a Component.
      $cached_components = array_filter(
        $cache_data,
        static fn(mixed $item) => $item instanceof Component
      );
      return array_filter($components);
    }, $this->scanDirs);
      $this->components = $components_by_key($cached_components);
      return array_values($this->components);
    }
    $paths = $this->findAllPaths();
    $this->components = array_filter(array_map([$this, 'createComponent'], $paths));
    $components = array_map([$this, 'createComponent'], $paths);
    $components = array_filter($components);
    $this->components = $components_by_key($components);
    $this->cache->set(
      'all-cache-ids',
      array_map(static fn(Component $component) => 'component::' . $component->getId(), $this->components)
      array_map(
        static fn(Component $component) => 'component::' . $component->getId(),
        $this->components
      )
    );
    $this->cache->setMultiple(array_reduce(
      $this->components,
      $components,
      static fn(array $items, Component $component) => array_merge(
        $items,
        ['component::' . $component->getId() => ['data' => $component]]
      ),
      []
    ));
    return $this->components;
    return array_values($this->components);
  }

  /**
@@ -158,6 +162,7 @@ class ComponentDiscovery {
    }, $this->scanDirs);
    return array_merge(...$unflattened);
  }

  /**
   * Returns all the components in the repository pointed by the iterator.
   *
@@ -297,20 +302,28 @@ class ComponentDiscovery {
   *   When the component cannot be found.
   */
  public function find(string $id): Component {
    // Check if the component is in memory cache.
    if (($this->components[$id] ?? NULL) instanceof Component) {
      return $this->components[$id];
    }
    // Check if the component is in persisted cache.
    $cached = $this->cache->get('component::' . $id);
    if ($cached && $cached->data instanceof Component) {
      return $cached->data;
    }
    // Find all components and search for ours.
    $components = $this->findAll();
    $matches = array_filter(
      $components,
      static function (Component $component) use ($id) {
        return $component->getId() === $id;
      }
      static fn(Component $c) => $c->getId() === $id
    );
    $component = reset($matches);
    if (!$component instanceof Component) {
    if ($component instanceof Component) {
      return $component;
    }
    $message = sprintf('Unable to find component "%s" in the component repository', $id);
    throw new ComponentNotFoundException($message);
  }
    return $component;
  }

  /**
   * Gets the directories to scan for components.
@@ -336,7 +349,10 @@ class ComponentDiscovery {
      return $this->instantiateComponent($path);
    }
    catch (InvalidComponentException $e) {
      watchdog_exception('cl_components', $e, 'Invalid component @path. Error: @error', ['@path' => $path, '@error' => $e->getMessage()]);
      watchdog_exception('cl_components', $e, 'Invalid component @path. Error: @error', [
        '@path' => $path,
        '@error' => $e->getMessage(),
      ]);
      return NULL;
    }
  }
+4 −9
Original line number Diff line number Diff line
@@ -204,15 +204,13 @@ final class ComponentMetadata {
   * @throws \Drupal\cl_components\Exception\InvalidComponentException
   */
  private function parseSchemaInfo(array $metadata_info): void {
    $default_props_schema = [
    $default_schema = [
      'type' => 'object',
      'additionalProperties' => FALSE,
      'required' => [],
      'properties' => [
        'children' => ['type' => 'string'],
      ],
      'properties' => [],
    ];
    $this->schemas = $metadata_info['schemas'] ?? ['props' => $default_props_schema];
    $this->schemas = $metadata_info['schemas'] ?? ['props' => $default_schema];
    if (($this->schemas['props']['type'] ?? 'object') !== 'object') {
      throw new InvalidComponentException('The schema for the props in the component metadata is invalid. The schema should be of type "object".');
    }
@@ -220,12 +218,9 @@ final class ComponentMetadata {
      throw new InvalidComponentException('The schema for the props in the component metadata is invalid. Arbitrary additional properties are not allowed.');
    }
    $this->schemas['props']['additionalProperties'] = FALSE;
    $this->schemas['props']['properties']['children'] = ['type' => 'string'];
    // Save the props.
    $schema_props = $metadata_info['schemas']['props'] ?? $default_props_schema;
    $required_info = $schema_props['required'] ?? [];
    $schema_props = $metadata_info['schemas']['props'] ?? $default_schema;
    foreach ($schema_props['properties'] ?? [] as $name => $schema) {
      $is_required = in_array($name, $required_info);
      // All props should also support "object" this allows deferring rendering
      // in Twig to the render pipeline.
      $type = $schema['type'] ?? '';