diff --git a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php index 44233e8..603f6b6 100644 --- a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php +++ b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php @@ -141,7 +141,7 @@ public function getTitle() { public function getWeight() { // By default the weight is 0, or -10 for the root tab. if (!isset($this->pluginDefinition['weight'])) { - if ($this->pluginDefinition['tab_root_id'] == $this->pluginDefinition['id']) { + if ($this->pluginDefinition['tab_root'] == $this->pluginDefinition['route_name'] && empty($this->pluginDefinition['tab_parent_id'])) { $this->pluginDefinition['weight'] = -10; } else { diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php index a02b8bb..013dff7 100644 --- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php +++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php @@ -39,8 +39,8 @@ class LocalTaskManager extends DefaultPluginManager { 'route_parameters' => array(), // The static title for the local task. 'title' => '', - // The plugin ID of the root tab. - 'tab_root_id' => '', + // The route name where the root tab appears. + 'tab_root' => '', // The plugin ID of the parent tab (or NULL for the top-level tab). 'tab_parent_id' => NULL, // The weight of the tab. @@ -127,6 +127,54 @@ public function processDefinition(&$definition, $plugin_id) { if (empty($definition['route_name'])) { throw new PluginException(sprintf('Plugin (%s) definition must include "route_name"', $plugin_id)); } + // If the root is not specified assume it's the same as the route. + if (empty($definition['tab_root'])) { + $definition['tab_root'] = $definition['route_name']; + } + } + + /** + * Finds plugin definitions. + * + * @return array + * List of definitions to store in cache. + */ + protected function findDefinitions() { + $definitions = parent::findDefinitions(); + // Add root tab in any cases where it is missing. + $found_routes = array(); + foreach ($definitions as $plugin_id => $definition) { + $found_routes[$definition['route_name']] = $definition['tab_root']; + } + $added_tabs = array(); + foreach ($definitions as $plugin_id => &$definition) { + if (!isset($found_routes[$definition['tab_root']])) { + // Create the missing tab. + $tabs = $this->createMissingTab($definition); + foreach ($tabs as $new_definition) { + $found_routes[$new_definition['route_name']] = $new_definition['tab_root']; + } + $added_tabs += $tabs; + } + else { + // If a developer adds a new tab and references an existing tab as + // the root, we want to copy that existing tab's root so that the + // value is consistent. + $definition['tab_root'] = $found_routes[$definition['tab_root']]; + } + } + return $definitions + $added_tabs; + } + + protected function addMissingTab($definition) { + // @todo: Load/validate the route object and get the title. + $plugin_id = 'default_local_task:' . $definition['tab_root']; + $definitions[$plugin_id] = array( + 'route_name' => $definition['tab_root'], + 'title' => 'Default', + 'weight' => -10, + ); + return $definitions; } /** @@ -173,7 +221,7 @@ public function getLocalTasksForRoute($route_name) { $children = array(); foreach ($definitions as $plugin_id => $task_info) { if ($route_name == $task_info['route_name']) { - $tab_root_ids[$task_info['tab_root_id']] = $task_info['tab_root_id']; + $tab_root_ids[$task_info['tab_root']] = $task_info['tab_root']; // Tabs that link to the current route are viable parents // and their parent and children should be visible also. // @todo - this only works for 2 levels of tabs. @@ -188,9 +236,9 @@ public function getLocalTasksForRoute($route_name) { // Find all the plugins with the same root and that are at the top // level or that have a visible parent. foreach ($definitions as $plugin_id => $task_info) { - if (!empty($tab_root_ids[$task_info['tab_root_id']]) && (empty($task_info['tab_parent_id']) || !empty($parents[$task_info['tab_parent_id']]))) { + if (!empty($tab_root_ids[$task_info['tab_root']]) && (empty($task_info['tab_parent_id']) || !empty($parents[$task_info['tab_parent_id']]))) { // Concat '> ' with root ID for the parent of top-level tabs. - $parent = empty($task_info['tab_parent_id']) ? '> ' . $task_info['tab_root_id'] : $task_info['tab_parent_id']; + $parent = empty($task_info['tab_parent_id']) ? '> ' . $task_info['tab_root'] : $task_info['tab_parent_id']; $children[$parent][$plugin_id] = $task_info; } } diff --git a/core/modules/comment/comment.local_tasks.yml b/core/modules/comment/comment.local_tasks.yml index ee8d3bf..f026671 100644 --- a/core/modules/comment/comment.local_tasks.yml +++ b/core/modules/comment/comment.local_tasks.yml @@ -1,15 +1,15 @@ comment_permalink_tab: route_name: comment_permalink title: 'View comment' - tab_root_id: comment_permalink_tab + tab_root: comment_permalink comment_edit_page_tab: route_name: comment_edit_page title: 'Edit' - tab_root_id: comment_permalink_tab + tab_root: comment_permalink weight: 0 comment_confirm_delete_tab: route_name: comment_confirm_delete title: 'Delete' - tab_root_id: comment_permalink_tab + tab_root: comment_permalink weight: 10 diff --git a/core/modules/system/tests/modules/menu_test/menu_test.local_tasks.yml b/core/modules/system/tests/modules/menu_test/menu_test.local_tasks.yml index 7d270f3..31c7c54 100644 --- a/core/modules/system/tests/modules/menu_test/menu_test.local_tasks.yml +++ b/core/modules/system/tests/modules/menu_test/menu_test.local_tasks.yml @@ -1,54 +1,64 @@ menu_local_task_test_tasks_view: route_name: menu_test.local_task_test_tasks_view title: View - tab_root_id: menu_local_task_test_tasks_view + tab_root: menu_test.local_task_test_tasks_view + menu_local_task_test_tasks_edit: route_name: menu_test.local_task_test_tasks_edit title: Edit - tab_root_id: menu_local_task_test_tasks_view + tab_root: menu_test.local_task_test_tasks_view + menu_local_task_test_tasks_settings: route_name: menu_test.local_task_test_tasks_settings title: Settings - tab_root_id: menu_local_task_test_tasks_view + tab_root: menu_test.local_task_test_tasks_view + menu_local_task_test_tasks_settings_sub1: route_name: menu_test.local_task_test_tasks_settings_sub1 title: sub1 - tab_root_id: menu_local_task_test_tasks_view + tab_root: menu_test.local_task_test_tasks_view tab_parent_id: menu_local_task_test_tasks_settings class: Drupal\menu_test\Plugin\Menu\LocalTask\TestTasksSettingsSub1 weight: -10 + menu_local_task_test_tasks_settings_sub2: route_name: menu_test.local_task_test_tasks_settings_sub2 title: sub2 - tab_root_id: menu_local_task_test_tasks_view + tab_root: menu_test.local_task_test_tasks_view tab_parent_id: menu_local_task_test_tasks_settings + menu_local_task_test_tasks_settings_sub3: route_name: menu_test.local_task_test_tasks_settings_sub3 title: sub3 - tab_root_id: menu_local_task_test_tasks_view + tab_root: menu_test.local_task_test_tasks_view tab_parent_id: menu_local_task_test_tasks_settings weight: 20 + menu_local_task_test_tasks_settings_derived: route_name: menu_test.local_task_test_tasks_settings_derived title: derived - tab_root_id: menu_local_task_test_tasks_view + tab_root: menu_test.local_task_test_tasks_view tab_parent_id: menu_local_task_test_tasks_settings derivative: Drupal\menu_test\Plugin\Derivative\LocalTaskTest weight: 50 + menu_local_task_test.placeholder_sub1: route_name: menu_test.local_task_test_placeholder_sub1 title: 'placeholder sub1' - tab_root_id: menu_local_task_test_placeholder_sub1 + tab_root: menu_test.local_task_test_tasks_view + menu_local_task_test_placeholder_sub2: route_name: menu_test.local_task_test_placeholder_sub2 title: 'placeholder sub2' - tab_root_id: menu_local_task_test_placeholder_sub1 + tab_root: menu_test.local_task_test_tasks_view + menu_local_task_test.upcasting_sub1: route_name: menu_test.local_task_test_upcasting_sub1 title: 'upcasting sub1' - tab_root_id: menu_local_task_test_upcasting_sub1 + tab_root: menu_test.local_task_test_tasks_view + menu_local_task_test_upcasting_sub2: route_name: menu_test.local_task_test_upcasting_sub2 title: 'upcasting sub2' - tab_root_id: menu_local_task_test_upcasting_sub1 + tab_root: menu_test.local_task_test_tasks_view weight: 10 diff --git a/core/modules/views_ui/views_ui.local_tasks.yml b/core/modules/views_ui/views_ui.local_tasks.yml index 383ef10..327a33b 100644 --- a/core/modules/views_ui/views_ui.local_tasks.yml +++ b/core/modules/views_ui/views_ui.local_tasks.yml @@ -1,22 +1,22 @@ views_ui_settings_tab: route_name: views_ui.settings_basic title: Settings - tab_root_id: views_ui_list_tab + tab_root: views_ui.list views_ui_settings_basic_tab: route_name: views_ui.settings_basic title: Basic - tab_root_id: views_ui_list_tab + tab_root: views_ui.list tab_parent_id: views_ui_settings_tab views_ui_settings_advanced_tab: route_name: views_ui.settings_advanced title: Advanced - tab_root_id: views_ui_list_tab + tab_root: views_ui.list tab_parent_id: views_ui_settings_tab weight: 10 views_ui_list_tab: route_name: views_ui.list title: List - tab_root_id: views_ui_list_tab + tab_root: views_ui.list diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php index 6a7c8af..1969937 100644 --- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php @@ -190,15 +190,17 @@ public function providerTestGetWeight() { // Ensure that a default tab get a lower weight. array( array( - 'tab_root_id' => 'local_task_default', - 'id' => 'local_task_default' + 'tab_root' => 'fake_route.default', + 'route_name' => 'fake_route.default', + 'id' => 'local_task_default', ), -10 ), array( array( - 'tab_root_id' => 'local_task_example', - 'id' => 'local_task_default' + 'tab_root' => 'fake_route.example', + 'route_name' => 'fake_route.default', + 'id' => 'local_task_default', ), 0 ), diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php index f10bb38..2509d60 100644 --- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php @@ -120,7 +120,7 @@ public function testGetLocalTasksForRouteSingleLevelTitle() { $this->setupFactory($mock_plugin); $this->setupLocalTaskManager(); - $local_tasks = $this->manager->getLocalTasksForRoute('menu_local_task_test_tasks_view'); + $local_tasks = $this->manager->getLocalTasksForRoute('menu_test.local_task_test_tasks_view'); $result = array( 0 => array( @@ -152,7 +152,7 @@ public function testGetLocalTaskForRouteWithEmptyCache() { $this->cacheBackend->expects($this->at(0)) ->method('get') - ->with('local_task:en:menu_local_task_test_tasks_view'); + ->with('local_task:en:menu_test.local_task_test_tasks_view'); $this->cacheBackend->expects($this->at(1)) ->method('get') @@ -166,9 +166,9 @@ public function testGetLocalTaskForRouteWithEmptyCache() { $this->cacheBackend->expects($this->at(3)) ->method('set') - ->with('local_task:en:menu_local_task_test_tasks_view', $expected_set, CacheBackendInterface::CACHE_PERMANENT, array('local_task')); + ->with('local_task:en:menu_test.local_task_test_tasks_view', $expected_set, CacheBackendInterface::CACHE_PERMANENT, array('local_task')); - $local_tasks = $this->manager->getLocalTasksForRoute('menu_local_task_test_tasks_view'); + $local_tasks = $this->manager->getLocalTasksForRoute('menu_test.local_task_test_tasks_view'); $this->assertEquals($result, $local_tasks); } @@ -188,14 +188,14 @@ public function testGetLocalTaskForRouteWithFilledCache() { $this->cacheBackend->expects($this->at(0)) ->method('get') - ->with('local_task:en:menu_local_task_test_tasks_view') + ->with('local_task:en:menu_test.local_task_test_tasks_view') ->will($this->returnValue((object) array('data' => $result))); $this->cacheBackend->expects($this->never()) ->method('set'); $result = $this->getLocalTasksForRouteResult($mock_plugin); - $local_tasks = $this->manager->getLocalTasksForRoute('menu_local_task_test_tasks_view'); + $local_tasks = $this->manager->getLocalTasksForRoute('menu_test.local_task_test_tasks_view'); $this->assertEquals($result, $local_tasks); } @@ -267,22 +267,22 @@ protected function getLocalTaskFixtures() { $definitions = array(); $definitions['menu_local_task_test_tasks_settings'] = array( 'id' => 'menu_local_task_test_tasks_settings', - 'route_name' => 'menu_local_task_test_tasks_settings', + 'route_name' => 'menu_test.local_task_test_tasks_settings', 'title' => 'Settings', - 'tab_root_id' => 'menu_local_task_test_tasks_view', + 'tab_root' => 'menu_test.local_task_test_tasks_view', ); $definitions['menu_local_task_test_tasks_edit'] = array( 'id' => 'menu_local_task_test_tasks_edit', - 'route_name' => 'menu_local_task_test_tasks_edit', + 'route_name' => 'menu_test.local_task_test_tasks_edit', 'title' => 'Settings', - 'tab_root_id' => 'menu_local_task_test_tasks_view', + 'tab_root' => 'menu_test.local_task_test_tasks_view', 'weight' => 20, ); $definitions['menu_local_task_test_tasks_view'] = array( 'id' => 'menu_local_task_test_tasks_view', - 'route_name' => 'menu_local_task_test_tasks_view', + 'route_name' => 'menu_test.local_task_test_tasks_view', 'title' => 'Settings', - 'tab_root_id' => 'menu_local_task_test_tasks_view', + 'tab_root' => 'menu_test.local_task_test_tasks_view', ); // Add the defaults from the LocalTaskManager. foreach ($definitions as $id => &$info) { @@ -291,7 +291,7 @@ protected function getLocalTaskFixtures() { 'route_name' => '', 'route_parameters' => array(), 'title' => '', - 'tab_root_id' => '', + 'tab_root' => '', 'tab_parent_id' => NULL, 'weight' => 0, 'options' => array(), @@ -346,13 +346,13 @@ protected function getLocalTasksForRouteResult($mock_plugin) { protected function getLocalTasksCache() { return array( 'tab_root_ids' => array( - 'menu_local_task_test_tasks_view' => 'menu_local_task_test_tasks_view', + 'menu_test.local_task_test_tasks_view' => 'menu_test.local_task_test_tasks_view', ), 'parents' => array( 'menu_local_task_test_tasks_view' => 1, ), 'children' => array( - '> menu_local_task_test_tasks_view' => $this->getLocalTaskFixtures(), + '> menu_test.local_task_test_tasks_view' => $this->getLocalTaskFixtures(), ) ); }