core/includes/menu.inc | 4 +- core/lib/Drupal/Core/Menu/MenuLinkTree.php | 18 ++++++--- core/modules/menu_ui/menu_ui.admin.inc | 2 +- core/modules/menu_ui/menu_ui.info.yml | 2 +- .../system/src/Controller/SystemController.php | 2 +- core/modules/system/src/Form/ModulesListForm.php | 38 +++++++++++++---- core/modules/system/system.api.php | 2 +- .../views/src/Plugin/Derivative/ViewsMenuLink.php | 8 ++-- .../src/Plugin/Menu/Form/ViewsMenuLinkForm.php | 47 +++++++++++++++------- .../views/src/Plugin/Menu/ViewsMenuLink.php | 38 +++++------------ .../src/Plugin/views/display/DisplayPluginBase.php | 8 ++-- .../src/Plugin/views/display/PathPluginBase.php | 3 +- core/modules/views/src/ViewExecutable.php | 6 +-- 13 files changed, 103 insertions(+), 75 deletions(-) diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 2e31ef3..405032e 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -285,12 +285,12 @@ * \Drupal\Core\Menu\DefaultMenuTreeManipulators for examples. This is only * necessary if you want to do things like adding extra metadata to rendered * links to display icons next to them. - * - Pass the menu tree to \Drupal\menu_link\MenuTree::build(), this will build + * - Pass the menu tree to \Drupal\Core\Menu\MenuLinkTree::build(), this will build * a renderable array. * * Combined, that would look like this: * @code - * $menu_tree = \Drupal::service('menu.link_tree'); + * $menu_tree = \Drupal::menuTree(); * $menu_name = 'my_menu'; * * // Build the typical default set of menu tree parameters. diff --git a/core/lib/Drupal/Core/Menu/MenuLinkTree.php b/core/lib/Drupal/Core/Menu/MenuLinkTree.php index aae6efd..943698c 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkTree.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkTree.php @@ -61,6 +61,15 @@ class MenuLinkTree implements MenuLinkTreeInterface { protected $routeMatch; /** + * Stores the cached current route parameters by menu and current route match. + * + * @todo Remove this non-static caching in https://www.drupal.org/node/1805054. + * + * @var \Drupal\Core\Menu\MenuTreeParameters[] + */ + protected $cachedCurrentRouteParameters; + + /** * Constructs a \Drupal\Core\Menu\MenuLinkTree object. * * @param \Drupal\Core\Menu\MenuTreeStorageInterface $tree_storage @@ -93,14 +102,11 @@ public function __construct(MenuTreeStorageInterface $tree_storage, MenuLinkMana * {@inheritdoc} */ public function getCurrentRouteMenuTreeParameters($menu_name) { - static $cached_parameters = array(); - - // @todo Remove this non-static caching in https://www.drupal.org/node/1805054. $route_parameters = $this->routeMatch->getRawParameters()->all(); ksort($route_parameters); $cid = 'current-route-parameters:' . $menu_name . ':route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters); - if (!isset($cached_parameters[$menu_name])) { + if (!isset($this->cachedCurrentRouteParameters[$menu_name])) { $cache = $this->cache->get($cid); if ($cache && $cache->data) { $parameters = $cache->data; @@ -119,10 +125,10 @@ public function getCurrentRouteMenuTreeParameters($menu_name) { $this->cache->set($cid, $parameters, CacheBackendInterface::CACHE_PERMANENT, array('menu' => $menu_name)); } - $cached_parameters[$menu_name] = $parameters; + $this->cachedCurrentRouteParameters[$menu_name] = $parameters; } - return $cached_parameters[$menu_name]; + return $this->cachedCurrentRouteParameters[$menu_name]; } /** diff --git a/core/modules/menu_ui/menu_ui.admin.inc b/core/modules/menu_ui/menu_ui.admin.inc index cedc396..408272a 100644 --- a/core/modules/menu_ui/menu_ui.admin.inc +++ b/core/modules/menu_ui/menu_ui.admin.inc @@ -51,7 +51,7 @@ function theme_menu_overview_form($variables) { ); $row = array(); - $row[] = drupal_render($indent) . drupal_render($element['title']); + $row[] = SafeMarkup::set(drupal_render($indent) . drupal_render($element['title'])); $row[] = array('data' => drupal_render($element['enabled']), 'class' => array('checkbox', 'menu-enabled')); $row[] = SafeMarkup::set(drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['id'])); $row[] = drupal_render($element['operations']); diff --git a/core/modules/menu_ui/menu_ui.info.yml b/core/modules/menu_ui/menu_ui.info.yml index 9dd90da..f3bf1be 100644 --- a/core/modules/menu_ui/menu_ui.info.yml +++ b/core/modules/menu_ui/menu_ui.info.yml @@ -6,4 +6,4 @@ version: VERSION core: 8.x configure: menu_ui.overview_page dependencies: - - menu_link_content \ No newline at end of file + - menu_link_content diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php index 8881e9f..c811e85 100644 --- a/core/modules/system/src/Controller/SystemController.php +++ b/core/modules/system/src/Controller/SystemController.php @@ -108,7 +108,7 @@ public static function create(ContainerInterface $container) { * Provide the administration overview page. * * @param string $link_id - * The ID of and administrative path link for which to display child links. + * The ID of the administrative path link for which to display child links. * * @return array * A renderable array of the administration overview page. diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php index 7dc500a..fe97c28 100644 --- a/core/modules/system/src/Form/ModulesListForm.php +++ b/core/modules/system/src/Form/ModulesListForm.php @@ -83,6 +83,13 @@ class ModulesListForm extends FormBase { protected $routeMatch; /** + * The menu link manager. + * + * @var \Drupal\Core\Menu\MenuLinkManagerInterface + */ + protected $menuLinkManager; + + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { @@ -94,7 +101,8 @@ public static function create(ContainerInterface $container) { $container->get('current_user'), $container->get('current_route_match'), $container->get('title_resolver'), - $container->get('router.route_provider') + $container->get('router.route_provider'), + $container->get('plugin.manager.menu.link') ); } @@ -117,8 +125,10 @@ public static function create(ContainerInterface $container) { * The title resolver. * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider * The route provider. + * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager + * The menu link manager. */ - public function __construct(ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable, AccessManager $access_manager, EntityManagerInterface $entity_manager, AccountInterface $current_user, RouteMatchInterface $route_match, TitleResolverInterface $title_resolver, RouteProviderInterface $route_provider) { + public function __construct(ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable, AccessManager $access_manager, EntityManagerInterface $entity_manager, AccountInterface $current_user, RouteMatchInterface $route_match, TitleResolverInterface $title_resolver, RouteProviderInterface $route_provider, $menu_link_manager) { $this->moduleHandler = $module_handler; $this->keyValueExpirable = $key_value_expirable; $this->accessManager = $access_manager; @@ -127,6 +137,7 @@ public function __construct(ModuleHandlerInterface $module_handler, KeyValueStor $this->routeMatch = $route_match; $this->titleResolver = $title_resolver; $this->routeProvider = $route_provider; + $this->menuLinkManager = $menu_link_manager; } /** @@ -262,11 +273,22 @@ protected function buildRow(array $modules, Extension $module, $distribution) { $route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array(); if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) { - $request = new Request(); - $request->attributes->set('_route_name', $module->info['configure']); - $route_object = $this->routeProvider->getRouteByName($module->info['configure']); - $request->attributes->set('_route', $route_object); - $title = $this->titleResolver->getTitle($request, $route_object); + $links = $this->menuLinkManager->loadLinksByRoute($module->info['configure']); + /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ + $link = reset($links); + // Most configure links have a corresponding menu link, though some just + // have a route. + if ($link) { + $description = $link->getDescription(); + } + else { + $request = new Request(); + $request->attributes->set('_route_name', $module->info['configure']); + $route_object = $this->routeProvider->getRouteByName($module->info['configure']); + $request->attributes->set('_route', $route_object); + $description = $this->titleResolver->getTitle($request, $route_object); + } + $row['links']['configure'] = array( '#type' => 'link', @@ -276,7 +298,7 @@ protected function buildRow(array $modules, Extension $module, $distribution) { '#options' => array( 'attributes' => array( 'class' => array('module-link', 'module-link-configure'), - 'title' => $title, + 'title' => $description, ), ), ); diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index e1cf853..02ae231 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -397,7 +397,7 @@ function hook_page_build(&$page) { } /** - * Alter all the menu links discovered by the menu link plugin manager. + * Alters all the menu links discovered by the menu link plugin manager. * * @param array $links * The link definitions to be altered. diff --git a/core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php b/core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php index 66fbaa9..da5007a 100644 --- a/core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php +++ b/core/modules/views/src/Plugin/Derivative/ViewsMenuLink.php @@ -11,7 +11,9 @@ use Drupal\views\Views; /** - * Provides menu links for views. + * Provides menu links for Views. + * + * @see \Drupal\views\Plugin\Menu\ViewsMenuLink */ class ViewsMenuLink implements DeriverInterface { @@ -31,15 +33,13 @@ public function getDerivativeDefinition($derivative_id, $base_plugin_definition) * {@inheritdoc} */ public function getDerivativeDefinitions($base_plugin_definition) { - // @todo Decide what to do with all the crazy logic in views_menu_alter() in - // https://drupal.org/node/2107533. $links = array(); // @todo Replaces uses_hook_menu with a different annotation. $views = Views::getApplicableViews('uses_hook_menu'); foreach ($views as $data) { /** @var \Drupal\views\ViewExecutable $view */ list($view, $display_id) = $data; - if ($result = $view->executeHookMenuLinks($display_id)) { + if ($result = $view->getMenuLinks($display_id)) { foreach ($result as $link_id => $link) { $links[$link_id] = $link + $base_plugin_definition; } diff --git a/core/modules/views/src/Plugin/Menu/Form/ViewsMenuLinkForm.php b/core/modules/views/src/Plugin/Menu/Form/ViewsMenuLinkForm.php index cfb3d9e..db8b691 100644 --- a/core/modules/views/src/Plugin/Menu/Form/ViewsMenuLinkForm.php +++ b/core/modules/views/src/Plugin/Menu/Form/ViewsMenuLinkForm.php @@ -8,12 +8,11 @@ namespace Drupal\views\Plugin\Menu\Form; use Drupal\Core\Menu\Form\MenuLinkDefaultForm; -use Drupal\views\Plugin\Menu\ViewsMenuLink; /** - * Provides an edit form for the views. + * Provides a form to edit Views menu links. * - * This provides the feature to change the title, in contrast to the static + * This provides the feature to edit the title, in contrast to the static * menu link form. * * @see \Drupal\views\Plugin\Menu\ViewsMenuLink @@ -21,6 +20,13 @@ class ViewsMenuLinkForm extends MenuLinkDefaultForm { /** + * The edited views menu link. + * + * @var \Drupal\views\Plugin\Menu\ViewsMenuLink + */ + protected $menuLink; + + /** * {@inheritdoc} */ public function buildConfigurationForm(array $form, array &$form_state) { @@ -31,22 +37,34 @@ public function buildConfigurationForm(array $form, array &$form_state) { '#title' => $this->t('Title'), // @todo how do we ensure that view is not loaded with a translation? '#default_value' => $this->menuLink->getTitle(), + '#weight' => -10, + ); + + $form['description'] = array( + '#type' => 'textfield', + '#title' => $this->t('Description'), + '#description' => $this->t('Shown when hovering over the menu link.'), + // @todo how do we ensure that view is not loaded with a translation, + // see https://www.drupal.org/node/2309507 + '#default_value' => $this->menuLink->getTitle(), + '#weight' => -5, ); $form += parent::buildConfigurationForm($form, $form_state); - if ($this->menuLink instanceof ViewsMenuLink) { - $view = $this->menuLink->loadView(); - $id = $view->storage->id(); - $label = $view->storage->label(); - if ($this->moduleHandler->moduleExists('views_ui')) { - $message = $this->t('This link is provided by the Views module. The path can be changed by editing the view @label', array('@url' => \Drupal::url('views_ui.edit', array('view' => $id)), '@label' => $label)); - } - else { - $message = $this->t('This link is provided by the Views module from view %label.', array('%label' => $label)); - } - $form['info']['#title'] = $message; + $form['info']['#weight'] = -8; + $form['path']['#weight'] = -7; + + $view = $this->menuLink->loadView(); + $id = $view->storage->id(); + $label = $view->storage->label(); + if ($this->moduleHandler->moduleExists('views_ui')) { + $message = $this->t('This link is provided by the Views module. The path can be changed by editing the view @label', array('@url' => \Drupal::url('views_ui.edit', array('view' => $id)), '@label' => $label)); + } + else { + $message = $this->t('This link is provided by the Views module from view %label.', array('%label' => $label)); } + $form['info']['#title'] = $message; return $form; } @@ -56,6 +74,7 @@ public function buildConfigurationForm(array $form, array &$form_state) { public function extractFormValues(array &$form, array &$form_state) { $definition = parent::extractFormValues($form, $form_state); $definition['title'] = $form_state['values']['title']; + $definition['description'] = $form_state['values']['description']; return $definition; } diff --git a/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php index a57fc9c..b7944a6 100644 --- a/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php +++ b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php @@ -15,6 +15,8 @@ /** * Defines menu links provided by views. + * + * @see \Drupal\views\Plugin\Derivative\ViewsMenuLink */ class ViewsMenuLink extends MenuLinkBase implements ContainerFactoryPluginInterface { @@ -134,12 +136,16 @@ public function updateLink(array $new_definition_values, $persist) { $view = $this->loadView(); $display = &$view->storage->getDisplay($view->current_display); // Just save the title to the original view. - // @todo What do we do about the other properties, like weight, - // description and menu name. - if ($display['display_options']['menu']['title'] != $new_definition_values['title']) { - $display['display_options']['menu']['title'] = $new_definition_values['title']; + $changed = FALSE; + foreach (array('title' => 'title', 'weight' => 'weight', 'menu' => 'name', 'description' => 'description') as $definition_key => $views_key) { + if ($display['display_options']['menu'][$views_key] != $new_definition_values[$definition_key]) { + $display['display_options']['menu'][$views_key] = $new_definition_values[$definition_key]; + $changed = TRUE; + } + } + if ($changed) { // @todo Note: This triggers a full rebuild of everything, even we just - // changed the title. + // changed some properties.. $view->storage->save(); } } @@ -148,26 +154,4 @@ public function updateLink(array $new_definition_values, $persist) { return $this->pluginDefinition; } - /** - * {@inheritdoc} - */ - public function getBaseId() { - $plugin_id = $this->getPluginId(); - if (strpos($plugin_id, 'views.') === 0) { - $plugin_id = 'views'; - } - return $plugin_id; - } - - /** - * {@inheritdoc} - */ - public function getDerivativeId() { - $plugin_id = $this->getPluginId(); - $derivative_id = NULL; - if (strpos($plugin_id, 'views.') === 0) { - list(, $derivative_id) = explode('views.', $plugin_id, 2); - } - return $derivative_id; - } } diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 6139f5f..6ce6c07 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -2119,16 +2119,14 @@ public function renderMoreLink() { } /** - * Creates menu links, if this display provides some. - * - * @internal param array $existing_links An array of already existing menu items provided by drupal.* An array of already existing menu items provided by drupal. + * Gets menu links, if this display provides some. * * @return array * The menu links registers for this display. * - * @see hook_menu_link_defaults() + * @see \Drupal\views\Plugin\Derivative\ViewsMenuLink */ - public function executeHookMenuLinks() { + public function getMenuLinks() { return array(); } diff --git a/core/modules/views/src/Plugin/views/display/PathPluginBase.php b/core/modules/views/src/Plugin/views/display/PathPluginBase.php index c3a3b97..a6e1759 100644 --- a/core/modules/views/src/Plugin/views/display/PathPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/PathPluginBase.php @@ -278,9 +278,8 @@ public function alterRoutes(RouteCollection $collection) { /** * {@inheritdoc} - * @return array */ - public function executeHookMenuLinks() { + public function getMenuLinks() { $links = array(); // Replace % with the link to our standard views argument loader diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php index 08e876b..c7e810b 100644 --- a/core/modules/views/src/ViewExecutable.php +++ b/core/modules/views/src/ViewExecutable.php @@ -1509,7 +1509,7 @@ public function attachDisplays() { } /** - * Returns default menu links from the view and the named display handler. + * Returns menu links from the view and the named display handler. * * @param string $display_id * A display ID. @@ -1518,7 +1518,7 @@ public function attachDisplays() { * The generated menu links for this view and display, FALSE if the call * to ::setDisplay failed. */ - public function executeHookMenuLinks($display_id = NULL) { + public function getMenuLinks($display_id = NULL) { // Prepare the view with the information we have. This was probably already // called, but it's good to be safe. if (!$this->setDisplay($display_id)) { @@ -1527,7 +1527,7 @@ public function executeHookMenuLinks($display_id = NULL) { // Execute the hook. if (isset($this->display_handler)) { - return $this->display_handler->executeHookMenuLinks(); + return $this->display_handler->getMenuLinks(); } }