3 namespace Drupal\drupalmoduleupgrader\Plugin\DMU\Routing;
5 use Drupal\Component\Plugin\PluginManagerInterface;
6 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
7 use Drupal\Core\Routing\RouteProviderInterface;
8 use Drupal\Core\StringTranslation\TranslationInterface;
9 use Drupal\drupalmoduleupgrader\ConverterBase;
10 use Drupal\drupalmoduleupgrader\Routing\Drupal7\RouteWrapper as Drupal7Route;
11 use Drupal\drupalmoduleupgrader\Routing\Drupal8\RouteWrapper as Drupal8Route;
12 use Drupal\drupalmoduleupgrader\Routing\ParameterMap;
13 use Drupal\drupalmoduleupgrader\Routing\RouteConverterInterface;
14 use Drupal\drupalmoduleupgrader\TargetInterface;
15 use Drupal\drupalmoduleupgrader\Utility\StringTransformTrait;
16 use Pharborist\ControlStructures\ReturnStatementNode;
17 use Pharborist\Filter;
18 use Pharborist\Functions\ParameterNode;
19 use Pharborist\Objects\ClassMethodCallNode;
20 use Psr\Log\LoggerInterface;
21 use Symfony\Component\Routing\Route as CoreRoute;
26 * description = @Translation("Converts a menu item to a _controller route."),
27 * dependencies = { "router.route_provider", "plugin.manager.drupalmoduleupgrader.rewriter" }
30 class ContentRoute extends ConverterBase implements RouteConverterInterface, ContainerFactoryPluginInterface {
32 use StringTransformTrait;
35 * @var RouteProviderInterface
37 protected $routeProvider;
40 * @var PluginManagerInterface
45 * Constructs a RouteConverterBase object.
47 public function __construct(array $configuration, $plugin_id, $plugin_definition, TranslationInterface $translator, LoggerInterface $log, RouteProviderInterface $route_provider, PluginManagerInterface $rewriters) {
48 parent::__construct($configuration, $plugin_id, $plugin_definition, $translator, $log);
49 $this->routeProvider = $route_provider;
50 $this->rewriters = $rewriters;
54 * Conform with ConverterInterface, which we implement through ConverterBase.
55 * Because route conversion is so complex, the Routing plugin never calls
56 * this method. It relies instead on the other methods defined in
57 * RouteConverterInterface.
59 final public function convert(TargetInterface $target) {}
64 public function getName(TargetInterface $target, Drupal7Route $route) {
65 $name = $target->id() . '.' . $this->unPrefix($route['page callback'], $target->id());
67 $arguments = array_filter($route['page arguments'], 'is_string');
69 $name .= '_' . implode('_', $arguments);
78 public function buildPath(TargetInterface $target, Drupal7Route $route) {
79 // The parameter map modifies the path in-place, so we'll clone it in order
80 // to keep this method non-destructive.
81 $path = clone $route->getPath();
82 $this->buildParameterMap($target, $route)->applyPath($path);
87 * Builds a parameter map from the aggregated arguments of the title,
88 * access, and page callbacks.
90 * @return \Drupal\drupalmoduleupgrader\Routing\ParameterMap
92 protected function buildParameterMap(TargetInterface $target, Drupal7Route $route) {
93 $map = new ParameterMap(clone $route->getPath(), []);
95 $indexer = $target->getIndexer('function');
97 if ($indexer->has($route['title callback'])) {
98 $map->merge(new ParameterMap(
100 $indexer->get($route['title callback'])->getParameters()->toArray(),
101 $route['title arguments']
105 if ($indexer->has($route['access callback'])) {
106 $map->merge(new ParameterMap(
108 $indexer->get($route['access callback'])->getParameters()->toArray(),
109 $route['access arguments']
113 if ($indexer->has($route['page callback'])) {
114 $map->merge(new ParameterMap(
116 $indexer->get($route['page callback'])->getParameters()->toArray(),
117 $route['page arguments']
127 public function buildRouteDefinition(TargetInterface $target, Drupal7Route $route) {
128 $indexer = $target->getIndexer('function');
130 $definition = new CoreRoute('');
131 $this->buildParameterMap($target, $route)->applyRoute($definition);
133 $controller = $this->getController($target, $route)->getName()->getAbsolutePath();
135 if ($route->containsKey('title')) {
136 $definition->setDefault('_title', $route['title']);
138 elseif ($indexer->has($route['title callback'])) {
139 $definition->setDefault('_title_callback', $controller . '::' . $route['title callback']);
142 if ($route->isAbsoluteAccess()) {
143 $definition->setRequirement('_access', $route['access callback'] ? 'true' : 'false');
145 elseif ($route->isPermissionBased()) {
146 $definition->setRequirement('_permission', $route['access arguments'][0]);
148 elseif ($indexer->has($route['access callback'])) {
149 $definition->setRequirement('_custom_access', $controller . '::' . $route['access callback']);
152 if ($indexer->has($route['page callback'])) {
153 $definition->setDefault('_controller', $controller . '::' . $route['page callback']);
156 return new Drupal8Route($this->getName($target, $route), $definition, $this->routeProvider);
162 public function buildRoute(TargetInterface $target, Drupal7Route $route) {
163 $definition = $this->buildRouteDefinition($target, $route);
165 $map = $this->buildParameterMap($target, $route);
166 $map->applyRoute($definition->unwrap());
168 $indexer = $target->getIndexer('function');
170 foreach ($map->toArray() as $function_name => $parameters) {
171 if ($parameters && $indexer->has($function_name)) {
172 /** @var \Pharborist\Functions\FunctionDeclarationNode $function */
173 $function = $indexer->get($function_name);
174 foreach ($parameters as $parameter_name => $info) {
175 $parameter = $function->getParameterByName($parameter_name)->setName($info['name'], TRUE);
176 if (isset($info['type'])) {
177 $plugin_id = '_rewriter:' . $info['type'];
178 if ($this->rewriters->hasDefinition($plugin_id)) {
179 $this->rewriters->createInstance($plugin_id)->rewrite($parameter);
186 $class_indexer = $target->getIndexer('class');
187 if ($class_indexer->has('DefaultController')) {
188 $controller = $class_indexer->get('DefaultController');
191 $controller = $this->getController($target, $route);
192 $class_indexer->addFile($this->writeClass($target, $controller));
195 if ($indexer->has($route['title callback'])) {
196 if (! $controller->hasMethod($route['title callback'])) {
197 $indexer->get($route['title callback'])->cloneAsMethodOf($controller);
201 if ($indexer->has($route['access callback'])) {
202 $func = $indexer->get($route['access callback']);
204 $returns = $func->find(Filter::isInstanceOf('\Pharborist\ReturnStatementNode'));
205 foreach ($returns as $ret) {
206 $call = ClassMethodCallNode::create('\Drupal\Core\Access\AccessResult', 'allowedIf')->appendArgument($ret->getExpression());
207 $ret->replaceWith(ReturnStatementNode::create($call));
210 // The access callback always receives an $account parameter.
211 if ($func->hasParameter('account')) {
212 $func->getParameter('account')->setTypeHint('Drupal\Core\Session\AccountInterface');
215 $account = ParameterNode::create('account')->setTypeHint('Drupal\Core\Session\AccountInterface');
216 $func->appendParameter($account);
219 if (! $controller->hasMethod($route['access callback'])) {
220 $func->cloneAsMethodOf($controller);
224 if ($indexer->has($route['page callback'])) {
225 if (! $controller->hasMethod($route['page callback'])) {
226 $indexer->get($route['page callback'])->cloneAsMethodOf($controller);
230 $this->writeClass($target, $controller);
233 protected function getController(TargetInterface $target, Drupal7Route $route) {
235 '#theme' => 'dmu_controller',
236 '#module' => $target->id(),
238 return $this->parse($render);