Pull merge.
[yaffs-website] / web / core / lib / Drupal / Core / Menu / ContextualLinkManager.php
1 <?php
2
3 namespace Drupal\Core\Menu;
4
5 use Drupal\Component\Plugin\Exception\PluginException;
6 use Drupal\Core\Access\AccessManagerInterface;
7 use Drupal\Core\Cache\CacheBackendInterface;
8 use Drupal\Core\Controller\ControllerResolverInterface;
9 use Drupal\Core\Extension\ModuleHandlerInterface;
10 use Drupal\Core\Language\LanguageManagerInterface;
11 use Drupal\Core\Plugin\DefaultPluginManager;
12 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
13 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
14 use Drupal\Core\Plugin\Factory\ContainerFactory;
15 use Drupal\Core\Session\AccountInterface;
16 use Symfony\Component\HttpFoundation\RequestStack;
17
18 /**
19  * Defines a contextual link plugin manager to deal with contextual links.
20  *
21  * @see \Drupal\Core\Menu\ContextualLinkInterface
22  */
23 class ContextualLinkManager extends DefaultPluginManager implements ContextualLinkManagerInterface {
24
25   /**
26    * Provides default values for a contextual link definition.
27    *
28    * @var array
29    */
30   protected $defaults = [
31     // (required) The name of the route to link to.
32     'route_name' => '',
33     // (required) The contextual links group.
34     'group' => '',
35     // The static title text for the link.
36     'title' => '',
37     // The default link options.
38     'options' => [],
39     // The weight of the link.
40     'weight' => NULL,
41     // Default class for contextual link implementations.
42     'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
43     // The plugin id. Set by the plugin system based on the top-level YAML key.
44     'id' => '',
45   ];
46
47   /**
48    * A controller resolver object.
49    *
50    * @var \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface
51    */
52   protected $controllerResolver;
53
54   /**
55    * The access manager.
56    *
57    * @var \Drupal\Core\Access\AccessManagerInterface
58    */
59   protected $accessManager;
60
61   /**
62    * The current user.
63    *
64    * @var \Drupal\Core\Session\AccountInterface
65    */
66   protected $account;
67
68   /**
69    * The request stack.
70    *
71    * @var \Symfony\Component\HttpFoundation\RequestStack
72    */
73   protected $requestStack;
74
75   /**
76    * A static cache of all the contextual link plugins by group name.
77    *
78    * @var array
79    */
80   protected $pluginsByGroup;
81
82   /**
83    * Constructs a new ContextualLinkManager instance.
84    *
85    * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
86    *   The controller resolver.
87    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
88    *   The module handler.
89    * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
90    *   The cache backend.
91    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
92    *   The language manager.
93    * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
94    *   The access manager.
95    * @param \Drupal\Core\Session\AccountInterface $account
96    *   The current user.
97    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
98    *   The request stack.
99    */
100   public function __construct(ControllerResolverInterface $controller_resolver, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account, RequestStack $request_stack) {
101     $this->factory = new ContainerFactory($this, '\Drupal\Core\Menu\ContextualLinkInterface');
102     $this->controllerResolver = $controller_resolver;
103     $this->accessManager = $access_manager;
104     $this->account = $account;
105     $this->moduleHandler = $module_handler;
106     $this->requestStack = $request_stack;
107     $this->alterInfo('contextual_links_plugins');
108     $this->setCacheBackend($cache_backend, 'contextual_links_plugins:' . $language_manager->getCurrentLanguage()->getId(), ['contextual_links_plugins']);
109   }
110
111   /**
112    * {@inheritdoc}
113    */
114   protected function getDiscovery() {
115     if (!isset($this->discovery)) {
116       $yaml_discovery = new YamlDiscovery('links.contextual', $this->moduleHandler->getModuleDirectories());
117       $yaml_discovery->addTranslatableProperty('title', 'title_context');
118       $this->discovery = new ContainerDerivativeDiscoveryDecorator($yaml_discovery);
119     }
120     return $this->discovery;
121   }
122
123   /**
124    * {@inheritdoc}
125    */
126   public function processDefinition(&$definition, $plugin_id) {
127     parent::processDefinition($definition, $plugin_id);
128
129     // If there is no route name, this is a broken definition.
130     if (empty($definition['route_name'])) {
131       throw new PluginException(sprintf('Contextual link plugin (%s) definition must include "route_name".', $plugin_id));
132     }
133     // If there is no group name, this is a broken definition.
134     if (empty($definition['group'])) {
135       throw new PluginException(sprintf('Contextual link plugin (%s) definition must include "group".', $plugin_id));
136     }
137   }
138
139   /**
140    * {@inheritdoc}
141    */
142   public function getContextualLinkPluginsByGroup($group_name) {
143     if (isset($this->pluginsByGroup[$group_name])) {
144       $contextual_links = $this->pluginsByGroup[$group_name];
145     }
146     elseif ($cache = $this->cacheBackend->get($this->cacheKey . ':' . $group_name)) {
147       $contextual_links = $cache->data;
148       $this->pluginsByGroup[$group_name] = $contextual_links;
149     }
150     else {
151       $contextual_links = [];
152       foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
153         if ($plugin_definition['group'] == $group_name) {
154           $contextual_links[$plugin_id] = $plugin_definition;
155         }
156       }
157       $this->cacheBackend->set($this->cacheKey . ':' . $group_name, $contextual_links);
158       $this->pluginsByGroup[$group_name] = $contextual_links;
159     }
160     return $contextual_links;
161   }
162
163   /**
164    * {@inheritdoc}
165    */
166   public function getContextualLinksArrayByGroup($group_name, array $route_parameters, array $metadata = []) {
167     $links = [];
168     $request = $this->requestStack->getCurrentRequest();
169     foreach ($this->getContextualLinkPluginsByGroup($group_name) as $plugin_id => $plugin_definition) {
170       /** @var $plugin \Drupal\Core\Menu\ContextualLinkInterface */
171       $plugin = $this->createInstance($plugin_id);
172       $route_name = $plugin->getRouteName();
173
174       // Check access.
175       if (!$this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account)) {
176         continue;
177       }
178
179       $links[$plugin_id] = [
180         'route_name' => $route_name,
181         'route_parameters' => $route_parameters,
182         'title' => $plugin->getTitle($request),
183         'weight' => $plugin->getWeight(),
184         'localized_options' => $plugin->getOptions(),
185         'metadata' => $metadata,
186       ];
187     }
188
189     $this->moduleHandler->alter('contextual_links', $links, $group_name, $route_parameters);
190
191     return $links;
192   }
193
194 }