MenuActiveTrail.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. namespace Drupal\Core\Menu;
  3. use Drupal\Core\Cache\CacheBackendInterface;
  4. use Drupal\Core\Cache\CacheCollector;
  5. use Drupal\Core\Lock\LockBackendInterface;
  6. use Drupal\Core\Routing\RouteMatchInterface;
  7. /**
  8. * Provides the default implementation of the active menu trail service.
  9. *
  10. * It uses the current route name and route parameters to compare with the ones
  11. * of the menu links.
  12. */
  13. class MenuActiveTrail extends CacheCollector implements MenuActiveTrailInterface {
  14. /**
  15. * The menu link plugin manager.
  16. *
  17. * @var \Drupal\Core\Menu\MenuLinkManagerInterface
  18. */
  19. protected $menuLinkManager;
  20. /**
  21. * The route match object for the current page.
  22. *
  23. * @var \Drupal\Core\Routing\RouteMatchInterface
  24. */
  25. protected $routeMatch;
  26. /**
  27. * Constructs a \Drupal\Core\Menu\MenuActiveTrail object.
  28. *
  29. * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
  30. * The menu link plugin manager.
  31. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
  32. * A route match object for finding the active link.
  33. * @param \Drupal\Core\Cache\CacheBackendInterface $cache
  34. * The cache backend.
  35. * @param \Drupal\Core\Lock\LockBackendInterface $lock
  36. * The lock backend.
  37. */
  38. public function __construct(MenuLinkManagerInterface $menu_link_manager, RouteMatchInterface $route_match, CacheBackendInterface $cache, LockBackendInterface $lock) {
  39. parent::__construct(NULL, $cache, $lock);
  40. $this->menuLinkManager = $menu_link_manager;
  41. $this->routeMatch = $route_match;
  42. }
  43. /**
  44. * {@inheritdoc}
  45. *
  46. * @see ::getActiveTrailIds()
  47. */
  48. protected function getCid() {
  49. if (!isset($this->cid)) {
  50. $route_parameters = $this->routeMatch->getRawParameters()->all();
  51. ksort($route_parameters);
  52. return 'active-trail:route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters);
  53. }
  54. return $this->cid;
  55. }
  56. /**
  57. * {@inheritdoc}
  58. *
  59. * @see ::getActiveTrailIds()
  60. */
  61. protected function resolveCacheMiss($menu_name) {
  62. $this->storage[$menu_name] = $this->doGetActiveTrailIds($menu_name);
  63. $this->tags[] = 'config:system.menu.' . $menu_name;
  64. $this->persist($menu_name);
  65. return $this->storage[$menu_name];
  66. }
  67. /**
  68. * {@inheritdoc}
  69. *
  70. * This implementation caches all active trail IDs per route match for *all*
  71. * menus whose active trails are calculated on that page. This ensures 1 cache
  72. * get for all active trails per page load, rather than N.
  73. *
  74. * It uses the cache collector pattern to do this.
  75. *
  76. * @see ::get()
  77. * @see \Drupal\Core\Cache\CacheCollectorInterface
  78. * @see \Drupal\Core\Cache\CacheCollector
  79. */
  80. public function getActiveTrailIds($menu_name) {
  81. return $this->get($menu_name);
  82. }
  83. /**
  84. * Helper method for ::getActiveTrailIds().
  85. */
  86. protected function doGetActiveTrailIds($menu_name) {
  87. // Parent ids; used both as key and value to ensure uniqueness.
  88. // We always want all the top-level links with parent == ''.
  89. $active_trail = ['' => ''];
  90. // If a link in the given menu indeed matches the route, then use it to
  91. // complete the active trail.
  92. if ($active_link = $this->getActiveLink($menu_name)) {
  93. if ($parents = $this->menuLinkManager->getParentIds($active_link->getPluginId())) {
  94. $active_trail = $parents + $active_trail;
  95. }
  96. }
  97. return $active_trail;
  98. }
  99. /**
  100. * {@inheritdoc}
  101. */
  102. public function getActiveLink($menu_name = NULL) {
  103. // Note: this is a very simple implementation. If you need more control
  104. // over the return value, such as matching a prioritized list of menu names,
  105. // you should substitute your own implementation for the 'menu.active_trail'
  106. // service in the container.
  107. // The menu links coming from the storage are already sorted by depth,
  108. // weight and ID.
  109. $found = NULL;
  110. $route_name = $this->routeMatch->getRouteName();
  111. // On a default (not custom) 403 page the route name is NULL. On a custom
  112. // 403 page we will get the route name for that page, so we can consider
  113. // it a feature that a relevant menu tree may be displayed.
  114. if ($route_name) {
  115. $route_parameters = $this->routeMatch->getRawParameters()->all();
  116. // Load links matching this route.
  117. $links = $this->menuLinkManager->loadLinksByRoute($route_name, $route_parameters, $menu_name);
  118. // Select the first matching link.
  119. if ($links) {
  120. $found = reset($links);
  121. }
  122. }
  123. return $found;
  124. }
  125. }