component_connector-1.1.0/src/ComponentConnectorManager.php

src/ComponentConnectorManager.php
<?php

namespace Drupal\component_connector;

use Drupal\Component\FileCache\FileCacheFactory;
use Drupal\Component\Utility\NestedArray;
use Drupal\component_connector\Plugin\Layout\ComponentConnectorLayout;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Layout\LayoutDefinition;
use Drupal\Core\Render\Element;
use Drupal\Core\Theme\Registry;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Core\Serialization\Yaml;

/**
 * ComponentConnectorManager service.
 */
class ComponentConnectorManager {

  /**
   * The theme manager.
   *
   * @var \Drupal\Core\Theme\ThemeManagerInterface
   */
  protected $themeManager;

  /**
   * The search theme.registry service.
   *
   * @var \Drupal\Core\Theme\Registry
   */
  protected $themeRegistry;

  /**
   * The file system service.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * The search manager.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The name of the theme from config.
   *
   * @var string|null
   */
  protected $themeName;

  /**
   * The theme manager.
   *
   * @var \Drupal\Core\Extension\ThemeHandlerInterface
   */
  protected $themeHandler;

  /**
   * Constructs a ComponentManager object.
   *
   * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
   *   The theme manager.
   * @param \Drupal\Core\Theme\Registry $theme_registry
   *   The theme.registry service.
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file_system service.
   * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
   *   The theme handler.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config factory service.
   */
  public function __construct(ThemeManagerInterface $theme_manager, Registry $theme_registry, FileSystemInterface $file_system, ThemeHandlerInterface $theme_handler, ConfigFactoryInterface $config_factory) {
    $this->themeRegistry = $theme_registry;
    $this->fileSystem = $file_system;
    $this->themeHandler = $theme_handler;
    $this->configFactory = $config_factory;
    $this->themeName = $config_factory->get('component_connector.settings')
      ->get('theme');
    $this->themeManager = $theme_manager;
  }

  /**
   * Get internal definitions.
   *
   * @return array
   *   Files array.
   */
  private function getDefinitions($type = 'theme') {
    if (!$this->themeName || !$this->themeHandler->themeExists($this->themeName)) {
      return [];
    }
    $mask = '/^.*\.' . $type . '\.yml$/';
    $theme = $this->themeHandler->getTheme($this->themeName);
    $file_cache = FileCacheFactory::get('component_connector:' . $type);
    $files = $this->fileSystem->scanDirectory($theme->getPath(), $mask, ['key' => 'uri']);
    $all = [];
    // Try to load from the file cache first.
    foreach ($file_cache->getMultiple(array_keys($files)) as $file => $data) {
      $all[$file] = $data;
      unset($files[$file]);
    }
    if ($files) {
      foreach ($files as $id => $file) {
        $data = Yaml::decode(file_get_contents($file->uri)) ?: [];
        $all[$id] = $data;
        $file_cache->set($id, $data);
      }
    }
    return $all;
  }

