Commit 516affdf authored by catch's avatar catch

Issue #2102125 by dawehner, tim.plunkett, neclimdul, pwolanin, YesCT,...

Issue #2102125 by dawehner, tim.plunkett, neclimdul, pwolanin, YesCT, damiankloip, Tim Bozeman: Big Local Task Conversion.
parent 1ce62e07
......@@ -388,7 +388,7 @@ services:
class: Drupal\Core\EventSubscriber\ViewSubscriber
tags:
- { name: event_subscriber }
arguments: ['@content_negotiation']
arguments: ['@content_negotiation', '@title_resolver']
private_key:
class: Drupal\Core\PrivateKey
arguments: ['@state']
......
......@@ -1503,6 +1503,7 @@ function theme_enable($theme_list) {
\Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
\Drupal::cache('cache')->deleteTags(array('local_task' => 1));
drupal_theme_rebuild();
// Invoke hook_themes_enabled() after the themes have been enabled.
......@@ -1539,6 +1540,7 @@ function theme_disable($theme_list) {
list_themes(TRUE);
\Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
\Drupal::cache('cache')->deleteTags(array('local_task' => 1));
drupal_theme_rebuild();
// Invoke hook_themes_disabled after the themes have been disabled.
......
......@@ -7,6 +7,8 @@
namespace Drupal\Core\EventSubscriber;
use Drupal\Core\Controller\TitleResolverInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\KernelEvents;
......@@ -27,8 +29,24 @@ class ViewSubscriber implements EventSubscriberInterface {
protected $negotiation;
public function __construct(ContentNegotiation $negotiation) {
/**
* The title resolver.
*
* @var \Drupal\Core\Controller\TitleResolverInterface
*/
protected $titleResolver;
/**
* Constructs a new ViewSubscriber.
*
* @param \Drupal\Core\ContentNegotiation $negotiation
* The content negotiation.
* @param \Drupal\Core\Controller\TitleResolverInterface $title_resolver
* The title resolver.
*/
public function __construct(ContentNegotiation $negotiation, TitleResolverInterface $title_resolver) {
$this->negotiation = $negotiation;
$this->titleResolver = $title_resolver;
}
/**
......@@ -154,6 +172,13 @@ public function onIframeUpload(GetResponseForControllerResultEvent $event) {
*/
public function onHtml(GetResponseForControllerResultEvent $event) {
$page_callback_result = $event->getControllerResult();
$request = $event->getRequest();
// If no title was returned fall back to one defined in the route.
if (!isset($page_callback_result['#title'])) {
$page_callback_result['#title'] = $this->titleResolver->getTitle($request, $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
}
return new Response(drupal_render_page($page_callback_result));
}
......
......@@ -115,7 +115,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re
$this->routeProvider = $route_provider;
$this->accessManager = $access_manager;
$this->alterInfo($module_handler, 'local_tasks');
$this->setCacheBackend($cache, $language_manager, 'local_task_plugins', array('local_task' => TRUE));
$this->setCacheBackend($cache, $language_manager, 'local_task_plugins', array('local_task' => 1));
}
/**
......@@ -200,7 +200,7 @@ public function getLocalTasksForRoute($route_name) {
'parents' => $parents,
'children' => $children,
);
$this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, CacheBackendInterface::CACHE_PERMANENT, array('local_task'));
$this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, CacheBackendInterface::CACHE_PERMANENT, $this->cacheTags);
}
// Create a plugin instance for each element of the hierarchy.
foreach ($tab_root_ids as $root_id) {
......
action.admin:
route_name: action.admin
title: 'Manage actions'
tab_root_id: action.admin
......@@ -53,26 +53,6 @@ function action_menu() {
'description' => 'Manage the actions defined for your site.',
'route_name' => 'action.admin',
);
$items['admin/config/system/actions/manage'] = array(
'title' => 'Manage actions',
'description' => 'Manage the actions defined for your site.',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/config/system/actions/add'] = array(
'title' => 'Create an advanced action',
'type' => MENU_VISIBLE_IN_BREADCRUMB,
'route_name' => 'action.admin_add',
);
$items['admin/config/system/actions/configure'] = array(
'title' => 'Configure an advanced action',
'type' => MENU_VISIBLE_IN_BREADCRUMB,
'route_name' => 'action.admin_configure',
);
$items['admin/config/system/actions/configure/%/delete'] = array(
'title' => 'Delete action',
'description' => 'Delete an action.',
'route_name' => 'action.delete',
);
return $items;
}
......
<?php
/**
* @file
* Contains \Drupal\action\Tests\Menu\ActionLocalTasksTest.
*/
namespace Drupal\action\Tests\Menu;
use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
/**
* Tests existence of action local tasks.
*
* @group Drupal
* @group Action
*/
class ActionLocalTasksTest extends LocalTaskIntegrationTest {
public static function getInfo() {
return array(
'name' => 'Action local tasks test',
'description' => 'Test action local tasks.',
'group' => 'Action',
);
}
public function setUp() {
$this->moduleList = array('action' => 'core/modules/action/action.info.yml');
parent::setUp();
}
/**
* Tests local task existence.
*/
public function testActionLocalTasks() {
$this->assertLocalTasks('action.admin', array(array('action.admin')));
}
}
aggregator.admin_overview:
route_name: aggregator.admin_overview
title: 'List'
tab_root_id: aggregator.admin_overview
aggregator.admin_settings:
route_name: aggregator.admin_settings
title: 'Settings'
weight: 100
tab_root_id: aggregator.admin_overview
aggregator.category_view:
route_name: aggregator.category_view
tab_root_id: aggregator.category_view
title: 'View'
aggregator.categorize_category_form:
route_name: aggregator.categorize_category_form
tab_root_id: aggregator.category_view
title: Categorize
aggregator.category_edit:
route_name: aggregator.category_edit
tab_root_id: aggregator.category_view
title: Configure
weight: 10
aggregator.feed_view:
route_name: aggregator.feed_view
tab_root_id: aggregator.feed_view
title: View
aggregator.categorize_feed_form:
route_name: aggregator.categorize_feed_form
tab_root_id: aggregator.feed_view
title: 'Categorize'
aggregator.feed_configure:
route_name: aggregator.feed_configure
tab_root_id: aggregator.feed_view
title: 'Configure'
weight: 10
......@@ -120,17 +120,6 @@ function aggregator_menu() {
'title' => 'Update items',
'route_name' => 'aggregator.feed_refresh',
);
$items['admin/config/services/aggregator/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/config/services/aggregator/settings'] = array(
'title' => 'Settings',
'description' => 'Configure the behavior of the feed aggregator, including when to discard feed items and how to present feed items and categories.',
'route_name' => 'aggregator.admin_settings',
'type' => MENU_LOCAL_TASK,
'weight' => 100,
);
$items['aggregator'] = array(
'title' => 'Feed aggregator',
'weight' => 5,
......@@ -149,41 +138,11 @@ function aggregator_menu() {
'title arguments' => array(2),
'route_name' => 'aggregator.category_view',
);
$items['aggregator/categories/%aggregator_category/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['aggregator/categories/%aggregator_category/categorize'] = array(
'title' => 'Categorize',
'type' => MENU_LOCAL_TASK,
'route_name' => 'aggregator.categorize_category_form',
);
$items['aggregator/categories/%aggregator_category/configure'] = array(
'title' => 'Configure',
'type' => MENU_LOCAL_TASK,
'weight' => 10,
'route_name' => 'aggregator.category_edit',
);
$items['aggregator/sources/%aggregator_feed'] = array(
'title callback' => 'entity_page_label',
'title arguments' => array(2),
'route_name' => 'aggregator.feed_view',
);
$items['aggregator/sources/%aggregator_feed/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['aggregator/sources/%aggregator_feed/categorize'] = array(
'title' => 'Categorize',
'route_name' => 'aggregator.categorize_feed_form',
'type' => MENU_LOCAL_TASK,
);
$items['aggregator/sources/%aggregator_feed/configure'] = array(
'title' => 'Configure',
'route_name' => 'aggregator.feed_configure',
'type' => MENU_LOCAL_TASK,
'weight' => 10,
);
$items['admin/config/services/aggregator/edit/feed/%aggregator_feed'] = array(
'title' => 'Edit feed',
'route_name' => 'aggregator.feed_edit',
......
<?php
/**
* @file
* Contains \Drupal\aggregator\Tests\Menu\AggregatorLocalTasksTest.
*/
namespace Drupal\aggregator\Tests\Menu;
use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
/**
* Tests existence of aggregator local tasks.
*
* @group Drupal
* @group Aggregator
*/
class AggregatorLocalTasksTest extends LocalTaskIntegrationTest {
public static function getInfo() {
return array(
'name' => 'Aggregator local tasks test',
'description' => 'Test existence of aggregator local tasks.',
'group' => 'Aggregator',
);
}
public function setUp() {
$this->moduleList = array('aggregator' => 'core/modules/aggregator/aggregator.info.yml');
parent::setUp();
}
/**
* Tests local task existence.
*
* @dataProvider getAggregatorAdminRoutes
*/
public function testAggregatorAdminLocalTasks($route) {
$this->assertLocalTasks($route, array(
0 => array('aggregator.admin_overview', 'aggregator.admin_settings'),
));
}
/**
* Provides a list of routes to test.
*/
public function getAggregatorAdminRoutes() {
return array(
array('aggregator.admin_overview'),
array('aggregator.admin_settings'),
);
}
/**
* Checks aggregator category tasks.
*
* @dataProvider getAggregatorCategoryRoutes
*/
public function testAggregatorCategoryLocalTasks($route) {
$this->assertLocalTasks($route, array(
0 => array('aggregator.category_view', 'aggregator.categorize_category_form', 'aggregator.category_edit'),
));
;
}
/**
* Provides a list of category routes to test.
*/
public function getAggregatorCategoryRoutes() {
return array(
array('aggregator.category_view'),
array('aggregator.categorize_category_form'),
array('aggregator.category_edit'),
);
}
/**
* Checks aggregator source tasks.
*
* @dataProvider getAggregatorSourceRoutes
*/
public function testAggregatorSourceLocalTasks($route) {
$this->assertLocalTasks($route, array(
0 => array('aggregator.feed_view', 'aggregator.categorize_feed_form', 'aggregator.feed_configure'),
));
;
}
/**
* Provides a list of source routes to test.
*/
public function getAggregatorSourceRoutes() {
return array(
array('aggregator.feed_view'),
array('aggregator.categorize_feed_form'),
array('aggregator.feed_configure'),
);
}
}
block.admin_edit:
title: 'Configure block'
route_name: block.admin_edit
tab_root_id: block.admin_edit
# Per theme block layout pages.
block.admin_display:
title: 'Block Layout'
route_name: block.admin_display
tab_root_id: block.admin_display
block.admin_display_theme:
title: 'Block Layout'
route_name: block.admin_display_theme
tab_root_id: block.admin_display
tab_parent_id: block.admin_display
derivative: 'Drupal\block\Plugin\Derivative\ThemeLocalTask'
......@@ -99,16 +99,11 @@ function block_permission() {
* @todo Clarify the documentation for the per-plugin block admin links.
*/
function block_menu() {
$default_theme = \Drupal::config('system.theme')->get('default');
$items['admin/structure/block'] = array(
'title' => 'Block layout',
'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
'route_name' => 'block.admin_display',
);
$items['admin/structure/block/list'] = array(
'title' => 'Block layout',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/structure/block/manage/%block'] = array(
'title' => 'Configure block',
'route_name' => 'block.admin_edit',
......@@ -116,7 +111,7 @@ function block_menu() {
$items['admin/structure/block/manage/%block/configure'] = array(
'title' => 'Configure block',
'type' => MENU_DEFAULT_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'context' => MENU_CONTEXT_INLINE,
);
$items['admin/structure/block/add/%/%'] = array(
'title' => 'Place block',
......@@ -126,15 +121,9 @@ function block_menu() {
// Block administration is tied to the theme and plugin definition so
// that the plugin can appropriately attach to this URL structure.
// @todo D8: Use dynamic % arguments instead of static, hard-coded theme names
// and plugin IDs to decouple the routes from these dependencies and allow
// hook_menu_local_tasks() to check for the untranslated tab_parent path.
// and plugin IDs to decouple the routes from these dependencies.
// @see http://drupal.org/node/1067408
foreach (list_themes() as $key => $theme) {
$items["admin/structure/block/list/$key"] = array(
'title' => check_plain($theme->info['name']),
'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
'route_name' => "block.admin_display_$key",
);
$items["admin/structure/block/demo/$key"] = array(
'route_name' => 'block.admin_demo',
'type' => MENU_CALLBACK,
......
......@@ -28,6 +28,14 @@ block.admin_display:
requirements:
_permission: 'administer blocks'
block.admin_display_theme:
path: 'admin/structure/block/list/{theme}'
defaults:
_controller: '\Drupal\block\Controller\BlockListController::listing'
requirements:
_access_theme: 'TRUE'
_permission: 'administer blocks'
block.admin_add:
path: '/admin/structure/block/add/{plugin_id}/{theme}'
defaults:
......
......@@ -9,7 +9,3 @@ services:
factory_method: get
factory_service: cache_factory
arguments: [block]
block.route_subscriber:
class: Drupal\block\Routing\RouteSubscriber
tags:
- { name: event_subscriber}
......@@ -9,3 +9,6 @@ custom_block_add_action:
title: 'Add custom block'
appears_on:
- block.admin_display
- block.admin_display_theme
class: \Drupal\custom_block\Plugin\Menu\LocalAction\CustomBlockAddLocalAction
custom_block.list:
title: 'Custom block library'
route_name: custom_block.list
tab_root_id: block.admin_display
custom_block.list_sub:
title: Blocks
route_name: custom_block.list
tab_root_id: block.admin_display
tab_parent_id: custom_block.list
custom_block.type_list:
title: Types
route_name: custom_block.type_list
tab_root_id: block.admin_display
tab_parent_id: custom_block.list
custom_block.edit:
title: Edit
route_name: custom_block.edit
tab_root_id: custom_block.edit
custom_block.delete:
title: Delete
route_name: custom_block.delete
tab_root_id: custom_block.edit
# Default tab for custom block type editing.
custom_block.type_edit:
title: 'Edit'
route_name: custom_block.type_edit
tab_root_id: custom_block.type_edit
......@@ -54,23 +54,6 @@ function custom_block_menu_local_tasks(&$data, $route_name) {
);
}
}
$routes = array_map(function ($theme) {
return "block.admin_display_$theme";
}, array_keys(list_themes()));
if (in_array($route_name, $routes)) {
// @todo Move to a LocalAction plugin when https://drupal.org/node/2045267
// allows local actions to work with query strings.
$item = menu_get_item('block/add');
if ($item['access']) {
// Add a destination parameter.
$item['localized_options']['query']['theme'] = \Drupal::request()->attributes->get('theme');
$data['actions']['block/add'] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
);
}
}
}
/**
......@@ -81,42 +64,22 @@ function custom_block_menu() {
'title' => 'Custom block library',
'description' => 'Manage custom blocks.',
'route_name' => 'custom_block.list',
'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
);
$items['admin/structure/block/custom-blocks/list'] = array(
'title' => 'Blocks',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/structure/block/custom-blocks/types'] = array(
'title' => 'Types',
'route_name' => 'custom_block.type_list',
'type' => MENU_LOCAL_TASK,
);
$items['admin/structure/block/custom-blocks/types/add'] = array(
'route_name' => 'custom_block.type_add',
'type' => MENU_SIBLING_LOCAL_TASK,
'weight' => 1,
'type' => MENU_NORMAL_ITEM,
);
$items['admin/structure/block/custom-blocks/manage/%custom_block_type'] = array(
'title' => 'Edit custom block type',
'title callback' => 'entity_page_label',
'title arguments' => array(5),
'route_name' => 'custom_block.type_edit',
);
$items['admin/structure/block/custom-blocks/manage/%custom_block_type/edit'] = array(
'title' => 'Edit',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['block/add'] = array(
'title' => 'Add custom block',
'route_name' => 'custom_block.add_page',
);
$items['block/add/%custom_block_type'] = array(
'title' => 'Add custom block',
'description' => 'Add custom block',
'route_name' => 'custom_block.add_form'
'route_name' => 'custom_block.add_page',
);
// There has to be a base-item in order for contextual links to work.
$items['block/%custom_block'] = array(
'title' => 'Edit',
......@@ -126,7 +89,7 @@ function custom_block_menu() {
'title' => 'Edit',
'weight' => 0,
'type' => MENU_DEFAULT_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'context' => MENU_CONTEXT_INLINE,
);
$items['block/%custom_block/delete'] = array(
'title' => 'Delete',
......
......@@ -33,7 +33,6 @@ custom_block.edit:
_entity_form: 'custom_block.edit'
requirements:
_entity_access: 'custom_block.update'
custom_block: \d+
custom_block.delete:
path: '/block/{custom_block}/delete'
......
......@@ -8,6 +8,7 @@
namespace Drupal\custom_block\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DerivativeBase;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
/**
* Retrieves block plugin definitions for all custom blocks.
......
<?php
/**
* @file
* Contains \Drupal\custom_block\Plugin\Menu\LocalAction\CustomBlockAddLocalAction.
*/
namespace Drupal\custom_block\Plugin\Menu\LocalAction;
use Drupal\Core\Menu\LocalActionDefault;
use Symfony\Component\HttpFoundation\Request;
/**
* Modifies the 'Add custom block' local action.
*/
class CustomBlockAddLocalAction extends LocalActionDefault {
/**
* {@inheritdoc}
*/
public function getOptions(Request $request) {
$options = parent::getOptions($request);
// If the route specifies a theme, append it to the query string.
if ($request->attributes->has('theme')) {
$options['query']['theme'] = $request->attributes->get('theme');
}
return $options;
}
}
<?php
/**
* @file
* Contains \Drupal\custom_block\Tests\Menu\CustomBlockLocalTasksTest.
*/
namespace Drupal\custom_block\Tests\Menu;
use Drupal\Tests\Core\Menu\LocalTaskIntegrationTest;
/**
* Tests existence of custom_block local tasks.
*
* @group Drupal
* @group Block
*/
class CustomBlockLocalTasksTest extends LocalTaskIntegrationTest {
public static function getInfo() {
return array(
'name' => 'Custom Block local tasks test',
'description' => 'Test custom_block local tasks.',
'group' => 'Block',
);
}
public function setUp() {
$this->moduleList = array(
'block' => 'core/modules/block/block.info.yml',
'custom_block' => 'core/modules/block/custom_block/custom_block.info.yml',
);
parent::setUp();
}
/**
* Checks custom_block listing local tasks.
*
* @dataProvider getCustomBlockListingRoutes
*/
public function testCustomBlockListLocalTasks($route) {
//
$this->assertLocalTasks($route, array(
0 => array(
'block.admin_display',
'custom_block.list',
),
1 => array(
'custom_block.list_sub',
'custom_block.type_list',
)
));
}
/**
* Provides a list of routes to test.
*/
public function getCustomBlockListingRoutes() {
return array(