You are here

ContentRoute.php in Drupal 7 to 8/9 Module Upgrader 8

File

src/Plugin/DMU/Routing/ContentRoute.php
View source
<?php

namespace Drupal\drupalmoduleupgrader\Plugin\DMU\Routing;

use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\drupalmoduleupgrader\ConverterBase;
use Drupal\drupalmoduleupgrader\Routing\Drupal7\RouteWrapper as Drupal7Route;
use Drupal\drupalmoduleupgrader\Routing\Drupal8\RouteWrapper as Drupal8Route;
use Drupal\drupalmoduleupgrader\Routing\ParameterMap;
use Drupal\drupalmoduleupgrader\Routing\RouteConverterInterface;
use Drupal\drupalmoduleupgrader\TargetInterface;
use Drupal\drupalmoduleupgrader\Utility\StringTransformTrait;
use Pharborist\ControlStructures\ReturnStatementNode;
use Pharborist\Filter;
use Pharborist\Functions\ParameterNode;
use Pharborist\Objects\ClassMethodCallNode;
use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Route as CoreRoute;

/**
 * @Converter(
 *  id = "default",
 *  description = @Translation("Converts a menu item to a _controller route."),
 *  dependencies = { "router.route_provider", "plugin.manager.drupalmoduleupgrader.rewriter" }
 * )
 */
class ContentRoute extends ConverterBase implements RouteConverterInterface, ContainerFactoryPluginInterface {
  use StringTransformTrait;

  /**
   * @var \Drupal\Core\Routing\RouteProviderInterface
   */
  protected $routeProvider;

  /**
   * @var \Drupal\Component\Plugin\PluginManagerInterface
   */
  protected $rewriters;

  /**
   * Constructs a RouteConverterBase object.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, TranslationInterface $translator, LoggerInterface $log, RouteProviderInterface $route_provider, PluginManagerInterface $rewriters) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $translator, $log);
    $this->routeProvider = $route_provider;
    $this->rewriters = $rewriters;
  }

  /**
   * Conform with ConverterInterface, which we implement through ConverterBase.
   * Because route conversion is so complex, the Routing plugin never calls
   * this method. It relies instead on the other methods defined in
   * RouteConverterInterface.
   */
  public final function convert(TargetInterface $target) {
  }

  /**
   * {@inheritdoc}
   */
  public function getName(TargetInterface $target, Drupal7Route $route) {
    $name = $target
      ->id() . '.' . $this
      ->unPrefix($route['page callback'], $target
      ->id());
    $arguments = array_filter($route['page arguments'], 'is_string');
    if ($arguments) {
      $name .= '_' . implode('_', $arguments);
    }
    return $name;
  }

  /**
   * {@inheritdoc}
   */
  public function buildPath(TargetInterface $target, Drupal7Route $route) {

    // The parameter map modifies the path in-place, so we'll clone it in order
    // to keep this method non-destructive.
    $path = clone $route
      ->getPath();
    $this
      ->buildParameterMap($target, $route)
      ->applyPath($path);
    return $path;
  }

  /**
   * Builds a parameter map from the aggregated arguments of the title,
   * access, and page callbacks.
   *
   * @return \Drupal\drupalmoduleupgrader\Routing\ParameterMap
   */
  protected function buildParameterMap(TargetInterface $target, Drupal7Route $route) {
    $map = new ParameterMap(clone $route
      ->getPath(), []);
    $indexer = $target
      ->getIndexer('function');
    if ($indexer
      ->has($route['title callback'])) {
      $map
        ->merge(new ParameterMap($route
        ->getPath(), $indexer
        ->get($route['title callback'])
        ->getParameters()
        ->toArray(), $route['title arguments']));
    }
    if ($indexer
      ->has($route['access callback'])) {
      $map
        ->merge(new ParameterMap($route
        ->getPath(), $indexer
        ->get($route['access callback'])
        ->getParameters()
        ->toArray(), $route['access arguments']));
    }
    if ($indexer
      ->has($route['page callback'])) {
      $map
        ->merge(new ParameterMap($route
        ->getPath(), $indexer
        ->get($route['page callback'])
        ->getParameters()
        ->toArray(), $route['page arguments']));
    }
    return $map;
  }