  /**
   * Altering registry.
   */
  public function alterRegistry(array &$theme_registry) {
    $active_theme_name = $this->themeManager->getActiveTheme()->getName();
    if (!$this->themeName || $this->themeName != $active_theme_name) {
      return;
    }
    foreach ($this->getDefinitions() as $id => $definition) {
      $definition = reset($definition);
      // Replace hooks.
      $new_hook_theme = [];
      if (isset($definition['hook theme'])) {
        $path_parts = pathinfo($id);
        $template = str_replace('.theme', '', $path_parts['filename']);
        $new_hook_theme['template'] = $template;
        $new_hook_theme['path'] = $path_parts['dirname'];
        $this->attachLibraries($definition, $new_hook_theme, $path_parts);
        // Check for additional preprocess functions.
        // Legacy to remove. See https://www.drupal.org/project/drupal/issues/2060773 for details.
        if (function_exists($this->themeName . '_preprocess_' . $definition['hook theme'])) {
          $new_hook_theme['preprocess functions'][] = $this->themeName . '_preprocess_' . $definition['hook theme'];
        }
        if (isset($definition['base hook']) && isset($theme_registry[$definition['base hook']])) {
          if ($definition['base hook'] == 'layout') {
            $new_hook_theme['preprocess functions'][] = [
              '\Drupal\component_connector\ComponentConnectorManager',
              'preprocessLayout',
            ];
          }

          $theme_registry[$definition['hook theme']] = NestedArray::mergeDeep($theme_registry[$definition['base hook']], $new_hook_theme);
          $theme_registry[$definition['hook theme']]['base hook'] = $definition['base hook'];
        }
        elseif (isset($theme_registry[$definition['hook theme']])) {
          // Replace hook theme.
          $theme_registry[$definition['hook theme']] = NestedArray::mergeDeep($theme_registry[$definition['hook theme']], $new_hook_theme);
        }
        else {
          // Check and add variables if any.
          if (isset($definition['fields'])) {
            $new_hook_theme['variables'] = array_fill_keys(array_keys($definition['fields']), NULL);
            if (isset($definition['settings'])) {
              $new_hook_theme['variables'] += array_fill_keys(array_keys($definition['settings']), NULL);
            }
          }
          // Register new hook theme.
          $new_hook_theme['type'] = 'theme_engine';
          $theme_registry[$definition['hook theme']] = $new_hook_theme;
        }
        if (isset($theme_registry[$definition['hook theme']]['render element'])) {
          $this->attachVariables($definition, $theme_registry[$definition['hook theme']]);
        }

      }
    }
    foreach ($this->getDefinitions('suggestion') as $id => $definition) {
      // Process template suggestion and map to component html.twig.
      $definition = reset($definition);
      if (isset($definition['base hook']) && !isset($definition['hook theme'])
        && isset($theme_registry[$definition['base hook']])) {
        $path_parts = pathinfo($id);
        $template = str_replace('.suggestion', '', $path_parts['filename']);
        $theme_registry[$definition['base hook']]['template'] = $template;
        $theme_registry[$definition['base hook']]['path'] = $path_parts['dirname'];
        $theme_registry[$definition['base hook']]['type'] = 'theme_engine';
        $this->attachLibraries($definition, $theme_registry[$definition['base hook']], $path_parts);
        $this->attachVariables($definition, $theme_registry[$definition['base hook']]);
        if (isset($theme_registry[$definition['base hook']]['variables'])) {
          // Merge variables if any.
          if (isset($definition['fields'])) {
            $theme_registry[$definition['base hook']]['variables'] += array_fill_keys(array_keys($definition['fields']), NULL);
            if (isset($definition['settings'])) {
              $theme_registry[$definition['base hook']]['variables'] += array_fill_keys(array_keys($definition['settings']), NULL);
            }
          }
        }
      }
    }
  }

  /**
   * Preprocess callback for attaching libraries.
   *
   * @param array $definition
   *   An definitions array.
   * @param array $new_hook_theme
   *   An new hook theme array.
   */
  private function attachLibraries(array $definition, array &$new_hook_theme, $path_parts) {
    $active_theme_name = $this->themeManager->getActiveTheme()->getName();
    $libraries = [];
    if (isset($definition['libraries'])) {
      // Attach libraries.
      foreach ($definition['libraries'] as $library) {
        if (is_array($library)) {
          $libraries[] = $active_theme_name . '/' . key($library);
        }
        else {
          $libraries[] = $library;
        }
      }
    }
    // Check and attach libraries detected automatically.
    $name = str_replace('.theme', '', $path_parts['filename']);
    $asset = $path_parts["dirname"] . '/' . $name;
    if (file_exists($asset . '.css') || file_exists($asset . '.js')) {
      $libraries[] = $active_theme_name . '/' . $name;
    }
    if (!empty($libraries)) {
      $libraries = array_unique($libraries);
      $new_hook_theme['attached']['library'] = $libraries;
      $new_hook_theme['preprocess functions'][] = [
        '\Drupal\component_connector\ComponentConnectorManager',
        'preprocessLibraries',
      ];
    }
  }

  /**
   * Preprocess callback for processing additional variables.
   *
   * @param array $definition
   *   An definitions array.
   * @param array $hook_theme
   *   Hook theme array to modify.
   */
  private function attachVariables(array $definition, array &$hook_theme) {
    if (isset($definition['fields']) || isset($definition['settings'])) {
      // Attach libraries.
      $hook_theme['preprocess functions'][] = [
        '\Drupal\component_connector\ComponentConnectorManager',
        'preprocessVariables',
      ];
    }
  }

