ToolbarHandler.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. namespace Drupal\devel;
  3. use Drupal\Core\Cache\CacheableMetadata;
  4. use Drupal\Core\Config\ConfigFactoryInterface;
  5. use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
  6. use Drupal\Core\Menu\MenuLinkTreeInterface;
  7. use Drupal\Core\Menu\MenuTreeParameters;
  8. use Drupal\Core\Session\AccountProxyInterface;
  9. use Drupal\Core\StringTranslation\StringTranslationTrait;
  10. use Drupal\Core\Url;
  11. use Symfony\Component\DependencyInjection\ContainerInterface;
  12. /**
  13. * Toolbar integration handler.
  14. */
  15. class ToolbarHandler implements ContainerInjectionInterface {
  16. use StringTranslationTrait;
  17. /**
  18. * The menu link tree service.
  19. *
  20. * @var \Drupal\Core\Menu\MenuLinkTreeInterface
  21. */
  22. protected $menuLinkTree;
  23. /**
  24. * The devel toolbar config.
  25. *
  26. * @var \Drupal\Core\Config\ImmutableConfig
  27. */
  28. protected $config;
  29. /**
  30. * The current user.
  31. *
  32. * @var \Drupal\Core\Session\AccountProxyInterface
  33. */
  34. protected $account;
  35. /**
  36. * ToolbarHandler constructor.
  37. *
  38. * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
  39. * The menu link tree service.
  40. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
  41. * The config factory.
  42. * @param \Drupal\Core\Session\AccountProxyInterface $account
  43. * The current user.
  44. */
  45. public function __construct(MenuLinkTreeInterface $menu_link_tree, ConfigFactoryInterface $config_factory, AccountProxyInterface $account) {
  46. $this->menuLinkTree = $menu_link_tree;
  47. $this->config = $config_factory->get('devel.toolbar.settings');
  48. $this->account = $account;
  49. }
  50. /**
  51. * {@inheritdoc}
  52. */
  53. public static function create(ContainerInterface $container) {
  54. return new static(
  55. $container->get('toolbar.menu_tree'),
  56. $container->get('config.factory'),
  57. $container->get('current_user')
  58. );
  59. }
  60. /**
  61. * Hook bridge.
  62. *
  63. * @return array
  64. * The devel toolbar items render array.
  65. *
  66. * @see hook_toolbar()
  67. */
  68. public function toolbar() {
  69. $items['devel'] = [
  70. '#cache' => [
  71. 'contexts' => ['user.permissions'],
  72. ],
  73. ];
  74. if ($this->account->hasPermission('access devel information')) {
  75. $items['devel'] += [
  76. '#type' => 'toolbar_item',
  77. '#weight' => 999,
  78. 'tab' => [
  79. '#type' => 'link',
  80. '#title' => $this->t('Devel'),
  81. '#url' => Url::fromRoute('devel.admin_settings'),
  82. '#attributes' => [
  83. 'title' => $this->t('Development menu'),
  84. 'class' => ['toolbar-icon', 'toolbar-icon-devel'],
  85. ],
  86. ],
  87. 'tray' => [
  88. '#heading' => $this->t('Development menu'),
  89. 'devel_menu' => [
  90. // Currently devel menu is uncacheable, so instead of poisoning the
  91. // entire page cache we use a lazy builder.
  92. // @see \Drupal\devel\Plugin\Menu\DestinationMenuLink
  93. // @see \Drupal\devel\Plugin\Menu\RouteDetailMenuItem
  94. '#lazy_builder' => [ToolbarHandler::class . ':lazyBuilder', []],
  95. // Force the creation of the placeholder instead of rely on the
  96. // automatical placeholdering or otherwise the page results
  97. // uncacheable when max-age 0 is bubbled up.
  98. '#create_placeholder' => TRUE,
  99. ],
  100. 'configuration' => [
  101. '#type' => 'link',
  102. '#title' => $this->t('Configure'),
  103. '#url' => Url::fromRoute('devel.toolbar.settings_form'),
  104. '#options' => [
  105. 'attributes' => ['class' => ['edit-devel-toolbar']],
  106. ],
  107. ],
  108. ],
  109. '#attached' => [
  110. 'library' => 'devel/devel-toolbar',
  111. ],
  112. ];
  113. }
  114. return $items;
  115. }
  116. /**
  117. * Lazy builder callback for the devel menu toolbar.
  118. *
  119. * @return array
  120. * The renderable array rapresentation of the devel menu.
  121. */
  122. public function lazyBuilder() {
  123. $parameters = new MenuTreeParameters();
  124. $parameters->onlyEnabledLinks()->setTopLevelOnly();
  125. $tree = $this->menuLinkTree->load('devel', $parameters);
  126. $manipulators = [
  127. ['callable' => 'menu.default_tree_manipulators:checkAccess'],
  128. ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
  129. ['callable' => ToolbarHandler::class . ':processTree'],
  130. ];
  131. $tree = $this->menuLinkTree->transform($tree, $manipulators);
  132. $build = $this->menuLinkTree->build($tree);
  133. CacheableMetadata::createFromRenderArray($build)
  134. ->addCacheableDependency($this->config)
  135. ->applyTo($build);
  136. return $build;
  137. }
  138. /**
  139. * Adds toolbar-specific attributes to the menu link tree.
  140. *
  141. * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
  142. * The menu link tree to manipulate.
  143. *
  144. * @return \Drupal\Core\Menu\MenuLinkTreeElement[]
  145. * The manipulated menu link tree.
  146. */
  147. public function processTree(array $tree) {
  148. $visible_items = $this->config->get('toolbar_items') ?: [];
  149. foreach ($tree as $element) {
  150. $plugin_id = $element->link->getPluginId();
  151. if (!in_array($plugin_id, $visible_items)) {
  152. // Add a class that allow to hide the non prioritized menu items when
  153. // the toolbar has horizontal orientation.
  154. $element->options['attributes']['class'][] = 'toolbar-horizontal-item-hidden';
  155. }
  156. }
  157. return $tree;
  158. }
  159. }