Commit 5feff937 authored by Dries's avatar Dries

Issue #2031473 by pwolanin, fubhy, dawehner, tim.plunkett: Convert menu local...

Issue #2031473 by pwolanin, fubhy, dawehner, tim.plunkett: Convert menu local actions to plugins so that we can generate dynamic titles and paths.
parent 3091a407
......@@ -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'];
}
......
<?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();
}
<?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, '/');
}
}
<?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();
}
<?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.
*
......
<?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.
*
......
<?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 {
}
<?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.
*
......
<?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().
*
......
<?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().
*/
......
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