  /**
   * Preprocess callback for attaching libraries.
   *
   * @param array $variables
   *   An associative array.
   * @param string $hook
   *   Hook name.
   * @param array $info
   *   Hook info.
   */
  public static function preprocessLibraries(array &$variables, $hook, array $info) {
    if (isset($info['attached'])) {
      if (!empty($variables['#attached'])) {
        $variables['#attached'] = NestedArray::mergeDeep($variables['#attached'], $info['attached']);
      }
      else {
        $variables['#attached'] = $info['attached'];
      }
    }
  }

  /**
   * Preprocess callback for processing additional variables.
   *
   * @param array $variables
   *   An associative array.
   * @param string $hook
   *   Hook name.
   * @param array $info
   *   Hook info.
   */
  public static function preprocessVariables(array &$variables, $hook, array $info) {
    if (isset($info['render element']) && !empty($variables[$info['render element']])) {
      $element = $variables[$info['render element']];
      if (!empty($element['#variables'])) {
        foreach ($element['#variables'] as $name => $variable) {
          $variables[$name] = $variable;
        }
      }
    }
  }

  /**
   * Preprocess callback for attaching libraries.
   *
   * @param array $variables
   *   An associative array.
   * @param string $hook
   *   Hook name.
   * @param array $info
   *   Hook info.
   */
  public static function preprocessLayout(array &$variables, $hook, array $info) {
    if (isset($info["base hook"]) && $info["base hook"] == 'layout' && !empty($variables['content'])) {
      // Move variables level up.
      $content = [];
      foreach (Element::children($variables['content']) as $child) {
        if (!empty(Element::children($variables['content'][$child]))) {
          $content[$child] = $variables['content'][$child];
        }
      }
      if (!empty($variables["content"]["#settings"])) {
        foreach ($variables["content"]["#settings"] as $key => $setting) {
          $content[$key] = $setting;
        }
      }
      unset($variables['content']);
      $variables += $content;
    }
  }

  /**
   * Altering libraries.
   *
   * @return array
   *   Components libraries.
   */
  public function buildLibraries(): array {
    $libraries = [];
    // Process components libraries.
    foreach (array_merge($this->getDefinitions(), $this->getDefinitions('suggestion')) as $id => $definition) {
      $definition = reset($definition);
      $path_parts = pathinfo($id);
      // Find and declare libraries automatically.
      $name = str_replace(['.theme','.suggestion'], '', $path_parts['filename']);
      $asset = $path_parts["dirname"] . '/' . $name;
      $data = [];
      if (file_exists($asset . '.css')) {
        $data['css'] = [
          'component' => [
            '/' . $asset . '.css' => [],
          ],
        ];
      }
      if (file_exists($asset . '.js')) {
        $data['js'] = ['/' . $asset . '.js' => [],];
      }
      if (!empty($data)) {
        $libraries[$name] = $data;
      }
    }
    return $libraries;
  }

  /**
   * Altering layouts.
   *
   * @param \Drupal\Core\Layout\LayoutDefinition[] $definitions
   *   The array of layout definitions, keyed by plugin ID.
   */
  public function alterLayouts(array &$definitions) {
    $this->themeRegistry->initDefault();
    foreach ($this->getDefinitions() as $id => $definition) {
      $pattern_name = key($definition);
      $pattern_definition = $definition[$pattern_name];
      if (isset($pattern_definition['base hook']) && $pattern_definition['base hook'] == 'layout') {
        // Register a layout.
        $definition = [
          'label' => $pattern_definition['label'],
          'category' => 'Layouts',
          'class' => ComponentConnectorLayout::class,
          'path' => pathinfo($id)['dirname'],
          'theme_hook' => $pattern_definition['hook theme'],
          'provider' => 'component_connector',
        ];
        if (isset($pattern_definition['fields'])) {
          foreach ($pattern_definition['fields'] as $key => $field) {
            $definition['regions'][$key]['label'] = $field['label'];
          }
          if (isset($pattern_definition['settings'])) {
            $definition['settings'] = $pattern_definition['settings'];
          }
          if (isset($pattern_definition['icon_map'])) {
            $definition['icon_map'] = $pattern_definition['icon_map'];
          }
        }
        $definitions[$pattern_name] = new LayoutDefinition($definition);;
      }
    }
  }

}

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

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