transmuter-1.0.0-alpha2/src/ThemeRegistryBuilder.php

src/ThemeRegistryBuilder.php
<?php

namespace Drupal\transmuter;

use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\transmuter\Plugin\TransmuterManagerInterface;

/**
 * The default implementation of the theme registry helper.
 */
class ThemeRegistryBuilder implements ThemeRegistryBuilderInterface {

  /**
   * Create a new instance of the ThemeRegistryHelper class.
   *
   * @param \Drupal\transmuter\Plugin\TransmuterManagerInterface $transmuterManager
   *   The element transmuter plugin manager.
   * @param \Drupal\Core\Theme\ThemeManagerInterface $themeManager
   *   The theme manager.
   */
  public function __construct(
    protected TransmuterManagerInterface $transmuterManager,
    protected ThemeManagerInterface $themeManager,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function alterRegistry(array &$themeRegistry): void {
    /** @var \Drupal\Core\Theme\ActiveTheme $activeTheme */
    $activeTheme = $this->themeManager->getActiveTheme();
    $themeName = $activeTheme->getName();
    $themes = array_keys($activeTheme->getBaseThemeExtensions());
    $themes[] = $themeName;

    // Create a pattern that inserts the module provided transmuters before
    // any theme hook, or before a preprocess hook that is more specific.
    $modulePattern = '/^(?:' . implode('|', $themes) . ')_preprocess_{{HOOK}}|_preprocess_{{HOOK}}__\w/';

    // Apply module defined transmuter plugins separately and before theme
    // any defined plugins to ensure that plugin defined hooks are added before
    // the theme hooks, so theme implementations can inherit these base hooks.
    // @see self::addMissingThemeHooks()
    $moduleDefs = $this->transmuterManager->getModuleDefinitions();
    $this->doAlter($themeRegistry, $moduleDefs, $modulePattern);

    // Apply plugins defined by the currently active theme.
    $themeDefs = $this->transmuterManager->getDefinitionsByTheme($themeName);
    $this->doAlter($themeRegistry, $themeDefs, '/_preprocess_{{HOOK}}__\w/');
  }

  /**
   * Sort plugin definitions by the theme hook they implement.
   *
   * Returns the transmuter plugin IDs sorted by the theme hook preprocess
   * plugin applies to.
   *
   * @param \Drupal\transmuter\Plugin\TransmuterDefinition[] $definitions
   *   The transmuter definitions to sort. Typically these are either
   *   definitions from modules OR the active theme.
   *
   * @return string[][]
   *   Preprocess plugin IDs sorted by the theme hook them belong to.
   */
  protected function sortDefinitionsByHook(array $definitions): array {
    $sorted = [];
    foreach ($definitions as $id => $def) {
      foreach ($def->getHooks() as $hook) {
        $sorted[$hook][$id] = $id;
      }
    }

    return $sorted;
  }

  /**
   * Add transmuter plugin from $definitions to the theme registry.
   *
   * @param array $themeRegistry
   *   Reference to the theme registry. This will be altered to include the
   *   calls to the element transmuter plugins.
   * @param \Drupal\transmuter\Plugin\TransmuterDefinition[] $definitions
   *   Transmuter plugin definitions to insert into the $themeRegistry.
   * @param string $pattern
   *   Regular expression to use when finding the place to insert theme
   *   transmuters. Use the placeholder "{{HOOK}}" to be replaced with the
   *   current hook being placed. When a matching function name is found, the
   *   transmuter will be placed before the matching preprocess function.
   */
  protected function doAlter(array &$themeRegistry, array $definitions, $pattern): void {
    // Get the module defined preprocess plugins, and sorted by their hooks.
    $byHook = $this->sortDefinitionsByHook($definitions);

    // Create a pattern that inserts the module provided tranmuters before
    // any theme hook, or before a preprocess hook that is more specific.
    foreach ($themeRegistry as $hook => &$info) {
      $this->addHookTransmuters($byHook, $hook, $info, $pattern);
    }

    // Add any hooks that are not already in the theme registry.
    // This happens when theme hook is a hook suggestion only defined by a
    // transmuter plugin. If a template or a hook_preprocess_HOOK() is defined
    // the theme hook will already be defined.
    foreach (array_diff_key($byHook, $themeRegistry) as $hook => $pluginIds) {
      foreach ($pluginIds as $pluginId) {
        $baseHook = $definitions[$pluginId]->getBaseHook();

        if ($baseHook && isset($themeRegistry[$baseHook])) {
          $themeRegistry[$hook] = $themeRegistry[$baseHook];
          $themeRegistry[$hook]['base hook'] = $baseHook;
          $themeRegistry[$hook]['preprocess functions'][] = new Transmuter($hook, $pluginIds);
          continue(2);
        }
      }

      // Using ungreedy search, we peel back the last theme pattern separator.
      $prefixes = explode('__', $hook);
      array_pop($prefixes);

      // We are looking for the longest prefix matching hook or closest
      // theme hook to base our new hook from. If we can't find a base hook
      // definition, the hook can't be added, but any valid theme definition
      // should at least have a theme function or template file and be defined.
      while ($prefixes) {
        $prefix = implode('__', $prefixes);
        if (!empty($themeRegistry[$prefix])) {
          $themeRegistry[$hook] = $themeRegistry[$prefix];
          $themeRegistry[$hook]['base hook'] = $prefix;
          $themeRegistry[$hook]['preprocess functions'][] = new Transmuter($hook, $pluginIds);
          break;
        }

        array_pop($prefixes);
      }
    }
  }

  /**
   * Inserts the transmuter based on the priority of the theme hook.
   *
   * This method adds the $transmuter into $tranmuters before the first
   * match of $insertPattern. This method also advances the internal pointer
   * of $existing the preprocess callback array, while searching for the place
   * to add the transmuter.
   *
   * @param \Drupal\transmuter\Transmuter $transmuter
   *   The transmuter instance to insert.
   * @param array $transmuters
   *   Current list of transmuters to insert the transmuter into.
   * @param array $existing
   *   Reference to an array with the existing theme preprocessor callbacks.
   *   The internal pointer of this array is advanced to position of the
   *   inserted transmuter.
   * @param string $insertPattern
   *   Regular expression to use when finding the place to insert theme
   *   preprocessors. Use the placeholder "{{HOOK}}" to be replaced with the
   *   current hook being placed. When a matching function name is found, the
   *   transmuter will be placed before the matching preprocess function.
   *
   * @see static::addHookTransmuters()
   */
  private function insertTransmuter(Transmuter $transmuter, array &$transmuters, array &$existing, $insertPattern): void {
    $pattern = str_replace('{{HOOK}}', preg_quote($transmuter->getHook()), $insertPattern);

    while ($callback = current($existing)) {
      // If matching the insert pattern, then place the transmuter here,
      // but _DO NOT_ advance the existing function position. The next
      // transmuter may still need to be placed before the next function.
      if (preg_match($pattern, $callback)) {
        $transmuters[] = $transmuter;
        return;
      }

      $transmuters[] = $callback;
      next($existing);
    }

    // Reached end of list, just add the rest to the end of list.
    $transmuters[] = $transmuter;
  }

  /**
   * Build a Transmuter item for the theme hooks.
   *
   * @param string[][] $definitions
   *   Transmuter plugin definitions to attempt to apply to the theme registry.
   * @param string $hook
   *   The theme hook name.
   * @param array $info
   *   Theme definition information from the theme registry.
   * @param string $insertPattern
   *   Regular expression to use when finding the place to insert theme
   *   transmuters. Use the placeholder "{{HOOK}}" to be replaced with the
   *   current hook being placed. When a matching function name is found, the
   *   transmuter will be placed before the matching preprocess function.
   */
  protected function addHookTransmuters(array $definitions, $hook, array &$info, $insertPattern): void {
    $transmuters = [];
    $prefixes = explode('__', $hook);
    $targetHook = reset($prefixes);
    $existing = $info['preprocess functions'] ?? [];
    reset($existing);

    // Apply any transmuter plugins defined for the base hook.
    // If not already the base hook, a base hook should be inserted before
    // any of the other hook implementations.
    $baseHook = $info['base hook'] ?? NULL;
    if ($baseHook && $baseHook !== $targetHook && !empty($definitions[$baseHook])) {
      $transmuter = new Transmuter($baseHook, $definitions[$baseHook]);
      $this->insertTransmuter($transmuter, $transmuters, $existing, $insertPattern);
    }

    do {
      if (!empty($definitions[$targetHook])) {
        $transmuter = new Transmuter($targetHook, $definitions[$targetHook]);
        $this->insertTransmuter($transmuter, $transmuters, $existing, $insertPattern);
      }

      $prefix = next($prefixes);
      $targetHook .= '__' . $prefix;
    } while ($prefix);

    // If tranmuters were added, put the remaining $existing callbacks
    // to the end of the preprocess list, and set the new set of
    // $transmuterss as the "preprocess functions" of this theme hook.
    if (!empty($transmuters)) {
      while ($callback = current($existing)) {
        $transmuters[] = $callback;
        next($existing);
      }

      $info['preprocess functions'] = $transmuters;
    }
  }

}

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

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