  /**
   * {@inheritdoc}
   */
  public function buildRouteDefinition(TargetInterface $target, Drupal7Route $route) {
    $indexer = $target
      ->getIndexer('function');
    $definition = new CoreRoute('');
    $this
      ->buildParameterMap($target, $route)
      ->applyRoute($definition);
    $controller = $this
      ->getController($target, $route)
      ->getName()
      ->getAbsolutePath();
    if ($route
      ->containsKey('title')) {
      $definition
        ->setDefault('_title', $route['title']);
    }
    elseif ($indexer
      ->has($route['title callback'])) {
      $definition
        ->setDefault('_title_callback', $controller . '::' . $route['title callback']);
    }
    if ($route
      ->isAbsoluteAccess()) {
      $definition
        ->setRequirement('_access', $route['access callback'] ? 'true' : 'false');
    }
    elseif ($route
      ->isPermissionBased()) {
      $definition
        ->setRequirement('_permission', $route['access arguments'][0]);
    }
    elseif ($indexer
      ->has($route['access callback'])) {
      $definition
        ->setRequirement('_custom_access', $controller . '::' . $route['access callback']);
    }
    if ($indexer
      ->has($route['page callback'])) {
      $definition
        ->setDefault('_controller', $controller . '::' . $route['page callback']);
    }
    return new Drupal8Route($this
      ->getName($target, $route), $definition, $this->routeProvider);
  }

  /**
   * {@inheritdoc}
   */
  public function buildRoute(TargetInterface $target, Drupal7Route $route) {
    $definition = $this
      ->buildRouteDefinition($target, $route);
    $map = $this
      ->buildParameterMap($target, $route);
    $map
      ->applyRoute($definition
      ->unwrap());
    $indexer = $target
      ->getIndexer('function');
    foreach ($map
      ->toArray() as $function_name => $parameters) {
      if ($parameters && $indexer
        ->has($function_name)) {

        /** @var \Pharborist\Functions\FunctionDeclarationNode $function */
        $function = $indexer
          ->get($function_name);
        foreach ($parameters as $parameter_name => $info) {
          $parameter = $function
            ->getParameterByName($parameter_name)
            ->setName($info['name'], TRUE);
          if (isset($info['type'])) {
            $plugin_id = '_rewriter:' . $info['type'];
            if ($this->rewriters
              ->hasDefinition($plugin_id)) {
              $this->rewriters
                ->createInstance($plugin_id)
                ->rewrite($parameter);
            }
          }
        }
      }
    }
    $class_indexer = $target
      ->getIndexer('class');
    if ($class_indexer
      ->has('DefaultController')) {
      $controller = $class_indexer
        ->get('DefaultController');
    }
    else {
      $controller = $this
        ->getController($target, $route);
      $class_indexer
        ->addFile($this
        ->writeClass($target, $controller));
    }
    if ($indexer
      ->has($route['title callback'])) {
      if (!$controller
        ->hasMethod($route['title callback'])) {
        $indexer
          ->get($route['title callback'])
          ->cloneAsMethodOf($controller);
      }
    }
    if ($indexer
      ->has($route['access callback'])) {
      $func = $indexer
        ->get($route['access callback']);
      $returns = $func
        ->find(Filter::isInstanceOf('\\Pharborist\\ReturnStatementNode'));
      foreach ($returns as $ret) {
        $call = ClassMethodCallNode::create('\\Drupal\\Core\\Access\\AccessResult', 'allowedIf')
          ->appendArgument($ret
          ->getExpression());
        $ret
          ->replaceWith(ReturnStatementNode::create($call));
      }

      // The access callback always receives an $account parameter.
      if ($func
        ->hasParameter('account')) {
        $func
          ->getParameter('account')
          ->setTypeHint('Drupal\\Core\\Session\\AccountInterface');
      }
      else {
        $account = ParameterNode::create('account')
          ->setTypeHint('Drupal\\Core\\Session\\AccountInterface');
        $func
          ->appendParameter($account);
      }
      if (!$controller
        ->hasMethod($route['access callback'])) {
        $func
          ->cloneAsMethodOf($controller);
      }
    }
    if ($indexer
      ->has($route['page callback'])) {
      if (!$controller
        ->hasMethod($route['page callback'])) {
        $indexer
          ->get($route['page callback'])
          ->cloneAsMethodOf($controller);
      }
    }
    $this
      ->writeClass($target, $controller);
  }
  protected function getController(TargetInterface $target, Drupal7Route $route) {
    $render = [
      '#theme' => 'dmu_controller',
      '#module' => $target
        ->id(),
    ];
    return $this
      ->parse($render);
  }

}

Classes

Namesort descending Description
ContentRoute Plugin annotation @Converter( id = "default", description = @Translation("Converts a menu item to a _controller route."), dependencies = { "router.route_provider", "plugin.manager.drupalmoduleupgrader.rewriter" } )