Issue #2301317 by pwolanin, dawehner, Wim Leers, effulgentsia, YesCT, xjm, alexpott: MenuLinkNG part4: Conversion.
parent
44f76c6bcf
commit
70bed3385f
|
|
@ -277,7 +277,7 @@ services:
|
||||||
arguments: ['@menu.tree_storage', '@menu_link.static.overrides', '@module_handler']
|
arguments: ['@menu.tree_storage', '@menu_link.static.overrides', '@module_handler']
|
||||||
menu.link_tree:
|
menu.link_tree:
|
||||||
class: Drupal\Core\Menu\MenuLinkTree
|
class: Drupal\Core\Menu\MenuLinkTree
|
||||||
arguments: ['@menu.tree_storage', '@plugin.manager.menu.link', '@router.route_provider', '@menu.active_trail', '@controller_resolver']
|
arguments: ['@menu.tree_storage', '@plugin.manager.menu.link', '@router.route_provider', '@menu.active_trail', '@controller_resolver', '@cache.menu', '@current_route_match']
|
||||||
menu.default_tree_manipulators:
|
menu.default_tree_manipulators:
|
||||||
class: Drupal\Core\Menu\DefaultMenuLinkTreeManipulators
|
class: Drupal\Core\Menu\DefaultMenuLinkTreeManipulators
|
||||||
arguments: ['@access_manager', '@current_user']
|
arguments: ['@access_manager', '@current_user']
|
||||||
|
|
@ -443,7 +443,12 @@ services:
|
||||||
arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler', '@controller_resolver', '@state']
|
arguments: ['@router.dumper', '@lock', '@event_dispatcher', '@module_handler', '@controller_resolver', '@state']
|
||||||
router.rebuild_subscriber:
|
router.rebuild_subscriber:
|
||||||
class: Drupal\Core\EventSubscriber\RouterRebuildSubscriber
|
class: Drupal\Core\EventSubscriber\RouterRebuildSubscriber
|
||||||
arguments: ['@router.builder', '@lock']
|
arguments: ['@router.builder']
|
||||||
|
tags:
|
||||||
|
- { name: event_subscriber }
|
||||||
|
menu.rebuild_subscriber:
|
||||||
|
class: Drupal\Core\EventSubscriber\MenuRouterRebuildSubscriber
|
||||||
|
arguments: ['@lock', '@plugin.manager.menu.link']
|
||||||
tags:
|
tags:
|
||||||
- { name: event_subscriber }
|
- { name: event_subscriber }
|
||||||
path.alias_storage:
|
path.alias_storage:
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,8 @@ use Drupal\Core\Template\Attribute;
|
||||||
* - weight: Lower (negative) numbers come before higher (positive) numbers,
|
* - weight: Lower (negative) numbers come before higher (positive) numbers,
|
||||||
* for menu items with the same parent.
|
* for menu items with the same parent.
|
||||||
*
|
*
|
||||||
* Menu items from other modules can be altered using
|
* Discovered menu links from other modules can be altered using
|
||||||
* hook_menu_link_defaults_alter().
|
* hook_menu_links_discovered_alter().
|
||||||
*
|
*
|
||||||
* @todo Derivatives will probably be defined for these; when they are, add
|
* @todo Derivatives will probably be defined for these; when they are, add
|
||||||
* documentation here.
|
* documentation here.
|
||||||
|
|
@ -264,18 +264,56 @@ use Drupal\Core\Template\Attribute;
|
||||||
const MENU_MAX_DEPTH = 9;
|
const MENU_MAX_DEPTH = 9;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reserved key to identify the most specific menu link for a given path.
|
* @section Rendering menus
|
||||||
|
* Once you have created menus (that contain menu links), you want to render
|
||||||
|
* them. Drupal provides a block (Drupal\system\Plugin\Block\SystemMenuBlock) to
|
||||||
|
* do so.
|
||||||
*
|
*
|
||||||
* The value of this constant is a hash of the constant name. We use the hash
|
* However, perhaps you have more advanced needs and you're not satisfied with
|
||||||
* so that the reserved key is over 32 characters in length and will not
|
* what the menu blocks offer you. If that's the case, you'll want to:
|
||||||
* collide with allowed menu names:
|
* - Instantiate \Drupal\Core\Menu\MenuTreeParameters, and set its values to
|
||||||
|
* match your needs. Alternatively, you can use
|
||||||
|
* MenuLinkTree::getCurrentRouteMenuTreeParameters() to get a typical
|
||||||
|
* default set of parameters, and then customize them to suit your needs.
|
||||||
|
* - Call \Drupal\Core\MenuLinkTree::load() with your menu link tree parameters,
|
||||||
|
* this will return a menu link tree.
|
||||||
|
* - Pass the menu tree to \Drupal\Core\Menu\MenuLinkTree::transform() to apply
|
||||||
|
* menu link tree manipulators that transform the tree. You will almost always
|
||||||
|
* want to apply access checking. The manipulators that you will typically
|
||||||
|
* need can be found in \Drupal\Core\Menu\DefaultMenuTreeManipulators.
|
||||||
|
* - Potentially write a custom menu tree manipulator, see
|
||||||
|
* \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\Core\Menu\MenuLinkTree::build(), this will
|
||||||
|
* build a renderable array.
|
||||||
|
*
|
||||||
|
* Combined, that would look like this:
|
||||||
* @code
|
* @code
|
||||||
* sha1('MENU_PREFERRED_LINK') = 1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91
|
* $menu_tree = \Drupal::menuTree();
|
||||||
* @endcode
|
* $menu_name = 'my_menu';
|
||||||
*
|
*
|
||||||
* @see menu_link_get_preferred()
|
* // Build the typical default set of menu tree parameters.
|
||||||
|
* $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
|
||||||
|
*
|
||||||
|
* // Load the tree based on this set of parameters.
|
||||||
|
* $tree = $menu_tree->load($menu_name, $parameters);
|
||||||
|
*
|
||||||
|
* // Transform the tree using the manipulators you want.
|
||||||
|
* $manipulators = array(
|
||||||
|
* // Only show links that are accessible for the current user.
|
||||||
|
* array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
|
* // Use the default sorting of menu links.
|
||||||
|
* array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
|
* );
|
||||||
|
* $tree = $menu_tree->transform($tree, $manipulators);
|
||||||
|
*
|
||||||
|
* // Finally, build a renderable array from the transformed tree.
|
||||||
|
* $menu = $menu_tree->build($tree);
|
||||||
|
*
|
||||||
|
* $menu_html = drupal_render($menu);
|
||||||
|
* @endcode
|
||||||
*/
|
*/
|
||||||
const MENU_PREFERRED_LINK = '1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Localizes a menu link title using t() if possible.
|
* Localizes a menu link title using t() if possible.
|
||||||
|
|
@ -367,21 +405,40 @@ function _menu_link_translate(&$item) {
|
||||||
* Implements template_preprocess_HOOK() for theme_menu_tree().
|
* Implements template_preprocess_HOOK() for theme_menu_tree().
|
||||||
*/
|
*/
|
||||||
function template_preprocess_menu_tree(&$variables) {
|
function template_preprocess_menu_tree(&$variables) {
|
||||||
$variables['tree'] = $variables['tree']['#children'];
|
if (isset($variables['tree']['#heading'])) {
|
||||||
}
|
$variables['heading'] = $variables['tree']['#heading'];
|
||||||
|
$heading = &$variables['heading'];
|
||||||
|
// Convert a string heading into an array, using a H2 tag by default.
|
||||||
|
if (is_string($heading)) {
|
||||||
|
$heading = array('text' => $heading);
|
||||||
|
}
|
||||||
|
// Merge in default array properties into $heading.
|
||||||
|
$heading += array(
|
||||||
|
'level' => 'h2',
|
||||||
|
'attributes' => array(),
|
||||||
|
);
|
||||||
|
// @todo Remove backwards compatibility for $heading['class'].
|
||||||
|
// https://www.drupal.org/node/2310341
|
||||||
|
if (isset($heading['class'])) {
|
||||||
|
$heading['attributes']['class'] = $heading['class'];
|
||||||
|
}
|
||||||
|
// Convert the attributes array into an Attribute object.
|
||||||
|
$heading['attributes'] = new Attribute($heading['attributes']);
|
||||||
|
$heading['text'] = String::checkPlain($heading['text']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (isset($variables['tree']['#attributes'])) {
|
||||||
* Returns HTML for a wrapper for a menu sub-tree.
|
$variables['attributes'] = new Attribute($variables['tree']['#attributes']);
|
||||||
*
|
}
|
||||||
* @param $variables
|
else {
|
||||||
* An associative array containing:
|
$variables['attributes'] = new Attribute();
|
||||||
* - tree: An HTML string containing the tree's items.
|
}
|
||||||
*
|
if (!isset($variables['attributes']['class'])) {
|
||||||
* @see template_preprocess_menu_tree()
|
$variables['attributes']['class'] = array();
|
||||||
* @ingroup themeable
|
}
|
||||||
*/
|
$variables['attributes']['class'][] = 'menu';
|
||||||
function theme_menu_tree($variables) {
|
|
||||||
return '<ul class="menu">' . $variables['tree'] . '</ul>';
|
$variables['tree'] = $variables['tree']['#children'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -400,8 +457,10 @@ function theme_menu_link(array $variables) {
|
||||||
if ($element['#below']) {
|
if ($element['#below']) {
|
||||||
$sub_menu = drupal_render($element['#below']);
|
$sub_menu = drupal_render($element['#below']);
|
||||||
}
|
}
|
||||||
$element['#localized_options']['set_active_class'] = TRUE;
|
/** @var \Drupal\Core\Url $url */
|
||||||
$output = l($element['#title'], $element['#href'], $element['#localized_options']);
|
$url = $element['#url'];
|
||||||
|
$url->setOption('set_active_class', TRUE);
|
||||||
|
$output = \Drupal::linkGenerator()->generateFromUrl($element['#title'], $url);
|
||||||
return '<li' . new Attribute($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
|
return '<li' . new Attribute($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,56 +600,28 @@ function _menu_get_links_source($name, $default) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of links for a navigation menu.
|
* Builds a renderable array for a navigation menu.
|
||||||
*
|
*
|
||||||
* @param $menu_name
|
* @param string $menu_name
|
||||||
* The name of the menu.
|
* The name of the menu.
|
||||||
* @param $level
|
* @param int $level
|
||||||
* Optional, the depth of the menu to be returned.
|
* Optional, the depth of the menu to be returned.
|
||||||
*
|
*
|
||||||
* @return
|
* @return array
|
||||||
* An array of links of the specified menu and level.
|
* A renderable array.
|
||||||
*/
|
*/
|
||||||
function menu_navigation_links($menu_name, $level = 0) {
|
function menu_navigation_links($menu_name, $level = 0) {
|
||||||
// Don't even bother querying the menu table if no menu is specified.
|
$menu_tree = \Drupal::menuTree();
|
||||||
if (empty($menu_name)) {
|
$parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
|
||||||
return array();
|
$parameters->setMaxDepth($level + 1);
|
||||||
}
|
$tree = $menu_tree->load($menu_name, $parameters);
|
||||||
|
$manipulators = array(
|
||||||
// Get the menu hierarchy for the current page.
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
/** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
$menu_tree = \Drupal::service('menu_link.tree');
|
array('callable' => 'menu.default_tree_manipulators:extractSubtreeOfActiveTrail', 'args' => array($level)),
|
||||||
$tree = $menu_tree->buildPageData($menu_name, $level + 1);
|
);
|
||||||
|
$tree = $menu_tree->transform($tree, $manipulators);
|
||||||
// Go down the active trail until the right level is reached.
|
return $menu_tree->build($tree);
|
||||||
while ($level-- > 0 && $tree) {
|
|
||||||
// Loop through the current level's items until we find one that is in trail.
|
|
||||||
while ($item = array_shift($tree)) {
|
|
||||||
if ($item['link']['in_active_trail']) {
|
|
||||||
// If the item is in the active trail, we continue in the subtree.
|
|
||||||
$tree = empty($item['below']) ? array() : $item['below'];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a single level of links.
|
|
||||||
$links = array();
|
|
||||||
foreach ($tree as $item) {
|
|
||||||
if (!$item['link']['hidden']) {
|
|
||||||
$class = '';
|
|
||||||
$l = $item['link']['localized_options'];
|
|
||||||
$l['href'] = $item['link']['link_path'];
|
|
||||||
$l['title'] = $item['link']['title'];
|
|
||||||
if ($item['link']['in_active_trail']) {
|
|
||||||
$class = ' active-trail';
|
|
||||||
$l['attributes']['class'][] = 'active-trail';
|
|
||||||
}
|
|
||||||
// Keyed with the unique mlid to generate classes in links.html.twig.
|
|
||||||
$links['menu-' . $item['link']['mlid'] . $class] = $l;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $links;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -853,17 +884,7 @@ function menu_link_get_preferred($path = NULL, $selected_menu = NULL) {
|
||||||
* might have been made to the router items or menu links.
|
* might have been made to the router items or menu links.
|
||||||
*/
|
*/
|
||||||
function menu_cache_clear_all() {
|
function menu_cache_clear_all() {
|
||||||
\Drupal::cache('data')->deleteAll();
|
\Drupal::cache('menu')->invalidateAll();
|
||||||
menu_reset_static_cache();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the menu system static cache.
|
|
||||||
*/
|
|
||||||
function menu_reset_static_cache() {
|
|
||||||
\Drupal::entityManager()
|
|
||||||
->getStorage('menu_link')->resetCache();
|
|
||||||
drupal_static_reset('menu_link_get_preferred');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2145,27 +2145,17 @@ function template_preprocess_page(&$variables) {
|
||||||
|
|
||||||
// Pass the main menu and secondary menu to the template as render arrays.
|
// Pass the main menu and secondary menu to the template as render arrays.
|
||||||
if (!empty($variables['main_menu'])) {
|
if (!empty($variables['main_menu'])) {
|
||||||
$variables['main_menu'] = array(
|
$variables['main_menu']['#heading'] = array(
|
||||||
'#theme' =>'links__system_main_menu',
|
|
||||||
'#links' => $variables['main_menu'],
|
|
||||||
'#heading' => array(
|
|
||||||
'text' => t('Main menu'),
|
'text' => t('Main menu'),
|
||||||
'class' => array('visually-hidden'),
|
'class' => array('visually-hidden'),
|
||||||
'attributes' => array('id' => 'links__system_main_menu'),
|
'attributes' => array('id' => 'links__system_main_menu'),
|
||||||
),
|
|
||||||
'#set_active_class' => TRUE,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!empty($variables['secondary_menu'])) {
|
if (!empty($variables['secondary_menu'])) {
|
||||||
$variables['secondary_menu'] = array(
|
$variables['secondary_menu']['#heading'] = array(
|
||||||
'#theme' =>'links__system_secondary_menu',
|
|
||||||
'#links' => $variables['secondary_menu'],
|
|
||||||
'#heading' => array(
|
|
||||||
'text' => t('Secondary menu'),
|
'text' => t('Secondary menu'),
|
||||||
'class' => array('visually-hidden'),
|
'class' => array('visually-hidden'),
|
||||||
'attributes' => array('id' => 'links__system_secondary_menu'),
|
'attributes' => array('id' => 'links__system_secondary_menu'),
|
||||||
),
|
|
||||||
'#set_active_class' => TRUE,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2651,6 +2641,7 @@ function drupal_common_theme() {
|
||||||
),
|
),
|
||||||
'menu_tree' => array(
|
'menu_tree' => array(
|
||||||
'render element' => 'tree',
|
'render element' => 'tree',
|
||||||
|
'template' => 'menu-tree',
|
||||||
),
|
),
|
||||||
'menu_local_task' => array(
|
'menu_local_task' => array(
|
||||||
'render element' => 'element',
|
'render element' => 'element',
|
||||||
|
|
|
||||||
|
|
@ -647,4 +647,14 @@ class Drupal {
|
||||||
return static::$container->get('logger.factory')->get($channel);
|
return static::$container->get('logger.factory')->get($channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the menu tree.
|
||||||
|
*
|
||||||
|
* @return \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||||
|
* The menu tree.
|
||||||
|
*/
|
||||||
|
public static function menuTree() {
|
||||||
|
return static::$container->get('menu.link_tree');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,10 +255,7 @@ class Tables implements TablesInterface {
|
||||||
$mapping = $storage->getTableMapping()->getAllColumns($table);
|
$mapping = $storage->getTableMapping()->getAllColumns($table);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// @todo Stop calling drupal_get_schema() once menu links are converted
|
return FALSE;
|
||||||
// to the Entity Field API. See https://drupal.org/node/1842858.
|
|
||||||
$schema = drupal_get_schema($table);
|
|
||||||
$mapping = array_keys($schema['fields']);
|
|
||||||
}
|
}
|
||||||
return array_flip($mapping);
|
return array_flip($mapping);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\Core\EventSubscriber\MenuRouterRebuildSubscriber.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Core\EventSubscriber;
|
||||||
|
|
||||||
|
use Drupal\Core\Cache\Cache;
|
||||||
|
use Drupal\Core\Lock\LockBackendInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||||
|
use Drupal\Core\Routing\RoutingEvents;
|
||||||
|
use Symfony\Component\EventDispatcher\Event;
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuilds the default menu links and runs menu-specific code if necessary.
|
||||||
|
*/
|
||||||
|
class MenuRouterRebuildSubscriber implements EventSubscriberInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Drupal\Core\Routing\RouteBuilderInterface
|
||||||
|
*/
|
||||||
|
protected $routeBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Drupal\Core\Lock\LockBackendInterface
|
||||||
|
*/
|
||||||
|
protected $lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu link plugin manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
|
||||||
|
*/
|
||||||
|
protected $menuLinkManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the MenuRouterRebuildSubscriber object.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Lock\LockBackendInterface $lock
|
||||||
|
* The lock backend.
|
||||||
|
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
||||||
|
* The menu link plugin manager.
|
||||||
|
*/
|
||||||
|
public function __construct(LockBackendInterface $lock, MenuLinkManagerInterface $menu_link_manager) {
|
||||||
|
$this->lock = $lock;
|
||||||
|
$this->menuLinkManager = $menu_link_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuilds the menu links and deletes the local_task cache tag.
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\EventDispatcher\Event $event
|
||||||
|
* The event object.
|
||||||
|
*/
|
||||||
|
public function onRouterRebuild(Event $event) {
|
||||||
|
$this->menuLinksRebuild();
|
||||||
|
Cache::deleteTags(array('local_task' => 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform menu-specific rebuilding.
|
||||||
|
*/
|
||||||
|
protected function menuLinksRebuild() {
|
||||||
|
if ($this->lock->acquire(__FUNCTION__)) {
|
||||||
|
$transaction = db_transaction();
|
||||||
|
try {
|
||||||
|
// Ensure the menu links are up to date.
|
||||||
|
$this->menuLinkManager->rebuild();
|
||||||
|
// Ignore any database replicas temporarily.
|
||||||
|
db_ignore_replica();
|
||||||
|
}
|
||||||
|
catch (\Exception $e) {
|
||||||
|
$transaction->rollback();
|
||||||
|
watchdog_exception('menu', $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->lock->release(__FUNCTION__);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Wait for another request that is already doing this work.
|
||||||
|
// We choose to block here since otherwise the router item may not
|
||||||
|
// be available during routing resulting in a 404.
|
||||||
|
$this->lock->wait(__FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
static function getSubscribedEvents() {
|
||||||
|
$events[RoutingEvents::FINISHED][] = array('onRouterRebuild', 200);
|
||||||
|
return $events;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ use Symfony\Component\HttpKernel\Event\PostResponseEvent;
|
||||||
use Symfony\Component\HttpKernel\KernelEvents;
|
use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuilds the default menu links and runs menu-specific code if necessary.
|
* Rebuilds the router if needed at the end of the request.
|
||||||
*/
|
*/
|
||||||
class RouterRebuildSubscriber implements EventSubscriberInterface {
|
class RouterRebuildSubscriber implements EventSubscriberInterface {
|
||||||
|
|
||||||
|
|
@ -26,22 +26,14 @@ class RouterRebuildSubscriber implements EventSubscriberInterface {
|
||||||
*/
|
*/
|
||||||
protected $routeBuilder;
|
protected $routeBuilder;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \Drupal\Core\Lock\LockBackendInterface
|
|
||||||
*/
|
|
||||||
protected $lock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the RouterRebuildSubscriber object.
|
* Constructs the RouterRebuildSubscriber object.
|
||||||
*
|
*
|
||||||
* @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
|
* @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
|
||||||
* The route builder.
|
* The route builder.
|
||||||
* @param \Drupal\Core\Lock\LockBackendInterface $lock
|
|
||||||
* The lock backend.
|
|
||||||
*/
|
*/
|
||||||
public function __construct(RouteBuilderInterface $route_builder, LockBackendInterface $lock) {
|
public function __construct(RouteBuilderInterface $route_builder) {
|
||||||
$this->routeBuilder = $route_builder;
|
$this->routeBuilder = $route_builder;
|
||||||
$this->lock = $lock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,54 +47,10 @@ class RouterRebuildSubscriber implements EventSubscriberInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuilds the menu links and deletes the local_task cache tag.
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @param \Symfony\Component\EventDispatcher\Event $event
|
|
||||||
* The event object.
|
|
||||||
*/
|
|
||||||
public function onRouterRebuild(Event $event) {
|
|
||||||
$this->menuLinksRebuild();
|
|
||||||
Cache::deleteTags(array('local_task' => 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform menu-specific rebuilding.
|
|
||||||
*/
|
|
||||||
protected function menuLinksRebuild() {
|
|
||||||
if ($this->lock->acquire(__FUNCTION__)) {
|
|
||||||
$transaction = db_transaction();
|
|
||||||
try {
|
|
||||||
// Ensure the menu links are up to date.
|
|
||||||
menu_link_rebuild_defaults();
|
|
||||||
// Clear the menu cache.
|
|
||||||
menu_cache_clear_all();
|
|
||||||
// Track which menu items are expanded.
|
|
||||||
_menu_update_expanded_menus();
|
|
||||||
}
|
|
||||||
catch (\Exception $e) {
|
|
||||||
$transaction->rollback();
|
|
||||||
watchdog_exception('menu', $e);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->lock->release(__FUNCTION__);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Wait for another request that is already doing this work.
|
|
||||||
// We choose to block here since otherwise the router item may not
|
|
||||||
// be available during routing resulting in a 404.
|
|
||||||
$this->lock->wait(__FUNCTION__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers the methods in this class that should be listeners.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* An array of event listener definitions.
|
|
||||||
*/
|
*/
|
||||||
static function getSubscribedEvents() {
|
static function getSubscribedEvents() {
|
||||||
$events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200);
|
$events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200);
|
||||||
$events[RoutingEvents::FINISHED][] = array('onRouterRebuild', 200);
|
|
||||||
return $events;
|
return $events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,22 +37,6 @@ abstract class MenuLinkBase extends PluginBase implements MenuLinkInterface {
|
||||||
return $this->pluginDefinition['weight'];
|
return $this->pluginDefinition['weight'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getTitle() {
|
|
||||||
// Subclasses may pull in the request or specific attributes as parameters.
|
|
||||||
$options = array();
|
|
||||||
if (!empty($this->pluginDefinition['title_context'])) {
|
|
||||||
$options['context'] = $this->pluginDefinition['title_context'];
|
|
||||||
}
|
|
||||||
$args = array();
|
|
||||||
if (isset($this->pluginDefinition['title_arguments']) && $title_arguments = $this->pluginDefinition['title_arguments']) {
|
|
||||||
$args = (array) $title_arguments;
|
|
||||||
}
|
|
||||||
return $this->t($this->pluginDefinition['title'], $args, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
@ -109,16 +93,6 @@ abstract class MenuLinkBase extends PluginBase implements MenuLinkInterface {
|
||||||
return (bool) $this->getDeleteRoute();
|
return (bool) $this->getDeleteRoute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getDescription() {
|
|
||||||
if ($this->pluginDefinition['description']) {
|
|
||||||
return $this->t($this->pluginDefinition['description']);
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,32 @@ class MenuLinkDefault extends MenuLinkBase implements ContainerFactoryPluginInte
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getTitle() {
|
||||||
|
// Subclasses may pull in the request or specific attributes as parameters.
|
||||||
|
$options = array();
|
||||||
|
if (!empty($this->pluginDefinition['title_context'])) {
|
||||||
|
$options['context'] = $this->pluginDefinition['title_context'];
|
||||||
|
}
|
||||||
|
$args = array();
|
||||||
|
if (isset($this->pluginDefinition['title_arguments']) && $title_arguments = $this->pluginDefinition['title_arguments']) {
|
||||||
|
$args = (array) $title_arguments;
|
||||||
|
}
|
||||||
|
return $this->t($this->pluginDefinition['title'], $args, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDescription() {
|
||||||
|
if ($this->pluginDefinition['description']) {
|
||||||
|
return $this->t($this->pluginDefinition['description']);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
@ -77,11 +103,13 @@ class MenuLinkDefault extends MenuLinkBase implements ContainerFactoryPluginInte
|
||||||
public function updateLink(array $new_definition_values, $persist) {
|
public function updateLink(array $new_definition_values, $persist) {
|
||||||
// Filter the list of updates to only those that are allowed.
|
// Filter the list of updates to only those that are allowed.
|
||||||
$overrides = array_intersect_key($new_definition_values, $this->overrideAllowed);
|
$overrides = array_intersect_key($new_definition_values, $this->overrideAllowed);
|
||||||
if ($persist) {
|
|
||||||
$this->staticOverride->saveOverride($this->getPluginId(), $overrides);
|
|
||||||
}
|
|
||||||
// Update the definition.
|
// Update the definition.
|
||||||
$this->pluginDefinition = $overrides + $this->getPluginDefinition();
|
$this->pluginDefinition = $overrides + $this->getPluginDefinition();
|
||||||
|
if ($persist) {
|
||||||
|
// Always save the menu name as an override to avoid defaulting to tools.
|
||||||
|
$overrides['menu_name'] = $this->pluginDefinition['menu_name'];
|
||||||
|
$this->staticOverride->saveOverride($this->getPluginId(), $overrides);
|
||||||
|
}
|
||||||
return $this->pluginDefinition;
|
return $this->pluginDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@
|
||||||
namespace Drupal\Core\Menu;
|
namespace Drupal\Core\Menu;
|
||||||
|
|
||||||
use Drupal\Component\Utility\NestedArray;
|
use Drupal\Component\Utility\NestedArray;
|
||||||
|
use Drupal\Core\Cache\CacheBackendInterface;
|
||||||
use Drupal\Core\Controller\ControllerResolverInterface;
|
use Drupal\Core\Controller\ControllerResolverInterface;
|
||||||
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
use Drupal\Core\Routing\RouteProviderInterface;
|
use Drupal\Core\Routing\RouteProviderInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -44,6 +46,30 @@ class MenuLinkTree implements MenuLinkTreeInterface {
|
||||||
*/
|
*/
|
||||||
protected $controllerResolver;
|
protected $controllerResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cache backend.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||||
|
*/
|
||||||
|
protected $cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current route match.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||||
|
*/
|
||||||
|
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.
|
* Constructs a \Drupal\Core\Menu\MenuLinkTree object.
|
||||||
*
|
*
|
||||||
|
|
@ -57,19 +83,36 @@ class MenuLinkTree implements MenuLinkTreeInterface {
|
||||||
* The active menu trail service.
|
* The active menu trail service.
|
||||||
* @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
|
* @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
|
||||||
* The controller resolver.
|
* The controller resolver.
|
||||||
|
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
|
||||||
|
* The cache backend.
|
||||||
|
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||||
|
* The current route match.
|
||||||
*/
|
*/
|
||||||
public function __construct(MenuTreeStorageInterface $tree_storage, MenuLinkManagerInterface $menu_link_manager, RouteProviderInterface $route_provider, MenuActiveTrailInterface $menu_active_trail, ControllerResolverInterface $controller_resolver) {
|
public function __construct(MenuTreeStorageInterface $tree_storage, MenuLinkManagerInterface $menu_link_manager, RouteProviderInterface $route_provider, MenuActiveTrailInterface $menu_active_trail, ControllerResolverInterface $controller_resolver, CacheBackendInterface $cache, RouteMatchInterface $route_match) {
|
||||||
$this->treeStorage = $tree_storage;
|
$this->treeStorage = $tree_storage;
|
||||||
$this->menuLinkManager = $menu_link_manager;
|
$this->menuLinkManager = $menu_link_manager;
|
||||||
$this->routeProvider = $route_provider;
|
$this->routeProvider = $route_provider;
|
||||||
$this->menuActiveTrail = $menu_active_trail;
|
$this->menuActiveTrail = $menu_active_trail;
|
||||||
$this->controllerResolver = $controller_resolver;
|
$this->controllerResolver = $controller_resolver;
|
||||||
|
// @todo Remove these two in https://www.drupal.org/node/1805054.
|
||||||
|
$this->cache = $cache;
|
||||||
|
$this->routeMatch = $route_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getCurrentRouteMenuTreeParameters($menu_name) {
|
public function getCurrentRouteMenuTreeParameters($menu_name) {
|
||||||
|
$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($this->cachedCurrentRouteParameters[$menu_name])) {
|
||||||
|
$cache = $this->cache->get($cid);
|
||||||
|
if ($cache && $cache->data) {
|
||||||
|
$parameters = $cache->data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
$active_trail = $this->menuActiveTrail->getActiveTrailIds($menu_name);
|
$active_trail = $this->menuActiveTrail->getActiveTrailIds($menu_name);
|
||||||
|
|
||||||
$parameters = new MenuTreeParameters();
|
$parameters = new MenuTreeParameters();
|
||||||
|
|
@ -81,7 +124,12 @@ class MenuLinkTree implements MenuLinkTreeInterface {
|
||||||
// expanded.
|
// expanded.
|
||||||
->addExpandedParents($this->treeStorage->getExpanded($menu_name, $active_trail));
|
->addExpandedParents($this->treeStorage->getExpanded($menu_name, $active_trail));
|
||||||
|
|
||||||
return $parameters;
|
$this->cache->set($cid, $parameters, CacheBackendInterface::CACHE_PERMANENT, array('menu' => $menu_name));
|
||||||
|
}
|
||||||
|
$this->cachedCurrentRouteParameters[$menu_name] = $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->cachedCurrentRouteParameters[$menu_name];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,9 @@ class LinkGenerator implements LinkGeneratorInterface {
|
||||||
// drupal.active-link library know the path in a standardized manner.
|
// drupal.active-link library know the path in a standardized manner.
|
||||||
if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) {
|
if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) {
|
||||||
// @todo System path is deprecated - use the route name and parameters.
|
// @todo System path is deprecated - use the route name and parameters.
|
||||||
$variables['options']['attributes']['data-drupal-link-system-path'] = $url->getInternalPath();
|
$system_path = $url->getInternalPath();
|
||||||
|
// Special case for the front page.
|
||||||
|
$variables['options']['attributes']['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Drupal\Component\Utility\SafeMarkup;
|
use Drupal\Component\Utility\SafeMarkup;
|
||||||
|
use Drupal\book\BookManager;
|
||||||
use Drupal\Core\Render\Element;
|
use Drupal\Core\Render\Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -87,7 +88,7 @@ function theme_book_admin_table($variables) {
|
||||||
'subgroup' => 'book-pid',
|
'subgroup' => 'book-pid',
|
||||||
'source' => 'book-nid',
|
'source' => 'book-nid',
|
||||||
'hidden' => TRUE,
|
'hidden' => TRUE,
|
||||||
'limit' => MENU_MAX_DEPTH - 2,
|
'limit' => BookManager::BOOK_MAX_DEPTH - 2,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'action' => 'order',
|
'action' => 'order',
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
* Allows users to create and organize related content in an outline.
|
* Allows users to create and organize related content in an outline.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Drupal\book\BookManager;
|
||||||
use Drupal\book\BookManagerInterface;
|
use Drupal\book\BookManagerInterface;
|
||||||
use Drupal\Component\Utility\String;
|
use Drupal\Component\Utility\String;
|
||||||
use Drupal\Core\Entity\EntityInterface;
|
use Drupal\Core\Entity\EntityInterface;
|
||||||
|
|
@ -123,7 +124,7 @@ function book_node_links_alter(array &$node_links, NodeInterface $node, array &$
|
||||||
if ($context['view_mode'] == 'full' && node_is_page($node)) {
|
if ($context['view_mode'] == 'full' && node_is_page($node)) {
|
||||||
$child_type = \Drupal::config('book.settings')->get('child_type');
|
$child_type = \Drupal::config('book.settings')->get('child_type');
|
||||||
$access_controller = \Drupal::entityManager()->getAccessController('node');
|
$access_controller = \Drupal::entityManager()->getAccessController('node');
|
||||||
if (($account->hasPermission('add content to books') || $account->hasPermission('administer book outlines')) && $access_controller->createAccess($child_type) && $node->isPublished() && $node->book['depth'] < MENU_MAX_DEPTH) {
|
if (($account->hasPermission('add content to books') || $account->hasPermission('administer book outlines')) && $access_controller->createAccess($child_type) && $node->isPublished() && $node->book['depth'] < BookManager::BOOK_MAX_DEPTH) {
|
||||||
$links['book_add_child'] = array(
|
$links['book_add_child'] = array(
|
||||||
'title' => t('Add child page'),
|
'title' => t('Add child page'),
|
||||||
'href' => 'node/add/' . $child_type,
|
'href' => 'node/add/' . $child_type,
|
||||||
|
|
|
||||||
|
|
@ -203,9 +203,9 @@ function content_translation_entity_operation_alter(array &$operations, \Drupal\
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_menu_link_defaults_alter().
|
* Implements hook_menu_links_discovered_alter().
|
||||||
*/
|
*/
|
||||||
function content_translation_menu_link_defaults_alter(array &$links) {
|
function content_translation_menu_links_discovered_alter(array &$links) {
|
||||||
// Clarify where translation settings are located.
|
// Clarify where translation settings are located.
|
||||||
$links['language.content_settings_page']['title'] = 'Content language and translation';
|
$links['language.content_settings_page']['title'] = 'Content language and translation';
|
||||||
$links['language.content_settings_page']['description'] = 'Configure language and translation support for content.';
|
$links['language.content_settings_page']['description'] = 'Configure language and translation support for content.';
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class ContentTranslationSettingsTest extends WebTestBase {
|
||||||
* Tests that the settings UI works as expected.
|
* Tests that the settings UI works as expected.
|
||||||
*/
|
*/
|
||||||
function testSettingsUI() {
|
function testSettingsUI() {
|
||||||
// Check for the content_translation_menu_link_defaults_alter() changes.
|
// Check for the content_translation_menu_links_discovered_alter() changes.
|
||||||
$this->drupalGet('admin/config');
|
$this->drupalGet('admin/config');
|
||||||
$this->assertLink('Content language and translation');
|
$this->assertLink('Content language and translation');
|
||||||
$this->assertText('Configure language and translation support for content.');
|
$this->assertText('Configure language and translation support for content.');
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ function dblog_help($route_name, RouteMatchInterface $route_match) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_menu_link_defaults_alter().
|
* Implements hook_menu_links_discovered_alter().
|
||||||
*/
|
*/
|
||||||
function dblog_menu_link_defaults_alter(&$links) {
|
function dblog_menu_links_discovered_alter(&$links) {
|
||||||
if (\Drupal::moduleHandler()->moduleExists('search')) {
|
if (\Drupal::moduleHandler()->moduleExists('search')) {
|
||||||
$links['dblog.search'] = array(
|
$links['dblog.search'] = array(
|
||||||
'title' => 'Top search phrases',
|
'title' => 'Top search phrases',
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,12 @@ function editor_help($route_name, RouteMatchInterface $route_match) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_menu_link_defaults_alter().
|
* Implements hook_menu_links_discovered_alter().
|
||||||
*
|
*
|
||||||
* Rewrites the menu entries for filter module that relate to the configuration
|
* Rewrites the menu entries for filter module that relate to the configuration
|
||||||
* of text editors.
|
* of text editors.
|
||||||
*/
|
*/
|
||||||
function editor_menu_link_defaults_alter(array &$links) {
|
function editor_menu_links_discovered_alter(array &$links) {
|
||||||
$links['filter.admin_overview']['title'] = 'Text formats and editors';
|
$links['filter.admin_overview']['title'] = 'Text formats and editors';
|
||||||
$links['filter.admin_overview']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
|
$links['filter.admin_overview']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
namespace Drupal\entity\Controller;
|
namespace Drupal\entity\Controller;
|
||||||
|
|
||||||
use Drupal\Core\Controller\ControllerBase;
|
use Drupal\Core\Controller\ControllerBase;
|
||||||
|
use Drupal\Core\Url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides methods for entity display mode routes.
|
* Provides methods for entity display mode routes.
|
||||||
|
|
@ -26,7 +27,7 @@ class EntityDisplayModeController extends ControllerBase {
|
||||||
if ($entity_type->isFieldable() && $entity_type->hasViewBuilderClass()) {
|
if ($entity_type->isFieldable() && $entity_type->hasViewBuilderClass()) {
|
||||||
$entity_types[$entity_type_id] = array(
|
$entity_types[$entity_type_id] = array(
|
||||||
'title' => $entity_type->getLabel(),
|
'title' => $entity_type->getLabel(),
|
||||||
'link_path' => 'admin/structure/display-modes/view/add/' . $entity_type_id,
|
'url' => new Url('entity.view_mode_add_type', array('entity_type_id' => $entity_type_id)),
|
||||||
'localized_options' => array(),
|
'localized_options' => array(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +50,7 @@ class EntityDisplayModeController extends ControllerBase {
|
||||||
if ($entity_type->isFieldable() && $entity_type->hasFormClasses()) {
|
if ($entity_type->isFieldable() && $entity_type->hasFormClasses()) {
|
||||||
$entity_types[$entity_type_id] = array(
|
$entity_types[$entity_type_id] = array(
|
||||||
'title' => $entity_type->getLabel(),
|
'title' => $entity_type->getLabel(),
|
||||||
'link_path' => 'admin/structure/display-modes/form/add/' . $entity_type_id,
|
'url' => new Url('entity.form_mode_add_type', array('entity_type_id' => $entity_type_id)),
|
||||||
'localized_options' => array(),
|
'localized_options' => array(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,8 +125,7 @@ class HelpController extends ControllerBase {
|
||||||
if (!empty($admin_tasks)) {
|
if (!empty($admin_tasks)) {
|
||||||
$links = array();
|
$links = array();
|
||||||
foreach ($admin_tasks as $task) {
|
foreach ($admin_tasks as $task) {
|
||||||
$link = $task['localized_options'];
|
$link = $task['url']->toArray();
|
||||||
$link['href'] = $task['link_path'];
|
|
||||||
$link['title'] = $task['title'];
|
$link['title'] = $task['title'];
|
||||||
$links[] = $link;
|
$links[] = $link;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class LanguageConfigSchemaTest extends WebTestBase {
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('language');
|
public static $modules = array('language', 'menu_link_content');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user with administrative permissions.
|
* A user with administrative permissions.
|
||||||
|
|
@ -55,8 +55,8 @@ class LanguageConfigSchemaTest extends WebTestBase {
|
||||||
$settings_path = 'admin/config/regional/content-language';
|
$settings_path = 'admin/config/regional/content-language';
|
||||||
|
|
||||||
// Enable translation for menu link.
|
// Enable translation for menu link.
|
||||||
$edit['entity_types[menu_link]'] = TRUE;
|
$edit['entity_types[menu_link_content]'] = TRUE;
|
||||||
$edit['settings[menu_link][menu_link][settings][language][language_show]'] = TRUE;
|
$edit['settings[menu_link_content][menu_link_content][settings][language][language_show]'] = TRUE;
|
||||||
|
|
||||||
// Enable translation for user.
|
// Enable translation for user.
|
||||||
$edit['entity_types[user]'] = TRUE;
|
$edit['entity_types[user]'] = TRUE;
|
||||||
|
|
@ -67,7 +67,7 @@ class LanguageConfigSchemaTest extends WebTestBase {
|
||||||
|
|
||||||
$config_data = \Drupal::config('language.settings')->get();
|
$config_data = \Drupal::config('language.settings')->get();
|
||||||
// Make sure configuration saved correctly.
|
// Make sure configuration saved correctly.
|
||||||
$this->assertTrue($config_data['entities']['menu_link']['menu_link']['language']['default_configuration']['language_show']);
|
$this->assertTrue($config_data['entities']['menu_link_content']['menu_link_content']['language']['default_configuration']['language_show']);
|
||||||
|
|
||||||
$this->assertConfigSchema(\Drupal::service('config.typed'), 'language.settings', $config_data);
|
$this->assertConfigSchema(\Drupal::service('config.typed'), 'language.settings', $config_data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class LocaleLocaleLookupTest extends WebTestBase {
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('locale', 'menu_link');
|
public static $modules = array('locale');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests hasTranslation().
|
* Tests hasTranslation().
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
name: Menu Link
|
|
||||||
type: module
|
|
||||||
description: Provides menu links.
|
|
||||||
package: Core
|
|
||||||
version: VERSION
|
|
||||||
core: 8.x
|
|
||||||
# @todo Menu links functionality has been moved from system.module and menu.inc
|
|
||||||
# to this module, so make it required until everything is moved over.
|
|
||||||
required: TRUE
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Install, update and uninstall functions for the menu_link_content module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_uninstall().
|
||||||
|
*/
|
||||||
|
function menu_link_content_uninstall() {
|
||||||
|
// Find all the entities and then call the manager and delete all the plugins.
|
||||||
|
$query = \Drupal::entityQueryAggregate('menu_link_content');
|
||||||
|
$query->groupBy('uuid');
|
||||||
|
$result = $query->execute();
|
||||||
|
$uuids = array();
|
||||||
|
foreach ($result as $row) {
|
||||||
|
$uuids[] = $row['uuid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
|
foreach ($uuids as $uuid) {
|
||||||
|
// Manually build the plugin ID, and remove it from the menu tree.
|
||||||
|
$menu_link_manager->removeDefinition("menu_link_content:$uuid", FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,8 +5,29 @@
|
||||||
* Allows administrators to create custom menu links.
|
* Allows administrators to create custom menu links.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
use Drupal\system\MenuInterface;
|
use Drupal\system\MenuInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_help().
|
||||||
|
*/
|
||||||
|
function menu_link_content_help($route_name, RouteMatchInterface $route_match) {
|
||||||
|
switch ($route_name) {
|
||||||
|
case 'help.page.menu_link_content':
|
||||||
|
$output = '';
|
||||||
|
$output .= '<h3>' . t('About') . '</h3>';
|
||||||
|
$output .= '<p>' . t('The Custom Menu Links module allows users to create menu links. These links can be translated if multiple languages are used for the site.');
|
||||||
|
if (\Drupal::moduleHandler()->moduleExists('menu_ui')) {
|
||||||
|
$output .= ' ' . t('It is required by the Menu UI module, which provides an interface for managing menus and menu links. See the <a href="!menu-help">Menu UI module help page</a> for more information.', array('!menu-help' => \Drupal::url('help.page', array('name' => 'menu_ui'))));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$output .= ' ' . t('If you enable the Menu UI module, it provides an interface for managing menus and menu links.');
|
||||||
|
}
|
||||||
|
$output .= '</p>';
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_menu_delete().
|
* Implements hook_menu_delete().
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ menu_link_content.link_edit:
|
||||||
defaults:
|
defaults:
|
||||||
_entity_form: 'menu_link_content.default'
|
_entity_form: 'menu_link_content.default'
|
||||||
_title: 'Edit menu link'
|
_title: 'Edit menu link'
|
||||||
|
options:
|
||||||
|
# @todo Remove once https://www.drupal.org/node/2310475 is in.
|
||||||
|
_admin_route: TRUE
|
||||||
requirements:
|
requirements:
|
||||||
_entity_access: 'menu_link_content.update'
|
_entity_access: 'menu_link_content.update'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,13 +144,6 @@ class MenuLinkContentForm extends ContentEntityForm implements MenuLinkFormInter
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function buildConfigurationForm(array $form, array &$form_state) {
|
public function buildConfigurationForm(array $form, array &$form_state) {
|
||||||
return $this->buildEditForm($form, $form_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function buildEditForm(array &$form, array &$form_state) {
|
|
||||||
$this->setOperation('default');
|
$this->setOperation('default');
|
||||||
$this->init($form_state);
|
$this->init($form_state);
|
||||||
|
|
||||||
|
|
@ -164,29 +157,13 @@ class MenuLinkContentForm extends ContentEntityForm implements MenuLinkFormInter
|
||||||
$this->doValidate($form, $form_state);
|
$this->doValidate($form, $form_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function validateEditForm(array &$form, array &$form_state) {
|
|
||||||
$this->doValidate($form, $form_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function submitConfigurationForm(array &$form, array &$form_state) {
|
public function submitConfigurationForm(array &$form, array &$form_state) {
|
||||||
return $this->submitEditForm($form, $form_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function submitEditForm(array &$form, array &$form_state) {
|
|
||||||
// Remove button and internal Form API values from submitted values.
|
// Remove button and internal Form API values from submitted values.
|
||||||
form_state_values_clean($form_state);
|
parent::submit($form, $form_state);
|
||||||
$this->entity = $this->buildEntity($form, $form_state);
|
$this->save($form, $form_state);
|
||||||
$this->entity->save();
|
|
||||||
return $form_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -234,7 +211,7 @@ class MenuLinkContentForm extends ContentEntityForm implements MenuLinkFormInter
|
||||||
*/
|
*/
|
||||||
public function extractFormValues(array &$form, array &$form_state) {
|
public function extractFormValues(array &$form, array &$form_state) {
|
||||||
$new_definition = array();
|
$new_definition = array();
|
||||||
$new_definition['expanded'] = !empty($form_state['values']['expanded']) ? 1 : 0;
|
$new_definition['expanded'] = !empty($form_state['values']['expanded']['value']) ? 1 : 0;
|
||||||
$new_definition['hidden'] = empty($form_state['values']['enabled']) ? 1 : 0;
|
$new_definition['hidden'] = empty($form_state['values']['enabled']) ? 1 : 0;
|
||||||
list($menu_name, $parent) = explode(':', $form_state['values']['menu_parent'], 2);
|
list($menu_name, $parent) = explode(':', $form_state['values']['menu_parent'], 2);
|
||||||
if (!empty($menu_name)) {
|
if (!empty($menu_name)) {
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,19 @@
|
||||||
* Administrative page callbacks for Menu UI module.
|
* Administrative page callbacks for Menu UI module.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Drupal\Component\Utility\SafeMarkup;
|
||||||
use Drupal\Core\Render\Element;
|
use Drupal\Core\Render\Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns HTML for the menu overview form into a table.
|
* Returns HTML for the menu overview form into a table.
|
||||||
*
|
*
|
||||||
* @param $variables
|
* @param array $variables
|
||||||
* An associative array containing:
|
* An associative array containing:
|
||||||
* - form: A render element representing the form.
|
* - form: A render element representing the form.
|
||||||
*
|
*
|
||||||
|
* @return string
|
||||||
|
* The themed HTML.
|
||||||
|
*
|
||||||
* @ingroup themeable
|
* @ingroup themeable
|
||||||
*/
|
*/
|
||||||
function theme_menu_overview_form($variables) {
|
function theme_menu_overview_form($variables) {
|
||||||
|
|
@ -27,27 +31,28 @@ function theme_menu_overview_form($variables) {
|
||||||
);
|
);
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
foreach (Element::children($form) as $mlid) {
|
foreach (Element::children($form) as $id) {
|
||||||
if (isset($form[$mlid]['hidden'])) {
|
if (isset($form[$id]['#item'])) {
|
||||||
$element = &$form[$mlid];
|
$element = &$form[$id];
|
||||||
|
|
||||||
// Add special classes to be used for tabledrag.js.
|
// Add special classes to be used for tabledrag.js.
|
||||||
$element['plid']['#attributes']['class'] = array('menu-plid');
|
$element['parent']['#attributes']['class'] = array('menu-parent');
|
||||||
$element['mlid']['#attributes']['class'] = array('menu-mlid');
|
$element['id']['#attributes']['class'] = array('menu-id');
|
||||||
$element['weight']['#attributes']['class'] = array('menu-weight');
|
$element['weight']['#attributes']['class'] = array('menu-weight');
|
||||||
|
|
||||||
// Change the parent field to a hidden. This allows any value but hides the field.
|
// Change the parent field to a hidden. This allows any value but hides
|
||||||
$element['plid']['#type'] = 'hidden';
|
// the field.
|
||||||
|
$element['parent']['#type'] = 'hidden';
|
||||||
|
|
||||||
$indent = array(
|
$indent = array(
|
||||||
'#theme' => 'indentation',
|
'#theme' => 'indentation',
|
||||||
'#size' => $element['#item']['depth'] - 1,
|
'#size' => $element['#item']->depth - 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
$row = array();
|
$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['hidden']), 'class' => array('checkbox', 'menu-enabled'));
|
$row[] = array('data' => drupal_render($element['enabled']), 'class' => array('checkbox', 'menu-enabled'));
|
||||||
$row[] = drupal_render($element['weight']) . drupal_render($element['plid']) . drupal_render($element['mlid']);
|
$row[] = SafeMarkup::set(drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['id']));
|
||||||
$row[] = drupal_render($element['operations']);
|
$row[] = drupal_render($element['operations']);
|
||||||
|
|
||||||
$row = array_merge(array('data' => $row), $element['#attributes']);
|
$row = array_merge(array('data' => $row), $element['#attributes']);
|
||||||
|
|
@ -71,11 +76,11 @@ function theme_menu_overview_form($variables) {
|
||||||
array(
|
array(
|
||||||
'action' => 'match',
|
'action' => 'match',
|
||||||
'relationship' => 'parent',
|
'relationship' => 'parent',
|
||||||
'group' => 'menu-plid',
|
'group' => 'menu-parent',
|
||||||
'subgroup' => 'menu-plid',
|
'subgroup' => 'menu-parent',
|
||||||
'source' => 'menu-mlid',
|
'source' => 'menu-id',
|
||||||
'hidden' => TRUE,
|
'hidden' => TRUE,
|
||||||
'limit' => MENU_MAX_DEPTH - 1,
|
'limit' => \Drupal::menuTree()->maxDepth() - 1,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'action' => 'order',
|
'action' => 'order',
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,4 @@ version: VERSION
|
||||||
core: 8.x
|
core: 8.x
|
||||||
configure: menu_ui.overview_page
|
configure: menu_ui.overview_page
|
||||||
dependencies:
|
dependencies:
|
||||||
- menu_link
|
- menu_link_content
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
menu_ui_link_add:
|
menu_ui.link_add:
|
||||||
route_name: menu_ui.link_add
|
route_name: menu_link_content.link_add
|
||||||
title: 'Add link'
|
title: 'Add link'
|
||||||
|
class: \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd
|
||||||
appears_on:
|
appears_on:
|
||||||
- menu_ui.menu_edit
|
- menu_ui.menu_edit
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@
|
||||||
|
|
||||||
use Drupal\Core\Entity\EntityInterface;
|
use Drupal\Core\Entity\EntityInterface;
|
||||||
use Drupal\block\BlockPluginInterface;
|
use Drupal\block\BlockPluginInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkInterface;
|
||||||
use Drupal\Core\Render\Element;
|
use Drupal\Core\Render\Element;
|
||||||
use Drupal\Core\Routing\RouteMatchInterface;
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
|
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||||
use Drupal\node\NodeTypeInterface;
|
use Drupal\node\NodeTypeInterface;
|
||||||
use Drupal\system\Entity\Menu;
|
use Drupal\system\Entity\Menu;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Drupal\menu_link\Entity\MenuLink;
|
|
||||||
use Drupal\menu_link\MenuLinkStorage;
|
|
||||||
use Drupal\node\NodeInterface;
|
use Drupal\node\NodeInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,31 +72,11 @@ function menu_ui_entity_type_build(array &$entity_types) {
|
||||||
->setFormClass('edit', 'Drupal\menu_ui\MenuForm')
|
->setFormClass('edit', 'Drupal\menu_ui\MenuForm')
|
||||||
->setFormClass('delete', 'Drupal\menu_ui\Form\MenuDeleteForm')
|
->setFormClass('delete', 'Drupal\menu_ui\Form\MenuDeleteForm')
|
||||||
->setListBuilderClass('Drupal\menu_ui\MenuListBuilder')
|
->setListBuilderClass('Drupal\menu_ui\MenuListBuilder')
|
||||||
->setLinkTemplate('add-form', 'menu_ui.link_add')
|
->setLinkTemplate('add-form', 'menu_ui.menu_add')
|
||||||
->setLinkTemplate('delete-form', 'menu_ui.delete_menu')
|
->setLinkTemplate('delete-form', 'menu_ui.delete_menu')
|
||||||
->setLinkTemplate('edit-form', 'menu_ui.menu_edit');
|
->setLinkTemplate('edit-form', 'menu_ui.menu_edit');
|
||||||
|
|
||||||
$entity_types['menu_link']
|
|
||||||
->setFormClass('delete', 'Drupal\menu_ui\Form\MenuLinkDeleteForm')
|
|
||||||
->setFormClass('reset', 'Drupal\menu_ui\Form\MenuLinkResetForm')
|
|
||||||
->setLinkTemplate('delete-form', 'menu_ui.link_delete');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_entity_bundle_info().
|
|
||||||
*/
|
|
||||||
function menu_ui_entity_bundle_info() {
|
|
||||||
$bundles = array();
|
|
||||||
$config_names = \Drupal::configFactory()->listAll('system.menu.');
|
|
||||||
foreach ($config_names as $config_name) {
|
|
||||||
$config = \Drupal::config($config_name);
|
|
||||||
$bundles['menu_link'][$config->get('id')] = array(
|
|
||||||
'label' => $config->get('label'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bundles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_theme().
|
* Implements hook_theme().
|
||||||
|
|
@ -119,23 +99,6 @@ function menu_ui_menu_insert(Menu $menu) {
|
||||||
if (\Drupal::moduleHandler()->moduleExists('block')) {
|
if (\Drupal::moduleHandler()->moduleExists('block')) {
|
||||||
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
|
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($menu->isSyncing()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the menu is present in the active menus variable so that its
|
|
||||||
// items may appear in the menu active trail.
|
|
||||||
// See menu_set_active_menu_names().
|
|
||||||
$config = \Drupal::config('system.menu');
|
|
||||||
|
|
||||||
$active_menus = $config->get('active_menus_default') ?: array_keys(menu_ui_get_menus());
|
|
||||||
if (!in_array($menu->id(), $active_menus)) {
|
|
||||||
$active_menus[] = $menu->id();
|
|
||||||
$config
|
|
||||||
->set('active_menus_default', $active_menus)
|
|
||||||
->save();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -154,20 +117,9 @@ function menu_ui_menu_update(Menu $menu) {
|
||||||
*/
|
*/
|
||||||
function menu_ui_menu_predelete(Menu $menu) {
|
function menu_ui_menu_predelete(Menu $menu) {
|
||||||
// Delete all links from the menu.
|
// Delete all links from the menu.
|
||||||
menu_delete_links($menu->id());
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
// Remove menu from active menus variable.
|
$menu_link_manager->deleteLinksInMenu($menu->id());
|
||||||
$config = \Drupal::config('system.menu');
|
|
||||||
$active_menus = $config->get('active_menus_default') ?: array_keys(menu_ui_get_menus());
|
|
||||||
if (in_array($menu->id(), $active_menus)) {
|
|
||||||
$active_menus = array_diff($active_menus, array($menu->id()));
|
|
||||||
// Prevent the gap left by the removed menu from causing array indices to
|
|
||||||
// be saved.
|
|
||||||
$active_menus = array_values($active_menus);
|
|
||||||
$config
|
|
||||||
->set('active_menus_default', $active_menus)
|
|
||||||
->save();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -182,103 +134,6 @@ function menu_ui_menu_delete(Menu $menu) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of menu links that are valid possible parents for the given
|
|
||||||
* menu link.
|
|
||||||
*
|
|
||||||
* @param array $menus
|
|
||||||
* An array of menu names and titles, such as from menu_ui_get_menus().
|
|
||||||
* @param \Drupal\menu_link\Entity\MenuLink $menu_link
|
|
||||||
* The menu link for which to generate a list of parents.
|
|
||||||
* If $menu_link->id() == 0 then the complete tree is returned.
|
|
||||||
* @param string $type
|
|
||||||
* The node type for which to generate a list of parents.
|
|
||||||
* If $item itself is a node type then $type is ignored.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* An array of menu link titles keyed by a string containing the menu name and
|
|
||||||
* mlid. The list excludes the given item and its children.
|
|
||||||
*
|
|
||||||
* @todo This has to be turned into a #process form element callback. The
|
|
||||||
* 'override_parent_selector' variable is entirely superfluous.
|
|
||||||
*/
|
|
||||||
function menu_ui_parent_options(array $menus, MenuLink $menu_link = NULL, $type = NULL) {
|
|
||||||
// The menu_links table can be practically any size and we need a way to
|
|
||||||
// allow contrib modules to provide more scalable pattern choosers.
|
|
||||||
// hook_form_alter is too late in itself because all the possible parents are
|
|
||||||
// retrieved here, unless override_parent_selector is set to TRUE.
|
|
||||||
if (\Drupal::config('menu_ui.settings')->get('override_parent_selector')) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$menu_link) {
|
|
||||||
$menu_link = entity_create('menu_link', array('mlid' => 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
$available_menus = array();
|
|
||||||
if (!$type) {
|
|
||||||
// If no node type is set, use all menus given to this function.
|
|
||||||
$available_menus = $menus;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// If a node type is set, use all available menus for this type.
|
|
||||||
$type_menus = \Drupal::config("menu.entity.node.$type")->get('available_menus');
|
|
||||||
foreach ($type_menus as $menu) {
|
|
||||||
$available_menus[$menu] = $menu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _menu_ui_get_options($menus, $available_menus, $menu_link);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to get the items of the given menu.
|
|
||||||
*/
|
|
||||||
function _menu_ui_get_options($menus, $available_menus, $item) {
|
|
||||||
// If the item has children, there is an added limit to the depth of valid parents.
|
|
||||||
if (isset($item['parent_depth_limit'])) {
|
|
||||||
$limit = $item['parent_depth_limit'];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$limit = _menu_ui_parent_depth_limit($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
|
|
||||||
$menu_tree = \Drupal::service('menu_link.tree');
|
|
||||||
|
|
||||||
$options = array();
|
|
||||||
foreach ($menus as $menu_name => $title) {
|
|
||||||
if (isset($available_menus[$menu_name])) {
|
|
||||||
$tree = $menu_tree->buildAllData($menu_name, NULL);
|
|
||||||
$options[$menu_name . ':0'] = '<' . $title . '>';
|
|
||||||
_menu_ui_parents_recurse($tree, $menu_name, '--', $options, $item['mlid'], $limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursive helper function for menu_ui_parent_options().
|
|
||||||
*/
|
|
||||||
function _menu_ui_parents_recurse($tree, $menu_name, $indent, &$options, $exclude, $depth_limit) {
|
|
||||||
foreach ($tree as $data) {
|
|
||||||
if ($data['link']['depth'] > $depth_limit) {
|
|
||||||
// Don't iterate through any links on this level.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($data['link']['mlid'] != $exclude && $data['link']['hidden'] >= 0) {
|
|
||||||
$title = $indent . ' ' . truncate_utf8($data['link']['title'], 30, TRUE, FALSE);
|
|
||||||
if ($data['link']['hidden']) {
|
|
||||||
$title .= ' (' . t('disabled') . ')';
|
|
||||||
}
|
|
||||||
$options[$menu_name . ':' . $data['link']['mlid']] = $title;
|
|
||||||
if ($data['below']) {
|
|
||||||
_menu_ui_parents_recurse($data['below'], $menu_name, $indent . '--', $options, $exclude, $depth_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_block_view_BASE_BLOCK_ID_alter() for 'system_menu_block'.
|
* Implements hook_block_view_BASE_BLOCK_ID_alter() for 'system_menu_block'.
|
||||||
*/
|
*/
|
||||||
|
|
@ -286,7 +141,7 @@ function menu_ui_block_view_system_menu_block_alter(array &$build, BlockPluginIn
|
||||||
// Add contextual links for system menu blocks.
|
// Add contextual links for system menu blocks.
|
||||||
$menus = menu_list_system_menus();
|
$menus = menu_list_system_menus();
|
||||||
$menu_name = $block->getDerivativeId();
|
$menu_name = $block->getDerivativeId();
|
||||||
if (isset($menus[$menu_name])) {
|
if (isset($menus[$menu_name]) && isset($build['content'])) {
|
||||||
$build['#contextual_links']['menu'] = array(
|
$build['#contextual_links']['menu'] = array(
|
||||||
'route_parameters' => array('menu' => $menu_name),
|
'route_parameters' => array('menu' => $menu_name),
|
||||||
);
|
);
|
||||||
|
|
@ -316,7 +171,7 @@ function menu_ui_node_type_insert(NodeTypeInterface $type) {
|
||||||
}
|
}
|
||||||
\Drupal::config('menu.entity.node.' . $type->id())
|
\Drupal::config('menu.entity.node.' . $type->id())
|
||||||
->set('available_menus', array('main'))
|
->set('available_menus', array('main'))
|
||||||
->set('parent', 'main:0')
|
->set('parent', 'main:')
|
||||||
->save();
|
->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,25 +189,35 @@ function menu_ui_node_type_delete(NodeTypeInterface $type) {
|
||||||
* Helper for hook_ENTITY_TYPE_insert() and hook_ENTITY_TYPE_update() for nodes.
|
* Helper for hook_ENTITY_TYPE_insert() and hook_ENTITY_TYPE_update() for nodes.
|
||||||
*/
|
*/
|
||||||
function menu_ui_node_save(EntityInterface $node) {
|
function menu_ui_node_save(EntityInterface $node) {
|
||||||
if (isset($node->menu)) {
|
if (!empty($node->menu)) {
|
||||||
$link = &$node->menu;
|
/** @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface $entity */
|
||||||
if (empty($link['enabled'])) {
|
$definition = $node->menu;
|
||||||
if (!$link->isNew()) {
|
if (trim($definition['title'])) {
|
||||||
menu_link_delete($link['mlid']);
|
if (!empty($definition['entity_id'])) {
|
||||||
}
|
$entity = entity_load('menu_link_content', $definition['entity_id']);
|
||||||
}
|
$entity->hidden->value = 0;
|
||||||
elseif (trim($link['link_title'])) {
|
$entity->title->value = trim($definition['title']);
|
||||||
$link['link_title'] = trim($link['link_title']);
|
$entity->description->value = trim($definition['description']);
|
||||||
$link['link_path'] = 'node/' . $node->id();
|
$entity->menu_name->value = $definition['menu_name'];
|
||||||
if (trim($link['description'])) {
|
$entity->parent->value = $definition['parent'];
|
||||||
$link['options']['attributes']['title'] = trim($link['description']);
|
$entity->weight->value = isset($definition['weight']) ? $definition['weight'] : 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If the description field was left empty, remove the title attribute
|
// Create a new menu_link_content entity.
|
||||||
// from the menu link.
|
$entity = entity_create('menu_link_content', array(
|
||||||
unset($link['options']['attributes']['title']);
|
'title' => trim($definition['title']),
|
||||||
|
'description' => trim($definition['description']),
|
||||||
|
'route_name' => 'node.view',
|
||||||
|
'route_parameters' => array('node' => $node->id()),
|
||||||
|
'menu_name' => $definition['menu_name'],
|
||||||
|
'parent' => $definition['parent'],
|
||||||
|
'weight' => isset($definition['weight']) ? $definition['weight'] : 0,
|
||||||
|
'hidden' => 0,
|
||||||
|
'bundle' => 'menu_link_content',
|
||||||
|
'langcode' => $node->getUntranslated()->language()->id,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
if (!menu_link_save($link)) {
|
if (!$entity->save()) {
|
||||||
drupal_set_message(t('There was an error saving the menu link.'), 'error');
|
drupal_set_message(t('There was an error saving the menu link.'), 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -363,14 +228,17 @@ function menu_ui_node_save(EntityInterface $node) {
|
||||||
* Implements hook_ENTITY_TYPE_predelete() for node entities.
|
* Implements hook_ENTITY_TYPE_predelete() for node entities.
|
||||||
*/
|
*/
|
||||||
function menu_ui_node_predelete(EntityInterface $node) {
|
function menu_ui_node_predelete(EntityInterface $node) {
|
||||||
// Delete all Menu UI module links that point to this node.
|
// Delete all MenuLinkContent links that point to this node.
|
||||||
$query = \Drupal::entityQuery('menu_link')
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
->condition('link_path', 'node/' . $node->id())
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
->condition('module', 'menu');
|
$result = $menu_link_manager->loadLinksByRoute('node.view', array('node' => $node->id()));
|
||||||
$result = $query->execute();
|
|
||||||
|
|
||||||
if (!empty($result)) {
|
if (!empty($result)) {
|
||||||
menu_link_delete_multiple($result);
|
foreach ($result as $id => $instance) {
|
||||||
|
if ($instance->isDeletable() && strpos($id, 'menu_link_content:') === 0) {
|
||||||
|
$instance->deleteLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,64 +246,66 @@ function menu_ui_node_predelete(EntityInterface $node) {
|
||||||
* Implements hook_node_prepare_form().
|
* Implements hook_node_prepare_form().
|
||||||
*/
|
*/
|
||||||
function menu_ui_node_prepare_form(NodeInterface $node, $operation, array &$form_state) {
|
function menu_ui_node_prepare_form(NodeInterface $node, $operation, array &$form_state) {
|
||||||
if (empty($node->menu)) {
|
if (empty($form_state['menu_link_definition'])) {
|
||||||
// Prepare the node for the edit form so that $node->menu always exists.
|
// Prepare the node for the edit form so that $node->menu always exists.
|
||||||
$node_type_config = \Drupal::config('menu.entity.node.' . $node->getType());
|
$node_type_config = \Drupal::config('menu.entity.node.' . $node->getType());
|
||||||
$menu_name = strtok($node_type_config->get('parent'), ':');
|
$menu_name = strtok($node_type_config->get('parent'), ':');
|
||||||
$menu_link = FALSE;
|
$definition = FALSE;
|
||||||
if ($node->id()) {
|
if ($node->id()) {
|
||||||
$mlid = FALSE;
|
$id = FALSE;
|
||||||
// Give priority to the default menu
|
// Give priority to the default menu
|
||||||
$type_menus = $node_type_config->get('available_menus');
|
$type_menus = $node_type_config->get('available_menus');
|
||||||
if (in_array($menu_name, $type_menus)) {
|
if (in_array($menu_name, $type_menus)) {
|
||||||
$query = \Drupal::entityQuery('menu_link')
|
$query = \Drupal::entityQuery('menu_link_content')
|
||||||
->condition('link_path', 'node/' . $node->id())
|
->condition('route_name', 'node.view')
|
||||||
|
->condition('route_parameters', serialize(array('node' => $node->id())))
|
||||||
->condition('menu_name', $menu_name)
|
->condition('menu_name', $menu_name)
|
||||||
->condition('module', 'menu_ui')
|
->sort('id', 'ASC')
|
||||||
->sort('mlid', 'ASC')
|
|
||||||
->range(0, 1);
|
->range(0, 1);
|
||||||
$result = $query->execute();
|
$result = $query->execute();
|
||||||
|
|
||||||
$mlid = (!empty($result)) ? reset($result) : FALSE;
|
$id = (!empty($result)) ? reset($result) : FALSE;
|
||||||
}
|
}
|
||||||
// Check all allowed menus if a link does not exist in the default menu.
|
// Check all allowed menus if a link does not exist in the default menu.
|
||||||
if (!$mlid && !empty($type_menus)) {
|
if (!$id && !empty($type_menus)) {
|
||||||
$query = \Drupal::entityQuery('menu_link')
|
$query = \Drupal::entityQuery('menu_link_content')
|
||||||
->condition('link_path', 'node/' . $node->id())
|
->condition('route_name', 'node.view')
|
||||||
|
->condition('route_parameters', serialize(array('node' => $node->id())))
|
||||||
->condition('menu_name', array_values($type_menus), 'IN')
|
->condition('menu_name', array_values($type_menus), 'IN')
|
||||||
->condition('module', 'menu_ui')
|
->sort('id', 'ASC')
|
||||||
->sort('mlid', 'ASC')
|
|
||||||
->range(0, 1);
|
->range(0, 1);
|
||||||
$result = $query->execute();
|
$result = $query->execute();
|
||||||
|
|
||||||
$mlid = (!empty($result)) ? reset($result) : FALSE;
|
$id = (!empty($result)) ? reset($result) : FALSE;
|
||||||
}
|
}
|
||||||
if ($mlid) {
|
if ($id) {
|
||||||
$menu_link = menu_link_load($mlid);
|
$menu_link = MenuLinkContent::load($id);
|
||||||
|
$definition = array(
|
||||||
|
'entity_id' => $menu_link->id(),
|
||||||
|
'id' => $menu_link->getPluginId(),
|
||||||
|
'title' => $menu_link->getTitle(),
|
||||||
|
'description' => $menu_link->getDescription(),
|
||||||
|
'menu_name' => $menu_link->getMenuName(),
|
||||||
|
'parent' => $menu_link->getParentId(),
|
||||||
|
'weight' => $menu_link->getWeight(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$menu_link) {
|
if (!$definition) {
|
||||||
$menu_link = entity_create('menu_link', array(
|
$definition = array(
|
||||||
'mlid' => 0,
|
'entity_id' => 0,
|
||||||
'plid' => 0,
|
'id' => '',
|
||||||
|
'title' => '',
|
||||||
|
'description' => '',
|
||||||
'menu_name' => $menu_name,
|
'menu_name' => $menu_name,
|
||||||
));
|
'parent' => '',
|
||||||
|
'weight' => 0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Set default values.
|
// Set default values.
|
||||||
$node->menu = $menu_link;
|
$form_state['menu_link_definition'] = $definition;
|
||||||
}
|
}
|
||||||
// Find the depth limit for the parent select.
|
|
||||||
if (!isset($node->menu['parent_depth_limit'])) {
|
|
||||||
$node->menu['parent_depth_limit'] = _menu_ui_parent_depth_limit($node->menu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the depth limit for items in the parent select.
|
|
||||||
*/
|
|
||||||
function _menu_ui_parent_depth_limit($item) {
|
|
||||||
return MENU_MAX_DEPTH - 1 - (($item['mlid'] && $item['has_children']) ? entity_get_controller('menu_link')->findChildrenRelativeDepth($item) : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -449,11 +319,25 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
|
||||||
// Generate a list of possible parents (not including this link or descendants).
|
// Generate a list of possible parents (not including this link or descendants).
|
||||||
// @todo This must be handled in a #process handler.
|
// @todo This must be handled in a #process handler.
|
||||||
$node = $form_state['controller']->getEntity();
|
$node = $form_state['controller']->getEntity();
|
||||||
$link = $node->menu;
|
$definition = $form_state['menu_link_definition'];
|
||||||
$type = $node->getType();
|
$type = $node->getType();
|
||||||
$options = menu_ui_parent_options(menu_ui_get_menus(), $link, $type);
|
/** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
|
||||||
|
$menu_parent_selector = \Drupal::service('menu.parent_form_selector');
|
||||||
|
$menu_names = menu_ui_get_menus();
|
||||||
|
$type_menus = \Drupal::config("menu.entity.node.$type")->get('available_menus');
|
||||||
|
$available_menus = array();
|
||||||
|
foreach ($type_menus as $menu) {
|
||||||
|
$available_menus[$menu] = $menu_names[$menu];
|
||||||
|
}
|
||||||
|
if ($definition['id']) {
|
||||||
|
$default = $definition['menu_name'] . ':' . $definition['parent'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$default = \Drupal::config('menu.entity.node.'.$type)->get('parent');
|
||||||
|
}
|
||||||
|
$parent_element = $menu_parent_selector->parentSelectElement($default, $definition['id'], $available_menus);
|
||||||
// If no possible parent menu items were found, there is nothing to display.
|
// If no possible parent menu items were found, there is nothing to display.
|
||||||
if (empty($options)) {
|
if (empty($parent_element)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -461,7 +345,7 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
|
||||||
'#type' => 'details',
|
'#type' => 'details',
|
||||||
'#title' => t('Menu settings'),
|
'#title' => t('Menu settings'),
|
||||||
'#access' => \Drupal::currentUser()->hasPermission('administer menu'),
|
'#access' => \Drupal::currentUser()->hasPermission('administer menu'),
|
||||||
'#open' => !empty($link['link_title']),
|
'#open' => (bool) $definition['id'],
|
||||||
'#group' => 'advanced',
|
'#group' => 'advanced',
|
||||||
'#attached' => array(
|
'#attached' => array(
|
||||||
'library' => array('menu/drupal.menu'),
|
'library' => array('menu/drupal.menu'),
|
||||||
|
|
@ -473,7 +357,7 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
|
||||||
$form['menu']['enabled'] = array(
|
$form['menu']['enabled'] = array(
|
||||||
'#type' => 'checkbox',
|
'#type' => 'checkbox',
|
||||||
'#title' => t('Provide a menu link'),
|
'#title' => t('Provide a menu link'),
|
||||||
'#default_value' => (int) (bool) $link['mlid'],
|
'#default_value' => (int) (bool) $definition['id'],
|
||||||
);
|
);
|
||||||
$form['menu']['link'] = array(
|
$form['menu']['link'] = array(
|
||||||
'#type' => 'container',
|
'#type' => 'container',
|
||||||
|
|
@ -486,57 +370,32 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Populate the element with the link data.
|
// Populate the element with the link data.
|
||||||
foreach (array('mlid', 'module', 'hidden', 'has_children', 'customized', 'options', 'expanded', 'hidden', 'parent_depth_limit') as $key) {
|
foreach (array('id', 'entity_id') as $key) {
|
||||||
$form['menu']['link'][$key] = array('#type' => 'value', '#value' => $link[$key]);
|
$form['menu']['link'][$key] = array('#type' => 'value', '#value' => $definition[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$form['menu']['link']['link_title'] = array(
|
$form['menu']['link']['title'] = array(
|
||||||
'#type' => 'textfield',
|
'#type' => 'textfield',
|
||||||
'#title' => t('Menu link title'),
|
'#title' => t('Menu link title'),
|
||||||
'#default_value' => $link['link_title'],
|
'#default_value' => $definition['title'],
|
||||||
);
|
);
|
||||||
|
|
||||||
$form['menu']['link']['description'] = array(
|
$form['menu']['link']['description'] = array(
|
||||||
'#type' => 'textarea',
|
'#type' => 'textarea',
|
||||||
'#title' => t('Description'),
|
'#title' => t('Description'),
|
||||||
'#default_value' => isset($link['options']['attributes']['title']) ? $link['options']['attributes']['title'] : '',
|
'#default_value' => $definition['description'],
|
||||||
'#rows' => 1,
|
'#rows' => 1,
|
||||||
'#description' => t('Shown when hovering over the menu link.'),
|
'#description' => t('Shown when hovering over the menu link.'),
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($link['mlid']) {
|
$form['menu']['link']['menu_parent'] = $parent_element;
|
||||||
$default = $link['menu_name'] . ':' . $link['plid'];
|
$form['menu']['link']['menu_parent']['#title'] = t('Parent item');
|
||||||
}
|
$form['menu']['link']['menu_parent']['#attributes']['class'][] = 'menu-parent-select';
|
||||||
else {
|
|
||||||
$default = \Drupal::config('menu.entity.node.'.$type)->get('parent');
|
|
||||||
}
|
|
||||||
// If the current parent menu item is not present in options, use the first
|
|
||||||
// available option as default value.
|
|
||||||
// @todo User should not be allowed to access menu link settings in such a
|
|
||||||
// case.
|
|
||||||
if (!isset($options[$default])) {
|
|
||||||
$array = array_keys($options);
|
|
||||||
$default = reset($array);
|
|
||||||
}
|
|
||||||
$form['menu']['link']['parent'] = array(
|
|
||||||
'#type' => 'select',
|
|
||||||
'#title' => t('Parent item'),
|
|
||||||
'#default_value' => $default,
|
|
||||||
'#options' => $options,
|
|
||||||
'#attributes' => array('class' => array('menu-parent-select')),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get number of items in menu so the weight selector is sized appropriately.
|
|
||||||
$delta = entity_get_controller('menu_link')->countMenuLinks($link->menu_name);
|
|
||||||
if ($delta < 50) {
|
|
||||||
// Old hardcoded value
|
|
||||||
$delta = 50;
|
|
||||||
}
|
|
||||||
$form['menu']['link']['weight'] = array(
|
$form['menu']['link']['weight'] = array(
|
||||||
'#type' => 'weight',
|
'#type' => 'number',
|
||||||
'#title' => t('Weight'),
|
'#title' => t('Weight'),
|
||||||
'#delta' => $delta,
|
'#default_value' => $definition['weight'],
|
||||||
'#default_value' => $link['weight'],
|
|
||||||
'#description' => t('Menu links with lower weights are displayed before links with higher weights.'),
|
'#description' => t('Menu links with lower weights are displayed before links with higher weights.'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -548,18 +407,26 @@ function menu_ui_form_node_form_alter(&$form, $form_state) {
|
||||||
*/
|
*/
|
||||||
function menu_ui_node_submit(EntityInterface $node, $form, $form_state) {
|
function menu_ui_node_submit(EntityInterface $node, $form, $form_state) {
|
||||||
if (!empty($form_state['values']['menu'])) {
|
if (!empty($form_state['values']['menu'])) {
|
||||||
$original_menu_id = !empty($node->menu) ? $node->menu->id() : NULL;
|
$definition = $form_state['values']['menu'];
|
||||||
$node->menu = entity_create('menu_link', $form_state['values']['menu']);
|
if (empty($definition['enabled'])) {
|
||||||
// @todo Do not create a new entity in order to update it, see
|
if ($definition['entity_id']) {
|
||||||
// https://drupal.org/node/2241865
|
$entity = entity_load('menu_link_content', $definition['entity_id']);
|
||||||
// If this menu had a previous menu link associated, mark it as not new.
|
$entity->delete();
|
||||||
if ($original_menu_id) {
|
|
||||||
$node->menu->setOriginalId($original_menu_id);
|
|
||||||
}
|
}
|
||||||
// Decompose the selected menu parent option into 'menu_name' and 'plid', if
|
}
|
||||||
// the form used the default parent selection widget.
|
elseif (trim($definition['title'])) {
|
||||||
if (!empty($form_state['values']['menu']['parent'])) {
|
// Decompose the selected menu parent option into 'menu_name' and 'parent',
|
||||||
list($node->menu['menu_name'], $node->menu['plid']) = explode(':', $form_state['values']['menu']['parent']);
|
// if the form used the default parent selection widget.
|
||||||
|
if (!empty($definition['menu_parent'])) {
|
||||||
|
list($menu_name, $parent) = explode(':', $definition['menu_parent'], 2);
|
||||||
|
$definition['menu_name'] = $menu_name;
|
||||||
|
$definition['parent'] = $parent;
|
||||||
|
}
|
||||||
|
// @todo Figure out how to save this data without adding non-Field API
|
||||||
|
// properties to the node entity. https://www.drupal.org/node/2310173
|
||||||
|
// We have to tack this onto the node so we can save it later when we
|
||||||
|
// have a node ID for any new node.
|
||||||
|
$node->menu = $definition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -573,6 +440,8 @@ function menu_ui_node_submit(EntityInterface $node, $form, $form_state) {
|
||||||
* @see menu_ui_form_node_type_form_submit().
|
* @see menu_ui_form_node_type_form_submit().
|
||||||
*/
|
*/
|
||||||
function menu_ui_form_node_type_form_alter(&$form, $form_state) {
|
function menu_ui_form_node_type_form_alter(&$form, $form_state) {
|
||||||
|
/** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
|
||||||
|
$menu_parent_selector = \Drupal::service('menu.parent_form_selector');
|
||||||
$menu_options = menu_ui_get_menus();
|
$menu_options = menu_ui_get_menus();
|
||||||
$type = $form_state['controller']->getEntity();
|
$type = $form_state['controller']->getEntity();
|
||||||
if ($type->id()) {
|
if ($type->id()) {
|
||||||
|
|
@ -581,7 +450,7 @@ function menu_ui_form_node_type_form_alter(&$form, $form_state) {
|
||||||
else {
|
else {
|
||||||
$config_values = array(
|
$config_values = array(
|
||||||
'available_menus' => array('main'),
|
'available_menus' => array('main'),
|
||||||
'parent' => 'main:0',
|
'parent' => 'main:',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$form['menu'] = array(
|
$form['menu'] = array(
|
||||||
|
|
@ -599,12 +468,12 @@ function menu_ui_form_node_type_form_alter(&$form, $form_state) {
|
||||||
'#options' => $menu_options,
|
'#options' => $menu_options,
|
||||||
'#description' => t('The menus available to place links in for this content type.'),
|
'#description' => t('The menus available to place links in for this content type.'),
|
||||||
);
|
);
|
||||||
|
// @todo See if we can avoid pre-loading all options by changing the form or
|
||||||
|
// using a #process callback. https://www.drupal.org/node/2310319
|
||||||
// To avoid an 'illegal option' error after saving the form we have to load
|
// To avoid an 'illegal option' error after saving the form we have to load
|
||||||
// all available menu items.
|
// all available menu parents. Otherwise, it is not possible to dynamically
|
||||||
// Otherwise it is not possible to dynamically add options to the list.
|
// add options to the list using ajax.
|
||||||
// @todo Convert menu_ui_parent_options() into a #process callback.
|
$options = $menu_parent_selector->getParentSelectOptions('');
|
||||||
$menu_link = entity_create('menu_link', array('mlid' => 0));
|
|
||||||
$options = menu_ui_parent_options(menu_ui_get_menus(), $menu_link);
|
|
||||||
$form['menu']['menu_parent'] = array(
|
$form['menu']['menu_parent'] = array(
|
||||||
'#type' => 'select',
|
'#type' => 'select',
|
||||||
'#title' => t('Default parent item'),
|
'#title' => t('Default parent item'),
|
||||||
|
|
@ -636,7 +505,8 @@ function menu_ui_form_node_type_form_submit(&$form, $form_state) {
|
||||||
* @param $all
|
* @param $all
|
||||||
* If FALSE return only user-added menus, or if TRUE also include
|
* If FALSE return only user-added menus, or if TRUE also include
|
||||||
* the menus defined by the system.
|
* the menus defined by the system.
|
||||||
* @return
|
*
|
||||||
|
* @return array
|
||||||
* An array with the machine-readable names as the keys, and human-readable
|
* An array with the machine-readable names as the keys, and human-readable
|
||||||
* titles as the values.
|
* titles as the values.
|
||||||
*/
|
*/
|
||||||
|
|
@ -661,3 +531,19 @@ function menu_ui_preprocess_block(&$variables) {
|
||||||
$variables['attributes']['role'] = 'navigation';
|
$variables['attributes']['role'] = 'navigation';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_system_breadcrumb_alter().
|
||||||
|
*/
|
||||||
|
function menu_ui_system_breadcrumb_alter(array &$breadcrumb, RouteMatchInterface $route_match, array $context) {
|
||||||
|
// Custom breadcrumb behavior for editing menu links, we append a link to
|
||||||
|
// the menu in which the link is found.
|
||||||
|
if (($route_match->getRouteName() == 'menu_ui.link_edit') && $menu_link = $route_match->getParameter('menu_link_plugin')) {
|
||||||
|
if (($menu_link instanceof MenuLinkInterface)) {
|
||||||
|
// Add a link to the menu admin screen.
|
||||||
|
$menu = entity_load('menu', $menu_link->getMenuName());
|
||||||
|
$breadcrumb[] = \Drupal::l($menu->label(), 'menu_ui.menu_edit', array('menu' => $menu->id()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,37 +21,30 @@ menu_ui.parent_options_js:
|
||||||
requirements:
|
requirements:
|
||||||
_permission: 'administer menu'
|
_permission: 'administer menu'
|
||||||
|
|
||||||
menu_ui.link_add:
|
|
||||||
path: '/admin/structure/menu/manage/{menu}/add'
|
|
||||||
defaults:
|
|
||||||
_content: '\Drupal\menu_ui\Controller\MenuController::addLink'
|
|
||||||
_title: 'Add menu link'
|
|
||||||
requirements:
|
|
||||||
_entity_create_access: 'menu_link'
|
|
||||||
|
|
||||||
menu_ui.link_edit:
|
menu_ui.link_edit:
|
||||||
path: '/admin/structure/menu/item/{menu_link}/edit'
|
path: '/admin/structure/menu/link/{menu_link_plugin}/edit'
|
||||||
defaults:
|
defaults:
|
||||||
_entity_form: 'menu_link'
|
_form: 'Drupal\menu_ui\Form\MenuLinkEditForm'
|
||||||
_title: 'Edit menu link'
|
_title: 'Edit menu link'
|
||||||
|
options:
|
||||||
|
parameters:
|
||||||
|
menu_link_plugin:
|
||||||
|
type: menu_link_plugin
|
||||||
requirements:
|
requirements:
|
||||||
_entity_access: 'menu_link.update'
|
_permission: 'administer menu'
|
||||||
|
|
||||||
menu_ui.link_reset:
|
menu_ui.link_reset:
|
||||||
path: '/admin/structure/menu/item/{menu_link}/reset'
|
path: '/admin/structure/menu/link/{menu_link_plugin}/reset'
|
||||||
defaults:
|
defaults:
|
||||||
_entity_form: 'menu_link.reset'
|
_form: 'Drupal\menu_ui\Form\MenuLinkResetForm'
|
||||||
_title: 'Reset menu link'
|
_title: 'Reset menu link'
|
||||||
|
options:
|
||||||
|
parameters:
|
||||||
|
menu_link_plugin:
|
||||||
|
type: menu_link_plugin
|
||||||
requirements:
|
requirements:
|
||||||
_entity_access: 'menu_link.reset'
|
_permission: 'administer menu'
|
||||||
|
_custom_access: '\Drupal\menu_ui\Form\MenuLinkResetForm::linkIsResettable'
|
||||||
menu_ui.link_delete:
|
|
||||||
path: '/admin/structure/menu/item/{menu_link}/delete'
|
|
||||||
defaults:
|
|
||||||
_entity_form: 'menu_link.delete'
|
|
||||||
_title: 'Delete menu link'
|
|
||||||
requirements:
|
|
||||||
_entity_access: 'menu_link.delete'
|
|
||||||
|
|
||||||
menu_ui.menu_add:
|
menu_ui.menu_add:
|
||||||
path: '/admin/structure/menu/add'
|
path: '/admin/structure/menu/add'
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ namespace Drupal\menu_ui\Controller;
|
||||||
|
|
||||||
use Drupal\Component\Utility\Xss;
|
use Drupal\Component\Utility\Xss;
|
||||||
use Drupal\Core\Controller\ControllerBase;
|
use Drupal\Core\Controller\ControllerBase;
|
||||||
|
use Drupal\Core\Menu\MenuParentFormSelectorInterface;
|
||||||
use Drupal\system\MenuInterface;
|
use Drupal\system\MenuInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
|
@ -18,6 +20,30 @@ use Symfony\Component\HttpFoundation\Request;
|
||||||
*/
|
*/
|
||||||
class MenuController extends ControllerBase {
|
class MenuController extends ControllerBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu parent form service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuParentFormSelectorInterface
|
||||||
|
*/
|
||||||
|
protected $menuParentSelector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new MenuController object.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_form
|
||||||
|
* The menu parent form service.
|
||||||
|
*/
|
||||||
|
public function __construct(MenuParentFormSelectorInterface $menu_parent_form) {
|
||||||
|
$this->menuParentSelector = $menu_parent_form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container) {
|
||||||
|
return new static($container->get('menu.parent_form_selector'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all the available menus and menu items as a JavaScript array.
|
* Gets all the available menus and menu items as a JavaScript array.
|
||||||
*
|
*
|
||||||
|
|
@ -34,29 +60,11 @@ class MenuController extends ControllerBase {
|
||||||
$available_menus[$menu] = $menu;
|
$available_menus[$menu] = $menu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$options = _menu_ui_get_options(menu_ui_get_menus(), $available_menus, array('mlid' => 0));
|
$options = $this->menuParentSelector->getParentSelectOptions('', $available_menus);
|
||||||
|
|
||||||
return new JsonResponse($options);
|
return new JsonResponse($options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the menu link submission form.
|
|
||||||
*
|
|
||||||
* @param \Drupal\system\MenuInterface $menu
|
|
||||||
* An entity representing a custom menu.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* Returns the menu link submission form.
|
|
||||||
*/
|
|
||||||
public function addLink(MenuInterface $menu) {
|
|
||||||
$menu_link = $this->entityManager()->getStorage('menu_link')->create(array(
|
|
||||||
'mlid' => 0,
|
|
||||||
'plid' => 0,
|
|
||||||
'menu_name' => $menu->id(),
|
|
||||||
));
|
|
||||||
return $this->entityFormBuilder()->getForm($menu_link);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route title callback.
|
* Route title callback.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Drupal\menu_ui\Form;
|
||||||
|
|
||||||
use Drupal\Core\Database\Connection;
|
use Drupal\Core\Database\Connection;
|
||||||
use Drupal\Core\Entity\EntityConfirmFormBase;
|
use Drupal\Core\Entity\EntityConfirmFormBase;
|
||||||
use Drupal\Core\Entity\EntityStorageInterface;
|
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||||
use Drupal\Core\Url;
|
use Drupal\Core\Url;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
|
@ -19,11 +19,11 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
class MenuDeleteForm extends EntityConfirmFormBase {
|
class MenuDeleteForm extends EntityConfirmFormBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The menu link storage.
|
* The menu link manager.
|
||||||
*
|
*
|
||||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
||||||
*/
|
*/
|
||||||
protected $storage;
|
protected $menuLinkManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The database connection.
|
* The database connection.
|
||||||
|
|
@ -35,13 +35,13 @@ class MenuDeleteForm extends EntityConfirmFormBase {
|
||||||
/**
|
/**
|
||||||
* Constructs a new MenuDeleteForm.
|
* Constructs a new MenuDeleteForm.
|
||||||
*
|
*
|
||||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
||||||
* The menu link storage.
|
* The menu link manager.
|
||||||
* @param \Drupal\Core\Database\Connection $connection
|
* @param \Drupal\Core\Database\Connection $connection
|
||||||
* The database connection.
|
* The database connection.
|
||||||
*/
|
*/
|
||||||
public function __construct(EntityStorageInterface $storage, Connection $connection) {
|
public function __construct(MenuLinkManagerInterface $menu_link_manager, Connection $connection) {
|
||||||
$this->storage = $storage;
|
$this->menuLinkManager = $menu_link_manager;
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ class MenuDeleteForm extends EntityConfirmFormBase {
|
||||||
*/
|
*/
|
||||||
public static function create(ContainerInterface $container) {
|
public static function create(ContainerInterface $container) {
|
||||||
return new static(
|
return new static(
|
||||||
$container->get('entity.manager')->getStorage('menu_link'),
|
$container->get('plugin.manager.menu.link'),
|
||||||
$container->get('database')
|
$container->get('database')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +74,7 @@ class MenuDeleteForm extends EntityConfirmFormBase {
|
||||||
*/
|
*/
|
||||||
public function getDescription() {
|
public function getDescription() {
|
||||||
$caption = '';
|
$caption = '';
|
||||||
$num_links = $this->storage->countMenuLinks($this->entity->id());
|
$num_links = $this->menuLinkManager->countMenuLinks($this->entity->id());
|
||||||
if ($num_links) {
|
if ($num_links) {
|
||||||
$caption .= '<p>' . format_plural($num_links, '<strong>Warning:</strong> There is currently 1 menu link in %title. It will be deleted (system-defined items will be reset).', '<strong>Warning:</strong> There are currently @count menu links in %title. They will be deleted (system-defined links will be reset).', array('%title' => $this->entity->label())) . '</p>';
|
$caption .= '<p>' . format_plural($num_links, '<strong>Warning:</strong> There is currently 1 menu link in %title. It will be deleted (system-defined items will be reset).', '<strong>Warning:</strong> There are currently @count menu links in %title. They will be deleted (system-defined links will be reset).', array('%title' => $this->entity->label())) . '</p>';
|
||||||
}
|
}
|
||||||
|
|
@ -100,21 +100,16 @@ class MenuDeleteForm extends EntityConfirmFormBase {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset all the menu links defined by the menu_link.static service.
|
|
||||||
$result = \Drupal::entityQuery('menu_link')
|
|
||||||
->condition('menu_name', $this->entity->id())
|
|
||||||
->condition('module', '', '>')
|
|
||||||
->condition('machine_name', '', '>')
|
|
||||||
->sort('depth', 'ASC')
|
|
||||||
->execute();
|
|
||||||
$menu_links = $this->storage->loadMultiple($result);
|
|
||||||
foreach ($menu_links as $link) {
|
|
||||||
$link->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete all links to the overview page for this menu.
|
// Delete all links to the overview page for this menu.
|
||||||
$menu_links = $this->storage->loadByProperties(array('link_path' => 'admin/structure/menu/manage/' . $this->entity->id()));
|
// @todo Add a more generic helper function to the menu link plugin
|
||||||
menu_link_delete_multiple(array_keys($menu_links));
|
// manager to remove links to a entity or other ID used as a route
|
||||||
|
// parameter that is being removed. Also, consider moving this to
|
||||||
|
// menu_ui.module as part of a generic response to entity deletion.
|
||||||
|
// https://www.drupal.org/node/2310329
|
||||||
|
$menu_links = $this->menuLinkManager->loadLinksByRoute('menu_ui.menu_edit', array('menu' => $this->entity->id()), TRUE);
|
||||||
|
foreach ($menu_links as $id => $link) {
|
||||||
|
$this->menuLinkManager->removeDefinition($id);
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the custom menu and all its menu links.
|
// Delete the custom menu and all its menu links.
|
||||||
$this->entity->delete();
|
$this->entity->delete();
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Contains \Drupal\menu_ui\Form\MenuLinkDeleteForm.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Drupal\menu_ui\Form;
|
|
||||||
|
|
||||||
use Drupal\Core\Entity\EntityConfirmFormBase;
|
|
||||||
use Drupal\Core\Url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines a confirmation form for deletion of a single menu link.
|
|
||||||
*/
|
|
||||||
class MenuLinkDeleteForm extends EntityConfirmFormBase {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getQuestion() {
|
|
||||||
return t('Are you sure you want to delete the custom menu link %item?', array('%item' => $this->entity->link_title));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getCancelUrl() {
|
|
||||||
return new Url('menu_ui.menu_edit', array(
|
|
||||||
'menu' => $this->entity->menu_name,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function submit(array $form, array &$form_state) {
|
|
||||||
menu_link_delete($this->entity->id());
|
|
||||||
$t_args = array('%title' => $this->entity->link_title);
|
|
||||||
drupal_set_message(t('The menu link %title has been deleted.', $t_args));
|
|
||||||
watchdog('menu', 'Deleted menu link %title.', $t_args, WATCHDOG_NOTICE);
|
|
||||||
$form_state['redirect_route'] = $this->getCancelUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -22,7 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
class MenuLinkEditForm extends FormBase {
|
class MenuLinkEditForm extends FormBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class resolver
|
* The class resolver.
|
||||||
*
|
*
|
||||||
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface
|
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,63 @@
|
||||||
|
|
||||||
namespace Drupal\menu_ui\Form;
|
namespace Drupal\menu_ui\Form;
|
||||||
|
|
||||||
use Drupal\Core\Entity\EntityConfirmFormBase;
|
|
||||||
use Drupal\Core\Url;
|
use Drupal\Core\Url;
|
||||||
|
use Drupal\Core\Form\ConfirmFormBase;
|
||||||
|
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkInterface;
|
||||||
|
use Drupal\Core\Routing\Access\AccessInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a confirmation form for resetting a single modified menu link.
|
* Defines a confirmation form for resetting a single modified menu link.
|
||||||
*/
|
*/
|
||||||
class MenuLinkResetForm extends EntityConfirmFormBase {
|
class MenuLinkResetForm extends ConfirmFormBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu link manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
||||||
|
*/
|
||||||
|
protected $menuLinkManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu link.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuLinkInterface
|
||||||
|
*/
|
||||||
|
protected $link;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a MenuLinkResetForm object.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
||||||
|
* The menu link manager.
|
||||||
|
*/
|
||||||
|
public function __construct(MenuLinkManagerInterface $menu_link_manager) {
|
||||||
|
$this->menuLinkManager = $menu_link_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container) {
|
||||||
|
return new static(
|
||||||
|
$container->get('plugin.manager.menu.link')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getFormId() {
|
||||||
|
return 'menu_link_reset_confirm';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getQuestion() {
|
public function getQuestion() {
|
||||||
return t('Are you sure you want to reset the link %item to its default values?', array('%item' => $this->entity->link_title));
|
return $this->t('Are you sure you want to reset the link %item to its default values?', array('%item' => $this->link->getTitle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -27,7 +71,7 @@ class MenuLinkResetForm extends EntityConfirmFormBase {
|
||||||
*/
|
*/
|
||||||
public function getCancelUrl() {
|
public function getCancelUrl() {
|
||||||
return new Url('menu_ui.menu_edit', array(
|
return new Url('menu_ui.menu_edit', array(
|
||||||
'menu' => $this->entity->menu_name,
|
'menu' => $this->link->getMenuName(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,23 +79,47 @@ class MenuLinkResetForm extends EntityConfirmFormBase {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getDescription() {
|
public function getDescription() {
|
||||||
return t('Any customizations will be lost. This action cannot be undone.');
|
return $this->t('Any customizations will be lost. This action cannot be undone.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getConfirmText() {
|
public function getConfirmText() {
|
||||||
return t('Reset');
|
return $this->t('Reset');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function submit(array $form, array &$form_state) {
|
public function buildForm(array $form, array &$form_state, MenuLinkInterface $menu_link_plugin = NULL) {
|
||||||
$this->entity = $this->entity->reset();
|
$this->link = $menu_link_plugin;
|
||||||
drupal_set_message(t('The menu link was reset to its default settings.'));
|
|
||||||
|
$form = parent::buildForm($form, $form_state);
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function submitForm(array &$form, array &$form_state) {
|
||||||
|
$this->link = $this->menuLinkManager->resetLink($this->link->getPluginId());
|
||||||
|
drupal_set_message($this->t('The menu link was reset to its default settings.'));
|
||||||
$form_state['redirect_route'] = $this->getCancelUrl();
|
$form_state['redirect_route'] = $this->getCancelUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks access based on whether the link can be reset.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin
|
||||||
|
* The menu link plugin being checked.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* AccessInterface::ALLOW when access was granted, otherwise
|
||||||
|
* AccessInterface::DENY.
|
||||||
|
*/
|
||||||
|
public function linkIsResettable(MenuLinkInterface $menu_link_plugin) {
|
||||||
|
return $menu_link_plugin->isResettable() ? AccessInterface::ALLOW : AccessInterface::DENY;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,13 @@ use Drupal\Component\Utility\NestedArray;
|
||||||
use Drupal\Core\Entity\EntityForm;
|
use Drupal\Core\Entity\EntityForm;
|
||||||
use Drupal\Core\Entity\Query\QueryFactory;
|
use Drupal\Core\Entity\Query\QueryFactory;
|
||||||
use Drupal\Core\Language\LanguageInterface;
|
use Drupal\Core\Language\LanguageInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkTreeElement;
|
||||||
|
use Drupal\Core\Menu\MenuLinkTreeInterface;
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
use Drupal\Core\Render\Element;
|
use Drupal\Core\Render\Element;
|
||||||
use Drupal\menu_link\MenuLinkStorageInterface;
|
use Drupal\Core\Routing\UrlGeneratorTrait;
|
||||||
use Drupal\menu_link\MenuTreeInterface;
|
use Drupal\Core\Utility\LinkGeneratorInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -29,19 +33,26 @@ class MenuForm extends EntityForm {
|
||||||
protected $entityQueryFactory;
|
protected $entityQueryFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The menu link storage.
|
* The menu link manager.
|
||||||
*
|
*
|
||||||
* @var \Drupal\menu_link\MenuLinkStorageInterface
|
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
||||||
*/
|
*/
|
||||||
protected $menuLinkStorage;
|
protected $menuLinkManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The menu tree service.
|
* The menu tree service.
|
||||||
*
|
*
|
||||||
* @var \Drupal\menu_link\MenuTreeInterface
|
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||||
*/
|
*/
|
||||||
protected $menuTree;
|
protected $menuTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The link generator.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Utility\LinkGeneratorInterface
|
||||||
|
*/
|
||||||
|
protected $linkGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The overview tree form.
|
* The overview tree form.
|
||||||
*
|
*
|
||||||
|
|
@ -54,15 +65,18 @@ class MenuForm extends EntityForm {
|
||||||
*
|
*
|
||||||
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
|
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
|
||||||
* The factory for entity queries.
|
* The factory for entity queries.
|
||||||
* @param \Drupal\menu_link\MenuLinkStorageInterface $menu_link_storage
|
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
||||||
* The menu link storage.
|
* The menu link manager.
|
||||||
* @param \Drupal\menu_link\MenuTreeInterface $menu_tree
|
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
|
||||||
* The menu tree service.
|
* The menu tree service.
|
||||||
|
* @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
|
||||||
|
* The link generator.
|
||||||
*/
|
*/
|
||||||
public function __construct(QueryFactory $entity_query_factory, MenuLinkStorageInterface $menu_link_storage, MenuTreeInterface $menu_tree) {
|
public function __construct(QueryFactory $entity_query_factory, MenuLinkManagerInterface $menu_link_manager, MenuLinkTreeInterface $menu_tree, LinkGeneratorInterface $link_generator) {
|
||||||
$this->entityQueryFactory = $entity_query_factory;
|
$this->entityQueryFactory = $entity_query_factory;
|
||||||
$this->menuLinkStorage = $menu_link_storage;
|
$this->menuLinkManager = $menu_link_manager;
|
||||||
$this->menuTree = $menu_tree;
|
$this->menuTree = $menu_tree;
|
||||||
|
$this->linkGenerator = $link_generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -71,8 +85,9 @@ class MenuForm extends EntityForm {
|
||||||
public static function create(ContainerInterface $container) {
|
public static function create(ContainerInterface $container) {
|
||||||
return new static(
|
return new static(
|
||||||
$container->get('entity.query'),
|
$container->get('entity.query'),
|
||||||
$container->get('entity.manager')->getStorage('menu_link'),
|
$container->get('plugin.manager.menu.link'),
|
||||||
$container->get('menu_link.tree')
|
$container->get('menu.link_tree'),
|
||||||
|
$container->get('link_generator')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,16 +103,16 @@ class MenuForm extends EntityForm {
|
||||||
|
|
||||||
$form['label'] = array(
|
$form['label'] = array(
|
||||||
'#type' => 'textfield',
|
'#type' => 'textfield',
|
||||||
'#title' => t('Title'),
|
'#title' => $this->t('Title'),
|
||||||
'#default_value' => $menu->label(),
|
'#default_value' => $menu->label(),
|
||||||
'#required' => TRUE,
|
'#required' => TRUE,
|
||||||
);
|
);
|
||||||
$form['id'] = array(
|
$form['id'] = array(
|
||||||
'#type' => 'machine_name',
|
'#type' => 'machine_name',
|
||||||
'#title' => t('Menu name'),
|
'#title' => $this->t('Menu name'),
|
||||||
'#default_value' => $menu->id(),
|
'#default_value' => $menu->id(),
|
||||||
'#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI,
|
'#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI,
|
||||||
'#description' => t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'),
|
'#description' => $this->t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'),
|
||||||
'#machine_name' => array(
|
'#machine_name' => array(
|
||||||
'exists' => array($this, 'menuNameExists'),
|
'exists' => array($this, 'menuNameExists'),
|
||||||
'source' => array('label'),
|
'source' => array('label'),
|
||||||
|
|
@ -120,28 +135,11 @@ class MenuForm extends EntityForm {
|
||||||
'#languages' => LanguageInterface::STATE_ALL,
|
'#languages' => LanguageInterface::STATE_ALL,
|
||||||
'#default_value' => $menu->language()->getId(),
|
'#default_value' => $menu->language()->getId(),
|
||||||
);
|
);
|
||||||
// Unlike the menu langcode, the default language configuration for menu
|
|
||||||
// links only works with language module installed.
|
|
||||||
if ($this->moduleHandler->moduleExists('language')) {
|
|
||||||
$form['default_menu_links_language'] = array(
|
|
||||||
'#type' => 'details',
|
|
||||||
'#title' => t('Menu links language'),
|
|
||||||
'#open' => TRUE,
|
|
||||||
);
|
|
||||||
$form['default_menu_links_language']['default_language'] = array(
|
|
||||||
'#type' => 'language_configuration',
|
|
||||||
'#entity_information' => array(
|
|
||||||
'entity_type' => 'menu_link',
|
|
||||||
'bundle' => $menu->id(),
|
|
||||||
),
|
|
||||||
'#default_value' => language_get_default_configuration('menu_link', $menu->id()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add menu links administration form for existing menus.
|
// Add menu links administration form for existing menus.
|
||||||
if (!$menu->isNew() || $menu->isLocked()) {
|
if (!$menu->isNew() || $menu->isLocked()) {
|
||||||
// Form API supports constructing and validating self-contained sections
|
// Form API supports constructing and validating self-contained sections
|
||||||
// within forms, but does not allow to handle the form section's submission
|
// within forms, but does not allow handling the form section's submission
|
||||||
// equally separated yet. Therefore, we use a $form_state key to point to
|
// equally separated yet. Therefore, we use a $form_state key to point to
|
||||||
// the parents of the form section.
|
// the parents of the form section.
|
||||||
// @see self::submitOverviewForm()
|
// @see self::submitOverviewForm()
|
||||||
|
|
@ -169,41 +167,7 @@ class MenuForm extends EntityForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a link assigned to this menu.
|
// Check for a link assigned to this menu.
|
||||||
return $this->entityQueryFactory->get('menu_link')->condition('menu_name', $value)->range(0, 1)->count()->execute();
|
return $this->menuLinkManager->menuNameInUse($value);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function actions(array $form, array &$form_state) {
|
|
||||||
$actions = parent::actions($form, $form_state);
|
|
||||||
|
|
||||||
// Add the language configuration submit handler. This is needed because the
|
|
||||||
// submit button has custom submit handlers.
|
|
||||||
if ($this->moduleHandler->moduleExists('language')) {
|
|
||||||
array_unshift($actions['submit']['#submit'],'language_configuration_element_submit');
|
|
||||||
array_unshift($actions['submit']['#submit'], array($this, 'languageConfigurationSubmit'));
|
|
||||||
}
|
|
||||||
// We cannot leverage the regular submit handler definition because we have
|
|
||||||
// button-specific ones here. Hence we need to explicitly set it for the
|
|
||||||
// submit action, otherwise it would be ignored.
|
|
||||||
if ($this->moduleHandler->moduleExists('content_translation')) {
|
|
||||||
array_unshift($actions['submit']['#submit'], 'content_translation_language_configuration_element_submit');
|
|
||||||
}
|
|
||||||
return $actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submit handler to update the bundle for the default language configuration.
|
|
||||||
*/
|
|
||||||
public function languageConfigurationSubmit(array &$form, array &$form_state) {
|
|
||||||
// Since the machine name is not known yet, and it can be changed anytime,
|
|
||||||
// we have to also update the bundle property for the default language
|
|
||||||
// configuration in order to have the correct bundle value.
|
|
||||||
$form_state['language']['default_language']['bundle'] = $form_state['values']['id'];
|
|
||||||
// Clear cache so new menus (bundles) show on the language settings admin
|
|
||||||
// page.
|
|
||||||
\Drupal::entityManager()->clearCachedBundles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -217,13 +181,13 @@ class MenuForm extends EntityForm {
|
||||||
|
|
||||||
$status = $menu->save();
|
$status = $menu->save();
|
||||||
|
|
||||||
$edit_link = \Drupal::linkGenerator()->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
|
$edit_link = $this->linkGenerator->generateFromUrl($this->t('Edit'), $this->entity->urlInfo());
|
||||||
if ($status == SAVED_UPDATED) {
|
if ($status == SAVED_UPDATED) {
|
||||||
drupal_set_message(t('Menu %label has been updated.', array('%label' => $menu->label())));
|
drupal_set_message($this->t('Menu %label has been updated.', array('%label' => $menu->label())));
|
||||||
watchdog('menu', 'Menu %label has been updated.', array('%label' => $menu->label()), WATCHDOG_NOTICE, $edit_link);
|
watchdog('menu', 'Menu %label has been updated.', array('%label' => $menu->label()), WATCHDOG_NOTICE, $edit_link);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
drupal_set_message(t('Menu %label has been added.', array('%label' => $menu->label())));
|
drupal_set_message($this->t('Menu %label has been added.', array('%label' => $menu->label())));
|
||||||
watchdog('menu', 'Menu %label has been added.', array('%label' => $menu->label()), WATCHDOG_NOTICE, $edit_link);
|
watchdog('menu', 'Menu %label has been added.', array('%label' => $menu->label()), WATCHDOG_NOTICE, $edit_link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,26 +217,30 @@ class MenuForm extends EntityForm {
|
||||||
|
|
||||||
$form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/css/menu.admin.css');
|
$form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/css/menu.admin.css');
|
||||||
|
|
||||||
$links = array();
|
$tree = $this->menuTree->load($this->entity->id(), new MenuTreeParameters());
|
||||||
$query = $this->entityQueryFactory->get('menu_link')
|
|
||||||
->condition('menu_name', $this->entity->id());
|
|
||||||
for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
|
|
||||||
$query->sort('p' . $i, 'ASC');
|
|
||||||
}
|
|
||||||
$result = $query->execute();
|
|
||||||
|
|
||||||
if (!empty($result)) {
|
|
||||||
$links = $this->menuLinkStorage->loadMultiple($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
$delta = max(count($links), 50);
|
|
||||||
// We indicate that a menu administrator is running the menu access check.
|
// We indicate that a menu administrator is running the menu access check.
|
||||||
$this->getRequest()->attributes->set('_menu_admin', TRUE);
|
$this->getRequest()->attributes->set('_menu_admin', TRUE);
|
||||||
$tree = $this->menuTree->buildTreeData($links);
|
$manipulators = array(
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
|
);
|
||||||
|
$tree = $this->menuTree->transform($tree, $manipulators);
|
||||||
$this->getRequest()->attributes->set('_menu_admin', FALSE);
|
$this->getRequest()->attributes->set('_menu_admin', FALSE);
|
||||||
|
|
||||||
|
// Determine the delta; the number of weights to be made available.
|
||||||
|
$count = function(array $tree) {
|
||||||
|
$sum = function ($carry, MenuLinkTreeElement $item) {
|
||||||
|
return $carry + $item->count();
|
||||||
|
};
|
||||||
|
return array_reduce($tree, $sum);
|
||||||
|
};
|
||||||
|
$delta = max($count($tree), 50);
|
||||||
|
|
||||||
$form = array_merge($form, $this->buildOverviewTreeForm($tree, $delta));
|
$form = array_merge($form, $this->buildOverviewTreeForm($tree, $delta));
|
||||||
$form['#empty_text'] = t('There are no menu links yet. <a href="@link">Add link</a>.', array('@link' => url('admin/structure/menu/manage/' . $this->entity->id() .'/add')));
|
$destination = $this->getUrlGenerator()->getPathFromRoute('menu_ui.menu_edit', array('menu' => $this->entity->id()));
|
||||||
|
$url = $destination = $this->url('menu_link_content.link_add', array('menu' => $this->entity->id()), array('query' => array('destination' => $destination)));
|
||||||
|
$form['#empty_text'] = $this->t('There are no menu links yet. <a href="@url">Add link</a>.', array('@url' => $url));
|
||||||
|
|
||||||
return $form;
|
return $form;
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +249,7 @@ class MenuForm extends EntityForm {
|
||||||
* Recursive helper function for buildOverviewForm().
|
* Recursive helper function for buildOverviewForm().
|
||||||
*
|
*
|
||||||
* @param $tree
|
* @param $tree
|
||||||
* The menu_tree retrieved by menu_tree_data.
|
* The tree retrieved by \Drupal\Core\Menu\MenuLinkTreeInterface::load().
|
||||||
* @param $delta
|
* @param $delta
|
||||||
* The default number of menu items used in the menu weight selector is 50.
|
* The default number of menu items used in the menu weight selector is 50.
|
||||||
*
|
*
|
||||||
|
|
@ -290,70 +258,87 @@ class MenuForm extends EntityForm {
|
||||||
*/
|
*/
|
||||||
protected function buildOverviewTreeForm($tree, $delta) {
|
protected function buildOverviewTreeForm($tree, $delta) {
|
||||||
$form = &$this->overviewTreeForm;
|
$form = &$this->overviewTreeForm;
|
||||||
foreach ($tree as $data) {
|
foreach ($tree as $element) {
|
||||||
$item = $data['link'];
|
/** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
||||||
// Don't show callbacks; these have $item['hidden'] < 0.
|
$link = $element->link;
|
||||||
if ($item && $item['hidden'] >= 0) {
|
if ($link) {
|
||||||
$mlid = 'mlid:' . $item['mlid'];
|
$id = 'menu_plugin_id:' . $link->getPluginId();
|
||||||
$form[$mlid]['#item'] = $item;
|
$form[$id]['#item'] = $element;
|
||||||
$form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled'));
|
$form[$id]['#attributes'] = $link->isHidden() ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled'));
|
||||||
$form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']);
|
$form[$id]['title']['#markup'] = $this->linkGenerator->generateFromUrl($link->getTitle(), $link->getUrlObject(), $link->getOptions());
|
||||||
if ($item['hidden']) {
|
if ($link->isHidden()) {
|
||||||
$form[$mlid]['title']['#markup'] .= ' (' . t('disabled') . ')';
|
$form[$id]['title']['#markup'] .= ' (' . $this->t('disabled') . ')';
|
||||||
}
|
}
|
||||||
elseif ($item['link_path'] == 'user' && $item['module'] == 'user') {
|
elseif (($url = $link->getUrlObject()) && !$url->isExternal() && $url->getRouteName() == 'user.page') {
|
||||||
$form[$mlid]['title']['#markup'] .= ' (' . t('logged in users only') . ')';
|
$form[$id]['title']['#markup'] .= ' (' . $this->t('logged in users only') . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
$form[$mlid]['hidden'] = array(
|
$form[$id]['enabled'] = array(
|
||||||
'#type' => 'checkbox',
|
'#type' => 'checkbox',
|
||||||
'#title' => t('Enable @title menu link', array('@title' => $item['title'])),
|
'#title' => $this->t('Enable @title menu link', array('@title' => $link->getTitle())),
|
||||||
'#title_display' => 'invisible',
|
'#title_display' => 'invisible',
|
||||||
'#default_value' => !$item['hidden'],
|
'#default_value' => !$link->isHidden(),
|
||||||
);
|
);
|
||||||
$form[$mlid]['weight'] = array(
|
$form[$id]['weight'] = array(
|
||||||
'#type' => 'weight',
|
'#type' => 'weight',
|
||||||
'#delta' => $delta,
|
'#delta' => $delta,
|
||||||
'#default_value' => $item['weight'],
|
'#default_value' => $link->getWeight(),
|
||||||
'#title' => t('Weight for @title', array('@title' => $item['title'])),
|
'#title' => $this->t('Weight for @title', array('@title' => $link->getTitle())),
|
||||||
'#title_display' => 'invisible',
|
'#title_display' => 'invisible',
|
||||||
);
|
);
|
||||||
$form[$mlid]['mlid'] = array(
|
$form[$id]['id'] = array(
|
||||||
'#type' => 'hidden',
|
'#type' => 'hidden',
|
||||||
'#value' => $item['mlid'],
|
'#value' => $link->getPluginId(),
|
||||||
);
|
);
|
||||||
$form[$mlid]['plid'] = array(
|
$form[$id]['parent'] = array(
|
||||||
'#type' => 'hidden',
|
'#type' => 'hidden',
|
||||||
'#default_value' => $item['plid'],
|
'#default_value' => $link->getParent(),
|
||||||
);
|
);
|
||||||
// Build a list of operations.
|
// Build a list of operations.
|
||||||
$operations = array();
|
$operations = array();
|
||||||
$operations['edit'] = array(
|
$operations['edit'] = array(
|
||||||
'title' => t('Edit'),
|
'title' => $this->t('Edit'),
|
||||||
'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/edit',
|
|
||||||
);
|
);
|
||||||
// Only items created by the Menu UI module can be deleted.
|
// Allow for a custom edit link per plugin.
|
||||||
if ($item->access('delete')) {
|
$edit_route = $link->getEditRoute();
|
||||||
$operations['delete'] = array(
|
if ($edit_route) {
|
||||||
'title' => t('Delete'),
|
$operations['edit'] += $edit_route;
|
||||||
'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/delete',
|
// Bring the user back to the menu overview.
|
||||||
|
$operations['edit']['query']['destination'] = $this->entity->url();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Fall back to the standard edit link.
|
||||||
|
$operations['edit'] += array(
|
||||||
|
'route_name' => 'menu_ui.link_edit',
|
||||||
|
'route_parameters' => array('menu_link_plugin' => $link->getPluginId()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Set the reset column.
|
// Links can either be reset or deleted, not both.
|
||||||
elseif ($item->access('reset')) {
|
if ($link->isResettable()) {
|
||||||
$operations['reset'] = array(
|
$operations['reset'] = array(
|
||||||
'title' => t('Reset'),
|
'title' => $this->t('Reset'),
|
||||||
'href' => 'admin/structure/menu/item/' . $item['mlid'] . '/reset',
|
'route_name' => 'menu_ui.link_reset',
|
||||||
|
'route_parameters' => array('menu_link_plugin' => $link->getPluginId()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$form[$mlid]['operations'] = array(
|
elseif ($delete_link = $link->getDeleteRoute()) {
|
||||||
|
$operations['delete'] = $delete_link;
|
||||||
|
$operations['delete']['query']['destination'] = $this->entity->url();
|
||||||
|
$operations['delete']['title'] = $this->t('Delete');
|
||||||
|
}
|
||||||
|
if ($link->isTranslatable()) {
|
||||||
|
$operations['translate'] = array(
|
||||||
|
'title' => $this->t('Translate'),
|
||||||
|
) + (array) $link->getTranslateRoute();
|
||||||
|
}
|
||||||
|
$form[$id]['operations'] = array(
|
||||||
'#type' => 'operations',
|
'#type' => 'operations',
|
||||||
'#links' => $operations,
|
'#links' => $operations,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($data['below']) {
|
if ($element->subtree) {
|
||||||
$this->buildOverviewTreeForm($data['below'], $delta);
|
$this->buildOverviewTreeForm($element->subtree, $delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $form;
|
return $form;
|
||||||
|
|
@ -363,7 +348,7 @@ class MenuForm extends EntityForm {
|
||||||
* Submit handler for the menu overview form.
|
* Submit handler for the menu overview form.
|
||||||
*
|
*
|
||||||
* This function takes great care in saving parent items first, then items
|
* This function takes great care in saving parent items first, then items
|
||||||
* underneath them. Saving items in the incorrect order can break the menu tree.
|
* underneath them. Saving items in the incorrect order can break the tree.
|
||||||
*/
|
*/
|
||||||
protected function submitOverviewForm(array $complete_form, array &$form_state) {
|
protected function submitOverviewForm(array $complete_form, array &$form_state) {
|
||||||
// Form API supports constructing and validating self-contained sections
|
// Form API supports constructing and validating self-contained sections
|
||||||
|
|
@ -384,31 +369,29 @@ class MenuForm extends EntityForm {
|
||||||
// Update our original form with the new order.
|
// Update our original form with the new order.
|
||||||
$form = array_intersect_key(array_merge($order, $form), $form);
|
$form = array_intersect_key(array_merge($order, $form), $form);
|
||||||
|
|
||||||
$updated_items = array();
|
$fields = array('weight', 'parent', 'enabled');
|
||||||
$fields = array('weight', 'plid');
|
foreach (Element::children($form) as $id) {
|
||||||
foreach (Element::children($form) as $mlid) {
|
if (isset($form[$id]['#item'])) {
|
||||||
if (isset($form[$mlid]['#item'])) {
|
$element = $form[$id];
|
||||||
$element = $form[$mlid];
|
$updated_values = array();
|
||||||
// Update any fields that have changed in this menu item.
|
// Update any fields that have changed in this menu item.
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
if ($element[$field]['#value'] != $element[$field]['#default_value']) {
|
if ($element[$field]['#value'] != $element[$field]['#default_value']) {
|
||||||
$element['#item'][$field] = $element[$field]['#value'];
|
// Hidden is a special case, the form value needs to be reversed.
|
||||||
$updated_items[$mlid] = $element['#item'];
|
if ($field == 'enabled') {
|
||||||
|
$updated_values['hidden'] = $element['enabled']['#value'] ? 0 : 1;
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
// Hidden is a special case, the value needs to be reversed.
|
$updated_values[$field] = $element[$field]['#value'];
|
||||||
if ($element['hidden']['#value'] != $element['hidden']['#default_value']) {
|
|
||||||
// Convert to integer rather than boolean due to PDO cast to string.
|
|
||||||
$element['#item']['hidden'] = $element['hidden']['#value'] ? 0 : 1;
|
|
||||||
$updated_items[$mlid] = $element['#item'];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($updated_values) {
|
||||||
// Save all our changed items to the database.
|
// Use the ID from the actual plugin instance since the hidden value
|
||||||
foreach ($updated_items as $item) {
|
// in the form could be tampered with.
|
||||||
$item['customized'] = 1;
|
$this->menuLinkManager->updateDefinition($element['#item']->link->getPLuginId(), $updated_values);
|
||||||
$item->save();
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\menu_ui\Plugin\Menu\LocalAction;
|
||||||
|
|
||||||
|
use Drupal\Core\Menu\LocalActionDefault;
|
||||||
|
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies the 'Add link' local action to add a destination.
|
||||||
|
*/
|
||||||
|
class MenuLinkAdd extends LocalActionDefault {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getOptions(Request $request) {
|
||||||
|
$options = parent::getOptions($request);
|
||||||
|
// Append the current path as destination to the query string.
|
||||||
|
if ($request->attributes->has(RouteObjectInterface::ROUTE_NAME)) {
|
||||||
|
$route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME);
|
||||||
|
$raw_variables = array();
|
||||||
|
if ($request->attributes->has('_raw_variables')) {
|
||||||
|
$raw_variables = $request->attributes->get('_raw_variables')->all();
|
||||||
|
}
|
||||||
|
// @todo Use RouteMatch instead of Request.
|
||||||
|
// https://www.drupal.org/node/2294157
|
||||||
|
$options['query']['destination'] = \Drupal::urlGenerator()->generateFromRoute($route_name, $raw_variables);
|
||||||
|
}
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* Contains \Drupal\menu\Tests\MenuCacheTagsTest.
|
* Contains \Drupal\menu_ui\Tests\MenuCacheTagsTest.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Drupal\menu_ui\Tests;
|
namespace Drupal\menu_ui\Tests;
|
||||||
|
|
@ -37,12 +37,10 @@ class MenuCacheTagsTest extends PageCacheTagsTestBase {
|
||||||
'description' => 'Description text',
|
'description' => 'Description text',
|
||||||
));
|
));
|
||||||
$menu->save();
|
$menu->save();
|
||||||
$menu_link = entity_create('menu_link', array(
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
'link_path' => '<front>',
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
'link_title' => 'Vicuña',
|
// Move a link into the new menu.
|
||||||
'menu_name' => 'llama',
|
$menu_link = $menu_link_manager->updateDefinition('test_page_test.test_page', array('menu_name' => 'llama', 'parent' => ''));
|
||||||
));
|
|
||||||
$menu_link->save();
|
|
||||||
$block = $this->drupalPlaceBlock('system_menu_block:llama', array('label' => 'Llama', 'provider' => 'system', 'region' => 'footer'));
|
$block = $this->drupalPlaceBlock('system_menu_block:llama', array('label' => 'Llama', 'provider' => 'system', 'region' => 'footer'));
|
||||||
|
|
||||||
// Prime the page cache.
|
// Prime the page cache.
|
||||||
|
|
@ -60,7 +58,6 @@ class MenuCacheTagsTest extends PageCacheTagsTestBase {
|
||||||
);
|
);
|
||||||
$this->verifyPageCache($path, 'HIT', $expected_tags);
|
$this->verifyPageCache($path, 'HIT', $expected_tags);
|
||||||
|
|
||||||
|
|
||||||
// Verify that after modifying the menu, there is a cache miss.
|
// Verify that after modifying the menu, there is a cache miss.
|
||||||
$this->pass('Test modification of menu.', 'Debug');
|
$this->pass('Test modification of menu.', 'Debug');
|
||||||
$menu->label = 'Awesome llama';
|
$menu->label = 'Awesome llama';
|
||||||
|
|
@ -70,23 +67,23 @@ class MenuCacheTagsTest extends PageCacheTagsTestBase {
|
||||||
// Verify a cache hit.
|
// Verify a cache hit.
|
||||||
$this->verifyPageCache($path, 'HIT');
|
$this->verifyPageCache($path, 'HIT');
|
||||||
|
|
||||||
|
// Verify that after modifying the menu link weight, there is a cache miss.
|
||||||
// Verify that after modifying the menu link, there is a cache miss.
|
$menu_link_manager->updateDefinition('test_page_test.test_page', array('weight' => -10));
|
||||||
$this->pass('Test modification of menu link.', 'Debug');
|
$this->pass('Test modification of menu link.', 'Debug');
|
||||||
$menu_link->link_title = 'Guanaco';
|
|
||||||
$menu_link->save();
|
|
||||||
$this->verifyPageCache($path, 'MISS');
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
// Verify a cache hit.
|
// Verify a cache hit.
|
||||||
$this->verifyPageCache($path, 'HIT');
|
$this->verifyPageCache($path, 'HIT');
|
||||||
|
|
||||||
|
|
||||||
// Verify that after adding a menu link, there is a cache miss.
|
// Verify that after adding a menu link, there is a cache miss.
|
||||||
$this->pass('Test addition of menu link.', 'Debug');
|
$this->pass('Test addition of menu link.', 'Debug');
|
||||||
$menu_link_2 = entity_create('menu_link', array(
|
$menu_link_2 = entity_create('menu_link_content', array(
|
||||||
'link_path' => '<front>',
|
'id' => '',
|
||||||
'link_title' => 'Alpaca',
|
'parent' => '',
|
||||||
|
'title' => 'Alpaca',
|
||||||
'menu_name' => 'llama',
|
'menu_name' => 'llama',
|
||||||
|
'route_name' => '<front>',
|
||||||
|
'bundle' => 'menu_name',
|
||||||
));
|
));
|
||||||
$menu_link_2->save();
|
$menu_link_2->save();
|
||||||
$this->verifyPageCache($path, 'MISS');
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
@ -94,16 +91,15 @@ class MenuCacheTagsTest extends PageCacheTagsTestBase {
|
||||||
// Verify a cache hit.
|
// Verify a cache hit.
|
||||||
$this->verifyPageCache($path, 'HIT');
|
$this->verifyPageCache($path, 'HIT');
|
||||||
|
|
||||||
|
// Verify that after resetting the first menu link, there is a cache miss.
|
||||||
// Verify that after deleting the first menu link, there is a cache miss.
|
$this->pass('Test reset of menu link.', 'Debug');
|
||||||
$this->pass('Test deletion of menu link.', 'Debug');
|
$this->assertTrue($menu_link->isResettable(), 'First link can be reset');
|
||||||
$menu_link->delete();
|
$menu_link = $menu_link_manager->resetLink($menu_link->getPluginId());
|
||||||
$this->verifyPageCache($path, 'MISS');
|
$this->verifyPageCache($path, 'MISS');
|
||||||
|
|
||||||
// Verify a cache hit.
|
// Verify a cache hit.
|
||||||
$this->verifyPageCache($path, 'HIT', $expected_tags);
|
$this->verifyPageCache($path, 'HIT', $expected_tags);
|
||||||
|
|
||||||
|
|
||||||
// Verify that after deleting the menu, there is a cache miss.
|
// Verify that after deleting the menu, there is a cache miss.
|
||||||
$this->pass('Test deletion of menu.', 'Debug');
|
$this->pass('Test deletion of menu.', 'Debug');
|
||||||
$menu->delete();
|
$menu->delete();
|
||||||
|
|
|
||||||
|
|
@ -59,21 +59,12 @@ class MenuLanguageTest extends MenuWebTestBase {
|
||||||
'description' => '',
|
'description' => '',
|
||||||
'label' => $label,
|
'label' => $label,
|
||||||
'langcode' => 'aa',
|
'langcode' => 'aa',
|
||||||
'default_language[langcode]' => 'bb',
|
|
||||||
'default_language[language_show]' => TRUE,
|
|
||||||
);
|
);
|
||||||
$this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
|
$this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
|
||||||
|
language_save_default_configuration('menu_link_content', 'menu_link_content', array('langcode' => 'bb', 'language_show' => TRUE));
|
||||||
|
|
||||||
// Check that the language settings were saved.
|
// Check menu language.
|
||||||
$this->assertEqual(entity_load('menu', $menu_name)->language()->getId(), $edit['langcode']);
|
|
||||||
$language_settings = language_get_default_configuration('menu_link', $menu_name);
|
|
||||||
$this->assertEqual($language_settings['langcode'], 'bb');
|
|
||||||
$this->assertEqual($language_settings['language_show'], TRUE);
|
|
||||||
|
|
||||||
// Check menu language and item language configuration.
|
|
||||||
$this->assertOptionSelected('edit-langcode', $edit['langcode'], 'The menu language was correctly selected.');
|
$this->assertOptionSelected('edit-langcode', $edit['langcode'], 'The menu language was correctly selected.');
|
||||||
$this->assertOptionSelected('edit-default-language-langcode', $edit['default_language[langcode]'], 'The menu link default language was correctly selected.');
|
|
||||||
$this->assertFieldChecked('edit-default-language-language-show');
|
|
||||||
|
|
||||||
// Test menu link language.
|
// Test menu link language.
|
||||||
$link_path = '<front>';
|
$link_path = '<front>';
|
||||||
|
|
@ -81,41 +72,35 @@ class MenuLanguageTest extends MenuWebTestBase {
|
||||||
// Add a menu link.
|
// Add a menu link.
|
||||||
$link_title = $this->randomString();
|
$link_title = $this->randomString();
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'link_title' => $link_title,
|
'title[0][value]' => $link_title,
|
||||||
'link_path' => $link_path,
|
'url' => $link_path,
|
||||||
);
|
);
|
||||||
$this->drupalPostForm("admin/structure/menu/manage/$menu_name/add", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/manage/$menu_name/add", $edit, t('Save'));
|
||||||
// Check the link was added with the correct menu link default language.
|
// Check the link was added with the correct menu link default language.
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $link_title));
|
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $link_title));
|
||||||
$menu_link = reset($menu_links);
|
$menu_link = reset($menu_links);
|
||||||
$this->assertMenuLink($menu_link->id(), array(
|
$this->assertMenuLink($menu_link->getPluginId(), array(
|
||||||
'menu_name' => $menu_name,
|
'menu_name' => $menu_name,
|
||||||
'link_path' => $link_path,
|
'route_name' => '<front>',
|
||||||
'langcode' => 'bb',
|
'langcode' => 'bb',
|
||||||
));
|
));
|
||||||
|
|
||||||
// Edit menu link default, changing it to cc.
|
// Edit menu link default, changing it to cc.
|
||||||
$edit = array(
|
language_save_default_configuration('menu_link_content', 'menu_link_content', array('langcode' => 'cc', 'language_show' => TRUE));
|
||||||
'default_language[langcode]' => 'cc',
|
|
||||||
);
|
|
||||||
$this->drupalPostForm("admin/structure/menu/manage/$menu_name", $edit, t('Save'));
|
|
||||||
|
|
||||||
// Check cc is the menu link default.
|
|
||||||
$this->assertOptionSelected('edit-default-language-langcode', $edit['default_language[langcode]'], 'The menu link default language was correctly selected.');
|
|
||||||
|
|
||||||
// Add a menu link.
|
// Add a menu link.
|
||||||
$link_title = $this->randomString();
|
$link_title = $this->randomString();
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'link_title' => $link_title,
|
'title[0][value]' => $link_title,
|
||||||
'link_path' => $link_path,
|
'url' => $link_path,
|
||||||
);
|
);
|
||||||
$this->drupalPostForm("admin/structure/menu/manage/$menu_name/add", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/manage/$menu_name/add", $edit, t('Save'));
|
||||||
// Check the link was added with the correct new menu link default language.
|
// Check the link was added with the correct new menu link default language.
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $link_title));
|
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $link_title));
|
||||||
$menu_link = reset($menu_links);
|
$menu_link = reset($menu_links);
|
||||||
$this->assertMenuLink($menu_link->id(), array(
|
$this->assertMenuLink($menu_link->getPluginId(), array(
|
||||||
'menu_name' => $menu_name,
|
'menu_name' => $menu_name,
|
||||||
'link_path' => $link_path,
|
'route_name' => '<front>',
|
||||||
'langcode' => 'cc',
|
'langcode' => 'cc',
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
@ -124,9 +109,9 @@ class MenuLanguageTest extends MenuWebTestBase {
|
||||||
'langcode' => 'bb',
|
'langcode' => 'bb',
|
||||||
);
|
);
|
||||||
$this->drupalPostForm('admin/structure/menu/item/' . $menu_link->id() . '/edit', $edit, t('Save'));
|
$this->drupalPostForm('admin/structure/menu/item/' . $menu_link->id() . '/edit', $edit, t('Save'));
|
||||||
$this->assertMenuLink($menu_link->id(), array(
|
$this->assertMenuLink($menu_link->getPluginId(), array(
|
||||||
'menu_name' => $menu_name,
|
'menu_name' => $menu_name,
|
||||||
'link_path' => $link_path,
|
'route_name' => '<front>',
|
||||||
'langcode' => 'bb',
|
'langcode' => 'bb',
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
@ -138,16 +123,7 @@ class MenuLanguageTest extends MenuWebTestBase {
|
||||||
$this->assertOptionSelected('edit-langcode', 'bb', 'The menu link language was correctly selected.');
|
$this->assertOptionSelected('edit-langcode', 'bb', 'The menu link language was correctly selected.');
|
||||||
|
|
||||||
// Edit menu to hide the language select on menu link item add.
|
// Edit menu to hide the language select on menu link item add.
|
||||||
$edit = array(
|
language_save_default_configuration('menu_link_content', 'menu_link_content', array('langcode' => 'cc', 'language_show' => FALSE));
|
||||||
'default_language[language_show]' => FALSE,
|
|
||||||
);
|
|
||||||
$this->drupalPostForm("admin/structure/menu/manage/$menu_name", $edit, t('Save'));
|
|
||||||
$this->assertNoFieldChecked('edit-default-language-language-show');
|
|
||||||
|
|
||||||
// Check that the language settings were saved.
|
|
||||||
$language_settings = language_get_default_configuration('menu_link', $menu_name);
|
|
||||||
$this->assertEqual($language_settings['langcode'], 'cc');
|
|
||||||
$this->assertEqual($language_settings['language_show'], FALSE);
|
|
||||||
|
|
||||||
// Check that the language selector is not available on menu link add page.
|
// Check that the language selector is not available on menu link add page.
|
||||||
$this->drupalGet("admin/structure/menu/manage/$menu_name/add");
|
$this->drupalGet("admin/structure/menu/manage/$menu_name/add");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* Definition of Drupal\menu_ui\Tests\MenuNodeTest.
|
* Contains \Drupal\menu_ui\Tests\MenuNodeTest.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Drupal\menu_ui\Tests;
|
namespace Drupal\menu_ui\Tests;
|
||||||
|
|
@ -65,7 +65,7 @@ class MenuNodeTest extends WebTestBase {
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'menu_options[main]' => 1,
|
'menu_options[main]' => 1,
|
||||||
'menu_options[tools]' => 1,
|
'menu_options[tools]' => 1,
|
||||||
'menu_parent' => 'main:0',
|
'menu_parent' => 'main:',
|
||||||
);
|
);
|
||||||
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
|
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ class MenuNodeTest extends WebTestBase {
|
||||||
// Edit the node and create a menu link.
|
// Edit the node and create a menu link.
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'menu[enabled]' => 1,
|
'menu[enabled]' => 1,
|
||||||
'menu[link_title]' => $node_title,
|
'menu[title]' => $node_title,
|
||||||
'menu[weight]' => 17,
|
'menu[weight]' => 17,
|
||||||
);
|
);
|
||||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
||||||
|
|
@ -102,7 +102,7 @@ class MenuNodeTest extends WebTestBase {
|
||||||
$this->assertLink($node_title);
|
$this->assertLink($node_title);
|
||||||
|
|
||||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||||
$this->assertOptionSelected('edit-menu-weight', 17, 'Menu weight correct in edit form');
|
$this->assertFieldById('edit-menu-weight', 17, 'Menu weight correct in edit form');
|
||||||
|
|
||||||
// Edit the node and remove the menu link.
|
// Edit the node and remove the menu link.
|
||||||
$edit = array(
|
$edit = array(
|
||||||
|
|
@ -114,10 +114,12 @@ class MenuNodeTest extends WebTestBase {
|
||||||
$this->assertNoLink($node_title);
|
$this->assertNoLink($node_title);
|
||||||
|
|
||||||
// Add a menu link to the Administration menu.
|
// Add a menu link to the Administration menu.
|
||||||
$item = entity_create('menu_link', array(
|
$item = entity_create('menu_link_content', array(
|
||||||
'link_path' => 'node/' . $node->id(),
|
'route_name' => 'node.view',
|
||||||
'link_title' => $this->randomName(16),
|
'route_parameters' => array('node' => $node->id()),
|
||||||
|
'title' => $this->randomName(16),
|
||||||
'menu_name' => 'admin',
|
'menu_name' => 'admin',
|
||||||
|
'bundle' => 'menu_link_content',
|
||||||
));
|
));
|
||||||
$item->save();
|
$item->save();
|
||||||
|
|
||||||
|
|
@ -127,27 +129,30 @@ class MenuNodeTest extends WebTestBase {
|
||||||
$this->assertText('Provide a menu link', 'Link in not allowed menu not shown in node edit form');
|
$this->assertText('Provide a menu link', 'Link in not allowed menu not shown in node edit form');
|
||||||
// Assert that the link is still in the Administration menu after save.
|
// Assert that the link is still in the Administration menu after save.
|
||||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
||||||
$link = menu_link_load($item['mlid']);
|
$link = entity_load('menu_link_content', $item->id());
|
||||||
$this->assertTrue($link, 'Link in not allowed menu still exists after saving node');
|
$this->assertTrue($link, 'Link in not allowed menu still exists after saving node');
|
||||||
|
|
||||||
// Move the menu link back to the Tools menu.
|
// Move the menu link back to the Tools menu.
|
||||||
$item['menu_name'] = 'tools';
|
$item->menu_name->value = 'tools';
|
||||||
menu_link_save($item);
|
$item->save();
|
||||||
// Create a second node.
|
// Create a second node.
|
||||||
$child_node = $this->drupalCreateNode(array('type' => 'article'));
|
$child_node = $this->drupalCreateNode(array('type' => 'article'));
|
||||||
// Assign a menu link to the second node, being a child of the first one.
|
// Assign a menu link to the second node, being a child of the first one.
|
||||||
$child_item = entity_create('menu_link', array(
|
$child_item = entity_create('menu_link_content', array(
|
||||||
'link_path' => 'node/'. $child_node->id(),
|
'route_name' => 'node.view',
|
||||||
'link_title' => $this->randomName(16),
|
'route_parameters' => array('node' => $child_node->id()),
|
||||||
'plid' => $item['mlid'],
|
'title' => $this->randomName(16),
|
||||||
|
'parent' => $item->getPluginId(),
|
||||||
|
'menu_name' => $item->getMenuName(),
|
||||||
|
'bundle' => 'menu_link_content',
|
||||||
));
|
));
|
||||||
$child_item->save();
|
$child_item->save();
|
||||||
// Edit the first node.
|
// Edit the first node.
|
||||||
$this->drupalGet('node/'. $node->id() .'/edit');
|
$this->drupalGet('node/'. $node->id() .'/edit');
|
||||||
// Assert that it is not possible to set the parent of the first node to itself or the second node.
|
// Assert that it is not possible to set the parent of the first node to itself or the second node.
|
||||||
$this->assertNoOption('edit-menu-parent', 'tools:'. $item['mlid']);
|
$this->assertNoOption('edit-menu-menu-parent', 'tools:'. $item->getPluginId());
|
||||||
$this->assertNoOption('edit-menu-parent', 'tools:'. $child_item['mlid']);
|
$this->assertNoOption('edit-menu-menu-parent', 'tools:'. $child_item->getPluginId());
|
||||||
// Assert that unallowed Administration menu is not available in options.
|
// Assert that unallowed Administration menu is not available in options.
|
||||||
$this->assertNoOption('edit-menu-parent', 'admin:0');
|
$this->assertNoOption('edit-menu-menu-parent', 'admin:');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* Definition of Drupal\menu_ui\Tests\MenuTest.
|
* Contains \Drupal\menu_ui\Tests\MenuTest.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Drupal\menu_ui\Tests;
|
namespace Drupal\menu_ui\Tests;
|
||||||
|
|
||||||
use Drupal\Component\Serialization\Json;
|
use Drupal\Component\Serialization\Json;
|
||||||
|
use Drupal\Core\Menu\MenuLinkInterface;
|
||||||
|
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||||
use Drupal\system\Entity\Menu;
|
use Drupal\system\Entity\Menu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -49,7 +51,7 @@ class MenuTest extends MenuWebTestBase {
|
||||||
/**
|
/**
|
||||||
* An array of test menu links.
|
* An array of test menu links.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface[]
|
||||||
*/
|
*/
|
||||||
protected $items;
|
protected $items;
|
||||||
|
|
||||||
|
|
@ -78,17 +80,20 @@ class MenuTest extends MenuWebTestBase {
|
||||||
|
|
||||||
// Verify that the menu links rebuild is idempotent and leaves the same
|
// Verify that the menu links rebuild is idempotent and leaves the same
|
||||||
// number of links in the table.
|
// number of links in the table.
|
||||||
$before_count = db_query('SELECT COUNT(*) FROM {menu_links}')->fetchField();
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
menu_link_rebuild_defaults();
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
$after_count = db_query('SELECT COUNT(*) FROM {menu_links}')->fetchField();
|
$before_count = $menu_link_manager->countMenuLinks(NULL);
|
||||||
$this->assertIdentical($before_count, $after_count, 'menu_link_rebuild_defaults() does not add more links');
|
$menu_link_manager->rebuild();
|
||||||
|
$after_count = $menu_link_manager->countMenuLinks(NULL);
|
||||||
|
$this->assertIdentical($before_count, $after_count, 'MenuLinkManager::rebuild() does not add more links');
|
||||||
// Do standard user tests.
|
// Do standard user tests.
|
||||||
// Login the user.
|
// Login the user.
|
||||||
$this->drupalLogin($this->authenticated_user);
|
$this->drupalLogin($this->authenticated_user);
|
||||||
$this->verifyAccess(403);
|
$this->verifyAccess(403);
|
||||||
|
|
||||||
foreach ($this->items as $item) {
|
foreach ($this->items as $item) {
|
||||||
// Paths were set as 'node/$nid'.
|
// Paths were set as 'node/$nid'.
|
||||||
$node = node_load(substr($item['link_path'], 5));
|
$node = node_load($item->getRouteParameters()['node']);
|
||||||
$this->verifyMenuLink($item, $node);
|
$this->verifyMenuLink($item, $node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,20 +109,20 @@ class MenuTest extends MenuWebTestBase {
|
||||||
$this->deleteCustomMenu();
|
$this->deleteCustomMenu();
|
||||||
|
|
||||||
// Modify and reset a standard menu link.
|
// Modify and reset a standard menu link.
|
||||||
$item = $this->getStandardMenuLink();
|
$instance = $this->getStandardMenuLink();
|
||||||
$old_title = $item['link_title'];
|
$old_weight = $instance->getWeight();
|
||||||
$this->modifyMenuLink($item);
|
// Edit the static menu link.
|
||||||
$item = entity_load('menu_link', $item['mlid']);
|
$edit = array();
|
||||||
// Verify that a change to the description is saved.
|
$edit['weight'] = 10;
|
||||||
$description = $this->randomName(16);
|
$id = $instance->getPluginId();
|
||||||
$item['options']['attributes']['title'] = $description;
|
$this->drupalPostForm("admin/structure/menu/link/$id/edit", $edit, t('Save'));
|
||||||
$return_value = menu_link_save($item);
|
$this->assertResponse(200);
|
||||||
// Save the menu link again to test the return value of the procedural save
|
$this->assertText('The menu link has been saved.');
|
||||||
// helper.
|
$menu_link_manager->resetDefinitions();
|
||||||
$this->assertIdentical($return_value, $item->save(), 'Return value of menu_link_save() is identical to the return value of $menu_link->save().');
|
|
||||||
$saved_item = entity_load('menu_link', $item['mlid']);
|
$instance = $menu_link_manager->createInstance($instance->getPluginId());
|
||||||
$this->assertEqual($description, $saved_item['options']['attributes']['title'], 'Saving an existing link updates the description (title attribute)');
|
$this->assertEqual($edit['weight'], $instance->getWeight(), 'Saving an existing link updates the weight.');
|
||||||
$this->resetMenuLink($item, $old_title);
|
$this->resetMenuLink($instance, $old_weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -214,7 +219,7 @@ class MenuTest extends MenuWebTestBase {
|
||||||
$this->assertRaw(t('The custom menu %title has been deleted.', array('%title' => $label)), 'Custom menu was deleted');
|
$this->assertRaw(t('The custom menu %title has been deleted.', array('%title' => $label)), 'Custom menu was deleted');
|
||||||
$this->assertNull(Menu::load($menu_name), 'Custom menu was deleted');
|
$this->assertNull(Menu::load($menu_name), 'Custom menu was deleted');
|
||||||
// Test if all menu links associated to the menu were removed from database.
|
// Test if all menu links associated to the menu were removed from database.
|
||||||
$result = entity_load_multiple_by_properties('menu_link', array('menu_name' => $menu_name));
|
$result = entity_load_multiple_by_properties('menu_link_content', array('menu_name' => $menu_name));
|
||||||
$this->assertFalse($result, 'All menu links associated to the custom menu were deleted.');
|
$this->assertFalse($result, 'All menu links associated to the custom menu were deleted.');
|
||||||
|
|
||||||
// Make sure there's no delete button on system menus.
|
// Make sure there's no delete button on system menus.
|
||||||
|
|
@ -245,33 +250,32 @@ class MenuTest extends MenuWebTestBase {
|
||||||
));
|
));
|
||||||
|
|
||||||
// Add menu links.
|
// Add menu links.
|
||||||
$item1 = $this->addMenuLink(0, 'node/' . $node1->id(), $menu_name);
|
$item1 = $this->addMenuLink('', 'node/' . $node1->id(), $menu_name, TRUE);
|
||||||
$item2 = $this->addMenuLink($item1['mlid'], 'node/' . $node2->id(), $menu_name, FALSE);
|
$item2 = $this->addMenuLink($item1->getPluginId(), 'node/' . $node2->id(), $menu_name, FALSE);
|
||||||
$item3 = $this->addMenuLink($item2['mlid'], 'node/' . $node3->id(), $menu_name);
|
$item3 = $this->addMenuLink($item2->getPluginId(), 'node/' . $node3->id(), $menu_name);
|
||||||
$this->assertMenuLink($item1['mlid'], array(
|
|
||||||
'depth' => 1,
|
// Hierarchy
|
||||||
'has_children' => 1,
|
// <$menu_name>
|
||||||
'p1' => $item1['mlid'],
|
// - item1
|
||||||
'p2' => 0,
|
// -- item2
|
||||||
|
// --- item3
|
||||||
|
|
||||||
|
$this->assertMenuLink($item1->getPluginId(), array(
|
||||||
|
'children' => array($item2->getPluginId(), $item3->getPluginId()),
|
||||||
|
'parents' => array($item1->getPluginId()),
|
||||||
// We assert the language code here to make sure that the language
|
// We assert the language code here to make sure that the language
|
||||||
// selection element degrades gracefully without the Language module.
|
// selection element degrades gracefully without the Language module.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item2['mlid'], array(
|
$this->assertMenuLink($item2->getPluginId(), array(
|
||||||
'depth' => 2, 'has_children' => 1,
|
'children' => array($item3->getPluginId()),
|
||||||
'p1' => $item1['mlid'],
|
'parents' => array($item2->getPluginId(), $item1->getPluginId()),
|
||||||
'p2' => $item2['mlid'],
|
|
||||||
'p3' => 0,
|
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item3['mlid'], array(
|
$this->assertMenuLink($item3->getPluginId(), array(
|
||||||
'depth' => 3,
|
'children' => array(),
|
||||||
'has_children' => 0,
|
'parents' => array($item3->getPluginId(), $item2->getPluginId(), $item1->getPluginId()),
|
||||||
'p1' => $item1['mlid'],
|
|
||||||
'p2' => $item2['mlid'],
|
|
||||||
'p3' => $item3['mlid'],
|
|
||||||
'p4' => 0,
|
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
|
|
@ -282,34 +286,37 @@ class MenuTest extends MenuWebTestBase {
|
||||||
$this->verifyMenuLink($item3, $node3, $item2, $node2);
|
$this->verifyMenuLink($item3, $node3, $item2, $node2);
|
||||||
|
|
||||||
// Add more menu links.
|
// Add more menu links.
|
||||||
$item4 = $this->addMenuLink(0, 'node/' . $node4->id(), $menu_name);
|
$item4 = $this->addMenuLink('', 'node/' . $node4->id(), $menu_name);
|
||||||
$item5 = $this->addMenuLink($item4['mlid'], 'node/' . $node5->id(), $menu_name);
|
$item5 = $this->addMenuLink($item4->getPluginId(), 'node/' . $node5->id(), $menu_name);
|
||||||
// Create a menu link pointing to an alias.
|
// Create a menu link pointing to an alias.
|
||||||
$item6 = $this->addMenuLink($item4['mlid'], 'node5', $menu_name, TRUE, '0', 'node/' . $node5->id());
|
$item6 = $this->addMenuLink($item4->getPluginId(), 'node5', $menu_name, TRUE, '0');
|
||||||
$this->assertMenuLink($item4['mlid'], array(
|
|
||||||
'depth' => 1,
|
// Hierarchy
|
||||||
'has_children' => 1,
|
// <$menu_name>
|
||||||
'p1' => $item4['mlid'],
|
// - item1
|
||||||
'p2' => 0,
|
// -- item2
|
||||||
|
// --- item3
|
||||||
|
// - item4
|
||||||
|
// -- item5
|
||||||
|
// -- item6
|
||||||
|
|
||||||
|
$this->assertMenuLink($item4->getPluginId(), array(
|
||||||
|
'children' => array($item5->getPluginId(), $item6->getPluginId()),
|
||||||
|
'parents' => array($item4->getPluginId()),
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item5['mlid'], array(
|
$this->assertMenuLink($item5->getPluginId(), array(
|
||||||
'depth' => 2,
|
'children' => array(),
|
||||||
'has_children' => 0,
|
'parents' => array($item5->getPluginId(), $item4->getPluginId()),
|
||||||
'p1' => $item4['mlid'],
|
|
||||||
'p2' => $item5['mlid'],
|
|
||||||
'p3' => 0,
|
|
||||||
// See above.
|
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item6['mlid'], array(
|
$this->assertMenuLink($item6->getPluginId(), array(
|
||||||
'depth' => 2,
|
'children' => array(),
|
||||||
'has_children' => 0,
|
'parents' => array($item6->getPluginId(), $item4->getPluginId()),
|
||||||
'p1' => $item4['mlid'],
|
'route_name' => 'node.view',
|
||||||
'p2' => $item6['mlid'],
|
'route_parameters' => array('node' => $node5->id()),
|
||||||
'p3' => 0,
|
'url' => '',
|
||||||
'link_path' => 'node/' . $node5->id(),
|
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
|
|
@ -323,50 +330,44 @@ class MenuTest extends MenuWebTestBase {
|
||||||
$this->toggleMenuLink($item2);
|
$this->toggleMenuLink($item2);
|
||||||
|
|
||||||
// Move link and verify that descendants are updated.
|
// Move link and verify that descendants are updated.
|
||||||
$this->moveMenuLink($item2, $item5['mlid'], $menu_name);
|
$this->moveMenuLink($item2, $item5->getPluginId(), $menu_name);
|
||||||
$this->assertMenuLink($item1['mlid'], array(
|
// Hierarchy
|
||||||
'depth' => 1,
|
// <$menu_name>
|
||||||
'has_children' => 0,
|
// - item1
|
||||||
'p1' => $item1['mlid'],
|
// - item4
|
||||||
'p2' => 0,
|
// -- item5
|
||||||
|
// --- item2
|
||||||
|
// ---- item3
|
||||||
|
// -- item6
|
||||||
|
|
||||||
|
$this->assertMenuLink($item1->getPluginId(), array(
|
||||||
|
'children' => array(),
|
||||||
|
'parents' => array($item1->getPluginId()),
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item4['mlid'], array(
|
$this->assertMenuLink($item4->getPluginId(), array(
|
||||||
'depth' => 1,
|
'children' => array($item5->getPluginId(), $item6->getPluginId(), $item2->getPluginId(), $item3->getPluginId()),
|
||||||
'has_children' => 1,
|
'parents' => array($item4->getPluginId()),
|
||||||
'p1' => $item4['mlid'],
|
|
||||||
'p2' => 0,
|
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item5['mlid'], array(
|
|
||||||
'depth' => 2,
|
$this->assertMenuLink($item5->getPluginId(), array(
|
||||||
'has_children' => 1,
|
'children' => array($item2->getPluginId(), $item3->getPluginId()),
|
||||||
'p1' => $item4['mlid'],
|
'parents' => array($item5->getPluginId(), $item4->getPluginId()),
|
||||||
'p2' => $item5['mlid'],
|
|
||||||
'p3' => 0,
|
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item2['mlid'], array(
|
$this->assertMenuLink($item2->getPluginId(), array(
|
||||||
'depth' => 3,
|
'children' => array($item3->getPluginId()),
|
||||||
'has_children' => 1,
|
'parents' => array($item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()),
|
||||||
'p1' => $item4['mlid'],
|
|
||||||
'p2' => $item5['mlid'],
|
|
||||||
'p3' => $item2['mlid'],
|
|
||||||
'p4' => 0,
|
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
$this->assertMenuLink($item3['mlid'], array(
|
$this->assertMenuLink($item3->getPluginId(), array(
|
||||||
'depth' => 4,
|
'children' => array(),
|
||||||
'has_children' => 0,
|
'parents' => array($item3->getPluginId(), $item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()),
|
||||||
'p1' => $item4['mlid'],
|
|
||||||
'p2' => $item5['mlid'],
|
|
||||||
'p3' => $item2['mlid'],
|
|
||||||
'p4' => $item3['mlid'],
|
|
||||||
'p5' => 0,
|
|
||||||
// See above.
|
// See above.
|
||||||
'langcode' => 'en',
|
'langcode' => 'en',
|
||||||
));
|
));
|
||||||
|
|
@ -375,33 +376,39 @@ class MenuTest extends MenuWebTestBase {
|
||||||
// item's weight doesn't get changed because of the old hardcoded delta=50.
|
// item's weight doesn't get changed because of the old hardcoded delta=50.
|
||||||
$items = array();
|
$items = array();
|
||||||
for ($i = -50; $i <= 51; $i++) {
|
for ($i = -50; $i <= 51; $i++) {
|
||||||
$items[$i] = $this->addMenuLink(0, 'node/' . $node1->id(), $menu_name, TRUE, strval($i));
|
$items[$i] = $this->addMenuLink('', 'node/' . $node1->id(), $menu_name, TRUE, strval($i));
|
||||||
}
|
}
|
||||||
$this->assertMenuLink($items[51]['mlid'], array('weight' => '51'));
|
$this->assertMenuLink($items[51]->getPluginId(), array('weight' => '51'));
|
||||||
|
|
||||||
// Enable a link via the overview form.
|
// Disable a link and then re-enable the link via the overview form.
|
||||||
$this->disableMenuLink($item1);
|
$this->disableMenuLink($item1);
|
||||||
$edit = array();
|
$edit = array();
|
||||||
|
$edit['links[menu_plugin_id:' . $item1->getPluginId() . '][enabled]'] = TRUE;
|
||||||
|
$this->drupalPostForm('admin/structure/menu/manage/' . $item1->getMenuName(), $edit, t('Save'));
|
||||||
|
|
||||||
// Note in the UI the 'links[mlid:x][hidden]' form element maps to enabled,
|
// Mark item2, item4 and item5 as expanded.
|
||||||
// or NOT hidden.
|
// This is done in order to show them on the frontpage.
|
||||||
$edit['links[mlid:' . $item1['mlid'] . '][hidden]'] = TRUE;
|
$item2->expanded->value = 1;
|
||||||
$this->drupalPostForm('admin/structure/menu/manage/' . $item1['menu_name'], $edit, t('Save'));
|
$item2->save();
|
||||||
|
$item4->expanded->value = 1;
|
||||||
|
$item4->save();
|
||||||
|
$item5->expanded->value = 1;
|
||||||
|
$item5->save();
|
||||||
|
|
||||||
// Verify in the database.
|
// Verify in the database.
|
||||||
$this->assertMenuLink($item1['mlid'], array('hidden' => 0));
|
$this->assertMenuLink($item1->getPluginId(), array('hidden' => 0));
|
||||||
|
|
||||||
// Add an external link.
|
// Add an external link.
|
||||||
$item7 = $this->addMenuLink(0, 'http://drupal.org', $menu_name);
|
$item7 = $this->addMenuLink('', 'http://drupal.org', $menu_name);
|
||||||
$this->assertMenuLink($item7['mlid'], array('link_path' => 'http://drupal.org', 'external' => 1));
|
$this->assertMenuLink($item7->getPluginId(), array('url' => 'http://drupal.org'));
|
||||||
|
|
||||||
// Add <front> menu item.
|
// Add <front> menu item.
|
||||||
$item8 = $this->addMenuLink(0, '<front>', $menu_name);
|
$item8 = $this->addMenuLink('', '<front>', $menu_name);
|
||||||
$this->assertMenuLink($item8['mlid'], array('link_path' => '<front>', 'external' => 1));
|
$this->assertMenuLink($item8->getPluginId(), array('route_name' => '<front>'));
|
||||||
$this->drupalGet('');
|
$this->drupalGet('');
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
// Make sure we get routed correctly.
|
// Make sure we get routed correctly.
|
||||||
$this->clickLink($item8['link_title']);
|
$this->clickLink($item8->getTitle());
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
|
|
||||||
// Save menu links for later tests.
|
// Save menu links for later tests.
|
||||||
|
|
@ -417,16 +424,16 @@ class MenuTest extends MenuWebTestBase {
|
||||||
|
|
||||||
// Make a path with query and fragment on.
|
// Make a path with query and fragment on.
|
||||||
$path = 'test-page?arg1=value1&arg2=value2';
|
$path = 'test-page?arg1=value1&arg2=value2';
|
||||||
$item = $this->addMenuLink(0, $path);
|
$item = $this->addMenuLink('', $path);
|
||||||
|
|
||||||
$this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
|
$this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
|
||||||
$this->assertFieldByName('link_path', $path, 'Path is found with both query and fragment.');
|
$this->assertFieldByName('url', $path, 'Path is found with both query and fragment.');
|
||||||
|
|
||||||
// Now change the path to something without query and fragment.
|
// Now change the path to something without query and fragment.
|
||||||
$path = 'test-page';
|
$path = 'test-page';
|
||||||
$this->drupalPostForm('admin/structure/menu/item/' . $item['mlid'] . '/edit', array('link_path' => $path), t('Save'));
|
$this->drupalPostForm('admin/structure/menu/item/' . $item->id() . '/edit', array('url' => $path), t('Save'));
|
||||||
$this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
|
$this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
|
||||||
$this->assertFieldByName('link_path', $path, 'Path no longer has query or fragment.');
|
$this->assertFieldByName('url', $path, 'Path no longer has query or fragment.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -456,15 +463,15 @@ class MenuTest extends MenuWebTestBase {
|
||||||
'status' => NODE_NOT_PUBLISHED,
|
'status' => NODE_NOT_PUBLISHED,
|
||||||
));
|
));
|
||||||
|
|
||||||
$item = $this->addMenuLink(0, 'node/' . $node->id());
|
$item = $this->addMenuLink('', 'node/' . $node->id());
|
||||||
$this->modifyMenuLink($item);
|
$this->modifyMenuLink($item);
|
||||||
|
|
||||||
// Test that a user with 'administer menu' but without 'bypass node access'
|
// Test that a user with 'administer menu' but without 'bypass node access'
|
||||||
// cannot see the menu item.
|
// cannot see the menu item.
|
||||||
$this->drupalLogout();
|
$this->drupalLogout();
|
||||||
$this->drupalLogin($this->admin_user);
|
$this->drupalLogin($this->admin_user);
|
||||||
$this->drupalGet('admin/structure/menu/manage/' . $item['menu_name']);
|
$this->drupalGet('admin/structure/menu/manage/' . $item->getMenuName());
|
||||||
$this->assertNoText($item['link_title'], "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
|
$this->assertNoText($item->getTitle(), "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -489,43 +496,13 @@ class MenuTest extends MenuWebTestBase {
|
||||||
$this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="menu-ui-edit"><a href="' . base_path() . 'admin/structure/menu/manage/tools">Edit menu</a></li></ul>');
|
$this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="menu-ui-edit"><a href="' . base_path() . 'admin/structure/menu/manage/tools">Edit menu</a></li></ul>');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests menu link bundles.
|
|
||||||
*/
|
|
||||||
public function testMenuBundles() {
|
|
||||||
$this->drupalLogin($this->admin_user);
|
|
||||||
$menu = $this->addCustomMenu();
|
|
||||||
// Clear the entity cache to ensure the static caches are rebuilt.
|
|
||||||
\Drupal::entityManager()->clearCachedBundles();
|
|
||||||
$bundles = entity_get_bundles('menu_link');
|
|
||||||
$this->assertTrue(isset($bundles[$menu->id()]));
|
|
||||||
$menus = menu_list_system_menus();
|
|
||||||
$menus[$menu->id()] = $menu->label();
|
|
||||||
ksort($menus);
|
|
||||||
$this->assertIdentical(array_keys($bundles), array_keys($menus));
|
|
||||||
|
|
||||||
// Test if moving a menu link between menus changes the bundle.
|
|
||||||
$node = $this->drupalCreateNode(array('type' => 'article'));
|
|
||||||
$item = $this->addMenuLink(0, 'node/' . $node->id(), 'tools');
|
|
||||||
$this->moveMenuLink($item, 0, $menu->id());
|
|
||||||
$this->assertEqual($item->bundle(), 'tools', 'Menu link bundle matches the menu');
|
|
||||||
|
|
||||||
$moved_item = entity_load('menu_link', $item->id(), TRUE);
|
|
||||||
$this->assertNotEqual($moved_item->bundle(), $item->bundle(), 'Menu link bundle was changed');
|
|
||||||
$this->assertEqual($moved_item->bundle(), $menu->id(), 'Menu link bundle matches the menu');
|
|
||||||
|
|
||||||
$unsaved_item = entity_create('menu_link', array('menu_name' => $menu->id(), 'link_title' => $this->randomName(16), 'link_path' => '<front>'));
|
|
||||||
$this->assertEqual($unsaved_item->bundle(), $menu->id(), 'Unsaved menu link bundle matches the menu');
|
|
||||||
$this->assertEqual($unsaved_item->menu_name, $menu->id(), 'Unsaved menu link menu name matches the menu');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a menu link using the UI.
|
* Adds a menu link using the UI.
|
||||||
*
|
*
|
||||||
* @param integer $plid
|
* @param string $parent
|
||||||
* Optional parent menu link id.
|
* Optional parent menu link id.
|
||||||
* @param string $link
|
* @param string $path
|
||||||
* Link path. Defaults to the front page.
|
* The path to enter on the form. Defaults to the front page.
|
||||||
* @param string $menu_name
|
* @param string $menu_name
|
||||||
* Menu name. Defaults to 'tools'.
|
* Menu name. Defaults to 'tools'.
|
||||||
* @param bool $expanded
|
* @param bool $expanded
|
||||||
|
|
@ -534,40 +511,36 @@ class MenuTest extends MenuWebTestBase {
|
||||||
* to FALSE.
|
* to FALSE.
|
||||||
* @param string $weight
|
* @param string $weight
|
||||||
* Menu weight. Defaults to 0.
|
* Menu weight. Defaults to 0.
|
||||||
* @param string $actual_link
|
|
||||||
* Actual link path in case $link is an alias.
|
|
||||||
*
|
*
|
||||||
* @return \Drupal\menu_link\Entity\MenuLink
|
* @return \Drupal\menu_link_content\Entity\MenuLinkContent
|
||||||
* A menu link entity.
|
* A menu link entity.
|
||||||
*/
|
*/
|
||||||
function addMenuLink($plid = 0, $link = '<front>', $menu_name = 'tools', $expanded = TRUE, $weight = '0', $actual_link = FALSE) {
|
function addMenuLink($parent = '', $path = '<front>', $menu_name = 'tools', $expanded = FALSE, $weight = '0') {
|
||||||
// View add menu link page.
|
// View add menu link page.
|
||||||
$this->drupalGet("admin/structure/menu/manage/$menu_name/add");
|
$this->drupalGet("admin/structure/menu/manage/$menu_name/add");
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
|
|
||||||
$title = '!link_' . $this->randomName(16);
|
$title = '!link_' . $this->randomName(16);
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'link_path' => $link,
|
'url' => $path,
|
||||||
'link_title' => $title,
|
'title[0][value]' => $title,
|
||||||
'description' => '',
|
'description[0][value]' => '',
|
||||||
'enabled' => TRUE,
|
'enabled' => 1,
|
||||||
'expanded' => $expanded,
|
'expanded[value]' => $expanded,
|
||||||
'parent' => $menu_name . ':' . $plid,
|
'menu_parent' => $menu_name . ':' . $parent,
|
||||||
'weight' => $weight,
|
'weight[0][value]' => $weight,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!$actual_link) {
|
|
||||||
$actual_link = $link;
|
|
||||||
}
|
|
||||||
// Add menu link.
|
// Add menu link.
|
||||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
$this->assertText('The menu link has been saved.');
|
$this->assertText('The menu link has been saved.');
|
||||||
|
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $title));
|
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $title));
|
||||||
|
|
||||||
$menu_link = reset($menu_links);
|
$menu_link = reset($menu_links);
|
||||||
$this->assertTrue($menu_link, 'Menu link was found in database.');
|
$this->assertTrue($menu_link, 'Menu link was found in database.');
|
||||||
$this->assertMenuLink($menu_link->id(), array('menu_name' => $menu_name, 'link_path' => $actual_link, 'has_children' => 0, 'plid' => $plid));
|
$this->assertMenuLink($menu_link->getPluginId(), array('menu_name' => $menu_name, 'children' => array(), 'parent' => $parent));
|
||||||
|
|
||||||
return $menu_link;
|
return $menu_link;
|
||||||
}
|
}
|
||||||
|
|
@ -578,27 +551,27 @@ class MenuTest extends MenuWebTestBase {
|
||||||
function addInvalidMenuLink() {
|
function addInvalidMenuLink() {
|
||||||
foreach (array('-&-', 'admin/people/permissions', '#') as $link_path) {
|
foreach (array('-&-', 'admin/people/permissions', '#') as $link_path) {
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'link_path' => $link_path,
|
'url' => $link_path,
|
||||||
'link_title' => 'title',
|
'title[0][value]' => 'title',
|
||||||
);
|
);
|
||||||
$this->drupalPostForm("admin/structure/menu/manage/{$this->menu->id()}/add", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/manage/{$this->menu->id()}/add", $edit, t('Save'));
|
||||||
$this->assertRaw(t("The path '@path' is either invalid or you do not have access to it.", array('@path' => $link_path)), 'Menu link was not created');
|
$this->assertRaw(t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $link_path)), 'Menu link was not created');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies a menu link using the UI.
|
* Verifies a menu link using the UI.
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||||
* Menu link.
|
* Menu link.
|
||||||
* @param object $item_node
|
* @param object $item_node
|
||||||
* Menu link content node.
|
* Menu link content node.
|
||||||
* @param array $parent
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $parent
|
||||||
* Parent menu link.
|
* Parent menu link.
|
||||||
* @param object $parent_node
|
* @param object $parent_node
|
||||||
* Parent menu link content node.
|
* Parent menu link content node.
|
||||||
*/
|
*/
|
||||||
function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL) {
|
function verifyMenuLink(MenuLinkContent $item, $item_node, MenuLinkContent $parent = NULL, $parent_node = NULL) {
|
||||||
// View home page.
|
// View home page.
|
||||||
$this->drupalGet('');
|
$this->drupalGet('');
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
|
|
@ -606,7 +579,7 @@ class MenuTest extends MenuWebTestBase {
|
||||||
// Verify parent menu link.
|
// Verify parent menu link.
|
||||||
if (isset($parent)) {
|
if (isset($parent)) {
|
||||||
// Verify menu link.
|
// Verify menu link.
|
||||||
$title = $parent['link_title'];
|
$title = $parent->getTitle();
|
||||||
$this->assertLink($title, 0, 'Parent menu link was displayed');
|
$this->assertLink($title, 0, 'Parent menu link was displayed');
|
||||||
|
|
||||||
// Verify menu link link.
|
// Verify menu link link.
|
||||||
|
|
@ -616,7 +589,7 @@ class MenuTest extends MenuWebTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify menu link.
|
// Verify menu link.
|
||||||
$title = $item['link_title'];
|
$title = $item->getTitle();
|
||||||
$this->assertLink($title, 0, 'Menu link was displayed');
|
$this->assertLink($title, 0, 'Menu link was displayed');
|
||||||
|
|
||||||
// Verify menu link link.
|
// Verify menu link link.
|
||||||
|
|
@ -628,18 +601,18 @@ class MenuTest extends MenuWebTestBase {
|
||||||
/**
|
/**
|
||||||
* Changes the parent of a menu link using the UI.
|
* Changes the parent of a menu link using the UI.
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContentInterface $item
|
||||||
* The menu link item to move.
|
* The menu link item to move.
|
||||||
* @param int $plid
|
* @param int $parent
|
||||||
* The id of the new parent.
|
* The id of the new parent.
|
||||||
* @param string $menu_name
|
* @param string $menu_name
|
||||||
* The menu the menu link will be moved to.
|
* The menu the menu link will be moved to.
|
||||||
*/
|
*/
|
||||||
function moveMenuLink($item, $plid, $menu_name) {
|
function moveMenuLink(MenuLinkContent $item, $parent, $menu_name) {
|
||||||
$mlid = $item['mlid'];
|
$mlid = $item->id();
|
||||||
|
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'parent' => $menu_name . ':' . $plid,
|
'menu_parent' => $menu_name . ':' . $parent,
|
||||||
);
|
);
|
||||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
|
|
@ -648,58 +621,54 @@ class MenuTest extends MenuWebTestBase {
|
||||||
/**
|
/**
|
||||||
* Modifies a menu link using the UI.
|
* Modifies a menu link using the UI.
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||||
* Menu link passed by reference.
|
* Menu link entity.
|
||||||
*/
|
*/
|
||||||
function modifyMenuLink(&$item) {
|
function modifyMenuLink(MenuLinkContent $item) {
|
||||||
$item['link_title'] = $this->randomName(16);
|
$item->title->value = $this->randomName(16);
|
||||||
|
|
||||||
$mlid = $item['mlid'];
|
$mlid = $item->id();
|
||||||
$title = $item['link_title'];
|
$title = $item->getTitle();
|
||||||
|
|
||||||
// Edit menu link.
|
// Edit menu link.
|
||||||
$edit = array();
|
$edit = array();
|
||||||
$edit['link_title'] = $title;
|
$edit['title[0][value]'] = $title;
|
||||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
$this->assertText('The menu link has been saved.');
|
$this->assertText('The menu link has been saved.');
|
||||||
// Verify menu link.
|
// Verify menu link.
|
||||||
$this->drupalGet('admin/structure/menu/manage/' . $item['menu_name']);
|
$this->drupalGet('admin/structure/menu/manage/' . $item->getMenuName());
|
||||||
$this->assertText($title, 'Menu link was edited');
|
$this->assertText($title, 'Menu link was edited');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets a standard menu link using the UI.
|
* Resets a standard menu link using the UI.
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param \Drupal\Core\Menu\MenuLinkInterface $menu_link
|
||||||
* Menu link.
|
* The Menu link.
|
||||||
* @param string $old_title
|
* @param int $old_weight
|
||||||
* Original title for menu link.
|
* Original title for menu link.
|
||||||
*/
|
*/
|
||||||
function resetMenuLink($item, $old_title) {
|
function resetMenuLink(MenuLinkInterface $menu_link, $old_weight) {
|
||||||
$mlid = $item['mlid'];
|
|
||||||
$title = $item['link_title'];
|
|
||||||
|
|
||||||
// Reset menu link.
|
// Reset menu link.
|
||||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/reset", array(), t('Reset'));
|
$this->drupalPostForm("admin/structure/menu/link/{$menu_link->getPluginId()}/reset", array(), t('Reset'));
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
$this->assertRaw(t('The menu link was reset to its default settings.'), 'Menu link was reset');
|
$this->assertRaw(t('The menu link was reset to its default settings.'), 'Menu link was reset');
|
||||||
|
|
||||||
// Verify menu link.
|
// Verify menu link.
|
||||||
$this->drupalGet('');
|
$instance = \Drupal::service('plugin.manager.menu.link')->createInstance($menu_link->getPluginId());
|
||||||
$this->assertNoText($title, 'Menu link was reset');
|
$this->assertEqual($old_weight, $instance->getWeight(), 'Resets to the old weight.');
|
||||||
$this->assertText($old_title, 'Menu link was reset');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a menu link using the UI.
|
* Deletes a menu link using the UI.
|
||||||
*
|
*
|
||||||
* @param array $item
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||||
* Menu link.
|
* Menu link.
|
||||||
*/
|
*/
|
||||||
function deleteMenuLink($item) {
|
function deleteMenuLink(MenuLinkContent $item) {
|
||||||
$mlid = $item['mlid'];
|
$mlid = $item->id();
|
||||||
$title = $item['link_title'];
|
$title = $item->getTitle();
|
||||||
|
|
||||||
// Delete menu link.
|
// Delete menu link.
|
||||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/delete", array(), t('Confirm'));
|
$this->drupalPostForm("admin/structure/menu/item/$mlid/delete", array(), t('Confirm'));
|
||||||
|
|
@ -714,51 +683,51 @@ class MenuTest extends MenuWebTestBase {
|
||||||
/**
|
/**
|
||||||
* Alternately disables and enables a menu link.
|
* Alternately disables and enables a menu link.
|
||||||
*
|
*
|
||||||
* @param $item
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||||
* Menu link.
|
* Menu link.
|
||||||
*/
|
*/
|
||||||
function toggleMenuLink($item) {
|
function toggleMenuLink(MenuLinkContent $item) {
|
||||||
$this->disableMenuLink($item);
|
$this->disableMenuLink($item);
|
||||||
|
|
||||||
// Verify menu link is absent.
|
// Verify menu link is absent.
|
||||||
$this->drupalGet('');
|
$this->drupalGet('');
|
||||||
$this->assertNoText($item['link_title'], 'Menu link was not displayed');
|
$this->assertNoText($item->getTitle(), 'Menu link was not displayed');
|
||||||
$this->enableMenuLink($item);
|
$this->enableMenuLink($item);
|
||||||
|
|
||||||
// Verify menu link is displayed.
|
// Verify menu link is displayed.
|
||||||
$this->drupalGet('');
|
$this->drupalGet('');
|
||||||
$this->assertText($item['link_title'], 'Menu link was displayed');
|
$this->assertText($item->getTitle(), 'Menu link was displayed');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables a menu link.
|
* Disables a menu link.
|
||||||
*
|
*
|
||||||
* @param $item
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||||
* Menu link.
|
* Menu link.
|
||||||
*/
|
*/
|
||||||
function disableMenuLink($item) {
|
function disableMenuLink(MenuLinkContent $item) {
|
||||||
$mlid = $item['mlid'];
|
$mlid = $item->id();
|
||||||
$edit['enabled'] = FALSE;
|
$edit['enabled'] = FALSE;
|
||||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||||
|
|
||||||
// Unlike most other modules, there is no confirmation message displayed.
|
// Unlike most other modules, there is no confirmation message displayed.
|
||||||
// Verify in the database.
|
// Verify in the database.
|
||||||
$this->assertMenuLink($mlid, array('hidden' => 1));
|
$this->assertMenuLink($item->getPluginId(), array('hidden' => 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables a menu link.
|
* Enables a menu link.
|
||||||
*
|
*
|
||||||
* @param $item
|
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||||
* Menu link.
|
* Menu link.
|
||||||
*/
|
*/
|
||||||
function enableMenuLink($item) {
|
function enableMenuLink(MenuLinkContent $item) {
|
||||||
$mlid = $item['mlid'];
|
$mlid = $item->id();
|
||||||
$edit['enabled'] = TRUE;
|
$edit['enabled'] = TRUE;
|
||||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||||
|
|
||||||
// Verify in the database.
|
// Verify in the database.
|
||||||
$this->assertMenuLink($mlid, array('hidden' => 0));
|
$this->assertMenuLink($item->getPluginId(), array('hidden' => 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -782,27 +751,19 @@ class MenuTest extends MenuWebTestBase {
|
||||||
/**
|
/**
|
||||||
* Returns standard menu link.
|
* Returns standard menu link.
|
||||||
*
|
*
|
||||||
* @return \Drupal\menu_link\Entity\MenuLink
|
* @return \Drupal\Core\Menu\MenuLinkInterface
|
||||||
* A menu link entity.
|
* A menu link plugin.
|
||||||
*/
|
*/
|
||||||
private function getStandardMenuLink() {
|
private function getStandardMenuLink() {
|
||||||
$mlid = 0;
|
|
||||||
// Retrieve menu link id of the Log out menu link, which will always be on
|
// Retrieve menu link id of the Log out menu link, which will always be on
|
||||||
// the front page.
|
// the front page.
|
||||||
$query = \Drupal::entityQuery('menu_link')
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
->condition('module', 'user')
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
->condition('machine_name', 'user.logout');
|
$result = $menu_link_manager->loadLinksByRoute('user.logout');
|
||||||
$result = $query->execute();
|
$instance = reset($result);
|
||||||
if (!empty($result)) {
|
|
||||||
$mlid = reset($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertTrue($mlid > 0, 'Standard menu link id was found');
|
$this->assertTrue((bool) $instance, 'Standard menu link was loaded');
|
||||||
// Load menu link.
|
return $instance;
|
||||||
// Use api function so that link is translated for rendering.
|
|
||||||
$item = entity_load('menu_link', $mlid);
|
|
||||||
$this->assertTrue((bool) $item, 'Standard menu link was loaded');
|
|
||||||
return $item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -833,9 +794,9 @@ class MenuTest extends MenuWebTestBase {
|
||||||
$this->assertText(t('Tools'), 'Tools menu page was displayed');
|
$this->assertText(t('Tools'), 'Tools menu page was displayed');
|
||||||
}
|
}
|
||||||
|
|
||||||
// View menu edit page.
|
// View menu edit page for a static link.
|
||||||
$item = $this->getStandardMenuLink();
|
$item = $this->getStandardMenuLink();
|
||||||
$this->drupalGet('admin/structure/menu/item/' . $item['mlid'] . '/edit');
|
$this->drupalGet('admin/structure/menu/link/' . $item->getPluginId() . '/edit');
|
||||||
$this->assertResponse($response);
|
$this->assertResponse($response);
|
||||||
if ($response == 200) {
|
if ($response == 200) {
|
||||||
$this->assertText(t('Edit menu item'), 'Menu edit page was displayed');
|
$this->assertText(t('Edit menu item'), 'Menu edit page was displayed');
|
||||||
|
|
|
||||||
|
|
@ -19,28 +19,58 @@ abstract class MenuWebTestBase extends WebTestBase {
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('menu_ui');
|
public static $modules = array('menu_ui', 'menu_link_content');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetchs the menu item from the database and compares it to expected item.
|
* Fetchs the menu item from the database and compares it to expected item.
|
||||||
*
|
*
|
||||||
* @param int $mlid
|
* @param int $menu_plugin_id
|
||||||
* Menu item id.
|
* Menu item id.
|
||||||
* @param array $item
|
* @param array $expected_item
|
||||||
* Array containing properties to verify.
|
* Array containing properties to verify.
|
||||||
*/
|
*/
|
||||||
function assertMenuLink($mlid, array $expected_item) {
|
function assertMenuLink($menu_plugin_id, array $expected_item) {
|
||||||
// Retrieve menu link.
|
// Retrieve menu link.
|
||||||
$item = entity_load('menu_link', $mlid);
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
$options = $item->options;
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
if (!empty($options['query'])) {
|
$menu_link_manager->resetDefinitions();
|
||||||
$item['link_path'] .= '?' . \Drupal::urlGenerator()->httpBuildQuery($options['query']);
|
// Reset the static load cache.
|
||||||
|
\Drupal::entityManager()->getStorage('menu_link_content')->resetCache();
|
||||||
|
$definition = $menu_link_manager->getDefinition($menu_plugin_id);
|
||||||
|
|
||||||
|
$entity = NULL;
|
||||||
|
|
||||||
|
// Pull the path from the menu link content.
|
||||||
|
if (strpos($menu_plugin_id, 'menu_link_content') === 0) {
|
||||||
|
list(, $uuid) = explode(':', $menu_plugin_id, 2);
|
||||||
|
/** @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity */
|
||||||
|
$entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $uuid);
|
||||||
}
|
}
|
||||||
if (!empty($options['fragment'])) {
|
|
||||||
$item['link_path'] .= '#' . $options['fragment'];
|
if (isset($expected_item['children'])) {
|
||||||
|
$child_ids = array_values($menu_link_manager->getChildIds($menu_plugin_id));
|
||||||
|
sort($expected_item['children']);
|
||||||
|
if ($child_ids) {
|
||||||
|
sort($child_ids);
|
||||||
}
|
}
|
||||||
|
$this->assertEqual($expected_item['children'], $child_ids);
|
||||||
|
unset($expected_item['children']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($expected_item['parents'])) {
|
||||||
|
$parent_ids = array_values($menu_link_manager->getParentIds($menu_plugin_id));
|
||||||
|
$this->assertEqual($expected_item['parents'], $parent_ids);
|
||||||
|
unset($expected_item['parents']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($expected_item['langcode']) && $entity) {
|
||||||
|
$this->assertEqual($entity->langcode->value, $expected_item['langcode']);
|
||||||
|
unset($expected_item['langcode']);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($expected_item as $key => $value) {
|
foreach ($expected_item as $key => $value) {
|
||||||
$this->assertEqual($item[$key], $value);
|
$this->assertTrue(isset($definition[$key]));
|
||||||
|
$this->assertEqual($definition[$key], $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -452,10 +452,10 @@ function hook_node_validate(\Drupal\node\NodeInterface $node, $form, &$form_stat
|
||||||
* @ingroup entity_crud
|
* @ingroup entity_crud
|
||||||
*/
|
*/
|
||||||
function hook_node_submit(\Drupal\node\NodeInterface $node, $form, &$form_state) {
|
function hook_node_submit(\Drupal\node\NodeInterface $node, $form, &$form_state) {
|
||||||
// Decompose the selected menu parent option into 'menu_name' and 'plid', if
|
// Decompose the selected menu parent option into 'menu_name' and 'parent', if
|
||||||
// the form used the default parent selection widget.
|
// the form used the default parent selection widget.
|
||||||
if (!empty($form_state['values']['menu']['parent'])) {
|
if (!empty($form_state['values']['menu']['parent'])) {
|
||||||
list($node->menu['menu_name'], $node->menu['plid']) = explode(':', $form_state['values']['menu']['parent']);
|
list($node->menu['menu_name'], $node->menu['parent']) = explode(':', $form_state['values']['menu']['parent']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ class KernelTestBaseTest extends KernelTestBase {
|
||||||
*/
|
*/
|
||||||
function testEnableModulesFixedList() {
|
function testEnableModulesFixedList() {
|
||||||
// Install system module.
|
// Install system module.
|
||||||
$this->container->get('module_handler')->install(array('system', 'menu_link'));
|
$this->container->get('module_handler')->install(array('system', 'menu_link_content'));
|
||||||
$entity_manager = \Drupal::entityManager();
|
$entity_manager = \Drupal::entityManager();
|
||||||
|
|
||||||
// entity_test is loaded via $modules; its entity type should exist.
|
// entity_test is loaded via $modules; its entity type should exist.
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
active_menus_default: []
|
|
||||||
|
|
@ -168,17 +168,6 @@ system.logging:
|
||||||
type: string
|
type: string
|
||||||
label: 'Error messages to display'
|
label: 'Error messages to display'
|
||||||
|
|
||||||
system.menu:
|
|
||||||
type: mapping
|
|
||||||
label: 'Menu settings'
|
|
||||||
mapping:
|
|
||||||
active_menus_default:
|
|
||||||
type: sequence
|
|
||||||
label: 'Active menus'
|
|
||||||
sequence:
|
|
||||||
- type: string
|
|
||||||
label: 'Menu'
|
|
||||||
|
|
||||||
system.performance:
|
system.performance:
|
||||||
type: mapping
|
type: mapping
|
||||||
label: 'Performance settings'
|
label: 'Performance settings'
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class AdminController extends ControllerBase {
|
||||||
// Sort links by title.
|
// Sort links by title.
|
||||||
uasort($admin_tasks, array('\Drupal\Component\Utility\SortArray', 'sortByTitleElement'));
|
uasort($admin_tasks, array('\Drupal\Component\Utility\SortArray', 'sortByTitleElement'));
|
||||||
// Move 'Configure permissions' links to the bottom of each section.
|
// Move 'Configure permissions' links to the bottom of each section.
|
||||||
$permission_key = "user.admin.people.permissions.$module";
|
$permission_key = "user.admin_permissions.$module";
|
||||||
if (isset($admin_tasks[$permission_key])) {
|
if (isset($admin_tasks[$permission_key])) {
|
||||||
$permission_task = $admin_tasks[$permission_key];
|
$permission_task = $admin_tasks[$permission_key];
|
||||||
unset($admin_tasks[$permission_key]);
|
unset($admin_tasks[$permission_key]);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ use Drupal\Core\Controller\ControllerBase;
|
||||||
use Drupal\Core\Entity\Query\QueryFactory;
|
use Drupal\Core\Entity\Query\QueryFactory;
|
||||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||||
use Drupal\Core\Form\FormBuilderInterface;
|
use Drupal\Core\Form\FormBuilderInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkTreeInterface;
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
use Drupal\Core\Theme\ThemeAccessCheck;
|
use Drupal\Core\Theme\ThemeAccessCheck;
|
||||||
use Drupal\system\SystemManager;
|
use Drupal\system\SystemManager;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
@ -56,6 +58,13 @@ class SystemController extends ControllerBase {
|
||||||
*/
|
*/
|
||||||
protected $themeHandler;
|
protected $themeHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu link tree service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||||
|
*/
|
||||||
|
protected $menuLinkTree;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new SystemController.
|
* Constructs a new SystemController.
|
||||||
*
|
*
|
||||||
|
|
@ -69,13 +78,16 @@ class SystemController extends ControllerBase {
|
||||||
* The form builder.
|
* The form builder.
|
||||||
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
||||||
* The theme handler.
|
* The theme handler.
|
||||||
|
* @param \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||||
|
* The menu link tree service.
|
||||||
*/
|
*/
|
||||||
public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler) {
|
public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler, MenuLinkTreeInterface $menu_link_tree) {
|
||||||
$this->systemManager = $systemManager;
|
$this->systemManager = $systemManager;
|
||||||
$this->queryFactory = $queryFactory;
|
$this->queryFactory = $queryFactory;
|
||||||
$this->themeAccess = $theme_access;
|
$this->themeAccess = $theme_access;
|
||||||
$this->formBuilder = $form_builder;
|
$this->formBuilder = $form_builder;
|
||||||
$this->themeHandler = $theme_handler;
|
$this->themeHandler = $theme_handler;
|
||||||
|
$this->menuLinkTree = $menu_link_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -87,66 +99,49 @@ class SystemController extends ControllerBase {
|
||||||
$container->get('entity.query'),
|
$container->get('entity.query'),
|
||||||
$container->get('access_check.theme'),
|
$container->get('access_check.theme'),
|
||||||
$container->get('form_builder'),
|
$container->get('form_builder'),
|
||||||
$container->get('theme_handler')
|
$container->get('theme_handler'),
|
||||||
|
$container->get('menu.link_tree')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide the administration overview page.
|
* Provide the administration overview page.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $link_id
|
||||||
* The administrative path for which to display child links.
|
* The ID of the administrative path link for which to display child links.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* A renderable array of the administration overview page.
|
* A renderable array of the administration overview page.
|
||||||
*/
|
*/
|
||||||
public function overview($path) {
|
public function overview($link_id) {
|
||||||
// Check for status report errors.
|
// Check for status report errors.
|
||||||
if ($this->systemManager->checkRequirements() && $this->currentUser()->hasPermission('administer site configuration')) {
|
if ($this->systemManager->checkRequirements() && $this->currentUser()->hasPermission('administer site configuration')) {
|
||||||
drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))), 'error');
|
drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))), 'error');
|
||||||
}
|
}
|
||||||
|
// Load all menu links below it.
|
||||||
|
$parameters = new MenuTreeParameters();
|
||||||
|
$parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
|
||||||
|
$tree = $this->menuLinkTree->load(NULL, $parameters);
|
||||||
|
$manipulators = array(
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
|
);
|
||||||
|
$tree = $this->menuLinkTree->transform($tree, $manipulators);
|
||||||
$blocks = array();
|
$blocks = array();
|
||||||
// Load all links on $path and menu links below it.
|
foreach ($tree as $key => $element) {
|
||||||
$query = $this->queryFactory->get('menu_link')
|
$link = $element->link;
|
||||||
->condition('link_path', $path)
|
$block['title'] = $link->getTitle();
|
||||||
->condition('module', 'system');
|
$block['description'] = $link->getDescription();
|
||||||
$result = $query->execute();
|
|
||||||
$menu_link_storage = $this->entityManager()->getStorage('menu_link');
|
|
||||||
if ($system_link = $menu_link_storage->loadMultiple($result)) {
|
|
||||||
$system_link = reset($system_link);
|
|
||||||
$query = $this->queryFactory->get('menu_link')
|
|
||||||
->condition('link_path', 'admin/help', '<>')
|
|
||||||
->condition('menu_name', $system_link->menu_name)
|
|
||||||
->condition('plid', $system_link->id())
|
|
||||||
->condition('hidden', 0);
|
|
||||||
$result = $query->execute();
|
|
||||||
if (!empty($result)) {
|
|
||||||
$menu_links = $menu_link_storage->loadMultiple($result);
|
|
||||||
foreach ($menu_links as $item) {
|
|
||||||
_menu_link_translate($item);
|
|
||||||
if (!$item['access']) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// The link description, either derived from 'description' in hook_menu()
|
|
||||||
// or customized via Menu UI module is used as title attribute.
|
|
||||||
if (!empty($item['localized_options']['attributes']['title'])) {
|
|
||||||
$item['description'] = $item['localized_options']['attributes']['title'];
|
|
||||||
unset($item['localized_options']['attributes']['title']);
|
|
||||||
}
|
|
||||||
$block = $item;
|
|
||||||
$block['content'] = array(
|
$block['content'] = array(
|
||||||
'#theme' => 'admin_block_content',
|
'#theme' => 'admin_block_content',
|
||||||
'#content' => $this->systemManager->getAdminBlock($item),
|
'#content' => $this->systemManager->getAdminBlock($link),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!empty($block['content']['#content'])) {
|
if (!empty($block['content']['#content'])) {
|
||||||
// Prepare for sorting as in function _menu_tree_check_access().
|
$blocks[$key] = $block;
|
||||||
// The weight is offset so it is always positive, with a uniform 5-digits.
|
|
||||||
$blocks[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($blocks) {
|
if ($blocks) {
|
||||||
ksort($blocks);
|
ksort($blocks);
|
||||||
return array(
|
return array(
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,20 @@ namespace Drupal\system\Form;
|
||||||
|
|
||||||
use Drupal\Component\Utility\String;
|
use Drupal\Component\Utility\String;
|
||||||
use Drupal\Component\Utility\Unicode;
|
use Drupal\Component\Utility\Unicode;
|
||||||
|
use Drupal\Core\Controller\TitleResolverInterface;
|
||||||
use Drupal\Core\Access\AccessManagerInterface;
|
use Drupal\Core\Access\AccessManagerInterface;
|
||||||
use Drupal\Core\Entity\EntityManagerInterface;
|
use Drupal\Core\Entity\EntityManagerInterface;
|
||||||
use Drupal\Core\Entity\Query\QueryFactory;
|
|
||||||
use Drupal\Core\Entity\Query\QueryFactoryInterface;
|
|
||||||
use Drupal\Core\Extension\Extension;
|
use Drupal\Core\Extension\Extension;
|
||||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||||
use Drupal\Core\Form\FormBase;
|
use Drupal\Core\Form\FormBase;
|
||||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||||
use Drupal\Core\Render\Element;
|
use Drupal\Core\Render\Element;
|
||||||
use Drupal\Core\Routing\RouteMatchInterface;
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
|
use Drupal\Core\Routing\RouteProviderInterface;
|
||||||
use Drupal\Core\Session\AccountInterface;
|
use Drupal\Core\Session\AccountInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides module installation interface.
|
* Provides module installation interface.
|
||||||
|
|
@ -61,11 +63,18 @@ class ModulesListForm extends FormBase {
|
||||||
protected $entityManager;
|
protected $entityManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The query factory.
|
* The title resolver.
|
||||||
*
|
*
|
||||||
* @var \Drupal\Core\Entity\Query\QueryFactory
|
* @var \Drupal\Core\Controller\TitleResolverInterface
|
||||||
*/
|
*/
|
||||||
protected $queryFactory;
|
protected $titleResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The route provider.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Routing\RouteProviderInterface
|
||||||
|
*/
|
||||||
|
protected $routeProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current route match.
|
* The current route match.
|
||||||
|
|
@ -74,6 +83,13 @@ class ModulesListForm extends FormBase {
|
||||||
*/
|
*/
|
||||||
protected $routeMatch;
|
protected $routeMatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu link manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
||||||
|
*/
|
||||||
|
protected $menuLinkManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
@ -83,9 +99,11 @@ class ModulesListForm extends FormBase {
|
||||||
$container->get('keyvalue.expirable')->get('module_list'),
|
$container->get('keyvalue.expirable')->get('module_list'),
|
||||||
$container->get('access_manager'),
|
$container->get('access_manager'),
|
||||||
$container->get('entity.manager'),
|
$container->get('entity.manager'),
|
||||||
$container->get('entity.query'),
|
|
||||||
$container->get('current_user'),
|
$container->get('current_user'),
|
||||||
$container->get('current_route_match')
|
$container->get('current_route_match'),
|
||||||
|
$container->get('title_resolver'),
|
||||||
|
$container->get('router.route_provider'),
|
||||||
|
$container->get('plugin.manager.menu.link')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,21 +118,27 @@ class ModulesListForm extends FormBase {
|
||||||
* Access manager.
|
* Access manager.
|
||||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||||
* The entity manager.
|
* The entity manager.
|
||||||
* @param \Drupal\Core\Entity\Query\QueryFactory $query_factory
|
|
||||||
* The entity query factory.
|
|
||||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||||
* The current user.
|
* The current user.
|
||||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||||
* The current route match.
|
* The current route match.
|
||||||
|
* @param \Drupal\Core\Controller\TitleResolverInterface $title_resolver
|
||||||
|
* 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, AccessManagerInterface $access_manager, EntityManagerInterface $entity_manager, QueryFactory $query_factory, AccountInterface $current_user, RouteMatchInterface $route_match) {
|
public function __construct(ModuleHandlerInterface $module_handler, KeyValueStoreExpirableInterface $key_value_expirable, AccessManagerInterface $access_manager, EntityManagerInterface $entity_manager, AccountInterface $current_user, RouteMatchInterface $route_match, TitleResolverInterface $title_resolver, RouteProviderInterface $route_provider, MenuLinkManagerInterface $menu_link_manager) {
|
||||||
$this->moduleHandler = $module_handler;
|
$this->moduleHandler = $module_handler;
|
||||||
$this->keyValueExpirable = $key_value_expirable;
|
$this->keyValueExpirable = $key_value_expirable;
|
||||||
$this->accessManager = $access_manager;
|
$this->accessManager = $access_manager;
|
||||||
$this->entityManager = $entity_manager;
|
$this->entityManager = $entity_manager;
|
||||||
$this->queryFactory = $query_factory;
|
|
||||||
$this->currentUser = $current_user;
|
$this->currentUser = $current_user;
|
||||||
$this->routeMatch = $route_match;
|
$this->routeMatch = $route_match;
|
||||||
|
$this->titleResolver = $title_resolver;
|
||||||
|
$this->routeProvider = $route_provider;
|
||||||
|
$this->menuLinkManager = $menu_link_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -249,11 +273,23 @@ class ModulesListForm extends FormBase {
|
||||||
if ($module->status && isset($module->info['configure'])) {
|
if ($module->status && isset($module->info['configure'])) {
|
||||||
$route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array();
|
$route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array();
|
||||||
if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) {
|
if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) {
|
||||||
$result = $this->queryFactory->get('menu_link')
|
|
||||||
->condition('route_name', $module->info['configure'])
|
$links = $this->menuLinkManager->loadLinksByRoute($module->info['configure']);
|
||||||
->execute();
|
/** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
||||||
$menu_items = $this->entityManager->getStorage('menu_link')->loadMultiple($result);
|
$link = reset($links);
|
||||||
$item = reset($menu_items);
|
// 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(
|
$row['links']['configure'] = array(
|
||||||
'#type' => 'link',
|
'#type' => 'link',
|
||||||
'#title' => $this->t('Configure'),
|
'#title' => $this->t('Configure'),
|
||||||
|
|
@ -262,7 +298,7 @@ class ModulesListForm extends FormBase {
|
||||||
'#options' => array(
|
'#options' => array(
|
||||||
'attributes' => array(
|
'attributes' => array(
|
||||||
'class' => array('module-link', 'module-link-configure'),
|
'class' => array('module-link', 'module-link-configure'),
|
||||||
'title' => $item['description'],
|
'title' => $description,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ namespace Drupal\system\Plugin\Block;
|
||||||
use Drupal\Component\Utility\NestedArray;
|
use Drupal\Component\Utility\NestedArray;
|
||||||
use Drupal\block\BlockBase;
|
use Drupal\block\BlockBase;
|
||||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||||
use Drupal\menu_link\MenuTreeInterface;
|
use Drupal\Core\Menu\MenuActiveTrailInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkTreeInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -27,12 +28,19 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The menu tree.
|
* The menu link tree service.
|
||||||
*
|
*
|
||||||
* @var \Drupal\menu_link\MenuTreeInterface
|
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||||
*/
|
*/
|
||||||
protected $menuTree;
|
protected $menuTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The active menu trail service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuActiveTrailInterface
|
||||||
|
*/
|
||||||
|
protected $menuActiveTrail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new SystemMenuBlock.
|
* Constructs a new SystemMenuBlock.
|
||||||
*
|
*
|
||||||
|
|
@ -42,12 +50,15 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
||||||
* The plugin_id for the plugin instance.
|
* The plugin_id for the plugin instance.
|
||||||
* @param array $plugin_definition
|
* @param array $plugin_definition
|
||||||
* The plugin implementation definition.
|
* The plugin implementation definition.
|
||||||
* @param \Drupal\menu_link\MenuTreeInterface $menu_tree
|
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
|
||||||
* The menu tree.
|
* The menu tree service.
|
||||||
|
* @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail
|
||||||
|
* The active menu trail service.
|
||||||
*/
|
*/
|
||||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuTreeInterface $menu_tree) {
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
|
||||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||||
$this->menuTree = $menu_tree;
|
$this->menuTree = $menu_tree;
|
||||||
|
$this->menuActiveTrail = $menu_active_trail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,7 +69,8 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
||||||
$configuration,
|
$configuration,
|
||||||
$plugin_id,
|
$plugin_id,
|
||||||
$plugin_definition,
|
$plugin_definition,
|
||||||
$container->get('menu_link.tree')
|
$container->get('menu.link_tree'),
|
||||||
|
$container->get('menu.active_trail')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,8 +78,15 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function build() {
|
public function build() {
|
||||||
$menu = $this->getDerivativeId();
|
$menu_name = $this->getDerivativeId();
|
||||||
return $this->menuTree->renderMenu($menu);
|
$parameters = $this->menuTree->getCurrentRouteMenuTreeParameters($menu_name);
|
||||||
|
$tree = $this->menuTree->load($menu_name, $parameters);
|
||||||
|
$manipulators = array(
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
|
);
|
||||||
|
$tree = $this->menuTree->transform($tree, $manipulators);
|
||||||
|
return $this->menuTree->build($tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -91,9 +110,7 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
||||||
public function getCacheKeys() {
|
public function getCacheKeys() {
|
||||||
// Add a key for the active menu trail.
|
// Add a key for the active menu trail.
|
||||||
$menu = $this->getDerivativeId();
|
$menu = $this->getDerivativeId();
|
||||||
$active_trail = $this->menuTree->getActiveTrailIds($menu);
|
return array_merge(parent::getCacheKeys(), array($this->menuActiveTrail->getActiveTrailCacheKey($menu)));
|
||||||
$active_trail_key = 'trail.' . implode('|', $active_trail);
|
|
||||||
return array_merge(parent::getCacheKeys(), array($active_trail_key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,7 +131,7 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
||||||
protected function getRequiredCacheContexts() {
|
protected function getRequiredCacheContexts() {
|
||||||
// Menu blocks must be cached per role: different roles may have access to
|
// Menu blocks must be cached per role: different roles may have access to
|
||||||
// different menu links.
|
// different menu links.
|
||||||
return array('cache_context.user.roles');
|
return array('cache_context.user.roles', 'cache_context.language');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@
|
||||||
|
|
||||||
namespace Drupal\system;
|
namespace Drupal\system;
|
||||||
|
|
||||||
use Drupal\Component\Utility\Unicode;
|
|
||||||
use Drupal\Core\Entity\EntityManagerInterface;
|
use Drupal\Core\Entity\EntityManagerInterface;
|
||||||
|
use Drupal\Core\Menu\MenuActiveTrailInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkTreeInterface;
|
||||||
|
use Drupal\Core\Menu\MenuLinkInterface;
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||||
use Drupal\Core\Database\Connection;
|
use Drupal\Core\Database\Connection;
|
||||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||||
|
|
@ -32,13 +35,6 @@ class SystemManager {
|
||||||
*/
|
*/
|
||||||
protected $database;
|
protected $database;
|
||||||
|
|
||||||
/**
|
|
||||||
* The menu link storage.
|
|
||||||
*
|
|
||||||
* @var \Drupal\menu_link\MenuLinkStorageInterface
|
|
||||||
*/
|
|
||||||
protected $menuLinkStorage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The request stack.
|
* The request stack.
|
||||||
*
|
*
|
||||||
|
|
@ -46,6 +42,20 @@ class SystemManager {
|
||||||
*/
|
*/
|
||||||
protected $requestStack;
|
protected $requestStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu link tree manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||||
|
*/
|
||||||
|
protected $menuTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The active menu trail service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuActiveTrailInterface
|
||||||
|
*/
|
||||||
|
protected $menuActiveTrail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A static cache of menu items.
|
* A static cache of menu items.
|
||||||
*
|
*
|
||||||
|
|
@ -79,12 +89,17 @@ class SystemManager {
|
||||||
* The entity manager.
|
* The entity manager.
|
||||||
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
||||||
* The request stack.
|
* The request stack.
|
||||||
|
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
|
||||||
|
* The menu tree manager.
|
||||||
|
* @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail
|
||||||
|
* The active menu trail service.
|
||||||
*/
|
*/
|
||||||
public function __construct(ModuleHandlerInterface $module_handler, Connection $database, EntityManagerInterface $entity_manager, RequestStack $request_stack) {
|
public function __construct(ModuleHandlerInterface $module_handler, Connection $database, EntityManagerInterface $entity_manager, RequestStack $request_stack, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
|
||||||
$this->moduleHandler = $module_handler;
|
$this->moduleHandler = $module_handler;
|
||||||
$this->database = $database;
|
$this->database = $database;
|
||||||
$this->menuLinkStorage = $entity_manager->getStorage('menu_link');
|
|
||||||
$this->requestStack = $request_stack;
|
$this->requestStack = $request_stack;
|
||||||
|
$this->menuTree = $menu_tree;
|
||||||
|
$this->menuActiveTrail = $menu_active_trail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -171,11 +186,10 @@ class SystemManager {
|
||||||
* A render array suitable for drupal_render.
|
* A render array suitable for drupal_render.
|
||||||
*/
|
*/
|
||||||
public function getBlockContents() {
|
public function getBlockContents() {
|
||||||
$request = $this->requestStack->getCurrentRequest();
|
// We hard-code the menu name here since otherwise a link in the tools menu
|
||||||
$route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME);
|
// or elsewhere could give us a blank block.
|
||||||
$items = $this->menuLinkStorage->loadByProperties(array('route_name' => $route_name));
|
$link = $this->menuActiveTrail->getActiveLink('admin');
|
||||||
$item = reset($items);
|
if ($link && $content = $this->getAdminBlock($link)) {
|
||||||
if ($content = $this->getAdminBlock($item)) {
|
|
||||||
$output = array(
|
$output = array(
|
||||||
'#theme' => 'admin_block_content',
|
'#theme' => 'admin_block_content',
|
||||||
'#content' => $content,
|
'#content' => $content,
|
||||||
|
|
@ -192,48 +206,33 @@ class SystemManager {
|
||||||
/**
|
/**
|
||||||
* Provide a single block on the administration overview page.
|
* Provide a single block on the administration overview page.
|
||||||
*
|
*
|
||||||
* @param \Drupal\menu_link\MenuLinkInterface|array $item
|
* @param \Drupal\Core\Menu\MenuLinkInterface $instance
|
||||||
* The menu item to be displayed.
|
* The menu item to be displayed.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* An array of menu items, as expected by theme_admin_block_content().
|
* An array of menu items, as expected by theme_admin_block_content().
|
||||||
*/
|
*/
|
||||||
public function getAdminBlock($item) {
|
public function getAdminBlock(MenuLinkInterface $instance) {
|
||||||
if (!isset($item['mlid'])) {
|
|
||||||
$menu_links = $this->menuLinkStorage->loadByProperties(array('link_path' => $item['path'], 'module' => 'system'));
|
|
||||||
if ($menu_links) {
|
|
||||||
$menu_link = reset($menu_links);
|
|
||||||
$item['mlid'] = $menu_link->id();
|
|
||||||
$item['menu_name'] = $menu_link->menu_name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($this->menuItems[$item['mlid']])) {
|
|
||||||
return $this->menuItems[$item['mlid']];
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = array();
|
$content = array();
|
||||||
$menu_links = $this->menuLinkStorage->loadByProperties(array('plid' => $item['mlid'], 'menu_name' => $item['menu_name'], 'hidden' => 0));
|
// Only find the children of this link.
|
||||||
foreach ($menu_links as $link) {
|
$link_id = $instance->getPluginId();
|
||||||
_menu_link_translate($link);
|
$parameters = new MenuTreeParameters();
|
||||||
if ($link['access']) {
|
$parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
|
||||||
// The link description, either derived from 'description' in
|
$tree = $this->menuTree->load(NULL, $parameters);
|
||||||
// hook_menu() or customized via Menu UI module is used as title attribute.
|
$manipulators = array(
|
||||||
if (!empty($link['localized_options']['attributes']['title'])) {
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
$link['description'] = $link['localized_options']['attributes']['title'];
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
unset($link['localized_options']['attributes']['title']);
|
);
|
||||||
}
|
$tree = $this->menuTree->transform($tree, $manipulators);
|
||||||
// Prepare for sorting as in function _menu_tree_check_access().
|
foreach ($tree as $key => $element) {
|
||||||
// The weight is offset so it is always positive, with a uniform 5-digits.
|
/** @var $link \Drupal\Core\Menu\MenuLinkInterface */
|
||||||
$key = (50000 + $link['weight']) . ' ' . Unicode::strtolower($link['title']) . ' ' . $link['mlid'];
|
$link = $element->link;
|
||||||
$content[$key] = $link;
|
$content[$key]['title'] = $link->getTitle();
|
||||||
}
|
$content[$key]['options'] = $link->getOptions();
|
||||||
|
$content[$key]['description'] = $link->getDescription();
|
||||||
|
$content[$key]['url'] = $link->getUrlObject();
|
||||||
}
|
}
|
||||||
ksort($content);
|
ksort($content);
|
||||||
$this->menuItems[$item['mlid']] = $content;
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,15 +83,10 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
);
|
);
|
||||||
$this->assertBreadcrumb('admin/structure/menu/manage/tools', $trail);
|
$this->assertBreadcrumb('admin/structure/menu/manage/tools', $trail);
|
||||||
|
|
||||||
$mlid_node_add = \Drupal::entityQuery('menu_link')
|
|
||||||
->condition('machine_name', 'node.add_page')
|
|
||||||
->condition('module', 'node')
|
|
||||||
->execute();
|
|
||||||
$mlid_node_add = reset($mlid_node_add);
|
|
||||||
$trail += array(
|
$trail += array(
|
||||||
'admin/structure/menu/manage/tools' => t('Tools'),
|
'admin/structure/menu/manage/tools' => t('Tools'),
|
||||||
);
|
);
|
||||||
$this->assertBreadcrumb("admin/structure/menu/item/$mlid_node_add/edit", $trail);
|
$this->assertBreadcrumb("admin/structure/menu/link/node.add_page/edit", $trail);
|
||||||
$this->assertBreadcrumb('admin/structure/menu/manage/tools/add', $trail);
|
$this->assertBreadcrumb('admin/structure/menu/manage/tools/add', $trail);
|
||||||
|
|
||||||
// Verify Node administration breadcrumbs.
|
// Verify Node administration breadcrumbs.
|
||||||
|
|
@ -165,7 +160,7 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
// Alter node type menu settings.
|
// Alter node type menu settings.
|
||||||
\Drupal::config("menu.entity.node.$type")
|
\Drupal::config("menu.entity.node.$type")
|
||||||
->set('available_menus', $menus)
|
->set('available_menus', $menus)
|
||||||
->set('parent', 'tools:0')
|
->set('parent', 'tools:')
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
foreach ($menus as $menu) {
|
foreach ($menus as $menu) {
|
||||||
|
|
@ -174,13 +169,13 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
$node2 = $this->drupalCreateNode(array(
|
$node2 = $this->drupalCreateNode(array(
|
||||||
'type' => $type,
|
'type' => $type,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'menu' => entity_create('menu_link', array(
|
'menu' => array(
|
||||||
'enabled' => 1,
|
'hidden' => 0,
|
||||||
'link_title' => 'Parent ' . $title,
|
'title' => 'Parent ' . $title,
|
||||||
'description' => '',
|
'description' => '',
|
||||||
'menu_name' => $menu,
|
'menu_name' => $menu,
|
||||||
'plid' => 0,
|
'parent' => '',
|
||||||
)),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($menu == 'tools') {
|
if ($menu == 'tools') {
|
||||||
|
|
@ -192,26 +187,26 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
// link below it, and verify a full breadcrumb for the last child node.
|
// link below it, and verify a full breadcrumb for the last child node.
|
||||||
$menu = 'tools';
|
$menu = 'tools';
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'link_title' => 'Root',
|
'title[0][value]' => 'Root',
|
||||||
'link_path' => 'node',
|
'url' => 'node',
|
||||||
);
|
);
|
||||||
$this->drupalPostForm("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => 'Root'));
|
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => 'Root'));
|
||||||
$link = reset($menu_links);
|
$link = reset($menu_links);
|
||||||
|
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'menu[parent]' => $link['menu_name'] . ':' . $link['mlid'],
|
'menu[menu_parent]' => $link->getMenuName() . ':' . $link->getPluginId(),
|
||||||
);
|
);
|
||||||
$this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save and keep published'));
|
$this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save and keep published'));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
"node" => $link['link_title'],
|
"node" => $link->getTitle(),
|
||||||
);
|
);
|
||||||
$trail = $home + $expected;
|
$trail = $home + $expected;
|
||||||
$tree = $expected + array(
|
$tree = $expected + array(
|
||||||
'node/' . $parent->id() => $parent->menu['link_title'],
|
'node/' . $parent->id() => $parent->menu['title'],
|
||||||
);
|
);
|
||||||
$trail += array(
|
$trail += array(
|
||||||
'node/' . $parent->id() => $parent->menu['link_title'],
|
'node/' . $parent->id() => $parent->menu['title'],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add a taxonomy term/tag to last node, and add a link for that term to the
|
// Add a taxonomy term/tag to last node, and add a link for that term to the
|
||||||
|
|
@ -241,32 +236,36 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
}
|
}
|
||||||
$parent_tid = $term->id();
|
$parent_tid = $term->id();
|
||||||
}
|
}
|
||||||
$parent_mlid = 0;
|
$parent_mlid = '';
|
||||||
foreach ($tags as $name => $data) {
|
foreach ($tags as $name => $data) {
|
||||||
$term = $data['term'];
|
$term = $data['term'];
|
||||||
$edit = array(
|
$edit = array(
|
||||||
'link_title' => "$name link",
|
'title[0][value]' => "$name link",
|
||||||
'link_path' => "taxonomy/term/{$term->id()}",
|
'url' => "taxonomy/term/{$term->id()}",
|
||||||
'parent' => "$menu:{$parent_mlid}",
|
'menu_parent' => "$menu:{$parent_mlid}",
|
||||||
);
|
);
|
||||||
$this->drupalPostForm("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_title' => $edit['link_title'], 'link_path' => $edit['link_path']));
|
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $edit['title[0][value]'], 'route_name' => 'taxonomy.term_page', 'route_parameters' => serialize(array('taxonomy_term' => $term->id()))));
|
||||||
$tags[$name]['link'] = reset($menu_links);
|
$tags[$name]['link'] = reset($menu_links);
|
||||||
$tags[$name]['link']['link_path'] = $edit['link_path'];
|
$parent_mlid = $tags[$name]['link']->getPluginId();
|
||||||
$parent_mlid = $tags[$name]['link']['mlid'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify expected breadcrumbs for menu links.
|
// Verify expected breadcrumbs for menu links.
|
||||||
$trail = $home;
|
$trail = $home;
|
||||||
$tree = array();
|
$tree = array();
|
||||||
|
// Logout the user because we want to check the active class as well, which
|
||||||
|
// is just rendered as anonymous user.
|
||||||
|
$this->drupalLogout();
|
||||||
foreach ($tags as $name => $data) {
|
foreach ($tags as $name => $data) {
|
||||||
$term = $data['term'];
|
$term = $data['term'];
|
||||||
|
/** @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface $link */
|
||||||
$link = $data['link'];
|
$link = $data['link'];
|
||||||
|
|
||||||
|
$link_path = $link->getUrlObject()->getInternalPath();
|
||||||
$tree += array(
|
$tree += array(
|
||||||
$link['link_path'] => $link['link_title'],
|
$link_path => $link->getTitle(),
|
||||||
);
|
);
|
||||||
$this->assertBreadcrumb($link['link_path'], $trail, $term->getName(), $tree);
|
$this->assertBreadcrumb($link_path, $trail, $term->getName(), $tree);
|
||||||
$this->assertRaw(String::checkPlain($parent->getTitle()), 'Tagged node found.');
|
$this->assertRaw(String::checkPlain($parent->getTitle()), 'Tagged node found.');
|
||||||
|
|
||||||
// Additionally make sure that this link appears only once; i.e., the
|
// Additionally make sure that this link appears only once; i.e., the
|
||||||
|
|
@ -275,14 +274,14 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
// other than the breadcrumb trail.
|
// other than the breadcrumb trail.
|
||||||
$elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array(
|
$elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array(
|
||||||
':menu' => 'block-bartik-tools',
|
':menu' => 'block-bartik-tools',
|
||||||
':href' => url($link['link_path']),
|
':href' => url($link_path),
|
||||||
));
|
));
|
||||||
$this->assertTrue(count($elements) == 1, "Link to {$link['link_path']} appears only once.");
|
$this->assertTrue(count($elements) == 1, "Link to {$link_path} appears only once.");
|
||||||
|
|
||||||
// Next iteration should expect this tag as parent link.
|
// Next iteration should expect this tag as parent link.
|
||||||
// Note: Term name, not link name, due to taxonomy_term_page().
|
// Note: Term name, not link name, due to taxonomy_term_page().
|
||||||
$trail += array(
|
$trail += array(
|
||||||
$link['link_path'] => $term->getName(),
|
$link_path => $term->getName(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,7 +291,6 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
|
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
|
||||||
'access user profiles',
|
'access user profiles',
|
||||||
));
|
));
|
||||||
$this->drupalLogout();
|
|
||||||
|
|
||||||
// Verify breadcrumb on front page.
|
// Verify breadcrumb on front page.
|
||||||
$this->assertBreadcrumb('<front>', array());
|
$this->assertBreadcrumb('<front>', array());
|
||||||
|
|
@ -359,4 +357,5 @@ class BreadcrumbTest extends MenuTestBase {
|
||||||
$this->assertBreadcrumb('admin/reports/dblog', $trail, t('Recent log messages'));
|
$this->assertBreadcrumb('admin/reports/dblog', $trail, t('Recent log messages'));
|
||||||
$this->assertNoResponse(403);
|
$this->assertNoResponse(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace Drupal\system\Tests\Menu;
|
namespace Drupal\system\Tests\Menu;
|
||||||
|
|
||||||
|
use Drupal\Component\Utility\String;
|
||||||
use Drupal\locale\TranslationString;
|
use Drupal\locale\TranslationString;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
|
|
@ -14,6 +15,9 @@ use Drupal\simpletest\WebTestBase;
|
||||||
* Tests handling of menu links hierarchies.
|
* Tests handling of menu links hierarchies.
|
||||||
*
|
*
|
||||||
* @group Menu
|
* @group Menu
|
||||||
|
*
|
||||||
|
* @todo Move this under menu_link_content module.
|
||||||
|
* https://www.drupal.org/node/2310353
|
||||||
*/
|
*/
|
||||||
class LinksTest extends WebTestBase {
|
class LinksTest extends WebTestBase {
|
||||||
|
|
||||||
|
|
@ -22,7 +26,14 @@ class LinksTest extends WebTestBase {
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('router_test');
|
public static $modules = array('router_test', 'menu_link_content');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu link plugin manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
|
||||||
|
*/
|
||||||
|
protected $menuLinkManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
|
@ -30,6 +41,8 @@ class LinksTest extends WebTestBase {
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->menuLinkManager = \Drupal::service('plugin.manager.menu.link');
|
||||||
|
|
||||||
entity_create('menu', array(
|
entity_create('menu', array(
|
||||||
'id' => 'menu_test',
|
'id' => 'menu_test',
|
||||||
'label' => 'Test menu',
|
'label' => 'Test menu',
|
||||||
|
|
@ -41,55 +54,60 @@ class LinksTest extends WebTestBase {
|
||||||
* Create a simple hierarchy of links.
|
* Create a simple hierarchy of links.
|
||||||
*/
|
*/
|
||||||
function createLinkHierarchy($module = 'menu_test') {
|
function createLinkHierarchy($module = 'menu_test') {
|
||||||
// First remove all the menu links.
|
// First remove all the menu links in the menu.
|
||||||
$menu_links = menu_link_load_multiple();
|
$this->menuLinkManager->deleteLinksInMenu('menu_test');
|
||||||
menu_link_delete_multiple(array_keys($menu_links), TRUE, TRUE);
|
|
||||||
|
|
||||||
// Then create a simple link hierarchy:
|
// Then create a simple link hierarchy:
|
||||||
// - $parent
|
// - parent
|
||||||
// - $child-1
|
// - child-1
|
||||||
// - $child-1-1
|
// - child-1-1
|
||||||
// - $child-1-2
|
// - child-1-2
|
||||||
// - $child-2
|
// - child-2
|
||||||
$base_options = array(
|
$base_options = array(
|
||||||
'link_title' => 'Menu link test',
|
'title' => 'Menu link test',
|
||||||
'module' => $module,
|
'provider' => $module,
|
||||||
'menu_name' => 'menu_test',
|
'menu_name' => 'menu_test',
|
||||||
|
'bundle' => 'menu_link_content'
|
||||||
);
|
);
|
||||||
|
|
||||||
$links['parent'] = $base_options + array(
|
$parent = $base_options + array(
|
||||||
'link_path' => 'menu-test/parent',
|
'route_name' => 'menu_test.hierarchy_parent',
|
||||||
);
|
);
|
||||||
$links['parent'] = entity_create('menu_link', $links['parent']);
|
$link = entity_create('menu_link_content', $parent);
|
||||||
$links['parent']->save();
|
$link->save();
|
||||||
|
$links['parent'] = $link->getPluginId();
|
||||||
|
|
||||||
$links['child-1'] = $base_options + array(
|
$child_1 = $base_options + array(
|
||||||
'link_path' => 'menu-test/parent/child-1',
|
'route_name' => 'menu_test.hierarchy_parent_child',
|
||||||
'plid' => $links['parent']['mlid'],
|
'parent' => $links['parent'],
|
||||||
);
|
);
|
||||||
$links['child-1'] = entity_create('menu_link', $links['child-1']);
|
$link = entity_create('menu_link_content', $child_1);
|
||||||
$links['child-1']->save();
|
$link->save();
|
||||||
|
$links['child-1'] = $link->getPluginId();
|
||||||
|
|
||||||
$links['child-1-1'] = $base_options + array(
|
$child_1_1 = $base_options + array(
|
||||||
'link_path' => 'menu-test/parent/child-1/child-1-1',
|
'route_name' => 'menu_test.hierarchy_parent_child2',
|
||||||
'plid' => $links['child-1']['mlid'],
|
'parent' => $links['child-1'],
|
||||||
);
|
);
|
||||||
$links['child-1-1'] = entity_create('menu_link', $links['child-1-1']);
|
$link = entity_create('menu_link_content', $child_1_1);
|
||||||
$links['child-1-1']->save();
|
$link->save();
|
||||||
|
$links['child-1-1'] = $link->getPluginId();
|
||||||
|
|
||||||
$links['child-1-2'] = $base_options + array(
|
$child_1_2 = $base_options + array(
|
||||||
'link_path' => 'menu-test/parent/child-1/child-1-2',
|
'route_name' => 'menu_test.hierarchy_parent_child2',
|
||||||
'plid' => $links['child-1']['mlid'],
|
'parent' => $links['child-1'],
|
||||||
);
|
);
|
||||||
$links['child-1-2'] = entity_create('menu_link', $links['child-1-2']);
|
$link = entity_create('menu_link_content', $child_1_2);
|
||||||
$links['child-1-2']->save();
|
$link->save();
|
||||||
|
$links['child-1-2'] = $link->getPluginId();
|
||||||
|
|
||||||
$links['child-2'] = $base_options + array(
|
$child_2 = $base_options + array(
|
||||||
'link_path' => 'menu-test/parent/child-2',
|
'route_name' => 'menu_test.hierarchy_parent_child',
|
||||||
'plid' => $links['parent']['mlid'],
|
'parent' => $links['parent'],
|
||||||
);
|
);
|
||||||
$links['child-2'] = entity_create('menu_link', $links['child-2']);
|
$link = entity_create('menu_link_content', $child_2);
|
||||||
$links['child-2']->save();
|
$link->save();
|
||||||
|
$links['child-2'] = $link->getPluginId();
|
||||||
|
|
||||||
return $links;
|
return $links;
|
||||||
}
|
}
|
||||||
|
|
@ -98,13 +116,12 @@ class LinksTest extends WebTestBase {
|
||||||
* Assert that at set of links is properly parented.
|
* Assert that at set of links is properly parented.
|
||||||
*/
|
*/
|
||||||
function assertMenuLinkParents($links, $expected_hierarchy) {
|
function assertMenuLinkParents($links, $expected_hierarchy) {
|
||||||
foreach ($expected_hierarchy as $child => $parent) {
|
foreach ($expected_hierarchy as $id => $parent) {
|
||||||
$mlid = $links[$child]['mlid'];
|
/* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin */
|
||||||
$plid = $parent ? $links[$parent]['mlid'] : 0;
|
$menu_link_plugin = $this->menuLinkManager->createInstance($links[$id]);
|
||||||
|
$expected_parent = isset($links[$parent]) ? $links[$parent] : '';
|
||||||
|
|
||||||
$menu_link = menu_link_load($mlid);
|
$this->assertEqual($menu_link_plugin->getParent(), $expected_parent, String::format('Menu link %id has parent of %parent, expected %expected_parent.', array('%id' => $id, '%parent' => $menu_link_plugin->getParent(), '%expected_parent' => $expected_parent)));
|
||||||
menu_link_save($menu_link);
|
|
||||||
$this->assertEqual($menu_link['plid'], $plid, format_string('Menu link %mlid has parent of %plid, expected %expected_plid.', array('%mlid' => $mlid, '%plid' => $menu_link['plid'], '%expected_plid' => $plid)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +133,7 @@ class LinksTest extends WebTestBase {
|
||||||
$links = $this->createLinkHierarchy($module);
|
$links = $this->createLinkHierarchy($module);
|
||||||
|
|
||||||
$expected_hierarchy = array(
|
$expected_hierarchy = array(
|
||||||
'parent' => FALSE,
|
'parent' => '',
|
||||||
'child-1' => 'parent',
|
'child-1' => 'parent',
|
||||||
'child-1-1' => 'child-1',
|
'child-1-1' => 'child-1',
|
||||||
'child-1-2' => 'child-1',
|
'child-1-2' => 'child-1',
|
||||||
|
|
@ -127,11 +144,15 @@ class LinksTest extends WebTestBase {
|
||||||
// Start over, and move child-1 under child-2, and check that all the
|
// Start over, and move child-1 under child-2, and check that all the
|
||||||
// childs of child-1 have been moved too.
|
// childs of child-1 have been moved too.
|
||||||
$links = $this->createLinkHierarchy($module);
|
$links = $this->createLinkHierarchy($module);
|
||||||
$links['child-1']['plid'] = $links['child-2']['mlid'];
|
/* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin */
|
||||||
menu_link_save($links['child-1']);
|
$this->menuLinkManager->updateDefinition($links['child-1'], array('parent' => $links['child-2']));
|
||||||
|
// Verify that the entity was updated too.
|
||||||
|
$menu_link_plugin = $this->menuLinkManager->createInstance($links['child-1']);
|
||||||
|
$entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $menu_link_plugin->getDerivativeId());
|
||||||
|
$this->assertEqual($entity->getParentId(), $links['child-2']);
|
||||||
|
|
||||||
$expected_hierarchy = array(
|
$expected_hierarchy = array(
|
||||||
'parent' => FALSE,
|
'parent' => '',
|
||||||
'child-1' => 'child-2',
|
'child-1' => 'child-2',
|
||||||
'child-1-1' => 'child-1',
|
'child-1-1' => 'child-1',
|
||||||
'child-1-2' => 'child-1',
|
'child-1-2' => 'child-1',
|
||||||
|
|
@ -140,29 +161,9 @@ class LinksTest extends WebTestBase {
|
||||||
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
||||||
|
|
||||||
// Start over, and delete child-1, and check that the children of child-1
|
// Start over, and delete child-1, and check that the children of child-1
|
||||||
// have been reassigned to the parent. menu_link_delete() will cowardly
|
// have been reassigned to the parent.
|
||||||
// refuse to delete a menu link defined by the system module, so skip the
|
|
||||||
// test in that case.
|
|
||||||
if ($module != 'system') {
|
|
||||||
$links = $this->createLinkHierarchy($module);
|
$links = $this->createLinkHierarchy($module);
|
||||||
menu_link_delete($links['child-1']['mlid']);
|
$this->menuLinkManager->removeDefinition($links['child-1']);
|
||||||
|
|
||||||
$expected_hierarchy = array(
|
|
||||||
'parent' => FALSE,
|
|
||||||
'child-1-1' => 'parent',
|
|
||||||
'child-1-2' => 'parent',
|
|
||||||
'child-2' => 'parent',
|
|
||||||
);
|
|
||||||
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start over, forcefully delete child-1 from the database, simulating a
|
|
||||||
// database crash. Check that the children of child-1 have been reassigned
|
|
||||||
// to the parent, going up on the old path hierarchy stored in each of the
|
|
||||||
// links.
|
|
||||||
$links = $this->createLinkHierarchy($module);
|
|
||||||
// Don't do that at home.
|
|
||||||
entity_delete_multiple('menu_link', array($links['child-1']['mlid']));
|
|
||||||
|
|
||||||
$expected_hierarchy = array(
|
$expected_hierarchy = array(
|
||||||
'parent' => FALSE,
|
'parent' => FALSE,
|
||||||
|
|
@ -172,119 +173,26 @@ class LinksTest extends WebTestBase {
|
||||||
);
|
);
|
||||||
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
||||||
|
|
||||||
// Start over, forcefully delete the parent from the database, simulating a
|
// @todo Figure out what makes sense to test in terms of automatic
|
||||||
// database crash. Check that the children of parent are now top-level.
|
// re-parenting. https://www.drupal.org/node/2309531
|
||||||
$links = $this->createLinkHierarchy($module);
|
|
||||||
// Don't do that at home.
|
|
||||||
db_delete('menu_links')
|
|
||||||
->condition('mlid', $links['parent']['mlid'])
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
$expected_hierarchy = array(
|
|
||||||
'child-1-1' => 'child-1',
|
|
||||||
'child-1-2' => 'child-1',
|
|
||||||
'child-2' => FALSE,
|
|
||||||
);
|
|
||||||
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests automatic reparenting.
|
* Tests uninstalling a module providing default links.
|
||||||
*
|
|
||||||
* Runs tests on menu links defined by the menu_link.static service.
|
|
||||||
*/
|
|
||||||
function testMenuLinkRouterReparenting() {
|
|
||||||
// Run all the standard parenting tests on menu links derived from
|
|
||||||
// menu routers.
|
|
||||||
$this->testMenuLinkReparenting('system');
|
|
||||||
|
|
||||||
// Additionnaly, test reparenting based on path.
|
|
||||||
$links = $this->createLinkHierarchy('system');
|
|
||||||
|
|
||||||
// Move child-1-2 has a child of child-2, making the link hierarchy
|
|
||||||
// inconsistent with the path hierarchy.
|
|
||||||
$links['child-1-2']['plid'] = $links['child-2']['mlid'];
|
|
||||||
menu_link_save($links['child-1-2']);
|
|
||||||
|
|
||||||
// Check the new hierarchy.
|
|
||||||
$expected_hierarchy = array(
|
|
||||||
'parent' => FALSE,
|
|
||||||
'child-1' => 'parent',
|
|
||||||
'child-1-1' => 'child-1',
|
|
||||||
'child-2' => 'parent',
|
|
||||||
'child-1-2' => 'child-2',
|
|
||||||
);
|
|
||||||
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
|
||||||
|
|
||||||
// Now delete 'parent' directly from the database, simulating a database
|
|
||||||
// crash. 'child-1' and 'child-2' should get moved to the
|
|
||||||
// top-level.
|
|
||||||
// Don't do that at home.
|
|
||||||
db_delete('menu_links')
|
|
||||||
->condition('mlid', $links['parent']['mlid'])
|
|
||||||
->execute();
|
|
||||||
$expected_hierarchy = array(
|
|
||||||
'child-1' => FALSE,
|
|
||||||
'child-1-1' => 'child-1',
|
|
||||||
'child-2' => FALSE,
|
|
||||||
'child-1-2' => 'child-2',
|
|
||||||
);
|
|
||||||
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
|
||||||
|
|
||||||
// Now delete 'child-2' directly from the database, simulating a database
|
|
||||||
// crash. 'child-1-2' will get reparented to the top.
|
|
||||||
// Don't do that at home.
|
|
||||||
db_delete('menu_links')
|
|
||||||
->condition('mlid', $links['child-2']['mlid'])
|
|
||||||
->execute();
|
|
||||||
$expected_hierarchy = array(
|
|
||||||
'child-1' => FALSE,
|
|
||||||
'child-1-1' => 'child-1',
|
|
||||||
'child-1-2' => FALSE,
|
|
||||||
);
|
|
||||||
$this->assertMenuLinkParents($links, $expected_hierarchy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the router system integration (route_name and route_parameters).
|
|
||||||
*/
|
|
||||||
public function testRouterIntegration() {
|
|
||||||
$menu_link = entity_create('menu_link', array(
|
|
||||||
'link_path' => 'router_test/test1',
|
|
||||||
));
|
|
||||||
$menu_link->save();
|
|
||||||
$this->assertEqual($menu_link->route_name, 'router_test.1');
|
|
||||||
$this->assertEqual($menu_link->route_parameters, array());
|
|
||||||
|
|
||||||
$menu_link = entity_create('menu_link', array(
|
|
||||||
'link_path' => 'router_test/test3/test',
|
|
||||||
));
|
|
||||||
$menu_link->save();
|
|
||||||
$this->assertEqual($menu_link->route_name, 'router_test.3');
|
|
||||||
$this->assertEqual($menu_link->route_parameters, array('value' => 'test'));
|
|
||||||
|
|
||||||
$menu_link = entity_load('menu_link', $menu_link->id());
|
|
||||||
$this->assertEqual($menu_link->route_name, 'router_test.3');
|
|
||||||
$this->assertEqual($menu_link->route_parameters, array('value' => 'test'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests uninstall a module providing default links.
|
|
||||||
*/
|
*/
|
||||||
public function testModuleUninstalledMenuLinks() {
|
public function testModuleUninstalledMenuLinks() {
|
||||||
\Drupal::moduleHandler()->install(array('menu_test'));
|
\Drupal::moduleHandler()->install(array('menu_test'));
|
||||||
\Drupal::service('router.builder')->rebuild();
|
\Drupal::service('router.builder')->rebuild();
|
||||||
menu_link_rebuild_defaults();
|
\Drupal::service('plugin.manager.menu.link')->rebuild();
|
||||||
$result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
|
$menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
|
||||||
$menu_links = \Drupal::entityManager()->getStorage('menu_link')->loadMultiple($result);
|
|
||||||
$this->assertEqual(count($menu_links), 1);
|
$this->assertEqual(count($menu_links), 1);
|
||||||
$menu_link = reset($menu_links);
|
$menu_link = reset($menu_links);
|
||||||
$this->assertEqual($menu_link->machine_name, 'menu_test');
|
$this->assertEqual($menu_link->getPluginId(), 'menu_test');
|
||||||
|
|
||||||
// Uninstall the module and ensure the menu link got removed.
|
// Uninstall the module and ensure the menu link got removed.
|
||||||
\Drupal::moduleHandler()->uninstall(array('menu_test'));
|
\Drupal::moduleHandler()->uninstall(array('menu_test'));
|
||||||
$result = $menu_link = \Drupal::entityQuery('menu_link')->condition('machine_name', 'menu_test')->execute();
|
\Drupal::service('plugin.manager.menu.link')->rebuild();
|
||||||
$menu_links = \Drupal::entityManager()->getStorage('menu_link')->loadMultiple($result);
|
$menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
|
||||||
$this->assertEqual(count($menu_links), 0);
|
$this->assertEqual(count($menu_links), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\system\Tests\Menu\MenuLinkDefaultIntegrationTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\system\Tests\Menu;
|
||||||
|
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
|
use Drupal\simpletest\KernelTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests integration of static menu links.
|
||||||
|
*
|
||||||
|
* @group Menu
|
||||||
|
*/
|
||||||
|
class MenuLinkDefaultIntegrationTest extends KernelTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modules to enable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $modules = array(
|
||||||
|
'system',
|
||||||
|
'menu_test',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->installSchema('system', array('router'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests moving a static menu link without a specified menu to the root.
|
||||||
|
*/
|
||||||
|
public function testMoveToRoot() {
|
||||||
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
|
$menu_link_manager->rebuild();
|
||||||
|
|
||||||
|
$menu_link = $menu_link_manager->getDefinition('menu_test.child');
|
||||||
|
$this->assertEqual($menu_link['parent'], 'menu_test.parent');
|
||||||
|
$this->assertEqual($menu_link['menu_name'], 'test');
|
||||||
|
|
||||||
|
$tree = \Drupal::menuTree()->load('test', new MenuTreeParameters());
|
||||||
|
$this->assertEqual(count($tree), 1);
|
||||||
|
$this->assertEqual($tree['menu_test.parent']->link->getPluginId(), 'menu_test.parent');
|
||||||
|
$this->assertEqual($tree['menu_test.parent']->subtree['menu_test.child']->link->getPluginId(), 'menu_test.child');
|
||||||
|
|
||||||
|
// Ensure that the menu name is not forgotten.
|
||||||
|
$menu_link_manager->updateDefinition('menu_test.child', array('parent' => ''));
|
||||||
|
$menu_link = $menu_link_manager->getDefinition('menu_test.child');
|
||||||
|
|
||||||
|
$this->assertEqual($menu_link['parent'], '');
|
||||||
|
$this->assertEqual($menu_link['menu_name'], 'test');
|
||||||
|
|
||||||
|
$tree = \Drupal::menuTree()->load('test', new MenuTreeParameters());
|
||||||
|
$this->assertEqual(count($tree), 2);
|
||||||
|
$this->assertEqual($tree['menu_test.parent']->link->getPluginId(), 'menu_test.parent');
|
||||||
|
$this->assertEqual($tree['menu_test.child']->link->getPluginId(), 'menu_test.child');
|
||||||
|
|
||||||
|
$this->assertTrue(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -43,7 +43,6 @@ class MenuLinkTreeTest extends KernelTestBase {
|
||||||
public static $modules = array(
|
public static $modules = array(
|
||||||
'system',
|
'system',
|
||||||
'menu_test',
|
'menu_test',
|
||||||
'menu_link',
|
|
||||||
'menu_link_content',
|
'menu_link_content',
|
||||||
'field',
|
'field',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Contains \Drupal\system\Tests\Menu\MenuRouterRebuildTest.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Drupal\system\Tests\Menu;
|
|
||||||
|
|
||||||
use Drupal\simpletest\WebTestBase;
|
|
||||||
use Drupal\Core\Language\Language;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests menu_router_rebuild().
|
|
||||||
*
|
|
||||||
* @group Menu
|
|
||||||
*/
|
|
||||||
class MenuRouterRebuildTest extends WebTestBase {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modules to enable.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public static $modules = array('language', 'menu_test');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
function setUp() {
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
$language = new Language(array('id' => 'nl'));
|
|
||||||
language_save($language);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests configuration context when rebuilding the menu router table.
|
|
||||||
*/
|
|
||||||
public function testMenuRouterRebuildContext() {
|
|
||||||
// Enter a language context before rebuilding the menu router tables.
|
|
||||||
\Drupal::languageManager()->setConfigOverrideLanguage(language_load('nl'));
|
|
||||||
\Drupal::service('router.builder')->rebuild();
|
|
||||||
|
|
||||||
// Check that the language context was not used for building the menu item.
|
|
||||||
$menu_items = \Drupal::entityManager()->getStorage('menu_link')->loadByProperties(array('route_name' => 'menu_test.context'));
|
|
||||||
$menu_item = reset($menu_items);
|
|
||||||
$this->assertTrue($menu_item['link_title'] == 'English', 'Config context overrides are ignored when rebuilding menu router items.');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -52,11 +52,7 @@ class MenuRouterTest extends WebTestBase {
|
||||||
$this->doTestMenuOptionalPlaceholders();
|
$this->doTestMenuOptionalPlaceholders();
|
||||||
$this->doTestMenuOnRoute();
|
$this->doTestMenuOnRoute();
|
||||||
$this->doTestMenuName();
|
$this->doTestMenuName();
|
||||||
$this->doTestMenuLinkDefaultsAlter();
|
$this->doTestMenuLinksDiscoveredAlter();
|
||||||
$this->doTestMenuItemTitlesCases();
|
|
||||||
$this->doTestMenuLinkMaintain();
|
|
||||||
$this->doTestMenuLinkOptions();
|
|
||||||
$this->doTestMenuItemHooks();
|
|
||||||
$this->doTestHookMenuIntegration();
|
$this->doTestHookMenuIntegration();
|
||||||
$this->doTestExoticPath();
|
$this->doTestExoticPath();
|
||||||
}
|
}
|
||||||
|
|
@ -108,183 +104,61 @@ class MenuRouterTest extends WebTestBase {
|
||||||
$this->assertText(t('Menu item description text'));
|
$this->assertText(t('Menu item description text'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for menu_link_maintain().
|
|
||||||
*/
|
|
||||||
protected function doTestMenuLinkMaintain() {
|
|
||||||
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
|
|
||||||
$this->drupalLogin($admin_user);
|
|
||||||
|
|
||||||
// Create three menu items.
|
|
||||||
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1');
|
|
||||||
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1-main');
|
|
||||||
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/2', 'Menu link #2');
|
|
||||||
|
|
||||||
// Move second link to the main-menu, to test caching later on.
|
|
||||||
$menu_links_to_update = entity_load_multiple_by_properties('menu_link', array('link_title' => 'Menu link #1-main', 'customized' => 0, 'module' => 'menu_test'));
|
|
||||||
foreach ($menu_links_to_update as $menu_link) {
|
|
||||||
$menu_link->menu_name = 'main';
|
|
||||||
$menu_link->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load front page.
|
|
||||||
$this->drupalGet('');
|
|
||||||
$this->assertLink('Menu link #1');
|
|
||||||
$this->assertLink('Menu link #1-main');
|
|
||||||
$this->assertLink('Menu link #2');
|
|
||||||
|
|
||||||
// Rename all links for the given path.
|
|
||||||
menu_link_maintain('menu_test', 'update', 'menu_test_maintain/1', 'Menu link updated');
|
|
||||||
// Load a different page to be sure that we have up to date information.
|
|
||||||
$this->drupalGet('menu_test_maintain/1');
|
|
||||||
$this->assertLink('Menu link updated');
|
|
||||||
$this->assertNoLink('Menu link #1');
|
|
||||||
$this->assertNoLink('Menu link #1-main');
|
|
||||||
$this->assertLink('Menu link #2');
|
|
||||||
|
|
||||||
// Delete all links for the given path.
|
|
||||||
menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/1', '');
|
|
||||||
// Load a different page to be sure that we have up to date information.
|
|
||||||
$this->drupalGet('menu_test_maintain/2');
|
|
||||||
$this->assertNoLink('Menu link updated');
|
|
||||||
$this->assertNoLink('Menu link #1');
|
|
||||||
$this->assertNoLink('Menu link #1-main');
|
|
||||||
$this->assertLink('Menu link #2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for menu_name parameter for default menu links.
|
* Tests for menu_name parameter for default menu links.
|
||||||
*/
|
*/
|
||||||
protected function doTestMenuName() {
|
protected function doTestMenuName() {
|
||||||
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
|
$admin_user = $this->drupalCreateUser(array('administer site configuration'));
|
||||||
$this->drupalLogin($admin_user);
|
$this->drupalLogin($admin_user);
|
||||||
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu_name_test'));
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
|
$menu_links = $menu_link_manager->loadLinksByRoute('menu_test.menu_name_test');
|
||||||
$menu_link = reset($menu_links);
|
$menu_link = reset($menu_links);
|
||||||
$this->assertEqual($menu_link->menu_name, 'original', 'Menu name is "original".');
|
$this->assertEqual($menu_link->getMenuName(), 'original', 'Menu name is "original".');
|
||||||
|
|
||||||
// Change the menu_name parameter in menu_test.module, then force a menu
|
// Change the menu_name parameter in menu_test.module, then force a menu
|
||||||
// rebuild.
|
// rebuild.
|
||||||
menu_test_menu_name('changed');
|
menu_test_menu_name('changed');
|
||||||
\Drupal::service('router.builder')->rebuild();
|
$menu_link_manager->rebuild();
|
||||||
|
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu_name_test'));
|
$menu_links = $menu_link_manager->loadLinksByRoute('menu_test.menu_name_test');
|
||||||
$menu_link = reset($menu_links);
|
$menu_link = reset($menu_links);
|
||||||
$this->assertEqual($menu_link->menu_name, 'changed', 'Menu name was successfully changed after rebuild.');
|
$this->assertEqual($menu_link->getMenuName(), 'changed', 'Menu name was successfully changed after rebuild.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests menu links added in hook_menu_link_defaults_alter().
|
* Tests menu links added in hook_menu_links_discovered_alter().
|
||||||
*/
|
*/
|
||||||
protected function doTestMenuLinkDefaultsAlter() {
|
protected function doTestMenuLinksDiscoveredAlter() {
|
||||||
// Check that machine name does not need to be defined since it is already
|
// Check that machine name does not need to be defined since it is already
|
||||||
// set as the key of each menu link.
|
// set as the key of each menu link.
|
||||||
$menu_links = entity_load_multiple_by_properties('menu_link', array('route_name' => 'menu_test.custom'));
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
|
$menu_links = $menu_link_manager->loadLinksByRoute('menu_test.custom');
|
||||||
$menu_link = reset($menu_links);
|
$menu_link = reset($menu_links);
|
||||||
$this->assertEqual($menu_link->machine_name, 'menu_test.custom', 'Menu links added at hook_menu_link_defaults_alter() obtain the machine name from the $links key.');
|
$this->assertEqual($menu_link->getPluginId(), 'menu_test.custom', 'Menu links added at hook_menu_links_discovered_alter() obtain the machine name from the $links key.');
|
||||||
// Make sure that rebuilding the menu tree does not produce duplicates of
|
// Make sure that rebuilding the menu tree does not produce duplicates of
|
||||||
// links added by hook_menu_link_defaults_alter().
|
// links added by hook_menu_links_discovered_alter().
|
||||||
\Drupal::service('router.builder')->rebuild();
|
\Drupal::service('router.builder')->rebuild();
|
||||||
$this->drupalGet('menu-test');
|
$this->drupalGet('menu-test');
|
||||||
$this->assertUniqueText('Custom link', 'Menu links added by hook_menu_link_defaults_alter() do not duplicate after a menu rebuild.');
|
$this->assertUniqueText('Custom link', 'Menu links added by hook_menu_links_discovered_alter() do not duplicate after a menu rebuild.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for menu hierarchy.
|
* Tests for menu hierarchy.
|
||||||
*/
|
*/
|
||||||
protected function doTestMenuHierarchy() {
|
protected function doTestMenuHierarchy() {
|
||||||
$parent_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent'));
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
$parent_link = reset($parent_links);
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
$child_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent/child'));
|
$menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent');
|
||||||
$child_link = reset($child_links);
|
$parent_link = reset($menu_links);
|
||||||
$unattached_child_links = entity_load_multiple_by_properties('menu_link', array('link_path' => 'menu-test/hierarchy/parent/child2/child'));
|
$menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent.child');
|
||||||
$unattached_child_link = reset($unattached_child_links);
|
$child_link = reset($menu_links);
|
||||||
|
$menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent.child2.child');
|
||||||
|
$unattached_child_link = reset($menu_links);
|
||||||
|
|
||||||
$this->assertEqual($child_link['plid'], $parent_link['mlid'], 'The parent of a directly attached child is correct.');
|
$this->assertEqual($child_link->getParent(), $parent_link->getPluginId(), 'The parent of a directly attached child is correct.');
|
||||||
$this->assertEqual($unattached_child_link['plid'], $parent_link['mlid'], 'The parent of a non-directly attached child is correct.');
|
$this->assertEqual($unattached_child_link->getParent(), $parent_link->getPluginId(), 'The parent of a non-directly attached child is correct.');
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test menu maintenance hooks.
|
|
||||||
*/
|
|
||||||
protected function doTestMenuItemHooks() {
|
|
||||||
// Create an item.
|
|
||||||
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/4', 'Menu link #4');
|
|
||||||
$this->assertEqual(menu_test_static_variable(), 'insert', 'hook_menu_link_insert() fired correctly');
|
|
||||||
// Update the item.
|
|
||||||
menu_link_maintain('menu_test', 'update', 'menu_test_maintain/4', 'Menu link updated');
|
|
||||||
$this->assertEqual(menu_test_static_variable(), 'update', 'hook_menu_link_update() fired correctly');
|
|
||||||
// Delete the item.
|
|
||||||
menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/4', '');
|
|
||||||
$this->assertEqual(menu_test_static_variable(), 'delete', 'hook_menu_link_delete() fired correctly');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test menu link 'options' storage and rendering.
|
|
||||||
*/
|
|
||||||
protected function doTestMenuLinkOptions() {
|
|
||||||
// Create a menu link with options.
|
|
||||||
$menu_link = entity_create('menu_link', array(
|
|
||||||
'link_title' => 'Menu link options test',
|
|
||||||
'link_path' => 'test-page',
|
|
||||||
'module' => 'menu_test',
|
|
||||||
'options' => array(
|
|
||||||
'attributes' => array(
|
|
||||||
'title' => 'Test title attribute',
|
|
||||||
),
|
|
||||||
'query' => array(
|
|
||||||
'testparam' => 'testvalue',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
menu_link_save($menu_link);
|
|
||||||
|
|
||||||
// Load front page.
|
|
||||||
$this->drupalGet('test-page');
|
|
||||||
$this->assertRaw('title="Test title attribute"', 'Title attribute of a menu link renders.');
|
|
||||||
$this->assertRaw('testparam=testvalue', 'Query parameter added to menu link.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the possible ways to set the title for menu items.
|
|
||||||
* Also tests that menu item titles work with string overrides.
|
|
||||||
*/
|
|
||||||
protected function doTestMenuItemTitlesCases() {
|
|
||||||
|
|
||||||
// Build array with string overrides.
|
|
||||||
$test_data = array(
|
|
||||||
1 => array('Example title - Case 1' => 'Alternative example title - Case 1'),
|
|
||||||
2 => array('Example title' => 'Alternative example title'),
|
|
||||||
3 => array('Example title' => 'Alternative example title'),
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($test_data as $case_no => $override) {
|
|
||||||
$this->menuItemTitlesCasesHelper($case_no);
|
|
||||||
$this->addCustomTranslations('en', array('' => $override));
|
|
||||||
$this->writeCustomTranslations();
|
|
||||||
|
|
||||||
$this->menuItemTitlesCasesHelper($case_no, TRUE);
|
|
||||||
$this->addCustomTranslations('en', array());
|
|
||||||
$this->writeCustomTranslations();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a URL and assert the title given a case number. If override is true,
|
|
||||||
* the title is asserted to begin with "Alternative".
|
|
||||||
*/
|
|
||||||
protected function menuItemTitlesCasesHelper($case_no, $override = FALSE) {
|
|
||||||
$this->drupalGet('menu-title-test/case' . $case_no);
|
|
||||||
$this->assertResponse(200);
|
|
||||||
$asserted_title = $override ? 'Alternative example title - Case ' . $case_no : 'Example title - Case ' . $case_no;
|
|
||||||
$this->assertTitle($asserted_title . ' | Drupal', format_string('Menu title is: %title.', array('%title' => $asserted_title)), 'Menu');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the router for a given path.
|
|
||||||
*/
|
|
||||||
protected function menuLoadRouter($router_path) {
|
|
||||||
return db_query('SELECT * FROM {menu_router} WHERE path = :path', array(':path' => $router_path))->fetchAssoc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace Drupal\system\Tests\System;
|
namespace Drupal\system\Tests\System;
|
||||||
|
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -62,9 +63,10 @@ class AdminTest extends WebTestBase {
|
||||||
// Verify that all visible, top-level administration links are listed on
|
// Verify that all visible, top-level administration links are listed on
|
||||||
// the main administration page.
|
// the main administration page.
|
||||||
foreach ($this->getTopLevelMenuLinks() as $item) {
|
foreach ($this->getTopLevelMenuLinks() as $item) {
|
||||||
$this->assertLink($item['title']);
|
$this->assertLink($item->getTitle());
|
||||||
$this->assertLinkByHref($item['link_path']);
|
$this->assertLinkByHref($item->getUrlObject()->toString());
|
||||||
$this->assertText($item['localized_options']['attributes']['title']);
|
// The description should appear below the link.
|
||||||
|
$this->assertText($item->getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each administrative listing page on which the Locale module appears,
|
// For each administrative listing page on which the Locale module appears,
|
||||||
|
|
@ -119,26 +121,28 @@ class AdminTest extends WebTestBase {
|
||||||
/**
|
/**
|
||||||
* Returns all top level menu links.
|
* Returns all top level menu links.
|
||||||
*
|
*
|
||||||
* @return \Drupal\menu_link\MenuLinkInterface[]
|
* @return \Drupal\Core\Menu\MenuLinkInterface[]
|
||||||
*/
|
*/
|
||||||
protected function getTopLevelMenuLinks() {
|
protected function getTopLevelMenuLinks() {
|
||||||
$route_provider = \Drupal::service('router.route_provider');
|
$menu_tree = \Drupal::menuTree();
|
||||||
$routes = array();
|
|
||||||
foreach ($route_provider->getAllRoutes() as $key => $value) {
|
|
||||||
$path = $value->getPath();
|
|
||||||
if (strpos($path, '/admin/') === 0 && count(explode('/', $path)) == 3) {
|
|
||||||
$routes[$key] = $key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$menu_link_ids = \Drupal::entityQuery('menu_link')
|
|
||||||
->condition('route_name', $routes)
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
$menu_items = \Drupal::entityManager()->getStorage('menu_link')->loadMultiple($menu_link_ids);
|
// The system.admin link is normally the parent of all top-level admin links.
|
||||||
foreach ($menu_items as &$menu_item) {
|
$parameters = new MenuTreeParameters();
|
||||||
_menu_link_translate($menu_item);
|
$parameters->setRoot('system.admin')->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
|
||||||
|
$tree = $menu_tree->load(NULL, $parameters);
|
||||||
|
$manipulators = array(
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:flatten'),
|
||||||
|
);
|
||||||
|
$tree = $menu_tree->transform($tree, $manipulators);
|
||||||
|
|
||||||
|
// Transform the tree to a list of menu links.
|
||||||
|
$menu_links = array();
|
||||||
|
foreach ($tree as $element) {
|
||||||
|
$menu_links[] = $element->link;
|
||||||
}
|
}
|
||||||
return $menu_items;
|
|
||||||
|
return $menu_links;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ function template_preprocess_admin_block_content(&$variables) {
|
||||||
$variables['attributes']['class'][] = 'compact';
|
$variables['attributes']['class'][] = 'compact';
|
||||||
}
|
}
|
||||||
foreach ($variables['content'] as $key => $item) {
|
foreach ($variables['content'] as $key => $item) {
|
||||||
$variables['content'][$key]['link'] = l($item['title'], $item['link_path'], $item['localized_options']);
|
$variables['content'][$key]['link'] = \Drupal::linkGenerator()->generateFromUrl($item['title'], $item['url']);
|
||||||
if (!$compact && isset($item['description'])) {
|
if (!$compact && isset($item['description'])) {
|
||||||
$variables['content'][$key]['description'] = Xss::filterAdmin($item['description']);
|
$variables['content'][$key]['description'] = Xss::filterAdmin($item['description']);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -397,13 +397,13 @@ function hook_page_build(&$page) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alter links for menus.
|
* Alters all the menu links discovered by the menu link plugin manager.
|
||||||
*
|
*
|
||||||
* @param array $links
|
* @param array $links
|
||||||
* The link definitions to be altered.
|
* The link definitions to be altered.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* An array of default menu links. Each link has a key that is the machine
|
* An array of discovered menu links. Each link has a key that is the machine
|
||||||
* name, which must be unique. By default, use the route name as the
|
* name, which must be unique. By default, use the route name as the
|
||||||
* machine name. In cases where multiple links use the same route name, such
|
* machine name. In cases where multiple links use the same route name, such
|
||||||
* as two links to the same page in different menus, or two links using the
|
* as two links to the same page in different menus, or two links using the
|
||||||
|
|
@ -440,7 +440,7 @@ function hook_page_build(&$page) {
|
||||||
*
|
*
|
||||||
* @ingroup menu
|
* @ingroup menu
|
||||||
*/
|
*/
|
||||||
function hook_menu_link_defaults_alter(&$links) {
|
function hook_menu_links_discovered_alter(&$links) {
|
||||||
// Change the weight and title of the user.logout link.
|
// Change the weight and title of the user.logout link.
|
||||||
$links['user.logout']['weight'] = -10;
|
$links['user.logout']['weight'] = -10;
|
||||||
$links['user.logout']['title'] = 'Logout';
|
$links['user.logout']['title'] = 'Logout';
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Extension\ExtensionDiscovery;
|
||||||
use Drupal\Core\Routing\RouteMatchInterface;
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||||
use Drupal\Core\Language\LanguageInterface;
|
use Drupal\Core\Language\LanguageInterface;
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
use Drupal\block\BlockPluginInterface;
|
use Drupal\block\BlockPluginInterface;
|
||||||
use Drupal\user\UserInterface;
|
use Drupal\user\UserInterface;
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
|
@ -1455,76 +1456,48 @@ function system_admin_compact_mode() {
|
||||||
* An array of task links.
|
* An array of task links.
|
||||||
*/
|
*/
|
||||||
function system_get_module_admin_tasks($module, array $info) {
|
function system_get_module_admin_tasks($module, array $info) {
|
||||||
$links = &drupal_static(__FUNCTION__);
|
$tree = &drupal_static(__FUNCTION__);
|
||||||
|
|
||||||
if (!isset($links)) {
|
$menu_tree = \Drupal::menuTree();
|
||||||
$links = array();
|
|
||||||
$menu_links = entity_get_controller('menu_link')->loadModuleAdminTasks();
|
if (!isset($tree)) {
|
||||||
foreach ($menu_links as $link) {
|
$parameters = new MenuTreeParameters();
|
||||||
_menu_link_translate($link);
|
$parameters->setRoot('system.admin')->excludeRoot()->excludeHiddenLinks();
|
||||||
if ($link['access']) {
|
$tree = $menu_tree->load('system.admin', $parameters);
|
||||||
$links[$link['machine_name']] = $link;
|
$manipulators = array(
|
||||||
}
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
}
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:flatten'),
|
||||||
|
);
|
||||||
|
$tree = $menu_tree->transform($tree, $manipulators);
|
||||||
}
|
}
|
||||||
|
|
||||||
$admin_tasks = array();
|
$admin_tasks = array();
|
||||||
$titles = array();
|
foreach ($tree as $element) {
|
||||||
foreach ($links as $item) {
|
$link = $element->link;
|
||||||
if ($item['module'] != $module) {
|
if ($link->getProvider() != $module) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$machine_name = $item['machine_name'];
|
$admin_tasks[] = array(
|
||||||
if (isset($links[$machine_name])) {
|
'title' => $link->getTitle(),
|
||||||
$task = $links[$machine_name];
|
'description' => $link->getDescription(),
|
||||||
// The link description, either derived from 'description' in the default
|
'url' => $link->getUrlObject(),
|
||||||
// menu link or customized via Menu UI module is used as title attribute.
|
);
|
||||||
if (!empty($task['localized_options']['attributes']['title'])) {
|
|
||||||
$task['description'] = $task['localized_options']['attributes']['title'];
|
|
||||||
unset($task['localized_options']['attributes']['title']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the admin tasks for duplicate names. If one is found,
|
|
||||||
// append the parent menu item's title to differentiate.
|
|
||||||
$duplicate_path = array_search($task['title'], $titles);
|
|
||||||
if ($duplicate_path !== FALSE) {
|
|
||||||
if ($parent = menu_link_load($task['plid'])) {
|
|
||||||
// Append the parent item's title to this task's title.
|
|
||||||
$task['title'] = t('@original_title (@parent_title)', array('@original_title' => $task['title'], '@parent_title' => $parent['title']));
|
|
||||||
}
|
|
||||||
if ($parent = menu_link_load($admin_tasks[$duplicate_path]['plid'])) {
|
|
||||||
// Append the parent item's title to the duplicated task's title.
|
|
||||||
// We use $links[$duplicate_path] in case there are triplicates.
|
|
||||||
$admin_tasks[$duplicate_path]['title'] = t('@original_title (@parent_title)', array('@original_title' => $links[$duplicate_path]['title'], '@parent_title' => $parent['title']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$titles[$machine_name] = $task['title'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$admin_tasks[$machine_name] = $task;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append link for permissions.
|
// Append link for permissions.
|
||||||
if (\Drupal::moduleHandler()->implementsHook($module, 'permission')) {
|
if (\Drupal::moduleHandler()->implementsHook($module, 'permission')) {
|
||||||
/** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
|
/** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
|
||||||
$access_manager = \Drupal::service('access_manager');
|
$access_manager = \Drupal::service('access_manager');
|
||||||
/** @var \Drupal\menu_link\MenuLinkStorageInterface $menu_link_storage */
|
|
||||||
$menu_link_storage = \Drupal::entityManager()
|
|
||||||
->getStorage('menu_link');
|
|
||||||
if ($access_manager->checkNamedRoute('user.admin_permissions', array(), \Drupal::currentUser())) {
|
if ($access_manager->checkNamedRoute('user.admin_permissions', array(), \Drupal::currentUser())) {
|
||||||
$path = \Drupal::urlGenerator()
|
/** @var \Drupal\Core\Url $url */
|
||||||
->getPathFromRoute('user.admin_permissions');
|
$url = new \Drupal\Core\Url('user.admin_permissions');
|
||||||
$options = array();
|
$url->setOption('fragment', 'module-' . $module);
|
||||||
$options['fragment'] = 'module-' . $module;
|
$admin_tasks["user.admin_permissions.$module"] = array(
|
||||||
$menu_link = $menu_link_storage->create(array(
|
|
||||||
'route_name' => 'user.admin_permissions',
|
|
||||||
'link_path' => $path,
|
|
||||||
'title' => t('Configure @module permissions', array('@module' => $info['name'])),
|
'title' => t('Configure @module permissions', array('@module' => $info['name'])),
|
||||||
'localized_options' => $options
|
'description' => '',
|
||||||
));
|
'url' => $url,
|
||||||
$admin_tasks["user.admin.people.permissions.$module"] = $menu_link;
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -382,7 +382,7 @@ system.admin_config:
|
||||||
path: '/admin/config'
|
path: '/admin/config'
|
||||||
defaults:
|
defaults:
|
||||||
_content: '\Drupal\system\Controller\SystemController::overview'
|
_content: '\Drupal\system\Controller\SystemController::overview'
|
||||||
path: 'admin/config'
|
link_id: 'system.admin_config'
|
||||||
_title: 'Configuration'
|
_title: 'Configuration'
|
||||||
requirements:
|
requirements:
|
||||||
_permission: 'access administration pages'
|
_permission: 'access administration pages'
|
||||||
|
|
@ -414,7 +414,7 @@ system.admin_content:
|
||||||
path: '/admin/content'
|
path: '/admin/content'
|
||||||
defaults:
|
defaults:
|
||||||
_content: '\Drupal\system\Controller\SystemController::overview'
|
_content: '\Drupal\system\Controller\SystemController::overview'
|
||||||
path: 'admin/content'
|
link_id: 'system.admin_content'
|
||||||
_title: 'Content'
|
_title: 'Content'
|
||||||
requirements:
|
requirements:
|
||||||
_permission: 'access administration pages'
|
_permission: 'access administration pages'
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ services:
|
||||||
- { name: access_check, applies_to: _access_system_cron }
|
- { name: access_check, applies_to: _access_system_cron }
|
||||||
system.manager:
|
system.manager:
|
||||||
class: Drupal\system\SystemManager
|
class: Drupal\system\SystemManager
|
||||||
arguments: ['@module_handler', '@database', '@entity.manager', '@request_stack']
|
arguments: ['@module_handler', '@database', '@entity.manager', '@request_stack', '@menu.link_tree', '@menu.active_trail']
|
||||||
system.breadcrumb.default:
|
system.breadcrumb.default:
|
||||||
class: Drupal\system\PathBasedBreadcrumbBuilder
|
class: Drupal\system\PathBasedBreadcrumbBuilder
|
||||||
arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user']
|
arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user']
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
{#
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Default theme implementation for a menu tree.
|
||||||
|
*
|
||||||
|
* Available variables:
|
||||||
|
* - attributes: Attributes for the UL containing the tree of links.
|
||||||
|
* - tree: Menu tree to be output.
|
||||||
|
* - heading: (optional) A heading to precede the links.
|
||||||
|
* - text: The heading text.
|
||||||
|
* - level: The heading level (e.g. 'h2', 'h3').
|
||||||
|
* - attributes: (optional) A keyed list of attributes for the heading.
|
||||||
|
* If the heading is a string, it will be used as the text of the heading and
|
||||||
|
* the level will default to 'h2'.
|
||||||
|
*
|
||||||
|
* Headings should be used on navigation menus and any list of links that
|
||||||
|
* consistently appears on multiple pages. To make the heading invisible use
|
||||||
|
* the 'visually-hidden' CSS class. Do not use 'display:none', which
|
||||||
|
* removes it from screen-readers and assistive technology. Headings allow
|
||||||
|
* screen-reader and keyboard only users to navigate to or skip the links.
|
||||||
|
* See http://juicystudio.com/article/screen-readers-display-none.php and
|
||||||
|
* http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
|
||||||
|
*
|
||||||
|
* @see template_preprocess_menu_tree()
|
||||||
|
*
|
||||||
|
* @ingroup themeable
|
||||||
|
*/
|
||||||
|
#}
|
||||||
|
{% if tree -%}
|
||||||
|
{%- if heading -%}
|
||||||
|
{%- if heading.level -%}
|
||||||
|
<{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}</{{ heading.level }}>
|
||||||
|
{%- else -%}
|
||||||
|
<h2{{ heading.attributes }}>{{ heading.text }}</h2>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endif -%}
|
||||||
|
<ul{{ attributes }}>
|
||||||
|
{{ tree }}
|
||||||
|
</ul>
|
||||||
|
{%- endif %}
|
||||||
|
|
@ -69,3 +69,13 @@ menu_test.menu-title-test.case3:
|
||||||
menu_test.context:
|
menu_test.context:
|
||||||
title: ''
|
title: ''
|
||||||
route_name: menu_test.context
|
route_name: menu_test.context
|
||||||
|
|
||||||
|
menu_test.parent:
|
||||||
|
title: 'Test menu_name parent'
|
||||||
|
route_name: menu_test.menu_name_test
|
||||||
|
menu_name: test
|
||||||
|
|
||||||
|
menu_test.child:
|
||||||
|
title: 'Test menu_name child'
|
||||||
|
route_name: menu_test.menu_name_test
|
||||||
|
parent: menu_test.parent
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,10 @@
|
||||||
* Module that implements various hooks for menu tests.
|
* Module that implements various hooks for menu tests.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Drupal\menu_link\Entity\MenuLink;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_menu_link_defaults_alter().
|
* Implements hook_menu_links_discovered_alter().
|
||||||
*/
|
*/
|
||||||
function menu_test_menu_link_defaults_alter(&$links) {
|
function menu_test_menu_links_discovered_alter(&$links) {
|
||||||
// Many of the machine names here are slightly different from the route name.
|
// Many of the machine names here are slightly different from the route name.
|
||||||
// Since the machine name is arbitrary, this helps ensure that core does not
|
// Since the machine name is arbitrary, this helps ensure that core does not
|
||||||
// add mistaken assumptions about the correlation.
|
// add mistaken assumptions about the correlation.
|
||||||
|
|
@ -96,29 +94,6 @@ function menu_test_callback() {
|
||||||
return 'This is menu_test_callback().';
|
return 'This is menu_test_callback().';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Page callback: Tests menu_test_menu_tree_set_path().
|
|
||||||
*
|
|
||||||
* Retrieves the current menu path and if the menu path is not empty updates
|
|
||||||
* the menu path that is used to determine the active menu trail.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* A string that can be used for comparison.
|
|
||||||
*
|
|
||||||
* @see menu_test_menu().
|
|
||||||
*
|
|
||||||
* @deprecated Use \Drupal\menu_test\Controller\MenuTestController::menuTrail()
|
|
||||||
*/
|
|
||||||
function menu_test_menu_trail_callback() {
|
|
||||||
$menu_path = \Drupal::state()->get('menu_test.menu_tree_set_path') ?: array();
|
|
||||||
/** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
|
|
||||||
$menu_tree = \Drupal::service('menu_link.tree');
|
|
||||||
if (!empty($menu_path)) {
|
|
||||||
$menu_tree->setPath($menu_path['menu_name'], $menu_path['path']);
|
|
||||||
}
|
|
||||||
return 'This is menu_test_menu_trail_callback().';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page callback: Tests the theme negotiation functionality.
|
* Page callback: Tests the theme negotiation functionality.
|
||||||
*
|
*
|
||||||
|
|
@ -166,44 +141,6 @@ function menu_test_menu_name($new_name = '') {
|
||||||
return $menu_name;
|
return $menu_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_ENTITY_TYPE_insert() for menu_link entities.
|
|
||||||
*/
|
|
||||||
function menu_test_menu_link_insert(MenuLink $item) {
|
|
||||||
menu_test_static_variable('insert');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_ENTITY_TYPE_update() for menu_link entities.
|
|
||||||
*/
|
|
||||||
function menu_test_menu_link_update(MenuLink $item) {
|
|
||||||
menu_test_static_variable('update');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_ENTITY_TYPE_delete() for menu_link entities.
|
|
||||||
*/
|
|
||||||
function menu_test_menu_link_delete(MenuLink $item) {
|
|
||||||
menu_test_static_variable('delete');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a static variable for testing hook results.
|
|
||||||
*
|
|
||||||
* @param null|string $value
|
|
||||||
* (optional) The value to set or NULL to return the current value.
|
|
||||||
*
|
|
||||||
* @return null|string
|
|
||||||
* A text string for comparison to test assertions.
|
|
||||||
*/
|
|
||||||
function menu_test_static_variable($value = NULL) {
|
|
||||||
static $variable;
|
|
||||||
if (!empty($value)) {
|
|
||||||
$variable = $value;
|
|
||||||
}
|
|
||||||
return $variable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title callback: Concatenates the title and case number.
|
* Title callback: Concatenates the title and case number.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
test_page_test.test_page:
|
||||||
|
route_name: test_page_test.test_page
|
||||||
|
title: 'Test front page link'
|
||||||
|
weight: 0
|
||||||
|
|
@ -125,30 +125,16 @@ class ToolbarAdminMenuTest extends WebTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests toolbar_menu_link_update() hook implementation.
|
* Tests toolbar cache tags implementation.
|
||||||
*/
|
*/
|
||||||
function testMenuLinkUpdateSubtreesHashCacheClear() {
|
function testMenuLinkUpdateSubtreesHashCacheClear() {
|
||||||
// Get subtree items for the admin menu.
|
// The ID of a (any) admin menu link.
|
||||||
$query = \Drupal::entityQuery('menu_link');
|
$admin_menu_link_id = 'system.admin_config_development';
|
||||||
for ($i = 1; $i <= 3; $i++) {
|
|
||||||
$query->sort('p' . $i, 'ASC');
|
|
||||||
}
|
|
||||||
$query->condition('menu_name', 'admin');
|
|
||||||
$query->condition('depth', '2', '>=');
|
|
||||||
|
|
||||||
// Build an ordered array of links using the query result object.
|
|
||||||
$links = array();
|
|
||||||
if ($result = $query->execute()) {
|
|
||||||
$links = menu_link_load_multiple($result);
|
|
||||||
}
|
|
||||||
// Get the first link in the set.
|
|
||||||
$links = array_values($links);
|
|
||||||
$link = array_shift($links);
|
|
||||||
|
|
||||||
// Disable the link.
|
// Disable the link.
|
||||||
$edit = array();
|
$edit = array();
|
||||||
$edit['enabled'] = FALSE;
|
$edit['enabled'] = FALSE;
|
||||||
$this->drupalPostForm("admin/structure/menu/item/" . $link['mlid'] . "/edit", $edit, t('Save'));
|
$this->drupalPostForm("admin/structure/menu/link/" . $admin_menu_link_id . "/edit", $edit, t('Save'));
|
||||||
$this->assertResponse(200);
|
$this->assertResponse(200);
|
||||||
$this->assertText('The menu link has been saved.');
|
$this->assertText('The menu link has been saved.');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,3 @@ package: Core
|
||||||
version: VERSION
|
version: VERSION
|
||||||
dependencies:
|
dependencies:
|
||||||
- breakpoint
|
- breakpoint
|
||||||
- menu_link
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Drupal\Core\Cache\Cache;
|
use Drupal\Core\Cache\Cache;
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
use Drupal\Core\Render\Element;
|
use Drupal\Core\Render\Element;
|
||||||
use Drupal\Core\Routing\RouteMatchInterface;
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
use Drupal\Core\Template\Attribute;
|
use Drupal\Core\Template\Attribute;
|
||||||
use Drupal\Component\Datetime\DateTimePlus;
|
use Drupal\Component\Datetime\DateTimePlus;
|
||||||
use Drupal\Component\Utility\Crypt;
|
use Drupal\Component\Utility\Crypt;
|
||||||
use Drupal\Component\Utility\String;
|
use Drupal\Component\Utility\String;
|
||||||
use Drupal\menu_link\MenuLinkInterface;
|
|
||||||
use Drupal\user\RoleInterface;
|
use Drupal\user\RoleInterface;
|
||||||
use Drupal\user\UserInterface;
|
use Drupal\user\UserInterface;
|
||||||
|
|
||||||
|
|
@ -326,8 +326,6 @@ function toolbar_pre_render_item($element) {
|
||||||
* Implements hook_toolbar().
|
* Implements hook_toolbar().
|
||||||
*/
|
*/
|
||||||
function toolbar_toolbar() {
|
function toolbar_toolbar() {
|
||||||
$items = array();
|
|
||||||
|
|
||||||
// The 'Home' tab is a simple link, with no corresponding tray.
|
// The 'Home' tab is a simple link, with no corresponding tray.
|
||||||
$items['home'] = array(
|
$items['home'] = array(
|
||||||
'#type' => 'toolbar_item',
|
'#type' => 'toolbar_item',
|
||||||
|
|
@ -352,33 +350,13 @@ function toolbar_toolbar() {
|
||||||
'#weight' => -20,
|
'#weight' => -20,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Retrieve the administration menu from the database.
|
|
||||||
$tree = toolbar_get_menu_tree();
|
|
||||||
|
|
||||||
// Add attributes to the links before rendering.
|
|
||||||
toolbar_menu_navigation_links($tree);
|
|
||||||
|
|
||||||
/** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
|
|
||||||
$menu_tree = \Drupal::service('menu_link.tree');
|
|
||||||
|
|
||||||
$menu = array(
|
|
||||||
'#heading' => t('Administration menu'),
|
|
||||||
'toolbar_administration' => array(
|
|
||||||
'#type' => 'container',
|
|
||||||
'#attributes' => array(
|
|
||||||
'class' => array('toolbar-menu-administration'),
|
|
||||||
),
|
|
||||||
'administration_menu' => $menu_tree->renderTree($tree),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// To conserve bandwidth, we only include the top-level links in the HTML.
|
// To conserve bandwidth, we only include the top-level links in the HTML.
|
||||||
// The subtrees are fetched through a JSONP script that is generated at the
|
// The subtrees are fetched through a JSONP script that is generated at the
|
||||||
// toolbar_subtrees route. We provide the JavaScript requesting that JSONP
|
// toolbar_subtrees route. We provide the JavaScript requesting that JSONP
|
||||||
// script here with the hash parameter that is needed for that route.
|
// script here with the hash parameter that is needed for that route.
|
||||||
// @see toolbar_subtrees_jsonp()
|
// @see toolbar_subtrees_jsonp()
|
||||||
$langcode = \Drupal::languageManager()->getCurrentLanguage()->id;
|
$langcode = \Drupal::languageManager()->getCurrentLanguage()->id;
|
||||||
$menu['toolbar_administration']['#attached']['js'][] = array(
|
$subtrees_attached['js'][] = array(
|
||||||
'type' => 'setting',
|
'type' => 'setting',
|
||||||
'data' => array('toolbar' => array(
|
'data' => array('toolbar' => array(
|
||||||
'subtreesHash' => _toolbar_get_subtrees_hash($langcode),
|
'subtreesHash' => _toolbar_get_subtrees_hash($langcode),
|
||||||
|
|
@ -405,7 +383,19 @@ function toolbar_toolbar() {
|
||||||
'data-drupal-subtrees' => '',
|
'data-drupal-subtrees' => '',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'tray' => $menu,
|
'tray' => array(
|
||||||
|
'#heading' => t('Administration menu'),
|
||||||
|
'#attached' => $subtrees_attached,
|
||||||
|
'toolbar_administration' => array(
|
||||||
|
'#pre_render' => array(
|
||||||
|
'toolbar_prerender_toolbar_administration_tray',
|
||||||
|
),
|
||||||
|
'#type' => 'container',
|
||||||
|
'#attributes' => array(
|
||||||
|
'class' => array('toolbar-menu-administration'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
'#weight' => -15,
|
'#weight' => -15,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -413,90 +403,102 @@ function toolbar_toolbar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets only the top level items below the 'admin' path.
|
* Renders the toolbar's administration tray.
|
||||||
*
|
*
|
||||||
* @return
|
* @param array $element
|
||||||
* An array containing a menu tree of top level items below the 'admin' path.
|
* A renderable array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The updated renderable array.
|
||||||
|
*
|
||||||
|
* @see drupal_render()
|
||||||
*/
|
*/
|
||||||
function toolbar_get_menu_tree() {
|
function toolbar_prerender_toolbar_administration_tray(array $element) {
|
||||||
$tree = array();
|
$menu_tree = \Drupal::menuTree();
|
||||||
/** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
|
// Render the top-level administration menu links.
|
||||||
$menu_tree = \Drupal::service('menu_link.tree');
|
$parameters = new MenuTreeParameters();
|
||||||
$query = \Drupal::entityQuery('menu_link')
|
$parameters->setRoot('system.admin')->excludeRoot()->setTopLevelOnly()->excludeHiddenLinks();
|
||||||
->condition('menu_name', 'admin')
|
$tree = $menu_tree->load(NULL, $parameters);
|
||||||
->condition('module', 'system')
|
$manipulators = array(
|
||||||
->condition('link_path', 'admin');
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
$result = $query->execute();
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
if (!empty($result)) {
|
array('callable' => 'toolbar_menu_navigation_links'),
|
||||||
$admin_link = menu_link_load(reset($result));
|
);
|
||||||
$tree = $menu_tree->buildTree('admin', array(
|
$tree = $menu_tree->transform($tree, $manipulators);
|
||||||
'expanded' => array($admin_link['mlid']),
|
$element['administration_menu'] = $menu_tree->build($tree);
|
||||||
'min_depth' => $admin_link['depth'] + 1,
|
return $element;
|
||||||
'max_depth' => $admin_link['depth'] + 1,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tree;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an array of links from a menu tree array.
|
* Adds toolbar-specific attributes to the menu link tree.
|
||||||
*
|
*
|
||||||
* Based on menu_navigation_links(). Adds path based IDs and icon placeholders
|
* @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
|
||||||
* to the links.
|
* The menu link tree to manipulate.
|
||||||
*
|
*
|
||||||
* @return
|
* @return \Drupal\Core\Menu\MenuLinkTreeElement[]
|
||||||
* An array of links as defined above.
|
* The manipulated menu link tree.
|
||||||
*/
|
*/
|
||||||
function toolbar_menu_navigation_links(&$tree) {
|
function toolbar_menu_navigation_links(array $tree) {
|
||||||
foreach ($tree as $key => $item) {
|
foreach ($tree as $element) {
|
||||||
// Configure sub-items.
|
if ($element->subtree) {
|
||||||
if (!empty($item['below'])) {
|
toolbar_menu_navigation_links($element->subtree);
|
||||||
toolbar_menu_navigation_links($tree[$key]['below']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we have a path specific ID in place, so we can attach icons
|
// Make sure we have a path specific ID in place, so we can attach icons
|
||||||
// and behaviors to the items.
|
// and behaviors to the menu links.
|
||||||
$tree[$key]['link']['localized_options']['attributes'] = array(
|
$link = $element->link;
|
||||||
'id' => 'toolbar-link-' . str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['link_path']),
|
$url = $link->getUrlObject();
|
||||||
'class' => array(
|
if ($url->isExternal()) {
|
||||||
'toolbar-icon',
|
// This is an unusual case, so just get a distinct, safe string.
|
||||||
'toolbar-icon-' . strtolower(str_replace(' ', '-', $item['link']['link_title'])),
|
$id = substr(Crypt::hashBase64($url->getPath()), 0, 16);
|
||||||
),
|
|
||||||
'title' => String::checkPlain($item['link']['description']),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$id = str_replace(array('.', '<', '>'), array('-', '', ''), $url->getRouteName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the non-localized title to make the icon class.
|
||||||
|
$definition = $link->getPluginDefinition();
|
||||||
|
|
||||||
|
$element->options['attributes']['id'] = 'toolbar-link-' . $id;
|
||||||
|
$element->options['attributes']['class'][] = 'toolbar-icon';
|
||||||
|
// @todo Change to use the plugin ID as class since titles might change.
|
||||||
|
// https://www.drupal.org/node/2310365
|
||||||
|
$element->options['attributes']['class'][] = 'toolbar-icon-' . strtolower(str_replace(' ', '-', $definition['title']));
|
||||||
|
$element->options['attributes']['title'] = String::checkPlain($link->getDescription());
|
||||||
|
}
|
||||||
|
return $tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the rendered subtree of each top-level toolbar link.
|
* Returns the rendered subtree of each top-level toolbar link.
|
||||||
*/
|
*/
|
||||||
function toolbar_get_rendered_subtrees() {
|
function toolbar_get_rendered_subtrees() {
|
||||||
|
$menu_tree = \Drupal::menuTree();
|
||||||
|
$parameters = new MenuTreeParameters();
|
||||||
|
$parameters->setRoot('system.admin')->excludeRoot()->setMaxDepth(3)->excludeHiddenLinks();
|
||||||
|
$tree = $menu_tree->load(NULL, $parameters);
|
||||||
|
$manipulators = array(
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||||
|
array('callable' => 'toolbar_menu_navigation_links'),
|
||||||
|
);
|
||||||
|
$tree = $menu_tree->transform($tree, $manipulators);
|
||||||
$subtrees = array();
|
$subtrees = array();
|
||||||
/** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
|
foreach ($tree as $element) {
|
||||||
$menu_tree = \Drupal::service('menu_link.tree');
|
/** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
||||||
$tree = toolbar_get_menu_tree();
|
$link = $element->link;
|
||||||
foreach ($tree as $tree_item) {
|
if ($element->subtree) {
|
||||||
$item = $tree_item['link'];
|
$subtree = $menu_tree->build($element->subtree);
|
||||||
if (!$item['hidden'] && $item['access']) {
|
$output = drupal_render($subtree);
|
||||||
if ($item['has_children']) {
|
|
||||||
$query = \Drupal::entityQuery('menu_link')
|
|
||||||
->condition('has_children', 1);
|
|
||||||
for ($i=1; $i <= $item['depth']; $i++) {
|
|
||||||
$query->condition('p' . $i, $item['p' . $i]);
|
|
||||||
}
|
|
||||||
$parents = $query->execute();
|
|
||||||
$subtree = $menu_tree->buildTree($item['menu_name'], array('expanded' => $parents, 'min_depth' => $item['depth']+1));
|
|
||||||
toolbar_menu_navigation_links($subtree);
|
|
||||||
$subtree = $menu_tree->renderTree($subtree);
|
|
||||||
$subtree = drupal_render($subtree);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$subtree = '';
|
$output = '';
|
||||||
}
|
}
|
||||||
|
// Many routes have dots as route name, while some special ones like <front>
|
||||||
|
// have <> characters in them.
|
||||||
|
$id = str_replace(array('.', '<', '>'), array('-', '', '' ), $link->getUrlObject()->getRouteName());
|
||||||
|
|
||||||
$id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['link_path']);
|
$subtrees[$id] = $output;
|
||||||
$subtrees[$id] = $subtree;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $subtrees;
|
return $subtrees;
|
||||||
}
|
}
|
||||||
|
|
@ -523,7 +525,7 @@ function _toolbar_get_subtrees_hash($langcode) {
|
||||||
// caches later, based on the user's ID regardless of language.
|
// caches later, based on the user's ID regardless of language.
|
||||||
// Clear the cache when the 'locale' tag is deleted. This ensures a fresh
|
// Clear the cache when the 'locale' tag is deleted. This ensures a fresh
|
||||||
// subtrees rendering when string translations are made.
|
// subtrees rendering when string translations are made.
|
||||||
\Drupal::cache('toolbar')->set($cid, $hash, Cache::PERMANENT, array('user' => array($uid), 'locale' => TRUE,));
|
\Drupal::cache('toolbar')->set($cid, $hash, Cache::PERMANENT, array('user' => array($uid), 'locale' => TRUE, 'menu' => 'admin'));
|
||||||
}
|
}
|
||||||
return $hash;
|
return $hash;
|
||||||
}
|
}
|
||||||
|
|
@ -542,15 +544,6 @@ function toolbar_modules_uninstalled($modules) {
|
||||||
_toolbar_clear_user_cache();
|
_toolbar_clear_user_cache();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_ENTITY_TYPE_update() for menu_link entities.
|
|
||||||
*/
|
|
||||||
function toolbar_menu_link_update(MenuLinkInterface $menu_link) {
|
|
||||||
if ($menu_link->menu_name === 'admin') {
|
|
||||||
_toolbar_clear_user_cache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_ENTITY_TYPE_update() for user entities.
|
* Implements hook_ENTITY_TYPE_update() for user entities.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\user\Plugin\Menu\MyAccountMenuLink.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\user\Plugin\Menu;
|
||||||
|
|
||||||
|
use Drupal\Core\Menu\MenuLinkDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides custom logic for the user.page menu link.
|
||||||
|
*/
|
||||||
|
class MyAccountMenuLink extends MenuLinkDefault {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isHidden() {
|
||||||
|
// The path 'user' must be accessible for anonymous users, but only visible
|
||||||
|
// for authenticated users. Authenticated users should see "My account", but
|
||||||
|
// anonymous users should not see it at all.
|
||||||
|
// @todo Re-write this as a link to user.view with dynamic route parameters
|
||||||
|
// to affect access since hidden should not be dynamic.
|
||||||
|
// https://www.drupal.org/node/2306991
|
||||||
|
return $this->pluginDefinition['hidden'] || \Drupal::currentUser()->isAnonymous();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isCacheable() {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace Drupal\user\Tests;
|
namespace Drupal\user\Tests;
|
||||||
|
|
||||||
|
use Drupal\Core\Menu\MenuTreeParameters;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -43,14 +44,14 @@ class UserAccountLinksTests extends WebTestBase {
|
||||||
// For a logged-in user, expect the secondary menu to have links for "My
|
// For a logged-in user, expect the secondary menu to have links for "My
|
||||||
// account" and "Log out".
|
// account" and "Log out".
|
||||||
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
||||||
':menu_class' => 'links',
|
':menu_class' => 'menu',
|
||||||
':href' => 'user',
|
':href' => 'user',
|
||||||
':text' => 'My account',
|
':text' => 'My account',
|
||||||
));
|
));
|
||||||
$this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
|
$this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
|
||||||
|
|
||||||
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
||||||
':menu_class' => 'links',
|
':menu_class' => 'menu',
|
||||||
':href' => 'user/logout',
|
':href' => 'user/logout',
|
||||||
':text' => 'Log out',
|
':text' => 'Log out',
|
||||||
));
|
));
|
||||||
|
|
@ -61,13 +62,15 @@ class UserAccountLinksTests extends WebTestBase {
|
||||||
$this->drupalGet('<front>');
|
$this->drupalGet('<front>');
|
||||||
|
|
||||||
// For a logged-out user, expect no secondary links.
|
// For a logged-out user, expect no secondary links.
|
||||||
/** @var \Drupal\menu_link\MenuTreeInterface $menu_tree */
|
$menu_tree = \Drupal::menuTree();
|
||||||
$menu_tree = \Drupal::service('menu_link.tree');
|
$tree = $menu_tree->load('account', new MenuTreeParameters());
|
||||||
$tree = $menu_tree->buildTree('account');
|
$manipulators = array(
|
||||||
|
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||||
|
);
|
||||||
|
$tree = $menu_tree->transform($tree, $manipulators);
|
||||||
$this->assertEqual(count($tree), 1, 'The secondary links menu contains only one menu link.');
|
$this->assertEqual(count($tree), 1, 'The secondary links menu contains only one menu link.');
|
||||||
$link = reset($tree);
|
$element = reset($tree);
|
||||||
$link = $link['link'];
|
$this->assertTrue($element->link->isHidden(), 'The menu link is hidden.');
|
||||||
$this->assertTrue((bool) $link->hidden, 'The menu link is hidden.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -80,7 +83,7 @@ class UserAccountLinksTests extends WebTestBase {
|
||||||
// Verify that the 'My account' link exists before we check for its
|
// Verify that the 'My account' link exists before we check for its
|
||||||
// disappearance.
|
// disappearance.
|
||||||
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
||||||
':menu_class' => 'links',
|
':menu_class' => 'menu',
|
||||||
':href' => 'user',
|
':href' => 'user',
|
||||||
':text' => 'My account',
|
':text' => 'My account',
|
||||||
));
|
));
|
||||||
|
|
@ -94,10 +97,7 @@ class UserAccountLinksTests extends WebTestBase {
|
||||||
$this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default.");
|
$this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default.");
|
||||||
|
|
||||||
// Disable the 'My account' link.
|
// Disable the 'My account' link.
|
||||||
$input = $this->xpath('//input[@id=:field_id]/@name', array(':field_id' => (string)$label[0]));
|
$edit['links[menu_plugin_id:user.page][enabled]'] = FALSE;
|
||||||
$edit = array(
|
|
||||||
(string) $input[0] => FALSE,
|
|
||||||
);
|
|
||||||
$this->drupalPostForm('admin/structure/menu/manage/account', $edit, t('Save'));
|
$this->drupalPostForm('admin/structure/menu/manage/account', $edit, t('Save'));
|
||||||
|
|
||||||
// Get the homepage.
|
// Get the homepage.
|
||||||
|
|
@ -105,7 +105,7 @@ class UserAccountLinksTests extends WebTestBase {
|
||||||
|
|
||||||
// Verify that the 'My account' link does not appear when disabled.
|
// Verify that the 'My account' link does not appear when disabled.
|
||||||
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
|
||||||
':menu_class' => 'links',
|
':menu_class' => 'menu',
|
||||||
':href' => 'user',
|
':href' => 'user',
|
||||||
':text' => 'My account',
|
':text' => 'My account',
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ user.page:
|
||||||
weight: -10
|
weight: -10
|
||||||
route_name: user.page
|
route_name: user.page
|
||||||
menu_name: account
|
menu_name: account
|
||||||
|
class: Drupal\user\Plugin\Menu\MyAccountMenuLink
|
||||||
user.logout:
|
user.logout:
|
||||||
title: 'Log out'
|
title: 'Log out'
|
||||||
route_name: user.logout
|
route_name: user.logout
|
||||||
|
|
|
||||||
|
|
@ -633,19 +633,6 @@ function template_preprocess_username(&$variables) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_menu_link_presave().
|
|
||||||
*/
|
|
||||||
function user_menu_link_presave(MenuLink $menu_link) {
|
|
||||||
// The path 'user' must be accessible for anonymous users, but only visible
|
|
||||||
// for authenticated users. Authenticated users should see "My account", but
|
|
||||||
// anonymous users should not see it at all. Therefore, invoke
|
|
||||||
// user_menu_link_load() to conditionally hide the link.
|
|
||||||
if ($menu_link->machine_name == 'user.page') {
|
|
||||||
$menu_link->options['alter'] = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_menu_breadcrumb_alter().
|
* Implements hook_menu_breadcrumb_alter().
|
||||||
*/
|
*/
|
||||||
|
|
@ -657,16 +644,6 @@ function user_menu_breadcrumb_alter(&$active_trail, $item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_translated_menu_link_alter().
|
|
||||||
*/
|
|
||||||
function user_translated_menu_link_alter(MenuLink &$menu_link) {
|
|
||||||
// Hide the "User account" link for anonymous users.
|
|
||||||
if ($menu_link->machine_name == 'user.page' && \Drupal::currentUser()->isAnonymous()) {
|
|
||||||
$menu_link->hidden = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finalizes the login process and logs in a user.
|
* Finalizes the login process and logs in a user.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\views\Plugin\Derivative\ViewsMenuLink.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\views\Plugin\Derivative;
|
||||||
|
|
||||||
|
use Drupal\Component\Plugin\Derivative\DeriverInterface;
|
||||||
|
use Drupal\views\Views;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides menu links for Views.
|
||||||
|
*
|
||||||
|
* @see \Drupal\views\Plugin\Menu\ViewsMenuLink
|
||||||
|
*/
|
||||||
|
class ViewsMenuLink implements DeriverInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
|
||||||
|
if (!isset($this->derivatives)) {
|
||||||
|
$this->getDerivativeDefinitions($base_plugin_definition);
|
||||||
|
}
|
||||||
|
if (isset($this->derivatives[$derivative_id])) {
|
||||||
|
return $this->derivatives[$derivative_id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||||
|
$links = array();
|
||||||
|
// @todo Replace uses_hook_menu with an annotation.
|
||||||
|
// https://www.drupal.org/node/2310371
|
||||||
|
$views = Views::getApplicableViews('uses_hook_menu');
|
||||||
|
foreach ($views as $data) {
|
||||||
|
/** @var \Drupal\views\ViewExecutable $view */
|
||||||
|
list($view, $display_id) = $data;
|
||||||
|
if ($result = $view->getMenuLinks($display_id)) {
|
||||||
|
foreach ($result as $link_id => $link) {
|
||||||
|
$links[$link_id] = $link + $base_plugin_definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $links;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\views\Plugin\Menu\Form\ViewsMenuLinkForm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\views\Plugin\Menu\Form;
|
||||||
|
|
||||||
|
use Drupal\Core\Menu\Form\MenuLinkDefaultForm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a form to edit Views menu links.
|
||||||
|
*
|
||||||
|
* This provides the feature to edit the title and description, in contrast to
|
||||||
|
* the default menu link form.
|
||||||
|
*
|
||||||
|
* @see \Drupal\views\Plugin\Menu\ViewsMenuLink
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
|
||||||
|
// Put the title field first.
|
||||||
|
$form['title'] = array(
|
||||||
|
'#type' => 'textfield',
|
||||||
|
'#title' => $this->t('Title'),
|
||||||
|
// @todo Ensure that the view is not loaded with a localized title.
|
||||||
|
// https://www.drupal.org/node/2309507
|
||||||
|
'#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 Ensure that the view is not loaded with a localized description.
|
||||||
|
// https://www.drupal.org/node/2309507
|
||||||
|
'#default_value' => $this->menuLink->getDescription(),
|
||||||
|
'#weight' => -5,
|
||||||
|
);
|
||||||
|
|
||||||
|
$form += parent::buildConfigurationForm($form, $form_state);
|
||||||
|
|
||||||
|
$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 <a href="@url">@label</a>', 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\views\Plugin\Menu\ViewsMenuLink.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\views\Plugin\Menu;
|
||||||
|
|
||||||
|
use Drupal\Core\Menu\MenuLinkBase;
|
||||||
|
use Drupal\Core\Entity\EntityManagerInterface;
|
||||||
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||||
|
use Drupal\views\ViewExecutableFactory;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines menu links provided by views.
|
||||||
|
*
|
||||||
|
* @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
|
||||||
|
*/
|
||||||
|
class ViewsMenuLink extends MenuLinkBase implements ContainerFactoryPluginInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected $overrideAllowed = array(
|
||||||
|
'menu_name' => 1,
|
||||||
|
'parent' => 1,
|
||||||
|
'weight' => 1,
|
||||||
|
'expanded' => 1,
|
||||||
|
'hidden' => 1,
|
||||||
|
'title' => 1,
|
||||||
|
'description' => 1,
|
||||||
|
'metadata' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||||
|
*/
|
||||||
|
protected $entityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The view executable factory.
|
||||||
|
*
|
||||||
|
* @var \Drupal\views\ViewExecutableFactory
|
||||||
|
*/
|
||||||
|
protected $viewExecutableFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The view executable of the menu link.
|
||||||
|
*
|
||||||
|
* @var \Drupal\views\ViewExecutable
|
||||||
|
*/
|
||||||
|
protected $view;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new ViewsMenuLink.
|
||||||
|
*
|
||||||
|
* @param array $configuration
|
||||||
|
* A configuration array containing information about the plugin instance.
|
||||||
|
* @param string $plugin_id
|
||||||
|
* The plugin_id for the plugin instance.
|
||||||
|
* @param mixed $plugin_definition
|
||||||
|
* The plugin implementation definition.
|
||||||
|
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||||
|
* The entity manager
|
||||||
|
* @param \Drupal\views\ViewExecutableFactory $view_executable_factory
|
||||||
|
* The view executable factory
|
||||||
|
*/
|
||||||
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ViewExecutableFactory $view_executable_factory) {
|
||||||
|
$this->configuration = $configuration;
|
||||||
|
$this->pluginId = $plugin_id;
|
||||||
|
$this->pluginDefinition = $plugin_definition;
|
||||||
|
|
||||||
|
$this->entityManager = $entity_manager;
|
||||||
|
$this->viewExecutableFactory = $view_executable_factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||||
|
return new static(
|
||||||
|
$configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
$container->get('entity.manager'),
|
||||||
|
$container->get('views.executable')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the proper view.
|
||||||
|
*
|
||||||
|
* @return \Drupal\views\ViewExecutable
|
||||||
|
* The view executable.
|
||||||
|
*/
|
||||||
|
public function loadView() {
|
||||||
|
if (empty($this->view)) {
|
||||||
|
$metadata = $this->getMetaData();
|
||||||
|
$view_id = $metadata['view_id'];
|
||||||
|
$display_id = $metadata['display_id'];
|
||||||
|
$view_entity = $this->entityManager->getStorage('view')->load($view_id);
|
||||||
|
$view = $this->viewExecutableFactory->get($view_entity);
|
||||||
|
$view->setDisplay($display_id);
|
||||||
|
$view->initDisplay();
|
||||||
|
$this->view = $view;
|
||||||
|
}
|
||||||
|
return $this->view;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getTitle() {
|
||||||
|
// @todo Get the translated value from the config without instantiating the
|
||||||
|
// view. https://www.drupal.org/node/2310379
|
||||||
|
return $this->loadView()->display_handler->getOption('menu')['title'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDescription() {
|
||||||
|
return $this->loadView()->display_handler->getOption('menu')['description'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function updateLink(array $new_definition_values, $persist) {
|
||||||
|
$overrides = array_intersect_key($new_definition_values, $this->overrideAllowed);
|
||||||
|
if ($persist) {
|
||||||
|
$view = $this->loadView();
|
||||||
|
$display = &$view->storage->getDisplay($view->current_display);
|
||||||
|
// Just save the title to the original view.
|
||||||
|
$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 Improve this to not trigger a full rebuild of everything, if we
|
||||||
|
// just changed some properties. https://www.drupal.org/node/2310389
|
||||||
|
$view->storage->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update the definition.
|
||||||
|
$this->pluginDefinition = $overrides + $this->pluginDefinition;
|
||||||
|
return $this->pluginDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2119,17 +2119,14 @@ abstract class DisplayPluginBase extends PluginBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates menu links, if this display provides some.
|
* Gets menu links, if this display provides some.
|
||||||
*
|
|
||||||
* @param array $existing_links
|
|
||||||
* An array of already existing menu items provided by drupal.
|
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* The menu links registers for this display.
|
* The menu links registers for this display.
|
||||||
*
|
*
|
||||||
* @see hook_menu_link_defaults()
|
* @see \Drupal\views\Plugin\Derivative\ViewsMenuLink
|
||||||
*/
|
*/
|
||||||
public function executeHookMenuLinkDefaults(array &$existing_links) {
|
public function getMenuLinks() {
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function executeHookMenuLinkDefaults(array &$existing_links) {
|
public function getMenuLinks() {
|
||||||
$links = array();
|
$links = array();
|
||||||
|
|
||||||
// Replace % with the link to our standard views argument loader
|
// Replace % with the link to our standard views argument loader
|
||||||
|
|
@ -300,7 +300,10 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
|
||||||
$view_route_names = $this->state->get('views.view_route_names') ?: array();
|
$view_route_names = $this->state->get('views.view_route_names') ?: array();
|
||||||
|
|
||||||
$path = implode('/', $bits);
|
$path = implode('/', $bits);
|
||||||
$menu_link_id = 'views.' . str_replace('/', '.', $path);
|
$view_id = $this->view->storage->id();
|
||||||
|
$display_id = $this->display['id'];
|
||||||
|
$view_id_display = "{$view_id}.{$display_id}";
|
||||||
|
$menu_link_id = 'views.' . str_replace('/', '.', $view_id_display);
|
||||||
|
|
||||||
if ($path) {
|
if ($path) {
|
||||||
$menu = $this->getOption('menu');
|
$menu = $this->getOption('menu');
|
||||||
|
|
@ -308,12 +311,11 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
|
||||||
$links[$menu_link_id] = array();
|
$links[$menu_link_id] = array();
|
||||||
// Some views might override existing paths, so we have to set the route
|
// Some views might override existing paths, so we have to set the route
|
||||||
// name based upon the altering.
|
// name based upon the altering.
|
||||||
$view_id_display = "{$this->view->storage->id()}.{$this->display['id']}";
|
|
||||||
$links[$menu_link_id] = array(
|
$links[$menu_link_id] = array(
|
||||||
'route_name' => isset($view_route_names[$view_id_display]) ? $view_route_names[$view_id_display] : "view.$view_id_display",
|
'route_name' => isset($view_route_names[$view_id_display]) ? $view_route_names[$view_id_display] : "view.$view_id_display",
|
||||||
// Identify URL embedded arguments and correlate them to a handler.
|
// Identify URL embedded arguments and correlate them to a handler.
|
||||||
'load arguments' => array($this->view->storage->id(), $this->display['id'], '%index'),
|
'load arguments' => array($this->view->storage->id(), $this->display['id'], '%index'),
|
||||||
'machine_name' => $menu_link_id,
|
'id' => $menu_link_id,
|
||||||
);
|
);
|
||||||
$links[$menu_link_id]['title'] = $menu['title'];
|
$links[$menu_link_id]['title'] = $menu['title'];
|
||||||
$links[$menu_link_id]['description'] = $menu['description'];
|
$links[$menu_link_id]['description'] = $menu['description'];
|
||||||
|
|
@ -324,6 +326,11 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
|
||||||
|
|
||||||
// Insert item into the proper menu.
|
// Insert item into the proper menu.
|
||||||
$links[$menu_link_id]['menu_name'] = $menu['name'];
|
$links[$menu_link_id]['menu_name'] = $menu['name'];
|
||||||
|
// Keep track of where we came from.
|
||||||
|
$links[$menu_link_id]['metadata'] = array(
|
||||||
|
'view_id' => $view_id,
|
||||||
|
'display_id' => $display_id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace Drupal\views\Tests\Plugin;
|
namespace Drupal\views\Tests\Plugin;
|
||||||
|
|
||||||
|
use Drupal\Core\Session\AnonymousUserSession;
|
||||||
use Drupal\views\Views;
|
use Drupal\views\Views;
|
||||||
use Drupal\views\Tests\ViewUnitTestBase;
|
use Drupal\views\Tests\ViewUnitTestBase;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
@ -32,7 +33,7 @@ class DisplayPageTest extends ViewUnitTestBase {
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('system', 'user', 'menu_link', 'field', 'entity');
|
public static $modules = array('system', 'user', 'field', 'entity');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The router dumper to get all routes.
|
* The router dumper to get all routes.
|
||||||
|
|
@ -49,13 +50,13 @@ class DisplayPageTest extends ViewUnitTestBase {
|
||||||
|
|
||||||
// Setup the needed tables in order to make the drupal router working.
|
// Setup the needed tables in order to make the drupal router working.
|
||||||
$this->installSchema('system', array('url_alias'));
|
$this->installSchema('system', array('url_alias'));
|
||||||
$this->installSchema('menu_link', 'menu_links');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the behavior of the page for access denied/not found behaviors.
|
* Checks the behavior of the page for access denied/not found behaviors.
|
||||||
*/
|
*/
|
||||||
public function testPageResponses() {
|
public function testPageResponses() {
|
||||||
|
\Drupal::currentUser()->setAccount(new AnonymousUserSession());
|
||||||
$subrequest = Request::create('/test_page_display_403', 'GET');
|
$subrequest = Request::create('/test_page_display_403', 'GET');
|
||||||
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
|
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
|
||||||
$this->assertEqual($response->getStatusCode(), 403);
|
$this->assertEqual($response->getStatusCode(), 403);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
namespace Drupal\views\Tests\Wizard;
|
namespace Drupal\views\Tests\Wizard;
|
||||||
|
|
||||||
|
use Drupal\Component\Utility\String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the ability of the views wizard to put views in a menu.
|
* Tests the ability of the views wizard to put views in a menu.
|
||||||
*
|
*
|
||||||
|
|
@ -39,15 +41,14 @@ class MenuTest extends WizardTestBase {
|
||||||
$this->assertLinkByHref(url($view['page[path]']));
|
$this->assertLinkByHref(url($view['page[path]']));
|
||||||
|
|
||||||
// Make sure the link is associated with the main menu.
|
// Make sure the link is associated with the main menu.
|
||||||
$links = menu_load_links('main');
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
$found = FALSE;
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
foreach ($links as $link) {
|
/** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
||||||
if ($link['link_path'] == $view['page[path]']) {
|
$link = $menu_link_manager->createInstance('views_view:views.' . $view['id'] . '.page_1');
|
||||||
$found = TRUE;
|
$url = $link->getUrlObject();
|
||||||
break;
|
$this->assertEqual($url->getRouteName(), 'view.' . $view['id'] . '.page_1', String::format('Found a link to %path in the main menu', array('%path' => $view['page[path]'])));
|
||||||
}
|
$metadata = $link->getMetaData();
|
||||||
}
|
$this->assertEqual(array('view_id' => $view['id'], 'display_id' => 'page_1'), $metadata);
|
||||||
$this->assertTrue($found, t('Found a link to %path in the main menu', array('%path' => $view['page[path]'])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1509,17 +1509,16 @@ class ViewExecutable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @param string $display_id
|
||||||
* A display ID.
|
* A display ID.
|
||||||
* @param array $links
|
|
||||||
* An array of default menu link items passed from
|
|
||||||
* views_menu_link_defaults_alter().
|
|
||||||
*
|
*
|
||||||
* @return array|bool
|
* @return array|bool
|
||||||
|
* The generated menu links for this view and display, FALSE if the call
|
||||||
|
* to ::setDisplay failed.
|
||||||
*/
|
*/
|
||||||
public function executeHookMenuLinkDefaults($display_id = NULL, &$links = array()) {
|
public function getMenuLinks($display_id = NULL) {
|
||||||
// Prepare the view with the information we have. This was probably already
|
// Prepare the view with the information we have. This was probably already
|
||||||
// called, but it's good to be safe.
|
// called, but it's good to be safe.
|
||||||
if (!$this->setDisplay($display_id)) {
|
if (!$this->setDisplay($display_id)) {
|
||||||
|
|
@ -1528,7 +1527,7 @@ class ViewExecutable {
|
||||||
|
|
||||||
// Execute the hook.
|
// Execute the hook.
|
||||||
if (isset($this->display_handler)) {
|
if (isset($this->display_handler)) {
|
||||||
return $this->display_handler->executeHookMenuLinkDefaults($links);
|
return $this->display_handler->getMenuLinks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
views_view:
|
||||||
|
class: Drupal\views\Plugin\Menu\ViewsMenuLink
|
||||||
|
form_class: Drupal\views\Plugin\Menu\Form\ViewsMenuLinkForm
|
||||||
|
deriver: \Drupal\views\Plugin\Derivative\ViewsMenuLink
|
||||||
|
|
@ -304,23 +304,6 @@ function views_permission() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements hook_menu_link_defaults_alter().
|
|
||||||
*/
|
|
||||||
function views_menu_link_defaults_alter(array &$links) {
|
|
||||||
// @todo Decide what to do with all the crazy logic in views_menu_alter() in
|
|
||||||
// https://drupal.org/node/2107533.
|
|
||||||
$views = Views::getApplicableViews('uses_hook_menu');
|
|
||||||
foreach ($views as $data) {
|
|
||||||
/** @var \Drupal\views\ViewExecutable $view */
|
|
||||||
list($view, $display_id) = $data;
|
|
||||||
$result = $view->executeHookMenuLinkDefaults($display_id, $links);
|
|
||||||
foreach ($result as $link_id => $link) {
|
|
||||||
$links[$link_id] = $link;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_page_alter().
|
* Implements hook_page_alter().
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ dependencies:
|
||||||
- comment
|
- comment
|
||||||
- contextual
|
- contextual
|
||||||
- contact
|
- contact
|
||||||
|
- menu_link_content
|
||||||
- datetime
|
- datetime
|
||||||
- block_content
|
- block_content
|
||||||
- quickedit
|
- quickedit
|
||||||
|
|
|
||||||
|
|
@ -43,16 +43,11 @@ function standard_install() {
|
||||||
->fields(array('uid' => 1, 'rid' => 'administrator'))
|
->fields(array('uid' => 1, 'rid' => 'administrator'))
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
// Create a Home link in the main menu.
|
|
||||||
$menu_link = entity_create('menu_link', array(
|
|
||||||
'link_title' => t('Home'),
|
|
||||||
'link_path' => '<front>',
|
|
||||||
'menu_name' => 'main',
|
|
||||||
));
|
|
||||||
$menu_link->save();
|
|
||||||
|
|
||||||
// Enable the Contact link in the footer menu.
|
// Enable the Contact link in the footer menu.
|
||||||
menu_link_maintain('contact', 'enable', 'contact');
|
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||||
|
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||||
|
$menu_link_manager->updateDefinition('contact.site_page', array('hidden' => 0));
|
||||||
|
|
||||||
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
|
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
|
||||||
user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access site-wide contact form'));
|
user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access site-wide contact form'));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
standard.front_page:
|
||||||
|
title: 'Home'
|
||||||
|
route_name: '<front>'
|
||||||
|
menu_name: main
|
||||||
|
|
@ -28,7 +28,6 @@ class MenuLinkMock extends MenuLinkBase {
|
||||||
'options' => array(),
|
'options' => array(),
|
||||||
'expanded' => '0',
|
'expanded' => '0',
|
||||||
'hidden' => '0',
|
'hidden' => '0',
|
||||||
'discovered' => '1',
|
|
||||||
'provider' => 'simpletest',
|
'provider' => 'simpletest',
|
||||||
'metadata' => array(),
|
'metadata' => array(),
|
||||||
'class' => 'Drupal\\Tests\\Core\Menu\\MenuLinkMock',
|
'class' => 'Drupal\\Tests\\Core\Menu\\MenuLinkMock',
|
||||||
|
|
|
||||||
|
|
@ -55,18 +55,15 @@ function bartik_preprocess_page(&$variables) {
|
||||||
// Store back the classes to the htmlpage object.
|
// Store back the classes to the htmlpage object.
|
||||||
$attributes['class'] = $classes;
|
$attributes['class'] = $classes;
|
||||||
|
|
||||||
// Pass the main menu and secondary menu to the template as render arrays.
|
// Set additional attributes on the primary and secondary navigation menus.
|
||||||
if (!empty($variables['main_menu'])) {
|
if (!empty($variables['main_menu'])) {
|
||||||
$variables['main_menu']['#attributes']['id'] = 'main-menu-links';
|
$variables['main_menu']['#attributes']['id'] = 'main-menu-links';
|
||||||
$variables['main_menu']['#attributes']['class'] = array('links', 'clearfix');
|
$variables['main_menu']['#attributes']['class'][] = 'links';
|
||||||
}
|
}
|
||||||
if (!empty($variables['secondary_menu'])) {
|
if (!empty($variables['secondary_menu'])) {
|
||||||
$variables['secondary_menu']['#attributes']['id'] = 'secondary-menu-links';
|
$variables['secondary_menu']['#attributes']['id'] = 'secondary-menu-links';
|
||||||
$variables['secondary_menu']['#attributes']['class'] = array(
|
$variables['secondary_menu']['#attributes']['class'][] = 'links';
|
||||||
'links',
|
$variables['secondary_menu']['#attributes']['class'][] = 'inline';
|
||||||
'inline',
|
|
||||||
'clearfix',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the options that apply to both page and maintenance page.
|
// Set the options that apply to both page and maintenance page.
|
||||||
|
|
@ -138,10 +135,12 @@ function bartik_preprocess_block(&$variables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements THEME_menu_tree().
|
* Implements hook_preprocess_HOOK() for menu-tree.html.twig.
|
||||||
|
*
|
||||||
|
* @see template_preprocess_menu_tree()
|
||||||
*/
|
*/
|
||||||
function bartik_menu_tree($variables) {
|
function bartik_preprocess_menu_tree(&$variables) {
|
||||||
return '<ul class="menu clearfix">' . $variables['tree'] . '</ul>';
|
$variables['attributes']['class'][] = 'clearfix';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ function seven_preprocess_block_content_add_list(&$variables) {
|
||||||
function seven_preprocess_admin_block_content(&$variables) {
|
function seven_preprocess_admin_block_content(&$variables) {
|
||||||
if (!empty($variables['content'])) {
|
if (!empty($variables['content'])) {
|
||||||
foreach ($variables['content'] as $key => $item) {
|
foreach ($variables['content'] as $key => $item) {
|
||||||
$variables['content'][$key]['url'] = url($item['link_path']);
|
$variables['content'][$key]['url'] = $item['url']->toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue