diff --git a/core/core.services.yml b/core/core.services.yml index a264f5a..11f53c1 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -444,7 +444,7 @@ services: arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler', '@controller_resolver', '@state'] router.rebuild_subscriber: class: Drupal\Core\EventSubscriber\RouterRebuildSubscriber - arguments: ['@router.builder', '@lock'] + arguments: ['@router.builder', '@lock', '@plugin.manager.menu.link'] tags: - { name: event_subscriber } path.alias_storage: diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 0174882..8ec894a 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -498,8 +498,7 @@ function _menu_get_links_source($name, $default) { * A renderable array. */ function menu_navigation_links($menu_name, $level = 0) { - /** @var \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree */ - $menu_tree = \Drupal::service('menu.link_tree'); + $menu_tree = \Drupal::menuTree(); $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name); $parameters->setMaxDepth($level + 1); $tree = $menu_tree->load($menu_name, $parameters); @@ -663,15 +662,5 @@ function menu_cache_clear_all() { } /** - * Builds menu links for the items discovered as plugins. - */ -function menu_link_rebuild_defaults() { - // Ignore any database replicas temporarily. - db_ignore_replica(); - $menu_manager = \Drupal::service('plugin.manager.menu.link'); - $menu_manager->rebuild(); -} - -/** * @} End of "defgroup menu". */ diff --git a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php index f492af7..e27d836 100644 --- a/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/RouterRebuildSubscriber.php @@ -11,6 +11,7 @@ use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\Routing\RouteBuilderInterface; use Drupal\Core\Routing\RoutingEvents; +use Drupal\Core\Menu\MenuLinkManagerInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\PostResponseEvent; @@ -32,16 +33,26 @@ class RouterRebuildSubscriber implements EventSubscriberInterface { protected $lock; /** + * The menu link plugin manager + * + * @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager + */ + protected $menuLinkManager; + + /** * Constructs the RouterRebuildSubscriber object. * * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder * The route builder. * @param \Drupal\Core\Lock\LockBackendInterface $lock * The lock backend. + * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager + * The menu link plugin manager. */ - public function __construct(RouteBuilderInterface $route_builder, LockBackendInterface $lock) { + public function __construct(RouteBuilderInterface $route_builder, LockBackendInterface $lock, MenuLinkManagerInterface $menu_link_manager) { $this->routeBuilder = $route_builder; $this->lock = $lock; + $this->menuLinkManager = $menu_link_manager; } /** @@ -73,9 +84,9 @@ protected function menuLinksRebuild() { $transaction = db_transaction(); try { // Ensure the menu links are up to date. - menu_link_rebuild_defaults(); - // Clear the menu cache. - menu_cache_clear_all(); + $this->menuLinkManager->rebuild(); + // Ignore any database replicas temporarily. + db_ignore_replica(); } catch (\Exception $e) { $transaction->rollback(); diff --git a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php index 003356c..1c94d54 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php @@ -38,7 +38,7 @@ class MenuTreeStorage implements MenuTreeStorageInterface { * * @var \Drupal\Core\Cache\CacheBackendInterface */ - protected $treeCacheBackend; + protected $menuCacheBackend; /** * The database table name. @@ -99,16 +99,16 @@ class MenuTreeStorage implements MenuTreeStorageInterface { * * @param \Drupal\Core\Database\Connection $connection * A Database connection to use for reading and writing configuration data. - * @param \Drupal\Core\Cache\CacheBackendInterface $tree_cache_backend + * @param \Drupal\Core\Cache\CacheBackendInterface $menu_cache_backend * Cache backend instance for the extracted tree data. * @param string $table * A database table name to store configuration data in. * @param array $options * (optional) Any additional database connection options to use in queries. */ - public function __construct(Connection $connection, CacheBackendInterface $tree_cache_backend, $table, array $options = array()) { + public function __construct(Connection $connection, CacheBackendInterface $menu_cache_backend, $table, array $options = array()) { $this->connection = $connection; - $this->treeCacheBackend = $tree_cache_backend; + $this->menuCacheBackend = $menu_cache_backend; $this->table = $table; $this->options = $options; } @@ -183,7 +183,11 @@ public function rebuild(array $definitions) { } $this->resetDefinitions(); $affected_menus = $this->getMenuNames() + $before_menus; + // Invalidate any cache tagged with any menu name. Cache::invalidateTags(array('menu' => $affected_menus)); + $this->resetDefinitions(); + // @todo - this is probably unneeded. + $this->menuCacheBackend->invalidateAll(); } /** @@ -243,8 +247,31 @@ protected function safeExecuteSelect(SelectInterface $query) { * {@inheritdoc} */ public function save(array $link) { + $affected_menus = $this->doSave($link); + $this->resetDefinitions(); + Cache::invalidateTags(array('menu' => $affected_menus)); + return $affected_menus; + } + + /** + * Helper function for rebuild that saves a link without clearing caches. + * + * @param array $link + * A definition for a \Drupal\Core\Menu\MenuLinkInterface plugin. + * + * @return array + * The names of the menus affected by the save operation (1 or 2). + * + * @throws \Exception + * If the storage back-end does not exist and could not be created. + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If the definition is invalid - for example, if the specified parent + * would cause the links children to be moved to greater than the maximum + * depth. + */ + protected function doSave(array $link) { $original = $this->loadFull($link['id']); - // @todo - should we just return here if the links values match the original + // @todo - should we just return here if the link values match the original // values completely?. $affected_menus = array(); @@ -278,8 +305,6 @@ public function save(array $link) { $transaction->rollback(); throw $e; } - $this->resetDefinitions(); - Cache::invalidateTags(array('menu' => $affected_menus)); return $affected_menus; } @@ -750,7 +775,7 @@ protected function saveRecursive($id, &$children, &$links) { // Invalid parent ID, so remove it. $links[$id]['parent'] = ''; } - $this->save($links[$id]); + $this->doSave($links[$id]); if (!empty($children[$id])) { foreach ($children[$id] as $next_id) { @@ -771,7 +796,7 @@ public function loadTreeData($menu_name, MenuTreeParameters $parameters) { sort($parameters->conditions); // @todo - may be able to skip hashing after https://drupal.org/node/2224847 $tree_cid = "tree-data:$menu_name:" . hash('sha256', serialize($parameters)); - $cache = $this->treeCacheBackend->get($tree_cid); + $cache = $this->menuCacheBackend->get($tree_cid); if ($cache && isset($cache->data)) { $data = $cache->data; // Cache the definitions in memory so they don't need to be loaded again. @@ -783,7 +808,7 @@ public function loadTreeData($menu_name, MenuTreeParameters $parameters) { $data['tree'] = $this->doBuildTreeData($links, $parameters->activeTrail, $parameters->minDepth); $data['definitions'] = array(); $data['route_names'] = $this->collectRoutesAndDefinitions($data['tree'], $data['definitions']); - $this->treeCacheBackend->set($tree_cid, $data, Cache::PERMANENT, array('menu' => $menu_name)); + $this->menuCacheBackend->set($tree_cid, $data, Cache::PERMANENT, array('menu' => $menu_name)); // The definitions were already added to $this->definitions in // $this->doBuildTreeData() unset($data['definitions']); diff --git a/core/modules/menu_ui/menu_ui.admin.inc b/core/modules/menu_ui/menu_ui.admin.inc index b8f0ef6..3248c94 100644 --- a/core/modules/menu_ui/menu_ui.admin.inc +++ b/core/modules/menu_ui/menu_ui.admin.inc @@ -80,7 +80,7 @@ function theme_menu_overview_form($variables) { 'subgroup' => 'menu-parent', 'source' => 'menu-id', 'hidden' => TRUE, - 'limit' => \Drupal::service('menu.link_tree')->maxDepth() - 1, + 'limit' => \Drupal::menuTree()->maxDepth() - 1, ), array( 'action' => 'order', diff --git a/core/modules/menu_ui/src/Tests/MenuTest.php b/core/modules/menu_ui/src/Tests/MenuTest.php index 96bdbd1..dcae3d9 100644 --- a/core/modules/menu_ui/src/Tests/MenuTest.php +++ b/core/modules/menu_ui/src/Tests/MenuTest.php @@ -88,9 +88,9 @@ function testMenu() { /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */ $menu_link_manager = $this->container->get('plugin.manager.menu.link'); $before_count = $menu_link_manager->countMenuLinks(NULL); - menu_link_rebuild_defaults(); + $menu_link_manager->rebuild(); $after_count = $menu_link_manager->countMenuLinks(NULL); - $this->assertIdentical($before_count, $after_count, 'menu_link_rebuild_defaults() does not add more links'); + $this->assertIdentical($before_count, $after_count, 'MenuLinkManager::rebuild() does not add more links'); // Do standard user tests. // Login the user. $this->drupalLogin($this->authenticated_user); diff --git a/core/modules/system/src/Tests/Menu/LinksTest.php b/core/modules/system/src/Tests/Menu/LinksTest.php index 716562a..1e5fb34 100644 --- a/core/modules/system/src/Tests/Menu/LinksTest.php +++ b/core/modules/system/src/Tests/Menu/LinksTest.php @@ -25,7 +25,7 @@ class LinksTest extends WebTestBase { public static $modules = array('router_test', 'menu_link_content'); /** - * The menu link plugin mananger + * The menu link plugin manager * * @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager */ @@ -185,10 +185,10 @@ function testMenuLinkReparenting($module = 'menu_test') { /** * Tests uninstalling a module providing default links. */ - public function XtestModuleUninstalledMenuLinks() { + public function testModuleUninstalledMenuLinks() { \Drupal::moduleHandler()->install(array('menu_test')); \Drupal::service('router.builder')->rebuild(); - menu_link_rebuild_defaults(); + \Drupal::service('plugin.manager.menu.link')->rebuild(); $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test'); $this->assertEqual(count($menu_links), 1); $menu_link = reset($menu_links); @@ -196,7 +196,7 @@ public function XtestModuleUninstalledMenuLinks() { // Uninstall the module and ensure the menu link got removed. \Drupal::moduleHandler()->uninstall(array('menu_test')); - menu_link_rebuild_defaults(); + \Drupal::service('plugin.manager.menu.link')->rebuild(); $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test'); $this->assertEqual(count($menu_links), 0); } diff --git a/core/modules/system/system.module b/core/modules/system/system.module index b9cea5d..90d9d80 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1458,8 +1458,7 @@ function system_admin_compact_mode() { function system_get_module_admin_tasks($module, array $info) { $tree = &drupal_static(__FUNCTION__); - /* @var \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree */ - $menu_tree = \Drupal::service('menu.link_tree'); + $menu_tree = \Drupal::menuTree(); if (!isset($tree)) { $parameters = new MenuTreeParameters(); diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index 2f34dfc..04ea138 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -469,8 +469,7 @@ function toolbar_menu_navigation_links(array $tree) { * Returns the rendered subtree of each top-level toolbar link. */ function toolbar_get_rendered_subtrees() { - /** @var \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree */ - $menu_tree = \Drupal::service('menu.link_tree'); + $menu_tree = \Drupal::menuTree(); $parameters = new MenuTreeParameters(); $parameters->setRoot('system.admin')->excludeRoot()->setMaxDepth(3)->excludeHiddenLinks(); $tree = $menu_tree->load(NULL, $parameters); diff --git a/core/modules/user/src/Tests/UserAccountLinksTests.php b/core/modules/user/src/Tests/UserAccountLinksTests.php index ed07028..d07c2e9 100644 --- a/core/modules/user/src/Tests/UserAccountLinksTests.php +++ b/core/modules/user/src/Tests/UserAccountLinksTests.php @@ -69,7 +69,7 @@ function testSecondaryMenu() { // For a logged-out user, expect no secondary links. /** @var \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree */ - $menu_tree = \Drupal::service('menu.link_tree'); + $menu_tree = $this->container->get('menu.link_tree'); $tree = $menu_tree->load('account', new MenuTreeParameters()); $manipulators = array( array('callable' => 'menu.default_tree_manipulators:checkAccess'),