Commit 1ceeda43 authored by catch's avatar catch

Issue #2032309 by dawehner, amateescu: Use local tasks derivatives to provide...

Issue #2032309 by dawehner, amateescu: Use local tasks derivatives to provide local tasks for views.
parent dc7a5b27
<?php
/**
* @file
* Contains \Drupal\Core\Menu\LocalTaskDerivativeBase.
*/
namespace Drupal\Core\Menu;
use Drupal\Component\Plugin\Derivative\DerivativeBase;
/**
* Provides a getPluginIdFromRoute method for local task derivatives.
*/
class LocalTaskDerivativeBase extends DerivativeBase {
/**
* Finds the local task ID of a route given the route name.
*
* @param string $route_name
* The route name.
* @param array $local_tasks
* An array of all local task definitions.
*
* @return string|null
* Returns the local task ID of the given route or NULL if none is found.
*/
protected function getPluginIdFromRoute($route_name, &$local_tasks) {
foreach ($local_tasks as $plugin_id => $local_task) {
if ($local_task['route_name'] == $route_name) {
return $plugin_id;
break;
}
}
}
}
......@@ -13,3 +13,21 @@ comment.confirm_delete_tab:
tab_root_id: comment.permalink_tab
weight: 10
comment.admin:
title: Comments
route_name: comment.admin
tab_root_id: node.content_overview
comment.admin_new:
title: 'Published comments'
route_name: comment.admin
tab_root_id: node.content_overview
tab_parent_id: comment.admin
comment.admin_approval:
title: 'Unapproved comments'
route_name: comment.admin_approval
class: Drupal\comment\Plugin\Menu\LocalTask\UnapprovedComments
tab_root_id: node.content_overview
tab_parent_id: comment.admin
weight: 1
......@@ -210,18 +210,6 @@ function comment_menu() {
'title' => 'Comments',
'description' => 'List and edit site comments and the comment approval queue.',
'route_name' => 'comment.admin',
'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
);
// Tabs begin here.
$items['admin/content/comment/new'] = array(
'title' => 'Published comments',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/content/comment/approval'] = array(
'title' => 'Unapproved comments',
'title callback' => 'comment_count_unpublished',
'route_name' => 'comment.admin_approval',
'type' => MENU_LOCAL_TASK,
);
return $items;
......@@ -239,6 +227,8 @@ function comment_menu_alter(&$items) {
/**
* Returns a menu title which includes the number of unapproved comments.
*
* @todo Move to the comment manager and replace by a entity query?
*/
function comment_count_unpublished() {
$count = db_query('SELECT COUNT(cid) FROM {comment} WHERE status = :status', array(
......
<?php
/**
* @file
* Contains \Drupal\comment\Plugin\Menu\LocalTask\UnapprovedComments.
*/
namespace Drupal\comment\Plugin\Menu\LocalTask;
use Drupal\Core\Menu\LocalTaskDefault;
/**
* Provides a local task that shows the amount of unapproved comments.
*/
class UnapprovedComments extends LocalTaskDefault {
/**
* {@inheritdoc}
*/
public function getTitle() {
return comment_count_unpublished();
}
}
......@@ -8,15 +8,14 @@
namespace Drupal\config_translation\Plugin\Derivative;
use Drupal\config_translation\ConfigMapperManagerInterface;
use Drupal\Component\Plugin\Derivative\DerivativeBase;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Menu\LocalTaskDerivativeBase;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides dynamic local tasks for config translation.
*/
class ConfigTranslationLocalTasks extends DerivativeBase implements ContainerDerivativeInterface {
class ConfigTranslationLocalTasks extends LocalTaskDerivativeBase implements ContainerDerivativeInterface {
/**
* The mapper plugin discovery service.
......@@ -80,7 +79,7 @@ public function alterLocalTasks(array &$local_tasks) {
/** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
$route_name = $mapper->getOverviewRouteName();
$translation_tab = $this->basePluginId . ':' . $route_name;
$tab_root_id = $this->getTaskFromRoute($mapper->getBaseRouteName(), $local_tasks);
$tab_root_id = $this->getPluginIdFromRoute($mapper->getBaseRouteName(), $local_tasks);
if (!empty($tab_root_id)) {
$local_tasks[$translation_tab]['tab_root_id'] = $tab_root_id;
}
......@@ -90,27 +89,5 @@ public function alterLocalTasks(array &$local_tasks) {
}
}
/**
* Find the local task ID of the parent route given the route name.
*
* @param string $route_name
* The route name of the parent local task.
* @param array $local_tasks
* An array of all local task definitions.
*
* @return bool|string
* Returns the local task ID of the parent task, otherwise return FALSE.
*/
protected function getTaskFromRoute($route_name, array &$local_tasks) {
$root_local_task = FALSE;
foreach ($local_tasks as $plugin_id => $local_task) {
if ($local_task['route_name'] == $route_name) {
$root_local_task = $plugin_id;
break;
}
}
return $root_local_task;
}
}
......@@ -7,15 +7,15 @@
namespace Drupal\content_translation\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DerivativeBase;
use Drupal\content_translation\ContentTranslationManagerInterface;
use Drupal\Core\Menu\LocalTaskDerivativeBase;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides dynamic local tasks for content translation.
*/
class ContentTranslationLocalTasks extends DerivativeBase implements ContainerDerivativeInterface {
class ContentTranslationLocalTasks extends LocalTaskDerivativeBase implements ContainerDerivativeInterface {
/**
* The base plugin ID
......@@ -84,31 +84,8 @@ public function alterLocalTasks(array &$local_tasks) {
$translation_route_name = $entity_info['links']['drupal:content-translation-overview'];
$translation_tab = $this->basePluginId . ':' . $translation_route_name;
$local_tasks[$translation_tab]['tab_root_id'] = $this->getTaskFromRoute($entity_route_name, $local_tasks);
$local_tasks[$translation_tab]['tab_root_id'] = $this->getPluginIdFromRoute($entity_route_name, $local_tasks);
}
}
/**
* Find the local task ID of the parent route given the route name.
*
* @param string $route_name
* The route name of the parent local task.
* @param array $local_tasks
* An array of all local task definitions.
*
* @return bool|string
* Returns the local task ID of the parent task, otherwise return FALSE.
*/
protected function getTaskFromRoute($route_name, &$local_tasks) {
$parent_local_task = FALSE;
foreach ($local_tasks as $plugin_id => $local_task) {
if ($local_task['route_name'] == $route_name) {
$parent_local_task = $plugin_id;
break;
}
}
return $parent_local_task;
}
}
......@@ -7,8 +7,8 @@
namespace Drupal\field_ui\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DerivativeBase;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Menu\LocalTaskDerivativeBase;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
......@@ -17,7 +17,7 @@
/**
* Provides local task definitions for all entity bundles.
*/
class FieldUiLocalTask extends DerivativeBase implements ContainerDerivativeInterface {
class FieldUiLocalTask extends LocalTaskDerivativeBase implements ContainerDerivativeInterface {
/**
* The route provider.
......@@ -199,29 +199,6 @@ public function alterLocalTasks(&$local_tasks) {
}
}
/**
* Finds the local task ID of a route given the route name.
*
* @param string $route_name
* The route name.
* @param array $local_tasks
* An array of all local task definitions.
*
* @return string|null
* Returns the local task ID of the given route or NULL if none is found.
*/
protected function getPluginIdFromRoute($route_name, &$local_tasks) {
$local_task_id = NULL;
foreach ($local_tasks as $plugin_id => $local_task) {
if ($local_task['route_name'] == $route_name) {
$local_task_id = $plugin_id;
break;
}
}
return $local_task_id;
}
/**
* Translates a string to the current language or to a given language.
*
......
......@@ -11,6 +11,10 @@ node.delete_confirm:
tab_root_id: node.view
title: Delete
weight: 10
node.content_overview:
title: Content
route_name: node.content_overview
tab_root_id: node.content_overview
node.revision_overview:
route_name: node.revision_overview
tab_root_id: node.view
......
......@@ -985,10 +985,6 @@ function node_menu() {
'route_name' => 'node.content_overview',
'weight' => -10,
);
$items['admin/content/node'] = array(
'title' => 'Content',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/structure/types'] = array(
'title' => 'Content types',
......
<?php
/**
* @file
* Contains \Drupal\views\Plugin\Derivative\ViewsLocalTask.
*/
namespace Drupal\views\Plugin\Derivative;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Drupal\Core\Menu\LocalTaskDerivativeBase;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\views\Views;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides local task definitions for all views configured as local tasks.
*/
class ViewsLocalTask extends LocalTaskDerivativeBase implements ContainerDerivativeInterface {
/**
* The route provider.
*
* @var \Drupal\Core\Routing\RouteProviderInterface
*/
protected $routeProvider;
/**
* The state key value store.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
*/
protected $state;
/**
* Constructs a \Drupal\views\Plugin\Derivative\ViewsLocalTask instance.
*
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
* The route provider.
* @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state
* The state key value store.
*/
public function __construct(RouteProviderInterface $route_provider, KeyValueStoreInterface $state) {
$this->routeProvider = $route_provider;
$this->state = $state;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
$container->get('router.route_provider'),
$container->get('state')
);
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions(array $base_plugin_definition) {
$this->derivatives = array();
$view_route_names = $this->state->get('views.view_route_names');
foreach ($this->getApplicableMenuViews() as $pair) {
/** @var $executable \Drupal\views\ViewExecutable */
list($executable, $display_id) = $pair;
$executable->setDisplay($display_id);
$menu = $executable->display_handler->getOption('menu');
if (in_array($menu['type'], array('tab', 'default tab'))) {
$plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
$route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
// Don't add a local task for views which override existing routes.
// @todo Alternative it could just change the existing entry.
if ($route_name != $plugin_id) {
continue;
}
$this->derivatives[$plugin_id] = array(
'route_name' => $route_name,
'weight' => $menu['weight'],
'title' => $menu['title'],
) + $base_plugin_definition;
// Default local tasks have themselves as tab root id.
if ($menu['type'] == 'default tab') {
$this->derivatives[$plugin_id]['tab_root_id'] = 'views_view:' . $plugin_id;
}
}
}
return $this->derivatives;
}
/**
* Alters tab_root_id and tab_parent_id into the views local tasks.
*/
public function alterLocalTasks(&$local_tasks) {
$view_route_names = $this->state->get('views.view_route_names');
foreach ($this->getApplicableMenuViews() as $pair) {
/** @var $executable \Drupal\views\ViewExecutable */
list($executable, $display_id) = $pair;
$executable->setDisplay($display_id);
$menu = $executable->display_handler->getOption('menu');
// We already have set the tab_root_id for default tabs.
if (in_array($menu['type'], array('tab'))) {
$plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
$view_route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
// Don't add a local task for views which override existing routes.
if ($view_route_name != $plugin_id) {
unset($local_tasks[$plugin_id]);
continue;
}
// Find out the parent route.
// @todo Find out how to find both the root and parent tab.
$path = $executable->display_handler->getPath();
$split = explode('/', $path);
array_pop($split);
$path = implode('/', $split);
$pattern = '/' . str_replace('%', '{}', $path);
if ($routes = $this->routeProvider->getRoutesByPattern($pattern)) {
foreach ($routes->all() as $name => $route) {
if ($parent_task = $this->getPluginIdFromRoute($name, $local_tasks)) {
$local_tasks['views_view:' . $plugin_id]['tab_root_id'] = $parent_task;
}
// Skip after the first found route.
break;
}
}
}
}
}
/**
* Return a list of all views and display IDs that have a menu entry.
*
* @return array
* A list of arrays containing the $view and $display_id.
* @code
* array(
* array($view, $display_id),
* array($view, $display_id),
* );
* @endcode
*/
protected function getApplicableMenuViews() {
return Views::getApplicableViews('uses_hook_menu');
}
}
......@@ -314,17 +314,20 @@ public function executeHookMenu($callbacks) {
$items[$path]['menu_name'] = $menu['name'];
break;
case 'tab':
$items[$path]['type'] = MENU_LOCAL_TASK;
$items[$path]['type'] = MENU_CALLBACK;
break;
case 'default tab':
$items[$path]['type'] = MENU_DEFAULT_LOCAL_TASK;
$items[$path]['type'] = MENU_CALLBACK;
break;
}
// Add context for contextual links.
if (!empty($menu['context'])) {
// @todo Make this work with the new contextual links system.
$items[$path]['context'] = TRUE;
if (in_array($menu['type'], array('tab', 'default tab'))) {
// @todo Remove once contextual links are ported to a new plugin based
// system.
if (!empty($menu['context'])) {
$items[$path]['context'] = TRUE;
}
}
// If this is a 'default' tab, check to see if we have to create the
......@@ -336,6 +339,11 @@ public function executeHookMenu($callbacks) {
// Remove the last piece.
$bit = array_pop($bits);
// Default tabs are handled by the local task plugins.
if ($tab_options['type'] == 'tab') {
return $items;
}
// we can't do this if they tried to make the last path bit variable.
// @todo: We can validate this.
if ($bit != '%views_arg' && !empty($bits)) {
......@@ -359,9 +367,6 @@ public function executeHookMenu($callbacks) {
case 'normal':
$items[$default_path]['type'] = MENU_NORMAL_ITEM;
break;
case 'tab':
$items[$default_path]['type'] = MENU_LOCAL_TASK;
break;
}
if (isset($tab_options['weight'])) {
$items[$default_path]['weight'] = intval($tab_options['weight']);
......
views_view:
class: Drupal\Core\Menu\LocalTaskDefault
derivative: \Drupal\views\Plugin\Derivative\ViewsLocalTask
......@@ -12,6 +12,7 @@
use Drupal\Core\Cache\Cache;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Language\Language;
use Drupal\views\Plugin\Derivative\ViewsLocalTask;
use Drupal\views\ViewExecutable;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\views\Entity\View;
......@@ -1355,3 +1356,12 @@ function views_element_validate_tags($element, &$form_state) {
}
}
}
/**
* Implements hook_local_tasks_alter().
*/
function views_local_tasks_alter(&$local_tasks) {
$container = \Drupal::getContainer();
$local_task = ViewsLocalTask::create($container, 'views_view');
$local_task->alterLocalTasks($local_tasks);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment