Chris@0: menuLinkManager = $menu_link_manager; Chris@0: $this->routeMatch = $route_match; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: * Chris@0: * @see ::getActiveTrailIds() Chris@0: */ Chris@0: protected function getCid() { Chris@0: if (!isset($this->cid)) { Chris@0: $route_parameters = $this->routeMatch->getRawParameters()->all(); Chris@0: ksort($route_parameters); Chris@0: return 'active-trail:route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters); Chris@0: } Chris@0: Chris@0: return $this->cid; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: * Chris@0: * @see ::getActiveTrailIds() Chris@0: */ Chris@0: protected function resolveCacheMiss($menu_name) { Chris@0: $this->storage[$menu_name] = $this->doGetActiveTrailIds($menu_name); Chris@0: $this->tags[] = 'config:system.menu.' . $menu_name; Chris@0: $this->persist($menu_name); Chris@0: Chris@0: return $this->storage[$menu_name]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: * Chris@0: * This implementation caches all active trail IDs per route match for *all* Chris@0: * menus whose active trails are calculated on that page. This ensures 1 cache Chris@0: * get for all active trails per page load, rather than N. Chris@0: * Chris@0: * It uses the cache collector pattern to do this. Chris@0: * Chris@0: * @see ::get() Chris@0: * @see \Drupal\Core\Cache\CacheCollectorInterface Chris@0: * @see \Drupal\Core\Cache\CacheCollector Chris@0: */ Chris@0: public function getActiveTrailIds($menu_name) { Chris@0: return $this->get($menu_name); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Helper method for ::getActiveTrailIds(). Chris@0: */ Chris@0: protected function doGetActiveTrailIds($menu_name) { Chris@0: // Parent ids; used both as key and value to ensure uniqueness. Chris@0: // We always want all the top-level links with parent == ''. Chris@0: $active_trail = ['' => '']; Chris@0: Chris@0: // If a link in the given menu indeed matches the route, then use it to Chris@0: // complete the active trail. Chris@0: if ($active_link = $this->getActiveLink($menu_name)) { Chris@0: if ($parents = $this->menuLinkManager->getParentIds($active_link->getPluginId())) { Chris@0: $active_trail = $parents + $active_trail; Chris@0: } Chris@0: } Chris@0: Chris@0: return $active_trail; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getActiveLink($menu_name = NULL) { Chris@0: // Note: this is a very simple implementation. If you need more control Chris@0: // over the return value, such as matching a prioritized list of menu names, Chris@0: // you should substitute your own implementation for the 'menu.active_trail' Chris@0: // service in the container. Chris@0: // The menu links coming from the storage are already sorted by depth, Chris@0: // weight and ID. Chris@0: $found = NULL; Chris@0: Chris@0: $route_name = $this->routeMatch->getRouteName(); Chris@0: // On a default (not custom) 403 page the route name is NULL. On a custom Chris@0: // 403 page we will get the route name for that page, so we can consider Chris@0: // it a feature that a relevant menu tree may be displayed. Chris@0: if ($route_name) { Chris@0: $route_parameters = $this->routeMatch->getRawParameters()->all(); Chris@0: Chris@0: // Load links matching this route. Chris@0: $links = $this->menuLinkManager->loadLinksByRoute($route_name, $route_parameters, $menu_name); Chris@0: // Select the first matching link. Chris@0: if ($links) { Chris@0: $found = reset($links); Chris@0: } Chris@0: } Chris@0: return $found; Chris@0: } Chris@0: Chris@0: }