You are here

class RouteHelper in Theme Compiler 2.0.x

Same name and namespace in other branches
  1. 8 src/Routing/RouteHelper.php \Drupal\theme_compiler\Routing\RouteHelper

Builds the route(s) that facilitate compilation of theme-provided assets.

Copyright (C) 2021 Library Solutions, LLC (et al.).

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

@internal

Hierarchy

Expanded class hierarchy of RouteHelper

1 string reference to 'RouteHelper'
theme_compiler.services.yml in ./theme_compiler.services.yml
theme_compiler.services.yml
1 service uses RouteHelper
theme_compiler.route_helper in ./theme_compiler.services.yml
\Drupal\theme_compiler\Routing\RouteHelper

File

src/Routing/RouteHelper.php, line 26

Namespace

Drupal\theme_compiler\Routing
View source
class RouteHelper {
  const COMPILER_CONTROLLER = 'theme_compiler.controller:serve';

  /**
   * A YAML discovery instance to find 'theme_compiler' configuration.
   *
   * @var \Drupal\Core\Plugin\Discovery\YamlDiscovery
   */
  protected $discovery;

  /**
   * Constructs a RouteHelper object.
   *
   * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
   *   The theme handler service.
   */
  public function __construct(ThemeHandlerInterface $theme_handler) {

    // Create a new YAML discovery plugin for 'theme_compiler' configuration.
    $this->discovery = new YamlDiscovery('theme_compiler', $theme_handler
      ->getThemeDirectories());
  }

  /**
   * Construct a compiler context from a theme, compiler, path, & config.
   *
   * The resulting compiler context will be serialized and stored as a default
   * route parameter value. Theme-relative file paths will be resolved before
   * being stored.
   *
   * @param string $theme
   *   The machine name of the theme containing the context.
   * @param string $compiler
   *   The machine name of the desired compiler plugin to use.
   * @param string $path
   *   A theme-relative path used to build the target route that will be used to
   *   serve the result of the configured compilation.
   * @param array $config
   *   Configuration values for the target route. The following keys are used
   *   directly by this module:
   *
   *   - 'files': an array exclusively containing file path strings (required)
   *   - 'options': an array of options to pass to the compiler
   *   - 'data': miscellaneous user-defined data to pass to the compiler
   *
   *   Keys that do not appear in this list will be ignored.
   *
   * @return \Drupal\compiler\RefineableCompilerContext
   *   A compiler context used to define a compilation.
   */
  protected function getThemeCompilerContext(string $theme, string $compiler, string $path, array $config) : RefineableCompilerContext {
    if (empty($files = $config['files'] ?? []) || !is_array($files) || $files !== array_filter($files, 'is_string')) {
      throw new \InvalidArgumentException('"files" is required to be a non-empty array that exclusively contains strings of file paths');
    }
    if (!is_array($options = $config['options'] ?? [])) {
      throw new \InvalidArgumentException('"options" can either be undefined or an array');
    }

    // Store the theme name and the theme-relative target path as options.
    $options['theme_compiler']['path'] = $path;
    $options['theme_compiler']['theme'] = $theme;

    // Compute the target URI for this context and hash it for an ID.
    $options['theme_compiler']['uri'] = '/' . drupal_get_path('theme', $theme) . '/' . $path;
    $options['theme_compiler']['id'] = hash('sha384', $options['theme_compiler']['uri']);

    // Iterate over each defined theme-relative file path for processing.
    foreach ($files as $index => $file) {
      if (empty($result = realpath(\DRUPAL_ROOT . '/' . drupal_get_path('theme', $theme) . '/' . $file))) {
        throw new \InvalidArgumentException('Unable to resolve theme-relative file path at index ' . var_export($index, TRUE) . ': ' . var_export($file, TRUE));
      }
      $inputs[] = new CompilerInputFile($result);
    }
    $context = new RefineableCompilerContext($compiler, $options, $inputs ?? [], $config['data'] ?? NULL);
    return $context;
  }

  /**
   * Generate a list of routes for a specific compiler's targets.
   *
   * @param string $theme
   *   The machine name of the theme for which routes should be generated.
   * @param string $compiler
   *   The machine name of the compiler for which routes should be generated.
   * @param array $targets
   *   An array of compiler target options keyed by a theme-relative
   *   target path.
   *
   * @return \Generator
   *   A collection of routes for the provided compiler's targets.
   */
  protected function getThemeCompilerRoutes(string $theme, string $compiler, array $targets) : \Generator {

    // Iterate over each target for this compiler for processing.
    foreach ($targets as $path => $config) {

      // Create a compiler context using this target's configuration; then
      // create a route using the compiler context.
      $context = $this
        ->getThemeCompilerContext($theme, $compiler, $path, $config);
      $route = $this
        ->getThemeCompilerTargetRoute($context);

      // Generate a keyed element for this route.
      (yield "theme_compiler.{$context->getOption('theme_compiler')['id']}" => $route);
    }
  }

  /**
   * Generate a route to a specific theme-provided, compiled asset.
   *
   * @param \Drupal\compiler\CompilerContextInterface $context
   *   The source context which defines or configures the compilation.
   *
   * @return \Symfony\Component\Routing\Route
   *   A route to a theme-provided, compiled assets.
   */
  protected function getThemeCompilerTargetRoute(CompilerContextInterface $context) : Route {
    $route = new Route($context
      ->getOption('theme_compiler')['uri'], [
      '_controller' => self::COMPILER_CONTROLLER,
      'theme_compiler_context' => $context,
    ], [
      '_access' => 'TRUE',
    ], [
      '_maintenance_access' => 'TRUE',
    ]);
    return $route;
  }

  /**
   * Generate a list of routes for a specific theme's compiler configuration.
   *
   * @param string $theme
   *   The machine name of the theme for which routes should be generated.
   * @param array $compilers
   *   An associative array of compiler target configurations keyed by the
   *   desired compiler's plugin identifier.
   *
   * @return \Generator
   *   A collection of routes for the provided theme's compiler configuration.
   */
  protected function getThemeRoutes(string $theme, array $compilers) : \Generator {
    foreach ($compilers as $compiler => $targets) {
      foreach ($this
        ->getThemeCompilerRoutes($theme, $compiler, $targets) as $name => $route) {
        (yield $name => $route);
      }
    }
  }

  /**
   * Generate a list of routes for all applicable compiler configurations.
   *
   * @return \Generator
   *   A collection of routes produced by this module.
   *
   * @internal
   */
  public function routes() : \Generator {
    foreach ($this->discovery
      ->findAll() as $theme => $compilers) {
      foreach ($this
        ->getThemeRoutes($theme, $compilers) as $name => $route) {
        (yield $name => $route);
      }
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
RouteHelper::$discovery protected property A YAML discovery instance to find 'theme_compiler' configuration.
RouteHelper::COMPILER_CONTROLLER constant
RouteHelper::getThemeCompilerContext protected function Construct a compiler context from a theme, compiler, path, & config.
RouteHelper::getThemeCompilerRoutes protected function Generate a list of routes for a specific compiler's targets.
RouteHelper::getThemeCompilerTargetRoute protected function Generate a route to a specific theme-provided, compiled asset.
RouteHelper::getThemeRoutes protected function Generate a list of routes for a specific theme's compiler configuration.
RouteHelper::routes public function Generate a list of routes for all applicable compiler configurations.
RouteHelper::__construct public function Constructs a RouteHelper object.