Issue #2031473 by pwolanin, fubhy, dawehner, tim.plunkett: Convert menu local actions to plugins so that we can generate dynamic titles and paths.
parent
3091a40783
commit
5feff937fa
|
@ -169,6 +169,9 @@ services:
|
|||
plugin.manager.action:
|
||||
class: Drupal\Core\Action\ActionManager
|
||||
arguments: ['@container.namespaces']
|
||||
plugin.manager.menu.local_action:
|
||||
class: Drupal\Core\Menu\LocalActionManager
|
||||
arguments: ['@container.namespaces', '@controller_resolver', '@request', '@module_handler']
|
||||
request:
|
||||
class: Symfony\Component\HttpFoundation\Request
|
||||
# @TODO the synthetic setting must be uncommented whenever drupal_session_initialize()
|
||||
|
|
|
@ -2273,21 +2273,20 @@ function menu_secondary_local_tasks() {
|
|||
function menu_get_local_actions() {
|
||||
$links = menu_local_tasks();
|
||||
$router_item = menu_get_item();
|
||||
// @todo Consider storing the results of hook_local_actions() in a static.
|
||||
foreach (Drupal::moduleHandler()->invokeAll('local_actions') as $route_info) {
|
||||
if (in_array($router_item['route_name'], $route_info['appears_on'])) {
|
||||
$route_path = _menu_router_translate_route($route_info['route_name']);
|
||||
$manager = Drupal::service('plugin.manager.menu.local_action');
|
||||
$local_actions = $manager->getActionsForRoute($router_item['route_name']);
|
||||
foreach ($local_actions as $plugin) {
|
||||
$route_path = $manager->getPath($plugin);
|
||||
$action_router_item = menu_get_item($route_path);
|
||||
$links['actions'][$route_path] = array(
|
||||
'#theme' => 'menu_local_action',
|
||||
'#link' => array(
|
||||
'title' => $route_info['title'],
|
||||
'title' => $manager->getTitle($plugin),
|
||||
'href' => $route_path,
|
||||
),
|
||||
'#access' => $action_router_item['access'],
|
||||
);
|
||||
}
|
||||
}
|
||||
return $links['actions'];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Annotation\LocalAction.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Annotation\Menu;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines a LocalAction type Plugin annotation object.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class LocalAction extends Plugin {
|
||||
|
||||
/**
|
||||
* The ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* A static title for the local action.
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* The route name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $route_name;
|
||||
|
||||
/**
|
||||
* An array of route names where this action appears.
|
||||
*
|
||||
* @var array (optional)
|
||||
*/
|
||||
public $appears_on = array();
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Menu\LocalActionBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Menu;
|
||||
|
||||
use Drupal\Component\Plugin\PluginBase;
|
||||
use Drupal\Core\Menu\LocalActionInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
/**
|
||||
* Provides defaults and base methods for menu local action plugins.
|
||||
*
|
||||
* @todo This class needs more documentation and/or @see references.
|
||||
*/
|
||||
abstract class LocalActionBase extends PluginBase implements LocalActionInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* String translation object.
|
||||
*
|
||||
* @var \Drupal\Core\StringTranslation\Translator\TranslatorInterface
|
||||
*/
|
||||
protected $t;
|
||||
|
||||
/**
|
||||
* URL generator object.
|
||||
*
|
||||
* @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface
|
||||
*/
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* Constructs a LocalActionBase object.
|
||||
*
|
||||
* @param \Drupal\Core\StringTranslation\Translator\TranslatorInterface $string_translation
|
||||
* A translator object for use by subclasses generating localized titles.
|
||||
* @param \Symfony\Component\Routing\Generator\UrlGeneratorInterface $generator
|
||||
* A URL generator object used to get the path from the route.
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param array $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(TranslatorInterface $string_translation, UrlGeneratorInterface $generator, array $configuration, $plugin_id, array $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->generator = $generator;
|
||||
// This is available for subclasses that need to translate a dynamic title.
|
||||
$this->t = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('string_translation'),
|
||||
$container->get('url_generator'),
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRouteName() {
|
||||
return $this->pluginDefinition['route_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTitle() {
|
||||
// Subclasses may pull in the request or specific attributes as parameters.
|
||||
return $this->pluginDefinition['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPath() {
|
||||
// Subclasses may set a request into the generator or use any desired method
|
||||
// to generate the path.
|
||||
// @todo - use the new method from https://drupal.org/node/2031353
|
||||
$path = $this->generator->generate($this->getRouteName());
|
||||
// In order to get the Drupal path the base URL has to be stripped off.
|
||||
$base_url = $this->generator->getContext()->getBaseUrl();
|
||||
if (!empty($base_url) && strpos($path, $base_url) === 0) {
|
||||
$path = substr($path, strlen($base_url));
|
||||
}
|
||||
return trim($path, '/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Menu\LocalActionInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Menu;
|
||||
|
||||
/**
|
||||
* Defines an interface for menu local actions.
|
||||
*/
|
||||
interface LocalActionInterface {
|
||||
|
||||
/**
|
||||
* Get the route name from the settings.
|
||||
*
|
||||
* @return string
|
||||
* The name of the route this action links to.
|
||||
*/
|
||||
public function getRouteName();
|
||||
|
||||
/**
|
||||
* Returns the localized title to be shown for this action.
|
||||
*
|
||||
* Subclasses may add optional arguments like NodeInterface $node = NULL that
|
||||
* will be supplied by the ControllerResolver.
|
||||
*
|
||||
* @return string
|
||||
* The title to be shown for this action.
|
||||
*
|
||||
* @see \Drupal\Core\Menu\LocalActionManager::getTitle()
|
||||
*/
|
||||
public function getTitle();
|
||||
|
||||
/**
|
||||
* Return an internal Drupal path to use when linking to the action.
|
||||
*
|
||||
* Subclasses may add arguments for request attributes which will then be
|
||||
* automatically supplied by the controller resolver.
|
||||
*
|
||||
* @return string
|
||||
* The path to use when linking to the action.
|
||||
*
|
||||
* @see \Drupal\Core\Menu\LocalActionManager::getPath()
|
||||
*/
|
||||
public function getPath();
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Menu\LocalActionManager.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Menu;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Menu\LocalActionInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
|
||||
|
||||
/**
|
||||
* Manages discovery and instantiation of menu local action plugins.
|
||||
*
|
||||
* Menu local actions are links that lead to actions like "add new". The plugin
|
||||
* format allows them (if needed) to dynamically generate a title or the path
|
||||
* they link to. The annotation on the plugin provides the default title,
|
||||
* and the list of routes where the action should be rendered.
|
||||
*/
|
||||
class LocalActionManager extends DefaultPluginManager {
|
||||
|
||||
/**
|
||||
* A controller resolver object.
|
||||
*
|
||||
* @var \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface
|
||||
*/
|
||||
protected $controllerResolver;
|
||||
|
||||
/**
|
||||
* A request object.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* The plugin instances.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $instances = array();
|
||||
|
||||
/**
|
||||
* Constructs a LocalActionManager object.
|
||||
*
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface $controller_resolver
|
||||
* An object to use in introspecting route methods.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object to use for building titles and paths for plugin
|
||||
* instances.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, ControllerResolverInterface $controller_resolver, Request $request, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct('Menu\LocalAction', $namespaces, array(), 'Drupal\Core\Annotation\Menu\LocalAction');
|
||||
|
||||
$this->controllerResolver = $controller_resolver;
|
||||
$this->request = $request;
|
||||
$this->alterInfo($module_handler, 'menu_local_actions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title for a local action.
|
||||
*
|
||||
* @param \Drupal\Core\Menu\LocalActionInterface $local_action
|
||||
* An object to get the title from.
|
||||
*
|
||||
* @return string
|
||||
* The title (already localized).
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
* If the plugin does not implement the getTitle() method.
|
||||
*/
|
||||
public function getTitle(LocalActionInterface $local_action) {
|
||||
$controller = array($local_action, 'getTitle');
|
||||
$arguments = $this->controllerResolver->getArguments($this->request, $controller);
|
||||
return call_user_func_array($controller, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Drupal path for a local action.
|
||||
*
|
||||
* @param \Drupal\Core\Menu\LocalActionInterface $local_action
|
||||
* An object to get the path from.
|
||||
*
|
||||
* @return string
|
||||
* The path.
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
* If the plugin does not implement the getPath() method.
|
||||
*/
|
||||
public function getPath(LocalActionInterface $local_action) {
|
||||
$controller = array($local_action, 'getPath');
|
||||
$arguments = $this->controllerResolver->getArguments($this->request, $controller);
|
||||
return call_user_func_array($controller, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all local actions that appear on a named route.
|
||||
*
|
||||
* @param string $route_name
|
||||
* The route for which to find local actions.
|
||||
*
|
||||
* @return \Drupal\Core\Menu\LocalActionInterface[]
|
||||
* An array of LocalActionInterface objects that appear on the route path.
|
||||
*/
|
||||
public function getActionsForRoute($route_name) {
|
||||
if (!isset($this->instances[$route_name])) {
|
||||
$this->instances[$route_name] = array();
|
||||
// @todo - optimize this lookup by compiling or caching.
|
||||
foreach ($this->getDefinitions() as $plugin_id => $action_info) {
|
||||
if (in_array($route_name, $action_info['appears_on'])) {
|
||||
$plugin = $this->createInstance($plugin_id);
|
||||
$this->instances[$route_name][$plugin_id] = $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->instances[$route_name];
|
||||
}
|
||||
|
||||
}
|
|
@ -57,21 +57,6 @@ function config_test_menu() {
|
|||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_local_actions()
|
||||
*/
|
||||
function config_test_local_actions() {
|
||||
return array(
|
||||
array(
|
||||
'route_name' => 'config_test_entity_add',
|
||||
'title' => t('Add test configuration'),
|
||||
'appears_on' => array(
|
||||
'config_test_list_page',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a ConfigTest object.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\config_test\Plugin\Menu\AddConfigTestEntityLocalAction.
|
||||
*/
|
||||
|
||||
namespace Drupal\config_test\Plugin\Menu\LocalAction;
|
||||
|
||||
use Drupal\Core\Annotation\Translation;
|
||||
use Drupal\Core\Menu\LocalActionBase;
|
||||
use Drupal\Core\Annotation\Menu\LocalAction;
|
||||
|
||||
/**
|
||||
* @LocalAction(
|
||||
* id = "config_test_entity_add_local_action",
|
||||
* route_name = "config_test_entity_add",
|
||||
* title = @Translation("Add test configuration"),
|
||||
* appears_on = {"config_test_list_page"}
|
||||
* )
|
||||
*/
|
||||
class AddConfigTestEntityLocalAction extends LocalActionBase {
|
||||
|
||||
}
|
|
@ -154,21 +154,6 @@ function filter_menu() {
|
|||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_local_actions().
|
||||
*/
|
||||
function filter_local_actions() {
|
||||
return array(
|
||||
array(
|
||||
'route_name' => 'filter_format_add',
|
||||
'title' => t('Add text format'),
|
||||
'appears_on' => array(
|
||||
'filter_admin_overview',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a text format object from the database.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\filter\Plugin\Menu\AddFilterFormatLocalAction.
|
||||
*/
|
||||
|
||||
namespace Drupal\filter\Plugin\Menu\LocalAction;
|
||||
|
||||
use Drupal\Core\Annotation\Translation;
|
||||
use Drupal\Core\Menu\LocalActionBase;
|
||||
use Drupal\Core\Annotation\Menu\LocalAction;
|
||||
|
||||
/**
|
||||
* @LocalAction(
|
||||
* id = "filter_format_add_local_action",
|
||||
* route_name = "filter_format_add",
|
||||
* title = @Translation("Add text format"),
|
||||
* appears_on = {"filter_admin_overview"}
|
||||
* )
|
||||
*/
|
||||
class AddFilterFormatLocalAction extends LocalActionBase {
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\shortcut\Plugin\Menu\AddShortcutSetLocalAction.
|
||||
*/
|
||||
|
||||
namespace Drupal\shortcut\Plugin\Menu\LocalAction;
|
||||
|
||||
use Drupal\Core\Annotation\Translation;
|
||||
use Drupal\Core\Annotation\Menu\LocalAction;
|
||||
use Drupal\Core\Menu\LocalActionBase;
|
||||
|
||||
/**
|
||||
* @LocalAction(
|
||||
* id = "shortcut_set_add_local_action",
|
||||
* route_name = "shortcut_set_add",
|
||||
* title = @Translation("Add shortcut set"),
|
||||
* appears_on = {"shortcut_set_admin"}
|
||||
* )
|
||||
*/
|
||||
class AddShortcutSetLocalAction extends LocalActionBase {
|
||||
|
||||
}
|
|
@ -574,18 +574,3 @@ function shortcut_library_info() {
|
|||
|
||||
return $libraries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_local_actions.
|
||||
*/
|
||||
function shortcut_local_actions() {
|
||||
return array(
|
||||
array(
|
||||
'route_name' => 'shortcut_set_add',
|
||||
'title' => t('Add shortcut set'),
|
||||
'appears_on' => array(
|
||||
'shortcut_set_admin',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -820,31 +820,6 @@ function hook_menu() {
|
|||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define route-based local actions.
|
||||
*
|
||||
* Instead of using MENU_LOCAL_ACTION in hook_menu(), implement
|
||||
* hook_local_actions().
|
||||
*
|
||||
* @return array
|
||||
* An associative array containing the following keys:
|
||||
* - route_name: The machine name of the local action route.
|
||||
* - title: The title of the local action.
|
||||
* - appears_on: An array of route names for this action to be display on.
|
||||
*/
|
||||
function hook_local_actions() {
|
||||
return array(
|
||||
array(
|
||||
'route_name' => 'mymodule.route.action',
|
||||
'title' => t('Perform local action'),
|
||||
'appears_on' => array(
|
||||
'mymodule.other_route',
|
||||
'mymodule.other_other_route',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the data being saved to the {menu_router} table after hook_menu is invoked.
|
||||
*
|
||||
|
@ -938,6 +913,18 @@ function hook_menu_local_tasks(&$data, $router_item, $root_path) {
|
|||
function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter local actions plugins.
|
||||
*
|
||||
* @param array $local_actions
|
||||
* The array of local action plugin definitions, keyed by plugin ID.
|
||||
*
|
||||
* @see \Drupal\Core\Menu\LocalActionInterface
|
||||
* @see \Drupal\Core\Menu\LocalActionManager
|
||||
*/
|
||||
function hook_menu_local_actions_alter(&$local_actions) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter links in the active trail before it is rendered as the breadcrumb.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_test\Plugin\Menu\MenuTestLocalAction.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_test\Plugin\Menu\LocalAction;
|
||||
|
||||
use Drupal\Core\Annotation\Translation;
|
||||
use Drupal\Core\Menu\LocalActionBase;
|
||||
use Drupal\Core\Annotation\Menu\LocalAction;
|
||||
|
||||
/**
|
||||
* @LocalAction(
|
||||
* id = "menu_test_local_action3",
|
||||
* route_name = "menu_test_local_action3",
|
||||
* title = @Translation("My routing action"),
|
||||
* appears_on = {"menu_test_local_action1"}
|
||||
* )
|
||||
*/
|
||||
class MenuTestLocalAction extends LocalActionBase {
|
||||
|
||||
}
|
|
@ -451,21 +451,6 @@ function menu_test_local_action_dynamic_title($arg) {
|
|||
return t('My @arg action', array('@arg' => $arg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_local_actions().
|
||||
*/
|
||||
function menu_test_local_actions() {
|
||||
return array(
|
||||
array(
|
||||
'route_name' => 'menu_test_local_action3',
|
||||
'title' => t('My routing action'),
|
||||
'appears_on' => array(
|
||||
'menu_test_local_action1',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_local_tasks().
|
||||
*
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\views_ui\Plugin\Menu\AddViewLocalAction.
|
||||
*/
|
||||
|
||||
namespace Drupal\views_ui\Plugin\Menu\LocalAction;
|
||||
|
||||
use Drupal\Core\Annotation\Translation;
|
||||
use Drupal\Core\Menu\LocalActionBase;
|
||||
use Drupal\Core\Annotation\Menu\LocalAction;
|
||||
|
||||
/**
|
||||
* @LocalAction(
|
||||
* id = "views_add_local_action",
|
||||
* route_name = "views_ui.add",
|
||||
* title = @Translation("Add new view"),
|
||||
* appears_on = {"views_ui.list"}
|
||||
* )
|
||||
*/
|
||||
class AddViewLocalAction extends LocalActionBase {
|
||||
|
||||
}
|
|
@ -114,21 +114,6 @@ function views_ui_entity_info(&$entity_info) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_local_actions().
|
||||
*/
|
||||
function views_ui_local_actions() {
|
||||
return array(
|
||||
array(
|
||||
'route_name' => 'views_ui.add',
|
||||
'title' => t('Add new view'),
|
||||
'appears_on' => array(
|
||||
'views_ui.list',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue