Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
83
core/modules/menu_ui/src/Controller/MenuController.php
Normal file
83
core/modules/menu_ui/src/Controller/MenuController.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Controller\MenuController.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Controller;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Menu\MenuParentFormSelectorInterface;
|
||||
use Drupal\system\MenuInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Returns responses for Menu routes.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request of the page.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* The available menu and menu items.
|
||||
*/
|
||||
public function getParentOptions(Request $request) {
|
||||
$available_menus = array();
|
||||
if ($menus = $request->request->get('menus')) {
|
||||
foreach ($menus as $menu) {
|
||||
$available_menus[$menu] = $menu;
|
||||
}
|
||||
}
|
||||
// @todo Update this to use the optional $cacheability parameter, so that
|
||||
// a cacheable JSON response can be sent.
|
||||
$options = $this->menuParentSelector->getParentSelectOptions('', $available_menus);
|
||||
|
||||
return new JsonResponse($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route title callback.
|
||||
*
|
||||
* @param \Drupal\system\MenuInterface $menu
|
||||
* The menu entity.
|
||||
*
|
||||
* @return string
|
||||
* The menu label.
|
||||
*/
|
||||
public function menuTitle(MenuInterface $menu) {
|
||||
return Xss::filter($menu->label());
|
||||
}
|
||||
|
||||
}
|
100
core/modules/menu_ui/src/Form/MenuDeleteForm.php
Normal file
100
core/modules/menu_ui/src/Form/MenuDeleteForm.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Form\MenuDeleteForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Form;
|
||||
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Entity\EntityDeleteForm;
|
||||
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a confirmation form for deletion of a custom menu.
|
||||
*/
|
||||
class MenuDeleteForm extends EntityDeleteForm {
|
||||
|
||||
/**
|
||||
* The menu link manager.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
||||
*/
|
||||
protected $menuLinkManager;
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* Constructs a new MenuDeleteForm.
|
||||
*
|
||||
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
||||
* The menu link manager.
|
||||
* @param \Drupal\Core\Database\Connection $connection
|
||||
* The database connection.
|
||||
*/
|
||||
public function __construct(MenuLinkManagerInterface $menu_link_manager, Connection $connection) {
|
||||
$this->menuLinkManager = $menu_link_manager;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.menu.link'),
|
||||
$container->get('database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
$caption = '';
|
||||
$num_links = $this->menuLinkManager->countMenuLinks($this->entity->id());
|
||||
if ($num_links) {
|
||||
$caption .= '<p>' . $this->formatPlural($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>' . t('This action cannot be undone.') . '</p>';
|
||||
return $caption;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function logDeletionMessage() {
|
||||
$this->logger('menu')->notice('Deleted custom menu %title and all its menu links.', array('%title' => $this->entity->label()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Locked menus may not be deleted.
|
||||
if ($this->entity->isLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete all links to the overview page for this menu.
|
||||
// @todo Add a more generic helper function to the menu link plugin
|
||||
// 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('entity.menu.edit_form', array('menu' => $this->entity->id()), TRUE);
|
||||
foreach ($menu_links as $id => $link) {
|
||||
$this->menuLinkManager->removeDefinition($id);
|
||||
}
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
}
|
104
core/modules/menu_ui/src/Form/MenuLinkEditForm.php
Normal file
104
core/modules/menu_ui/src/Form/MenuLinkEditForm.php
Normal file
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Form\MenuLinkEditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Form;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Menu\MenuLinkInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a generic edit form for all menu link plugin types.
|
||||
*
|
||||
* The menu link plugin defines which class defines the corresponding form.
|
||||
*
|
||||
* @see \Drupal\Core\Menu\MenuLinkInterface::getFormClass()
|
||||
*/
|
||||
class MenuLinkEditForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The class resolver.
|
||||
*
|
||||
* @var \Drupal\Core\DependencyInjection\ClassResolverInterface
|
||||
*/
|
||||
protected $classResolver;
|
||||
|
||||
/**
|
||||
* Constructs a MenuLinkEditForm object.
|
||||
*
|
||||
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
|
||||
* The class resolver.
|
||||
*/
|
||||
public function __construct(ClassResolverInterface $class_resolver) {
|
||||
$this->classResolver = $class_resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('class_resolver')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'menu_link_edit';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin
|
||||
* The plugin instance to use for this form.
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, MenuLinkInterface $menu_link_plugin = NULL) {
|
||||
$form['menu_link_id'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $menu_link_plugin->getPluginId(),
|
||||
);
|
||||
$class_name = $menu_link_plugin->getFormClass();
|
||||
$form['#plugin_form'] = $this->classResolver->getInstanceFromDefinition($class_name);
|
||||
$form['#plugin_form']->setMenuLinkInstance($menu_link_plugin);
|
||||
|
||||
$form += $form['#plugin_form']->buildConfigurationForm($form, $form_state);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$form['#plugin_form']->validateConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$link = $form['#plugin_form']->submitConfigurationForm($form, $form_state);
|
||||
|
||||
drupal_set_message($this->t('The menu link has been saved.'));
|
||||
$form_state->setRedirect(
|
||||
'entity.menu.edit_form',
|
||||
array('menu' => $link->getMenuName())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
125
core/modules/menu_ui/src/Form/MenuLinkResetForm.php
Normal file
125
core/modules/menu_ui/src/Form/MenuLinkResetForm.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Form\MenuLinkResetForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Form;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||
use Drupal\Core\Menu\MenuLinkInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a confirmation form for resetting a single modified menu link.
|
||||
*/
|
||||
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}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to reset the link %item to its default values?', array('%item' => $this->link->getTitle()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('entity.menu.edit_form', array(
|
||||
'menu' => $this->link->getMenuName(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->t('Any customizations will be lost. This action cannot be undone.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Reset');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, MenuLinkInterface $menu_link_plugin = NULL) {
|
||||
$this->link = $menu_link_plugin;
|
||||
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $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->setRedirectUrl($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 \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function linkIsResettable(MenuLinkInterface $menu_link_plugin) {
|
||||
return AccessResult::allowedIf($menu_link_plugin->isResettable())->setCacheMaxAge(0);
|
||||
}
|
||||
|
||||
}
|
485
core/modules/menu_ui/src/MenuForm.php
Normal file
485
core/modules/menu_ui/src/MenuForm.php
Normal file
|
@ -0,0 +1,485 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\MenuForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
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\Routing\UrlGeneratorTrait;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Utility\LinkGeneratorInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Base form for menu edit forms.
|
||||
*/
|
||||
class MenuForm extends EntityForm {
|
||||
|
||||
/**
|
||||
* The factory for entity queries.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Query\QueryFactory
|
||||
*/
|
||||
protected $entityQueryFactory;
|
||||
|
||||
/**
|
||||
* The menu link manager.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
||||
*/
|
||||
protected $menuLinkManager;
|
||||
|
||||
/**
|
||||
* The menu tree service.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||
*/
|
||||
protected $menuTree;
|
||||
|
||||
/**
|
||||
* The link generator.
|
||||
*
|
||||
* @var \Drupal\Core\Utility\LinkGeneratorInterface
|
||||
*/
|
||||
protected $linkGenerator;
|
||||
|
||||
/**
|
||||
* The overview tree form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $overviewTreeForm = array('#tree' => TRUE);
|
||||
|
||||
/**
|
||||
* Constructs a MenuForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query_factory
|
||||
* The factory for entity queries.
|
||||
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
||||
* The menu link manager.
|
||||
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
|
||||
* The menu tree service.
|
||||
* @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
|
||||
* The link generator.
|
||||
*/
|
||||
public function __construct(QueryFactory $entity_query_factory, MenuLinkManagerInterface $menu_link_manager, MenuLinkTreeInterface $menu_tree, LinkGeneratorInterface $link_generator) {
|
||||
$this->entityQueryFactory = $entity_query_factory;
|
||||
$this->menuLinkManager = $menu_link_manager;
|
||||
$this->menuTree = $menu_tree;
|
||||
$this->linkGenerator = $link_generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.query'),
|
||||
$container->get('plugin.manager.menu.link'),
|
||||
$container->get('menu.link_tree'),
|
||||
$container->get('link_generator')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$menu = $this->entity;
|
||||
|
||||
if ($this->operation == 'edit') {
|
||||
$form['#title'] = $this->t('Edit menu %label', array('%label' => $menu->label()));
|
||||
}
|
||||
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Title'),
|
||||
'#default_value' => $menu->label(),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['id'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#title' => $this->t('Menu name'),
|
||||
'#default_value' => $menu->id(),
|
||||
'#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI,
|
||||
'#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(
|
||||
'exists' => array($this, 'menuNameExists'),
|
||||
'source' => array('label'),
|
||||
'replace_pattern' => '[^a-z0-9-]+',
|
||||
'replace' => '-',
|
||||
),
|
||||
// A menu's machine name cannot be changed.
|
||||
'#disabled' => !$menu->isNew() || $menu->isLocked(),
|
||||
);
|
||||
$form['description'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Administrative summary'),
|
||||
'#maxlength' => 512,
|
||||
'#default_value' => $menu->getDescription(),
|
||||
);
|
||||
|
||||
$form['langcode'] = array(
|
||||
'#type' => 'language_select',
|
||||
'#title' => t('Menu language'),
|
||||
'#languages' => LanguageInterface::STATE_ALL,
|
||||
'#default_value' => $menu->language()->getId(),
|
||||
);
|
||||
|
||||
// Add menu links administration form for existing menus.
|
||||
if (!$menu->isNew() || $menu->isLocked()) {
|
||||
// Form API supports constructing and validating self-contained sections
|
||||
// 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
|
||||
// the parents of the form section.
|
||||
// @see self::submitOverviewForm()
|
||||
$form_state->set('menu_overview_form_parents', ['links']);
|
||||
$form['links'] = array();
|
||||
$form['links'] = $this->buildOverviewForm($form['links'], $form_state);
|
||||
}
|
||||
|
||||
return parent::form($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a menu name already exists.
|
||||
*
|
||||
* @param string $value
|
||||
* The name of the menu.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if the menu already exists, FALSE otherwise.
|
||||
*/
|
||||
public function menuNameExists($value) {
|
||||
// Check first to see if a menu with this ID exists.
|
||||
if ($this->entityQueryFactory->get('menu')->condition('id', $value)->range(0, 1)->count()->execute()) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check for a link assigned to this menu.
|
||||
return $this->menuLinkManager->menuNameInUse($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$menu = $this->entity;
|
||||
if (!$menu->isNew() || $menu->isLocked()) {
|
||||
$this->submitOverviewForm($form, $form_state);
|
||||
}
|
||||
|
||||
$status = $menu->save();
|
||||
|
||||
$edit_link = $this->entity->link($this->t('Edit'));
|
||||
if ($status == SAVED_UPDATED) {
|
||||
drupal_set_message($this->t('Menu %label has been updated.', array('%label' => $menu->label())));
|
||||
$this->logger('menu')->notice('Menu %label has been updated.', array('%label' => $menu->label(), 'link' => $edit_link));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('Menu %label has been added.', array('%label' => $menu->label())));
|
||||
$this->logger('menu')->notice('Menu %label has been added.', array('%label' => $menu->label(), 'link' => $edit_link));
|
||||
}
|
||||
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('edit-form'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor to edit an entire menu tree at once.
|
||||
*
|
||||
* Shows for one menu the menu links accessible to the current user and
|
||||
* relevant operations.
|
||||
*
|
||||
* This form constructor can be integrated as a section into another form. It
|
||||
* relies on the following keys in $form_state:
|
||||
* - menu: A menu entity.
|
||||
* - menu_overview_form_parents: An array containing the parent keys to this
|
||||
* form.
|
||||
* Forms integrating this section should call menu_overview_form_submit() from
|
||||
* their form submit handler.
|
||||
*/
|
||||
protected function buildOverviewForm(array &$form, FormStateInterface $form_state) {
|
||||
// Ensure that menu_overview_form_submit() knows the parents of this form
|
||||
// section.
|
||||
if (!$form_state->has('menu_overview_form_parents')) {
|
||||
$form_state->set('menu_overview_form_parents', []);
|
||||
}
|
||||
|
||||
$form['#attached']['library'][] = 'menu_ui/drupal.menu_ui.adminforms';
|
||||
|
||||
$tree = $this->menuTree->load($this->entity->id(), new MenuTreeParameters());
|
||||
|
||||
// We indicate that a menu administrator is running the menu access check.
|
||||
$this->getRequest()->attributes->set('_menu_admin', TRUE);
|
||||
$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);
|
||||
|
||||
// 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['links'] = array(
|
||||
'#type' => 'table',
|
||||
'#theme' => 'table__menu_overview',
|
||||
'#header' => array(
|
||||
$this->t('Menu link'),
|
||||
array(
|
||||
'data' => $this->t('Enabled'),
|
||||
'class' => array('checkbox'),
|
||||
),
|
||||
$this->t('Weight'),
|
||||
array(
|
||||
'data' => $this->t('Operations'),
|
||||
'colspan' => 3,
|
||||
),
|
||||
),
|
||||
'#attributes' => array(
|
||||
'id' => 'menu-overview',
|
||||
),
|
||||
'#tabledrag' => array(
|
||||
array(
|
||||
'action' => 'match',
|
||||
'relationship' => 'parent',
|
||||
'group' => 'menu-parent',
|
||||
'subgroup' => 'menu-parent',
|
||||
'source' => 'menu-id',
|
||||
'hidden' => TRUE,
|
||||
'limit' => \Drupal::menuTree()->maxDepth() - 1,
|
||||
),
|
||||
array(
|
||||
'action' => 'order',
|
||||
'relationship' => 'sibling',
|
||||
'group' => 'menu-weight',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['links']['#empty'] = $this->t('There are no menu links yet. <a href="@url">Add link</a>.', [
|
||||
'@url' => $this->url('entity.menu.add_link_form', ['menu' => $this->entity->id()], [
|
||||
'query' => ['destination' => $this->entity->url('edit-form')],
|
||||
]),
|
||||
]);
|
||||
$links = $this->buildOverviewTreeForm($tree, $delta);
|
||||
foreach (Element::children($links) as $id) {
|
||||
if (isset($links[$id]['#item'])) {
|
||||
$element = $links[$id];
|
||||
|
||||
$form['links'][$id]['#item'] = $element['#item'];
|
||||
|
||||
// TableDrag: Mark the table row as draggable.
|
||||
$form['links'][$id]['#attributes'] = $element['#attributes'];
|
||||
$form['links'][$id]['#attributes']['class'][] = 'draggable';
|
||||
|
||||
$form['links'][$id]['#item'] = $element['#item'];
|
||||
|
||||
// TableDrag: Sort the table row according to its existing/configured weight.
|
||||
$form['links'][$id]['#weight'] = $element['#item']->link->getWeight();
|
||||
|
||||
// Add special classes to be used for tabledrag.js.
|
||||
$element['parent']['#attributes']['class'] = array('menu-parent');
|
||||
$element['weight']['#attributes']['class'] = array('menu-weight');
|
||||
$element['id']['#attributes']['class'] = array('menu-id');
|
||||
|
||||
$form['links'][$id]['title'] = array(
|
||||
array(
|
||||
'#theme' => 'indentation',
|
||||
'#size' => $element['#item']->depth - 1,
|
||||
),
|
||||
$element['title'],
|
||||
);
|
||||
$form['links'][$id]['enabled'] = $element['enabled'];
|
||||
$form['links'][$id]['enabled']['#wrapper_attributes']['class'] = array('checkbox', 'menu-enabled');
|
||||
|
||||
$form['links'][$id]['weight'] = $element['weight'];
|
||||
|
||||
// Operations (dropbutton) column.
|
||||
$form['links'][$id]['operations'] = $element['operations'];
|
||||
|
||||
$form['links'][$id]['id'] = $element['id'];
|
||||
$form['links'][$id]['parent'] = $element['parent'];
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper function for buildOverviewForm().
|
||||
*
|
||||
* @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
|
||||
* The tree retrieved by \Drupal\Core\Menu\MenuLinkTreeInterface::load().
|
||||
* @param int $delta
|
||||
* The default number of menu items used in the menu weight selector is 50.
|
||||
*
|
||||
* @return array
|
||||
* The overview tree form.
|
||||
*/
|
||||
protected function buildOverviewTreeForm($tree, $delta) {
|
||||
$form = &$this->overviewTreeForm;
|
||||
$tree_access_cacheability = new CacheableMetadata();
|
||||
foreach ($tree as $element) {
|
||||
$tree_access_cacheability = $tree_access_cacheability->merge(CacheableMetadata::createFromObject($element->access));
|
||||
|
||||
// Only render accessible links.
|
||||
if (!$element->access->isAllowed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
||||
$link = $element->link;
|
||||
if ($link) {
|
||||
$id = 'menu_plugin_id:' . $link->getPluginId();
|
||||
$form[$id]['#item'] = $element;
|
||||
$form[$id]['#attributes'] = $link->isEnabled() ? array('class' => array('menu-enabled')) : array('class' => array('menu-disabled'));
|
||||
$form[$id]['title']['#markup'] = $this->linkGenerator->generate($link->getTitle(), $link->getUrlObject());
|
||||
if (!$link->isEnabled()) {
|
||||
$form[$id]['title']['#markup'] .= ' (' . $this->t('disabled') . ')';
|
||||
}
|
||||
elseif (($url = $link->getUrlObject()) && $url->isRouted() && $url->getRouteName() == 'user.page') {
|
||||
$form[$id]['title']['#markup'] .= ' (' . $this->t('logged in users only') . ')';
|
||||
}
|
||||
|
||||
$form[$id]['enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Enable @title menu link', array('@title' => $link->getTitle())),
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => $link->isEnabled(),
|
||||
);
|
||||
$form[$id]['weight'] = array(
|
||||
'#type' => 'weight',
|
||||
'#delta' => $delta,
|
||||
'#default_value' => $link->getWeight(),
|
||||
'#title' => $this->t('Weight for @title', array('@title' => $link->getTitle())),
|
||||
'#title_display' => 'invisible',
|
||||
);
|
||||
$form[$id]['id'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $link->getPluginId(),
|
||||
);
|
||||
$form[$id]['parent'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#default_value' => $link->getParent(),
|
||||
);
|
||||
// Build a list of operations.
|
||||
$operations = array();
|
||||
$operations['edit'] = array(
|
||||
'title' => $this->t('Edit'),
|
||||
);
|
||||
// Allow for a custom edit link per plugin.
|
||||
$edit_route = $link->getEditRoute();
|
||||
if ($edit_route) {
|
||||
$operations['edit']['url'] = $edit_route;
|
||||
// Bring the user back to the menu overview.
|
||||
$operations['edit']['query'] = $this->getDestinationArray();
|
||||
}
|
||||
else {
|
||||
// Fall back to the standard edit link.
|
||||
$operations['edit'] += array(
|
||||
'url' => Url::fromRoute('menu_ui.link_edit', ['menu_link_plugin' => $link->getPluginId()]),
|
||||
);
|
||||
}
|
||||
// Links can either be reset or deleted, not both.
|
||||
if ($link->isResettable()) {
|
||||
$operations['reset'] = array(
|
||||
'title' => $this->t('Reset'),
|
||||
'url' => Url::fromRoute('menu_ui.link_reset', ['menu_link_plugin' => $link->getPluginId()]),
|
||||
);
|
||||
}
|
||||
elseif ($delete_link = $link->getDeleteRoute()) {
|
||||
$operations['delete']['url'] = $delete_link;
|
||||
$operations['delete']['query'] = $this->getDestinationArray();
|
||||
$operations['delete']['title'] = $this->t('Delete');
|
||||
}
|
||||
if ($link->isTranslatable()) {
|
||||
$operations['translate'] = array(
|
||||
'title' => $this->t('Translate'),
|
||||
'url' => $link->getTranslateRoute(),
|
||||
);
|
||||
}
|
||||
$form[$id]['operations'] = array(
|
||||
'#type' => 'operations',
|
||||
'#links' => $operations,
|
||||
);
|
||||
}
|
||||
|
||||
if ($element->subtree) {
|
||||
$this->buildOverviewTreeForm($element->subtree, $delta);
|
||||
}
|
||||
}
|
||||
|
||||
$tree_access_cacheability
|
||||
->merge(CacheableMetadata::createFromRenderArray($form))
|
||||
->applyTo($form);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the menu overview form.
|
||||
*
|
||||
* This function takes great care in saving parent items first, then items
|
||||
* underneath them. Saving items in the incorrect order can break the tree.
|
||||
*/
|
||||
protected function submitOverviewForm(array $complete_form, FormStateInterface $form_state) {
|
||||
// Form API supports constructing and validating self-contained sections
|
||||
// within forms, but does not allow to handle the form section's submission
|
||||
// equally separated yet. Therefore, we use a $form_state key to point to
|
||||
// the parents of the form section.
|
||||
$parents = $form_state->get('menu_overview_form_parents');
|
||||
$input = NestedArray::getValue($form_state->getUserInput(), $parents);
|
||||
$form = &NestedArray::getValue($complete_form, $parents);
|
||||
|
||||
// When dealing with saving menu items, the order in which these items are
|
||||
// saved is critical. If a changed child item is saved before its parent,
|
||||
// the child item could be saved with an invalid path past its immediate
|
||||
// parent. To prevent this, save items in the form in the same order they
|
||||
// are sent, ensuring parents are saved first, then their children.
|
||||
// See https://www.drupal.org/node/181126#comment-632270.
|
||||
$order = is_array($input) ? array_flip(array_keys($input)) : array();
|
||||
// Update our original form with the new order.
|
||||
$form = array_intersect_key(array_merge($order, $form), $form);
|
||||
|
||||
$fields = array('weight', 'parent', 'enabled');
|
||||
$form_links = $form['links'];
|
||||
foreach (Element::children($form_links) as $id) {
|
||||
if (isset($form_links[$id]['#item'])) {
|
||||
$element = $form_links[$id];
|
||||
$updated_values = array();
|
||||
// Update any fields that have changed in this menu item.
|
||||
foreach ($fields as $field) {
|
||||
if ($element[$field]['#value'] != $element[$field]['#default_value']) {
|
||||
$updated_values[$field] = $element[$field]['#value'];
|
||||
}
|
||||
}
|
||||
if ($updated_values) {
|
||||
// Use the ID from the actual plugin instance since the hidden value
|
||||
// in the form could be tampered with.
|
||||
$this->menuLinkManager->updateDefinition($element['#item']->link->getPLuginId(), $updated_values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
75
core/modules/menu_ui/src/MenuListBuilder.php
Normal file
75
core/modules/menu_ui/src/MenuListBuilder.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\MenuListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of menu entities.
|
||||
*
|
||||
* @see \Drupal\system\Entity\Menu
|
||||
* @see menu_entity_info()
|
||||
*/
|
||||
class MenuListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['title'] = t('Title');
|
||||
$header['description'] = array(
|
||||
'data' => t('Description'),
|
||||
'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
|
||||
);
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
$row['title'] = array(
|
||||
'data' => $this->getLabel($entity),
|
||||
'class' => array('menu-label'),
|
||||
);
|
||||
$row['description'] = Xss::filterAdmin($entity->getDescription());
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultOperations(EntityInterface $entity) {
|
||||
$operations = parent::getDefaultOperations($entity);
|
||||
|
||||
if (isset($operations['edit'])) {
|
||||
$operations['edit']['title'] = t('Edit menu');
|
||||
$operations['add'] = array(
|
||||
'title' => t('Add link'),
|
||||
'weight' => 20,
|
||||
'url' => $entity->urlInfo('add-link-form'),
|
||||
);
|
||||
}
|
||||
if (isset($operations['delete'])) {
|
||||
$operations['delete']['title'] = t('Delete menu');
|
||||
}
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render() {
|
||||
$build = parent::render();
|
||||
$build['#attached']['library'][] = "menu_ui/drupal.menu_ui.adminforms";
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Plugin\Menu\LocalAction\MenuLinkAdd.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Plugin\Menu\LocalAction;
|
||||
|
||||
use Drupal\Core\Menu\LocalActionDefault;
|
||||
use Drupal\Core\Routing\RedirectDestination;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Modifies the 'Add link' local action to add a destination.
|
||||
*/
|
||||
class MenuLinkAdd extends LocalActionDefault {
|
||||
|
||||
/**
|
||||
* The redirect destination.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RedirectDestination
|
||||
*/
|
||||
private $redirectDestination;
|
||||
|
||||
/**
|
||||
* Constructs a MenuLinkAdd object.
|
||||
*
|
||||
* @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\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider to load routes by name.
|
||||
* @param \Drupal\Core\Routing\RedirectDestination $redirect_destination
|
||||
* The redirect destination.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, RedirectDestination $redirect_destination) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider);
|
||||
|
||||
$this->redirectDestination = $redirect_destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('router.route_provider'),
|
||||
$container->get('redirect.destination')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOptions(RouteMatchInterface $route_match) {
|
||||
$options = parent::getOptions($route_match);
|
||||
// Append the current path as destination to the query string.
|
||||
$options['query']['destination'] = $this->redirectDestination->get();
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
116
core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
Normal file
116
core/modules/menu_ui/src/Tests/MenuCacheTagsTest.php
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Tests\MenuCacheTagsTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Tests;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
|
||||
|
||||
/**
|
||||
* Tests the Menu and Menu Link entities' cache tags.
|
||||
*
|
||||
* @group menu_ui
|
||||
*/
|
||||
class MenuCacheTagsTest extends PageCacheTagsTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = array('menu_ui', 'block', 'test_page_test');
|
||||
|
||||
/**
|
||||
* Tests cache tags presence and invalidation of the Menu entity.
|
||||
*
|
||||
* Tests the following cache tags:
|
||||
* - "menu:<menu ID>"
|
||||
*/
|
||||
public function testMenuBlock() {
|
||||
$url = Url::fromRoute('test_page_test.test_page');
|
||||
|
||||
// Create a Llama menu, add a link to it and place the corresponding block.
|
||||
$menu = entity_create('menu', array(
|
||||
'id' => 'llama',
|
||||
'label' => 'Llama',
|
||||
'description' => 'Description text',
|
||||
));
|
||||
$menu->save();
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
// Move a link into the new menu.
|
||||
$menu_link = $menu_link_manager->updateDefinition('test_page_test.test_page', array('menu_name' => 'llama', 'parent' => ''));
|
||||
$block = $this->drupalPlaceBlock('system_menu_block:llama', array('label' => 'Llama', 'provider' => 'system', 'region' => 'footer'));
|
||||
|
||||
// Prime the page cache.
|
||||
$this->verifyPageCache($url, 'MISS');
|
||||
|
||||
// Verify a cache hit, but also the presence of the correct cache tags.
|
||||
$expected_tags = array(
|
||||
'rendered',
|
||||
'block_view',
|
||||
'config:block_list',
|
||||
'config:block.block.' . $block->id(),
|
||||
'config:system.menu.llama',
|
||||
// The cache contexts associated with the (in)accessible menu links are
|
||||
// bubbled.
|
||||
'config:user.role.anonymous',
|
||||
);
|
||||
$this->verifyPageCache($url, 'HIT', $expected_tags);
|
||||
|
||||
// Verify that after modifying the menu, there is a cache miss.
|
||||
$this->pass('Test modification of menu.', 'Debug');
|
||||
$menu->set('label', 'Awesome llama');
|
||||
$menu->save();
|
||||
$this->verifyPageCache($url, 'MISS');
|
||||
|
||||
// Verify a cache hit.
|
||||
$this->verifyPageCache($url, 'HIT');
|
||||
|
||||
// Verify that after modifying the menu link weight, 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->verifyPageCache($url, 'MISS');
|
||||
|
||||
// Verify a cache hit.
|
||||
$this->verifyPageCache($url, 'HIT');
|
||||
|
||||
// Verify that after adding a menu link, there is a cache miss.
|
||||
$this->pass('Test addition of menu link.', 'Debug');
|
||||
$menu_link_2 = entity_create('menu_link_content', array(
|
||||
'id' => '',
|
||||
'parent' => '',
|
||||
'title' => 'Alpaca',
|
||||
'menu_name' => 'llama',
|
||||
'link' => [[
|
||||
'uri' => 'internal:/',
|
||||
]],
|
||||
'bundle' => 'menu_name',
|
||||
));
|
||||
$menu_link_2->save();
|
||||
$this->verifyPageCache($url, 'MISS');
|
||||
|
||||
// Verify a cache hit.
|
||||
$this->verifyPageCache($url, 'HIT');
|
||||
|
||||
// Verify that after resetting the first menu link, there is a cache miss.
|
||||
$this->pass('Test reset of menu link.', 'Debug');
|
||||
$this->assertTrue($menu_link->isResettable(), 'First link can be reset');
|
||||
$menu_link = $menu_link_manager->resetLink($menu_link->getPluginId());
|
||||
$this->verifyPageCache($url, 'MISS');
|
||||
|
||||
// Verify a cache hit.
|
||||
$this->verifyPageCache($url, 'HIT', $expected_tags);
|
||||
|
||||
// Verify that after deleting the menu, there is a cache miss.
|
||||
$this->pass('Test deletion of menu.', 'Debug');
|
||||
$menu->delete();
|
||||
$this->verifyPageCache($url, 'MISS');
|
||||
|
||||
// Verify a cache hit.
|
||||
$this->verifyPageCache($url, 'HIT', ['config:block_list', 'rendered']);
|
||||
}
|
||||
|
||||
}
|
139
core/modules/menu_ui/src/Tests/MenuLanguageTest.php
Normal file
139
core/modules/menu_ui/src/Tests/MenuLanguageTest.php
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Tests\MenuLanguageTest.
|
||||
*
|
||||
* Tests for menu_ui language settings.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Tests;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\system\Entity\Menu;
|
||||
|
||||
/**
|
||||
* Create menu and menu links in non-English language, and edit language
|
||||
* settings.
|
||||
*
|
||||
* @group menu_ui
|
||||
*/
|
||||
class MenuLanguageTest extends MenuWebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('language');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer menu')));
|
||||
|
||||
// Add some custom languages.
|
||||
foreach (array('aa', 'bb', 'cc', 'cs') as $language_code) {
|
||||
ConfigurableLanguage::create(array(
|
||||
'id' => $language_code,
|
||||
'label' => $this->randomMachineName(),
|
||||
))->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests menu language settings and the defaults for menu link items.
|
||||
*/
|
||||
function testMenuLanguage() {
|
||||
// Create a test menu to test the various language-related settings.
|
||||
// Machine name has to be lowercase.
|
||||
$menu_name = Unicode::strtolower($this->randomMachineName(16));
|
||||
$label = $this->randomString();
|
||||
$edit = array(
|
||||
'id' => $menu_name,
|
||||
'description' => '',
|
||||
'label' => $label,
|
||||
'langcode' => 'aa',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
|
||||
ContentLanguageSettings::loadByEntityTypeBundle('menu_link_content', 'menu_link_content')
|
||||
->setDefaultLangcode('bb')
|
||||
->setLanguageAlterable(TRUE)
|
||||
->save();
|
||||
|
||||
// Check menu language.
|
||||
$this->assertOptionSelected('edit-langcode', $edit['langcode'], 'The menu language was correctly selected.');
|
||||
|
||||
// Test menu link language.
|
||||
$link_path = '/';
|
||||
|
||||
// Add a menu link.
|
||||
$link_title = $this->randomString();
|
||||
$edit = array(
|
||||
'title[0][value]' => $link_title,
|
||||
'link[0][uri]' => $link_path,
|
||||
);
|
||||
$this->drupalPostForm("admin/structure/menu/manage/$menu_name/add", $edit, t('Save'));
|
||||
// Check the link was added with the correct menu link default language.
|
||||
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $link_title));
|
||||
$menu_link = reset($menu_links);
|
||||
$this->assertMenuLink($menu_link->getPluginId(), array(
|
||||
'menu_name' => $menu_name,
|
||||
'route_name' => '<front>',
|
||||
'langcode' => 'bb',
|
||||
));
|
||||
|
||||
// Edit menu link default, changing it to cc.
|
||||
ContentLanguageSettings::loadByEntityTypeBundle('menu_link_content', 'menu_link_content')
|
||||
->setDefaultLangcode('cc')
|
||||
->setLanguageAlterable(TRUE)
|
||||
->save();
|
||||
|
||||
// Add a menu link.
|
||||
$link_title = $this->randomString();
|
||||
$edit = array(
|
||||
'title[0][value]' => $link_title,
|
||||
'link[0][uri]' => $link_path,
|
||||
);
|
||||
$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.
|
||||
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $link_title));
|
||||
$menu_link = reset($menu_links);
|
||||
$this->assertMenuLink($menu_link->getPluginId(), array(
|
||||
'menu_name' => $menu_name,
|
||||
'route_name' => '<front>',
|
||||
'langcode' => 'cc',
|
||||
));
|
||||
|
||||
// Now change the language of the new link to 'bb'.
|
||||
$edit = array(
|
||||
'langcode[0][value]' => 'bb',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/menu/item/' . $menu_link->id() . '/edit', $edit, t('Save'));
|
||||
$this->assertMenuLink($menu_link->getPluginId(), array(
|
||||
'menu_name' => $menu_name,
|
||||
'route_name' => '<front>',
|
||||
'langcode' => 'bb',
|
||||
));
|
||||
|
||||
// Saving menu link items ends up on the edit menu page. To check the menu
|
||||
// link has the correct language default on edit, go to the menu link edit
|
||||
// page first.
|
||||
$this->drupalGet('admin/structure/menu/item/' . $menu_link->id() . '/edit');
|
||||
// Check that the language selector has the correct default value.
|
||||
$this->assertOptionSelected('edit-langcode-0-value', 'bb', 'The menu link language was correctly selected.');
|
||||
|
||||
// Edit menu to hide the language select on menu link item add.
|
||||
ContentLanguageSettings::loadByEntityTypeBundle('menu_link_content', 'menu_link_content')
|
||||
->setDefaultLangcode('cc')
|
||||
->setLanguageAlterable(FALSE)
|
||||
->save();
|
||||
|
||||
// Check that the language selector is not available on menu link add page.
|
||||
$this->drupalGet("admin/structure/menu/manage/$menu_name/add");
|
||||
$this->assertNoField('edit-langcode-0-value', 'The language selector field was hidden the page');
|
||||
}
|
||||
|
||||
}
|
231
core/modules/menu_ui/src/Tests/MenuNodeTest.php
Normal file
231
core/modules/menu_ui/src/Tests/MenuNodeTest.php
Normal file
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Tests\MenuNodeTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
|
||||
/**
|
||||
* Add, edit, and delete a node with menu link.
|
||||
*
|
||||
* @group menu_ui
|
||||
*/
|
||||
class MenuNodeTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* An editor user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $editor;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('menu_ui', 'test_page_test', 'node', 'block');
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('system_menu_block:main');
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
|
||||
$this->editor = $this->drupalCreateUser(array(
|
||||
'access administration pages',
|
||||
'administer content types',
|
||||
'administer menu',
|
||||
'create page content',
|
||||
'edit any page content',
|
||||
'delete any page content',
|
||||
));
|
||||
$this->drupalLogin($this->editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creating, editing, deleting menu links via node form widget.
|
||||
*/
|
||||
function testMenuNodeFormWidget() {
|
||||
// Verify that cacheability metadata is bubbled from the menu link tree
|
||||
// access checking that is performed when determining the "default parent
|
||||
// item" options in menu_ui_form_node_type_form_alter(). The "log out" link
|
||||
// adds the "user.roles:authenticated" cache context.
|
||||
$this->drupalGet('admin/structure/types/manage/page');
|
||||
$this->assertCacheContext('user.roles:authenticated');
|
||||
|
||||
// Disable the default main menu, so that no menus are enabled.
|
||||
$edit = array(
|
||||
'menu_options[main]' => FALSE,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
|
||||
|
||||
// Verify that no menu settings are displayed and nodes can be created.
|
||||
$this->drupalGet('node/add/page');
|
||||
$this->assertText(t('Create Basic page'));
|
||||
$this->assertNoText(t('Menu settings'));
|
||||
$node_title = $this->randomMachineName();
|
||||
$edit = array(
|
||||
'title[0][value]' => $node_title,
|
||||
'body[0][value]' => $this->randomString(),
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$node = $this->drupalGetNodeByTitle($node_title);
|
||||
$this->assertEqual($node->getTitle(), $edit['title[0][value]']);
|
||||
|
||||
// Test that we cannot set a menu item from a menu that is not set as
|
||||
// available.
|
||||
$edit = array(
|
||||
'menu_options[tools]' => 1,
|
||||
'menu_parent' => 'main:',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
|
||||
$this->assertText(t('The selected menu item is not under one of the selected menus.'));
|
||||
$this->assertNoRaw(t('The content type %name has been updated.', array('%name' => 'Basic page')));
|
||||
|
||||
// Enable Tools menu as available menu.
|
||||
$edit = array(
|
||||
'menu_options[main]' => 1,
|
||||
'menu_options[tools]' => 1,
|
||||
'menu_parent' => 'main:',
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
|
||||
$this->assertRaw(t('The content type %name has been updated.', array('%name' => 'Basic page')));
|
||||
|
||||
// Test that we can preview a node that will create a menu item.
|
||||
$edit = array(
|
||||
'title[0][value]' => $node_title,
|
||||
'menu[enabled]' => 1,
|
||||
'menu[title]' => 'Test preview',
|
||||
);
|
||||
$this->drupalPostForm('node/add/page', $edit, t('Preview'));
|
||||
|
||||
// Create a node.
|
||||
$node_title = $this->randomMachineName();
|
||||
$edit = array(
|
||||
'title[0][value]' => $node_title,
|
||||
'body[0][value]' => $this->randomString(),
|
||||
);
|
||||
$this->drupalPostForm('node/add/page', $edit, t('Save'));
|
||||
$node = $this->drupalGetNodeByTitle($node_title);
|
||||
// Assert that there is no link for the node.
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertNoLink($node_title);
|
||||
|
||||
// Edit the node, enable the menu link setting, but skip the link title.
|
||||
$edit = array(
|
||||
'menu[enabled]' => 1,
|
||||
);
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
||||
// Assert that there is no link for the node.
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertNoLink($node_title);
|
||||
|
||||
// Use not only the save button, but also the two special buttons:
|
||||
// 'Save and publish' as well as 'Save and keep published'.
|
||||
// These buttons just appear for 'administer nodes' users.
|
||||
$admin_user = $this->drupalCreateUser([
|
||||
'access administration pages',
|
||||
'administer content types',
|
||||
'administer nodes',
|
||||
'administer menu',
|
||||
'create page content',
|
||||
'edit any page content',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
foreach ([t('Save and unpublish') => FALSE, t('Save and keep unpublished') => FALSE, t('Save and publish') => TRUE, t('Save and keep published') => TRUE] as $submit => $visible) {
|
||||
$edit = [
|
||||
'menu[enabled]' => 1,
|
||||
'menu[title]' => $node_title,
|
||||
];
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, $submit);
|
||||
// Assert that the link exists.
|
||||
$this->drupalGet('test-page');
|
||||
if ($visible) {
|
||||
$this->assertLink($node_title, 0, 'Found a menu link after submitted with ' . $submit);
|
||||
}
|
||||
else {
|
||||
$this->assertNoLink($node_title, 'Found no menu link after submitted with ' . $submit);
|
||||
}
|
||||
}
|
||||
|
||||
// Log back in as normal user.
|
||||
$this->drupalLogin($this->editor);
|
||||
// Edit the node and create a menu link.
|
||||
$edit = array(
|
||||
'menu[enabled]' => 1,
|
||||
'menu[title]' => $node_title,
|
||||
'menu[weight]' => 17,
|
||||
);
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
||||
// Assert that the link exists.
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertLink($node_title);
|
||||
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->assertFieldById('edit-menu-weight', 17, 'Menu weight correct in edit form');
|
||||
|
||||
// Disable the menu link, then edit the node--the link should stay disabled.
|
||||
$link_id = menu_ui_get_menu_link_defaults($node)['entity_id'];
|
||||
/** @var \Drupal\menu_link_content\Entity\MenuLinkContent $link */
|
||||
$link = MenuLinkContent::load($link_id);
|
||||
$link->set('enabled', FALSE);
|
||||
$link->save();
|
||||
$this->drupalPostForm($node->urlInfo('edit-form'), $edit, t('Save'));
|
||||
$link = MenuLinkContent::load($link_id);
|
||||
$this->assertFalse($link->isEnabled(), 'Saving a node with a disabled menu link keeps the menu link disabled.');
|
||||
|
||||
// Edit the node and remove the menu link.
|
||||
$edit = array(
|
||||
'menu[enabled]' => FALSE,
|
||||
);
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
||||
// Assert that there is no link for the node.
|
||||
$this->drupalGet('test-page');
|
||||
$this->assertNoLink($node_title);
|
||||
|
||||
// Add a menu link to the Administration menu.
|
||||
$item = entity_create('menu_link_content', array(
|
||||
'link' => [['uri' => 'entity:node/' . $node->id()]],
|
||||
'title' => $this->randomMachineName(16),
|
||||
'menu_name' => 'admin',
|
||||
));
|
||||
$item->save();
|
||||
|
||||
// Assert that disabled Administration menu is not shown on the
|
||||
// node/$nid/edit page.
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$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.
|
||||
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
|
||||
$link = MenuLinkContent::load($item->id());
|
||||
$this->assertTrue($link, 'Link in not allowed menu still exists after saving node');
|
||||
|
||||
// Move the menu link back to the Tools menu.
|
||||
$item->menu_name->value = 'tools';
|
||||
$item->save();
|
||||
// Create a second node.
|
||||
$child_node = $this->drupalCreateNode(array('type' => 'article'));
|
||||
// Assign a menu link to the second node, being a child of the first one.
|
||||
$child_item = entity_create('menu_link_content', array(
|
||||
'link' => [['uri' => 'entity:node/' . $child_node->id()]],
|
||||
'title' => $this->randomMachineName(16),
|
||||
'parent' => $item->getPluginId(),
|
||||
'menu_name' => $item->getMenuName(),
|
||||
));
|
||||
$child_item->save();
|
||||
// Edit the first node.
|
||||
$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.
|
||||
$this->assertNoOption('edit-menu-menu-parent', 'tools:'. $item->getPluginId());
|
||||
$this->assertNoOption('edit-menu-menu-parent', 'tools:'. $child_item->getPluginId());
|
||||
// Assert that unallowed Administration menu is not available in options.
|
||||
$this->assertNoOption('edit-menu-menu-parent', 'admin:');
|
||||
}
|
||||
}
|
963
core/modules/menu_ui/src/Tests/MenuTest.php
Normal file
963
core/modules/menu_ui/src/Tests/MenuTest.php
Normal file
|
@ -0,0 +1,963 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Tests\MenuTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Tests;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Menu\MenuLinkInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\menu_link_content\Entity\MenuLinkContent;
|
||||
use Drupal\system\Entity\Menu;
|
||||
use Drupal\node\Entity\Node;
|
||||
|
||||
/**
|
||||
* Add a custom menu, add menu links to the custom menu and Tools menu, check
|
||||
* their data, and delete them using the UI.
|
||||
*
|
||||
* @group menu_ui
|
||||
*/
|
||||
class MenuTest extends MenuWebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'block', 'contextual', 'help', 'path', 'test_page_test');
|
||||
|
||||
/**
|
||||
* A user with administration rights.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* An authenticated user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $authenticatedUser;
|
||||
|
||||
/**
|
||||
* Array of placed menu blocks keyed by block ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $blockPlacements;
|
||||
|
||||
/**
|
||||
* A test menu.
|
||||
*
|
||||
* @var \Drupal\system\Entity\Menu
|
||||
*/
|
||||
protected $menu;
|
||||
|
||||
/**
|
||||
* An array of test menu links.
|
||||
*
|
||||
* @var \Drupal\menu_link_content\MenuLinkContentInterface[]
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
|
||||
|
||||
// Create users.
|
||||
$this->adminUser = $this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content'));
|
||||
$this->authenticatedUser = $this->drupalCreateUser(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests menu functionality using the admin and user interfaces.
|
||||
*/
|
||||
function testMenu() {
|
||||
// Login the user.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->items = array();
|
||||
|
||||
$this->menu = $this->addCustomMenu();
|
||||
$this->doMenuTests();
|
||||
$this->doTestMenuBlock();
|
||||
$this->addInvalidMenuLink();
|
||||
$this->addCustomMenuCRUD();
|
||||
|
||||
// Verify that the menu links rebuild is idempotent and leaves the same
|
||||
// number of links in the table.
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
$before_count = $menu_link_manager->countMenuLinks(NULL);
|
||||
$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.
|
||||
// Login the user.
|
||||
$this->drupalLogin($this->authenticatedUser);
|
||||
$this->verifyAccess(403);
|
||||
|
||||
foreach ($this->items as $item) {
|
||||
// Menu link URIs are stored as 'internal:/node/$nid'.
|
||||
$node = Node::load(str_replace('internal:/node/', '', $item->link->uri));
|
||||
$this->verifyMenuLink($item, $node);
|
||||
}
|
||||
|
||||
// Login the administrator.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Verify delete link exists and reset link does not exist.
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $this->menu->id());
|
||||
$this->assertLinkByHref(Url::fromRoute('entity.menu_link_content.delete_form', ['menu_link_content' => $this->items[0]->id()])->toString());
|
||||
$this->assertNoLinkByHref(Url::fromRoute('menu_ui.link_reset', ['menu_link_plugin' => $this->items[0]->getPluginId()])->toString());
|
||||
// Check delete and reset access.
|
||||
$this->drupalGet('admin/structure/menu/item/' . $this->items[0]->id() . '/delete');
|
||||
$this->assertResponse(200);
|
||||
$this->drupalGet('admin/structure/menu/link/' . $this->items[0]->getPluginId() . '/reset');
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Delete menu links.
|
||||
foreach ($this->items as $item) {
|
||||
$this->deleteMenuLink($item);
|
||||
}
|
||||
|
||||
// Delete custom menu.
|
||||
$this->deleteCustomMenu();
|
||||
|
||||
// Modify and reset a standard menu link.
|
||||
$instance = $this->getStandardMenuLink();
|
||||
$old_weight = $instance->getWeight();
|
||||
// Edit the static menu link.
|
||||
$edit = array();
|
||||
$edit['weight'] = 10;
|
||||
$id = $instance->getPluginId();
|
||||
$this->drupalPostForm("admin/structure/menu/link/$id/edit", $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('The menu link has been saved.');
|
||||
$menu_link_manager->resetDefinitions();
|
||||
|
||||
$instance = $menu_link_manager->createInstance($instance->getPluginId());
|
||||
$this->assertEqual($edit['weight'], $instance->getWeight(), 'Saving an existing link updates the weight.');
|
||||
$this->resetMenuLink($instance, $old_weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom menu using CRUD functions.
|
||||
*/
|
||||
function addCustomMenuCRUD() {
|
||||
// Add a new custom menu.
|
||||
$menu_name = substr(hash('sha256', $this->randomMachineName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
|
||||
$label = $this->randomMachineName(16);
|
||||
|
||||
$menu = entity_create('menu', array(
|
||||
'id' => $menu_name,
|
||||
'label' => $label,
|
||||
'description' => 'Description text',
|
||||
));
|
||||
$menu->save();
|
||||
|
||||
// Assert the new menu.
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $menu_name);
|
||||
$this->assertRaw($label, 'Custom menu was added.');
|
||||
|
||||
// Edit the menu.
|
||||
$new_label = $this->randomMachineName(16);
|
||||
$menu->set('label', $new_label);
|
||||
$menu->save();
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $menu_name);
|
||||
$this->assertRaw($new_label, 'Custom menu was edited.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a custom menu.
|
||||
*
|
||||
* @return \Drupal\system\Entity\Menu
|
||||
* The custom menu that has been created.
|
||||
*/
|
||||
function addCustomMenu() {
|
||||
// Try adding a menu using a menu_name that is too long.
|
||||
$this->drupalGet('admin/structure/menu/add');
|
||||
$menu_name = substr(hash('sha256', $this->randomMachineName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI + 1);
|
||||
$label = $this->randomMachineName(16);
|
||||
$edit = array(
|
||||
'id' => $menu_name,
|
||||
'description' => '',
|
||||
'label' => $label,
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
|
||||
|
||||
// Verify that using a menu_name that is too long results in a validation
|
||||
// message.
|
||||
$this->assertRaw(t('!name cannot be longer than %max characters but is currently %length characters long.', array(
|
||||
'!name' => t('Menu name'),
|
||||
'%max' => MENU_MAX_MENU_NAME_LENGTH_UI,
|
||||
'%length' => Unicode::strlen($menu_name),
|
||||
)));
|
||||
|
||||
// Change the menu_name so it no longer exceeds the maximum length.
|
||||
$menu_name = substr(hash('sha256', $this->randomMachineName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI);
|
||||
$edit['id'] = $menu_name;
|
||||
$this->drupalPostForm('admin/structure/menu/add', $edit, t('Save'));
|
||||
|
||||
// Verify that no validation error is given for menu_name length.
|
||||
$this->assertNoRaw(t('!name cannot be longer than %max characters but is currently %length characters long.', array(
|
||||
'!name' => t('Menu name'),
|
||||
'%max' => MENU_MAX_MENU_NAME_LENGTH_UI,
|
||||
'%length' => Unicode::strlen($menu_name),
|
||||
)));
|
||||
// Verify that the confirmation message is displayed.
|
||||
$this->assertRaw(t('Menu %label has been added.', array('%label' => $label)));
|
||||
$this->drupalGet('admin/structure/menu');
|
||||
$this->assertText($label, 'Menu created');
|
||||
|
||||
// Confirm that the custom menu block is available.
|
||||
$this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
|
||||
$this->assertText($label);
|
||||
|
||||
// Enable the block.
|
||||
$block = $this->drupalPlaceBlock('system_menu_block:' . $menu_name);
|
||||
$this->blockPlacements[$menu_name] = $block->id();
|
||||
return Menu::load($menu_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the locally stored custom menu.
|
||||
*
|
||||
* This deletes the custom menu that is stored in $this->menu and performs
|
||||
* tests on the menu delete user interface.
|
||||
*/
|
||||
function deleteCustomMenu() {
|
||||
$menu_name = $this->menu->id();
|
||||
$label = $this->menu->label();
|
||||
|
||||
// Delete custom menu.
|
||||
$this->drupalPostForm("admin/structure/menu/manage/$menu_name/delete", array(), t('Delete'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw(t('The menu %title has been deleted.', array('%title' => $label)), '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.
|
||||
$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.');
|
||||
|
||||
// Make sure there's no delete button on system menus.
|
||||
$this->drupalGet('admin/structure/menu/manage/main');
|
||||
$this->assertNoRaw('edit-delete', 'The delete button was not found');
|
||||
|
||||
// Try to delete the main menu.
|
||||
$this->drupalGet('admin/structure/menu/manage/main/delete');
|
||||
$this->assertText(t('You are not authorized to access this page.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests menu functionality.
|
||||
*/
|
||||
function doMenuTests() {
|
||||
$menu_name = $this->menu->id();
|
||||
|
||||
// Test the 'Add link' local action.
|
||||
$this->drupalGet(Url::fromRoute('entity.menu.edit_form', ['menu' => $menu_name]));
|
||||
|
||||
$this->clickLink(t('Add link'));
|
||||
$link_title = $this->randomString();
|
||||
$this->drupalPostForm(NULL, array('link[0][uri]' => '/', 'title[0][value]' => $link_title), t('Save'));
|
||||
$this->assertUrl(Url::fromRoute('entity.menu.edit_form', ['menu' => $menu_name]));
|
||||
// Test the 'Edit' operation.
|
||||
$this->clickLink(t('Edit'));
|
||||
$this->assertFieldByName('title[0][value]', $link_title);
|
||||
$link_title = $this->randomString();
|
||||
$this->drupalPostForm(NULL, array('title[0][value]' => $link_title), t('Save'));
|
||||
$this->assertUrl(Url::fromRoute('entity.menu.edit_form', ['menu' => $menu_name]));
|
||||
// Test the 'Delete' operation.
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->assertRaw(t('Are you sure you want to delete the custom menu link %item?', array('%item' => $link_title)));
|
||||
$this->drupalPostForm(NULL, array(), t('Delete'));
|
||||
$this->assertUrl(Url::fromRoute('entity.menu.edit_form', ['menu' => $menu_name]));
|
||||
|
||||
// Add nodes to use as links for menu links.
|
||||
$node1 = $this->drupalCreateNode(array('type' => 'article'));
|
||||
$node2 = $this->drupalCreateNode(array('type' => 'article'));
|
||||
$node3 = $this->drupalCreateNode(array('type' => 'article'));
|
||||
$node4 = $this->drupalCreateNode(array('type' => 'article'));
|
||||
// Create a node with an alias.
|
||||
$node5 = $this->drupalCreateNode(array(
|
||||
'type' => 'article',
|
||||
'path' => array(
|
||||
'alias' => '/node5',
|
||||
),
|
||||
));
|
||||
|
||||
// Verify add link button.
|
||||
$this->drupalGet('admin/structure/menu');
|
||||
$this->assertLinkByHref('admin/structure/menu/manage/' . $menu_name . '/add', 0, "The add menu link button url is correct");
|
||||
|
||||
// Verify form defaults.
|
||||
$this->doMenuLinkFormDefaultsTest();
|
||||
|
||||
// Add menu links.
|
||||
$item1 = $this->addMenuLink('', '/node/' . $node1->id(), $menu_name, TRUE);
|
||||
$item2 = $this->addMenuLink($item1->getPluginId(), '/node/' . $node2->id(), $menu_name, FALSE);
|
||||
$item3 = $this->addMenuLink($item2->getPluginId(), '/node/' . $node3->id(), $menu_name);
|
||||
|
||||
// Hierarchy
|
||||
// <$menu_name>
|
||||
// - item1
|
||||
// -- 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
|
||||
// selection element degrades gracefully without the Language module.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
$this->assertMenuLink($item2->getPluginId(), array(
|
||||
'children' => array($item3->getPluginId()),
|
||||
'parents' => array($item2->getPluginId(), $item1->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
$this->assertMenuLink($item3->getPluginId(), array(
|
||||
'children' => array(),
|
||||
'parents' => array($item3->getPluginId(), $item2->getPluginId(), $item1->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
|
||||
// Verify menu links.
|
||||
$this->verifyMenuLink($item1, $node1);
|
||||
$this->verifyMenuLink($item2, $node2, $item1, $node1);
|
||||
$this->verifyMenuLink($item3, $node3, $item2, $node2);
|
||||
|
||||
// Add more menu links.
|
||||
$item4 = $this->addMenuLink('', '/node/' . $node4->id(), $menu_name);
|
||||
$item5 = $this->addMenuLink($item4->getPluginId(), '/node/' . $node5->id(), $menu_name);
|
||||
// Create a menu link pointing to an alias.
|
||||
$item6 = $this->addMenuLink($item4->getPluginId(), '/node5', $menu_name, TRUE, '0');
|
||||
|
||||
// Hierarchy
|
||||
// <$menu_name>
|
||||
// - item1
|
||||
// -- item2
|
||||
// --- item3
|
||||
// - item4
|
||||
// -- item5
|
||||
// -- item6
|
||||
|
||||
$this->assertMenuLink($item4->getPluginId(), array(
|
||||
'children' => array($item5->getPluginId(), $item6->getPluginId()),
|
||||
'parents' => array($item4->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
$this->assertMenuLink($item5->getPluginId(), array(
|
||||
'children' => array(),
|
||||
'parents' => array($item5->getPluginId(), $item4->getPluginId()),
|
||||
'langcode' => 'en',
|
||||
));
|
||||
$this->assertMenuLink($item6->getPluginId(), array(
|
||||
'children' => array(),
|
||||
'parents' => array($item6->getPluginId(), $item4->getPluginId()),
|
||||
'route_name' => 'entity.node.canonical',
|
||||
'route_parameters' => array('node' => $node5->id()),
|
||||
'url' => '',
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
|
||||
// Modify menu links.
|
||||
$this->modifyMenuLink($item1);
|
||||
$this->modifyMenuLink($item2);
|
||||
|
||||
// Toggle menu links.
|
||||
$this->toggleMenuLink($item1);
|
||||
$this->toggleMenuLink($item2);
|
||||
|
||||
// Move link and verify that descendants are updated.
|
||||
$this->moveMenuLink($item2, $item5->getPluginId(), $menu_name);
|
||||
// Hierarchy
|
||||
// <$menu_name>
|
||||
// - item1
|
||||
// - item4
|
||||
// -- item5
|
||||
// --- item2
|
||||
// ---- item3
|
||||
// -- item6
|
||||
|
||||
$this->assertMenuLink($item1->getPluginId(), array(
|
||||
'children' => array(),
|
||||
'parents' => array($item1->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
$this->assertMenuLink($item4->getPluginId(), array(
|
||||
'children' => array($item5->getPluginId(), $item6->getPluginId(), $item2->getPluginId(), $item3->getPluginId()),
|
||||
'parents' => array($item4->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
|
||||
$this->assertMenuLink($item5->getPluginId(), array(
|
||||
'children' => array($item2->getPluginId(), $item3->getPluginId()),
|
||||
'parents' => array($item5->getPluginId(), $item4->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
$this->assertMenuLink($item2->getPluginId(), array(
|
||||
'children' => array($item3->getPluginId()),
|
||||
'parents' => array($item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
$this->assertMenuLink($item3->getPluginId(), array(
|
||||
'children' => array(),
|
||||
'parents' => array($item3->getPluginId(), $item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()),
|
||||
// See above.
|
||||
'langcode' => 'en',
|
||||
));
|
||||
|
||||
// Add 102 menu links with increasing weights, then make sure the last-added
|
||||
// item's weight doesn't get changed because of the old hardcoded delta=50.
|
||||
$items = array();
|
||||
for ($i = -50; $i <= 51; $i++) {
|
||||
$items[$i] = $this->addMenuLink('', '/node/' . $node1->id(), $menu_name, TRUE, strval($i));
|
||||
}
|
||||
$this->assertMenuLink($items[51]->getPluginId(), array('weight' => '51'));
|
||||
|
||||
// Disable a link and then re-enable the link via the overview form.
|
||||
$this->disableMenuLink($item1);
|
||||
$edit = array();
|
||||
$edit['links[menu_plugin_id:' . $item1->getPluginId() . '][enabled]'] = TRUE;
|
||||
$this->drupalPostForm('admin/structure/menu/manage/' . $item1->getMenuName(), $edit, t('Save'));
|
||||
|
||||
// Mark item2, item4 and item5 as expanded.
|
||||
// This is done in order to show them on the frontpage.
|
||||
$item2->expanded->value = 1;
|
||||
$item2->save();
|
||||
$item4->expanded->value = 1;
|
||||
$item4->save();
|
||||
$item5->expanded->value = 1;
|
||||
$item5->save();
|
||||
|
||||
// Verify in the database.
|
||||
$this->assertMenuLink($item1->getPluginId(), array('enabled' => 1));
|
||||
|
||||
// Add an external link.
|
||||
$item7 = $this->addMenuLink('', 'https://www.drupal.org', $menu_name);
|
||||
$this->assertMenuLink($item7->getPluginId(), array('url' => 'https://www.drupal.org'));
|
||||
|
||||
// Add <front> menu item.
|
||||
$item8 = $this->addMenuLink('', '/', $menu_name);
|
||||
$this->assertMenuLink($item8->getPluginId(), array('route_name' => '<front>'));
|
||||
$this->drupalGet('');
|
||||
$this->assertResponse(200);
|
||||
// Make sure we get routed correctly.
|
||||
$this->clickLink($item8->getTitle());
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Check invalid menu link parents.
|
||||
$this->checkInvalidParentMenuLinks();
|
||||
|
||||
// Save menu links for later tests.
|
||||
$this->items[] = $item1;
|
||||
$this->items[] = $item2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the proper default values are set when adding a menu link
|
||||
*/
|
||||
protected function doMenuLinkFormDefaultsTest() {
|
||||
$this->drupalGet("admin/structure/menu/manage/tools/add");
|
||||
$this->assertResponse(200);
|
||||
|
||||
$this->assertFieldByName('title[0][value]', '');
|
||||
$this->assertFieldByName('link[0][uri]', '');
|
||||
|
||||
$this->assertNoFieldChecked('edit-expanded-value');
|
||||
$this->assertFieldChecked('edit-enabled-value');
|
||||
|
||||
$this->assertFieldByName('description[0][value]', '');
|
||||
$this->assertFieldByName('weight[0][value]', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds and removes a menu link with a query string and fragment.
|
||||
*/
|
||||
function testMenuQueryAndFragment() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Make a path with query and fragment on.
|
||||
$path = '/test-page?arg1=value1&arg2=value2';
|
||||
$item = $this->addMenuLink('', $path);
|
||||
|
||||
$this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
|
||||
$this->assertFieldByName('link[0][uri]', $path, 'Path is found with both query and fragment.');
|
||||
|
||||
// Now change the path to something without query and fragment.
|
||||
$path = '/test-page';
|
||||
$this->drupalPostForm('admin/structure/menu/item/' . $item->id() . '/edit', array('link[0][uri]' => $path), t('Save'));
|
||||
$this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
|
||||
$this->assertFieldByName('link[0][uri]', $path, 'Path no longer has query or fragment.');
|
||||
|
||||
// Use <front>#fragment and ensure that saving it does not lose its content.
|
||||
$path = '<front>?arg1=value#fragment';
|
||||
$item = $this->addMenuLink('', $path);
|
||||
|
||||
$this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
|
||||
$this->assertFieldByName('link[0][uri]', $path, 'Path is found with both query and fragment.');
|
||||
|
||||
$this->drupalPostForm('admin/structure/menu/item/' . $item->id() . '/edit', array(), t('Save'));
|
||||
|
||||
$this->drupalGet('admin/structure/menu/item/' . $item->id() . '/edit');
|
||||
$this->assertFieldByName('link[0][uri]', $path, 'Path is found with both query and fragment.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests renaming the built-in menu.
|
||||
*/
|
||||
function testSystemMenuRename() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$edit = array(
|
||||
'label' => $this->randomMachineName(16),
|
||||
);
|
||||
$this->drupalPostForm('admin/structure/menu/manage/main', $edit, t('Save'));
|
||||
|
||||
// Make sure menu shows up with new name in block addition.
|
||||
$default_theme = $this->config('system.theme')->get('default');
|
||||
$this->drupalget('admin/structure/block/list/' . $default_theme);
|
||||
$this->assertText($edit['label']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that menu items pointing to unpublished nodes are editable.
|
||||
*/
|
||||
function testUnpublishedNodeMenuItem() {
|
||||
$this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content', 'bypass node access')));
|
||||
// Create an unpublished node.
|
||||
$node = $this->drupalCreateNode(array(
|
||||
'type' => 'article',
|
||||
'status' => NODE_NOT_PUBLISHED,
|
||||
));
|
||||
|
||||
$item = $this->addMenuLink('', '/node/' . $node->id());
|
||||
$this->modifyMenuLink($item);
|
||||
|
||||
// Test that a user with 'administer menu' but without 'bypass node access'
|
||||
// cannot see the menu item.
|
||||
$this->drupalLogout();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $item->getMenuName());
|
||||
$this->assertNoText($item->getTitle(), "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
|
||||
// The cache contexts associated with the (in)accessible menu links are
|
||||
// bubbled. See DefaultMenuLinkTreeManipulators::menuLinkCheckAccess().
|
||||
$this->assertCacheContext('user.permissions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the contextual links on a menu block.
|
||||
*/
|
||||
public function testBlockContextualLinks() {
|
||||
$this->drupalLogin($this->drupalCreateUser(array('administer menu', 'access contextual links', 'administer blocks')));
|
||||
$custom_menu = $this->addCustomMenu();
|
||||
$this->addMenuLink('', '/', $custom_menu->id());
|
||||
$block = $this->drupalPlaceBlock('system_menu_block:' . $custom_menu->id(), array('label' => 'Custom menu', 'provider' => 'system'));
|
||||
$this->drupalGet('test-page');
|
||||
|
||||
$id = 'block:block=' . $block->id() . ':langcode=en|menu:menu=' . $custom_menu->id() . ':langcode=en';
|
||||
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
|
||||
$this->assertRaw('<div data-contextual-id="'. $id . '"></div>', format_string('Contextual link placeholder with id @id exists.', array('@id' => $id)));
|
||||
|
||||
// Get server-rendered contextual links.
|
||||
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks()
|
||||
$post = array('ids[0]' => $id);
|
||||
$response = $this->drupalPost('contextual/render', 'application/json', $post, array('query' => array('destination' => 'test-page')));
|
||||
$this->assertResponse(200);
|
||||
$json = Json::decode($response);
|
||||
$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="entitymenuedit-form"><a href="' . base_path() . 'admin/structure/menu/manage/' . $custom_menu->id() . '">Edit menu</a></li></ul>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a menu link using the UI.
|
||||
*
|
||||
* @param string $parent
|
||||
* Optional parent menu link id.
|
||||
* @param string $path
|
||||
* The path to enter on the form. Defaults to the front page.
|
||||
* @param string $menu_name
|
||||
* Menu name. Defaults to 'tools'.
|
||||
* @param bool $expanded
|
||||
* Whether or not this menu link is expanded. Setting this to TRUE should
|
||||
* test whether it works when we do the authenticatedUser tests. Defaults
|
||||
* to FALSE.
|
||||
* @param string $weight
|
||||
* Menu weight. Defaults to 0.
|
||||
*
|
||||
* @return \Drupal\menu_link_content\Entity\MenuLinkContent
|
||||
* A menu link entity.
|
||||
*/
|
||||
function addMenuLink($parent = '', $path = '/', $menu_name = 'tools', $expanded = FALSE, $weight = '0') {
|
||||
// View add menu link page.
|
||||
$this->drupalGet("admin/structure/menu/manage/$menu_name/add");
|
||||
$this->assertResponse(200);
|
||||
|
||||
$title = '!link_' . $this->randomMachineName(16);
|
||||
$edit = array(
|
||||
'link[0][uri]' => $path,
|
||||
'title[0][value]' => $title,
|
||||
'description[0][value]' => '',
|
||||
'enabled[value]' => 1,
|
||||
'expanded[value]' => $expanded,
|
||||
'menu_parent' => $menu_name . ':' . $parent,
|
||||
'weight[0][value]' => $weight,
|
||||
);
|
||||
|
||||
// Add menu link.
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('The menu link has been saved.');
|
||||
|
||||
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $title));
|
||||
|
||||
$menu_link = reset($menu_links);
|
||||
$this->assertTrue($menu_link, 'Menu link was found in database.');
|
||||
$this->assertMenuLink($menu_link->getPluginId(), array('menu_name' => $menu_name, 'children' => array(), 'parent' => $parent));
|
||||
|
||||
return $menu_link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to add menu link with invalid path or no access permission.
|
||||
*/
|
||||
function addInvalidMenuLink() {
|
||||
foreach (array('access' => '/admin/people/permissions') as $type => $link_path) {
|
||||
$edit = array(
|
||||
'link[0][uri]' => $link_path,
|
||||
'title[0][value]' => 'title',
|
||||
);
|
||||
$this->drupalPostForm("admin/structure/menu/manage/{$this->menu->id()}/add", $edit, t('Save'));
|
||||
$this->assertRaw(t("The path '@link_path' is inaccessible.", array('@link_path' => $link_path)), 'Menu link was not created');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that parent options are limited by depth when adding menu links.
|
||||
*/
|
||||
function checkInvalidParentMenuLinks() {
|
||||
$last_link = null;
|
||||
$created_links = array();
|
||||
|
||||
// Get the max depth of the tree.
|
||||
$menu_link_tree = \Drupal::service('menu.link_tree');
|
||||
$max_depth = $menu_link_tree->maxDepth();
|
||||
|
||||
// Create a maximum number of menu links, each a child of the previous.
|
||||
for ($i = 0; $i <= $max_depth - 1; $i++) {
|
||||
$parent = $last_link ? 'tools:' . $last_link->getPluginId() : 'tools:';
|
||||
$title = 'title' . $i;
|
||||
$edit = array(
|
||||
'link[0][uri]' => '/',
|
||||
'title[0][value]' => $title,
|
||||
'menu_parent' => $parent,
|
||||
'description[0][value]' => '',
|
||||
'enabled[value]' => 1,
|
||||
'expanded[value]' => FALSE,
|
||||
'weight[0][value]' => '0',
|
||||
);
|
||||
$this->drupalPostForm("admin/structure/menu/manage/{$this->menu->id()}/add", $edit, t('Save'));
|
||||
$menu_links = entity_load_multiple_by_properties('menu_link_content', array('title' => $title));
|
||||
$last_link = reset($menu_links);
|
||||
$created_links[] = 'tools:' . $last_link->getPluginId();
|
||||
}
|
||||
|
||||
// The last link cannot be a parent in the new menu link form.
|
||||
$this->drupalGet('admin/structure/menu/manage/admin/add');
|
||||
$value = 'tools:' . $last_link->getPluginId();
|
||||
$this->assertNoOption('edit-menu-parent', $value, 'The invalid option is not there.');
|
||||
|
||||
// All but the last link can be parents in the new menu link form.
|
||||
array_pop($created_links);
|
||||
foreach ($created_links as $key => $link) {
|
||||
$this->assertOption('edit-menu-parent', $link, 'The valid option number ' . ($key + 1) . ' is there.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a menu link using the UI.
|
||||
*
|
||||
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||
* Menu link.
|
||||
* @param object $item_node
|
||||
* Menu link content node.
|
||||
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $parent
|
||||
* Parent menu link.
|
||||
* @param object $parent_node
|
||||
* Parent menu link content node.
|
||||
*/
|
||||
function verifyMenuLink(MenuLinkContent $item, $item_node, MenuLinkContent $parent = NULL, $parent_node = NULL) {
|
||||
// View home page.
|
||||
$this->drupalGet('');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Verify parent menu link.
|
||||
if (isset($parent)) {
|
||||
// Verify menu link.
|
||||
$title = $parent->getTitle();
|
||||
$this->assertLink($title, 0, 'Parent menu link was displayed');
|
||||
|
||||
// Verify menu link link.
|
||||
$this->clickLink($title);
|
||||
$title = $parent_node->label();
|
||||
$this->assertTitle(t("@title | Drupal", array('@title' => $title)), 'Parent menu link link target was correct');
|
||||
}
|
||||
|
||||
// Verify menu link.
|
||||
$title = $item->getTitle();
|
||||
$this->assertLink($title, 0, 'Menu link was displayed');
|
||||
|
||||
// Verify menu link link.
|
||||
$this->clickLink($title);
|
||||
$title = $item_node->label();
|
||||
$this->assertTitle(t("@title | Drupal", array('@title' => $title)), 'Menu link link target was correct');
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the parent of a menu link using the UI.
|
||||
*
|
||||
* @param \Drupal\menu_link_content\MenuLinkContentInterface $item
|
||||
* The menu link item to move.
|
||||
* @param int $parent
|
||||
* The id of the new parent.
|
||||
* @param string $menu_name
|
||||
* The menu the menu link will be moved to.
|
||||
*/
|
||||
function moveMenuLink(MenuLinkContent $item, $parent, $menu_name) {
|
||||
$mlid = $item->id();
|
||||
|
||||
$edit = array(
|
||||
'menu_parent' => $menu_name . ':' . $parent,
|
||||
);
|
||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies a menu link using the UI.
|
||||
*
|
||||
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||
* Menu link entity.
|
||||
*/
|
||||
function modifyMenuLink(MenuLinkContent $item) {
|
||||
$item->title->value = $this->randomMachineName(16);
|
||||
|
||||
$mlid = $item->id();
|
||||
$title = $item->getTitle();
|
||||
|
||||
// Edit menu link.
|
||||
$edit = array();
|
||||
$edit['title[0][value]'] = $title;
|
||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('The menu link has been saved.');
|
||||
// Verify menu link.
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $item->getMenuName());
|
||||
$this->assertText($title, 'Menu link was edited');
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a standard menu link using the UI.
|
||||
*
|
||||
* @param \Drupal\Core\Menu\MenuLinkInterface $menu_link
|
||||
* The Menu link.
|
||||
* @param int $old_weight
|
||||
* Original title for menu link.
|
||||
*/
|
||||
function resetMenuLink(MenuLinkInterface $menu_link, $old_weight) {
|
||||
// Reset menu link.
|
||||
$this->drupalPostForm("admin/structure/menu/link/{$menu_link->getPluginId()}/reset", array(), t('Reset'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw(t('The menu link was reset to its default settings.'), 'Menu link was reset');
|
||||
|
||||
// Verify menu link.
|
||||
$instance = \Drupal::service('plugin.manager.menu.link')->createInstance($menu_link->getPluginId());
|
||||
$this->assertEqual($old_weight, $instance->getWeight(), 'Resets to the old weight.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a menu link using the UI.
|
||||
*
|
||||
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||
* Menu link.
|
||||
*/
|
||||
function deleteMenuLink(MenuLinkContent $item) {
|
||||
$mlid = $item->id();
|
||||
$title = $item->getTitle();
|
||||
|
||||
// Delete menu link.
|
||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/delete", array(), t('Delete'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw(t('The menu link %title has been deleted.', array('%title' => $title)), 'Menu link was deleted');
|
||||
|
||||
// Verify deletion.
|
||||
$this->drupalGet('');
|
||||
$this->assertNoText($title, 'Menu link was deleted');
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternately disables and enables a menu link.
|
||||
*
|
||||
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||
* Menu link.
|
||||
*/
|
||||
function toggleMenuLink(MenuLinkContent $item) {
|
||||
$this->disableMenuLink($item);
|
||||
|
||||
// Verify menu link is absent.
|
||||
$this->drupalGet('');
|
||||
$this->assertNoText($item->getTitle(), 'Menu link was not displayed');
|
||||
$this->enableMenuLink($item);
|
||||
|
||||
// Verify menu link is displayed.
|
||||
$this->drupalGet('');
|
||||
$this->assertText($item->getTitle(), 'Menu link was displayed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables a menu link.
|
||||
*
|
||||
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||
* Menu link.
|
||||
*/
|
||||
function disableMenuLink(MenuLinkContent $item) {
|
||||
$mlid = $item->id();
|
||||
$edit['enabled[value]'] = FALSE;
|
||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||
|
||||
// Unlike most other modules, there is no confirmation message displayed.
|
||||
// Verify in the database.
|
||||
$this->assertMenuLink($item->getPluginId(), array('enabled' => 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a menu link.
|
||||
*
|
||||
* @param \Drupal\menu_link_content\Entity\MenuLinkContent $item
|
||||
* Menu link.
|
||||
*/
|
||||
function enableMenuLink(MenuLinkContent $item) {
|
||||
$mlid = $item->id();
|
||||
$edit['enabled[value]'] = TRUE;
|
||||
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
|
||||
|
||||
// Verify in the database.
|
||||
$this->assertMenuLink($item->getPluginId(), array('enabled' => 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if administrative users other than user 1 can access the menu parents
|
||||
* AJAX callback.
|
||||
*/
|
||||
public function testMenuParentsJsAccess() {
|
||||
$admin = $this->drupalCreateUser(array('administer menu'));
|
||||
$this->drupalLogin($admin);
|
||||
// Just check access to the callback overall, the POST data is irrelevant.
|
||||
$this->drupalGetAjax('admin/structure/menu/parents');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Do standard user tests.
|
||||
// Login the user.
|
||||
$this->drupalLogin($this->authenticatedUser);
|
||||
$this->drupalGetAjax('admin/structure/menu/parents');
|
||||
$this->assertResponse(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns standard menu link.
|
||||
*
|
||||
* @return \Drupal\Core\Menu\MenuLinkInterface
|
||||
* A menu link plugin.
|
||||
*/
|
||||
private function getStandardMenuLink() {
|
||||
// Retrieve menu link id of the Log out menu link, which will always be on
|
||||
// the front page.
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
$result = $menu_link_manager->loadLinksByRoute('user.logout');
|
||||
$instance = reset($result);
|
||||
|
||||
$this->assertTrue((bool) $instance, 'Standard menu link was loaded');
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the logged in user has the desired access to various menu pages.
|
||||
*
|
||||
* @param integer $response
|
||||
* The expected HTTP response code. Defaults to 200.
|
||||
*/
|
||||
private function verifyAccess($response = 200) {
|
||||
// View menu help page.
|
||||
$this->drupalGet('admin/help/menu');
|
||||
$this->assertResponse($response);
|
||||
if ($response == 200) {
|
||||
$this->assertText(t('Menu'), 'Menu help was displayed');
|
||||
}
|
||||
|
||||
// View menu build overview page.
|
||||
$this->drupalGet('admin/structure/menu');
|
||||
$this->assertResponse($response);
|
||||
if ($response == 200) {
|
||||
$this->assertText(t('Menus'), 'Menu build overview page was displayed');
|
||||
}
|
||||
|
||||
// View tools menu customization page.
|
||||
$this->drupalGet('admin/structure/menu/manage/' . $this->menu->id());
|
||||
$this->assertResponse($response);
|
||||
if ($response == 200) {
|
||||
$this->assertText(t('Tools'), 'Tools menu page was displayed');
|
||||
}
|
||||
|
||||
// View menu edit page for a static link.
|
||||
$item = $this->getStandardMenuLink();
|
||||
$this->drupalGet('admin/structure/menu/link/' . $item->getPluginId() . '/edit');
|
||||
$this->assertResponse($response);
|
||||
if ($response == 200) {
|
||||
$this->assertText(t('Edit menu item'), 'Menu edit page was displayed');
|
||||
}
|
||||
|
||||
// View add menu page.
|
||||
$this->drupalGet('admin/structure/menu/add');
|
||||
$this->assertResponse($response);
|
||||
if ($response == 200) {
|
||||
$this->assertText(t('Menus'), 'Add menu page was displayed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests menu block settings.
|
||||
*/
|
||||
protected function doTestMenuBlock() {
|
||||
$menu_id = $this->menu->id();
|
||||
$block_id = $this->blockPlacements[$menu_id];
|
||||
$this->drupalGet('admin/structure/block/manage/' . $block_id);
|
||||
$this->drupalPostForm(NULL, [
|
||||
'settings[depth]' => 3,
|
||||
'settings[level]' => 2,
|
||||
], t('Save block'));
|
||||
$block = Block::load($block_id);
|
||||
$settings = $block->getPlugin()->getConfiguration();
|
||||
$this->assertEqual($settings['depth'], 3);
|
||||
$this->assertEqual($settings['level'], 2);
|
||||
// Reset settings.
|
||||
$block->getPlugin()->setConfigurationValue('depth', 0);
|
||||
$block->getPlugin()->setConfigurationValue('level', 1);
|
||||
$block->save();
|
||||
}
|
||||
|
||||
}
|
38
core/modules/menu_ui/src/Tests/MenuUninstallTest.php
Normal file
38
core/modules/menu_ui/src/Tests/MenuUninstallTest.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Tests\MenuUninstallTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\system\Entity\Menu;
|
||||
|
||||
/**
|
||||
* Tests that uninstalling menu does not remove custom menus.
|
||||
*
|
||||
* @group menu_ui
|
||||
*/
|
||||
class MenuUninstallTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('menu_ui');
|
||||
|
||||
/**
|
||||
* Tests Menu uninstall.
|
||||
*/
|
||||
public function testMenuUninstall() {
|
||||
\Drupal::service('module_installer')->uninstall(array('menu_ui'));
|
||||
|
||||
\Drupal::entityManager()->getStorage('menu')->resetCache(array('admin'));
|
||||
|
||||
$this->assertTrue(Menu::load('admin'), 'The \'admin\' menu still exists after uninstalling Menu UI module.');
|
||||
}
|
||||
|
||||
}
|
82
core/modules/menu_ui/src/Tests/MenuWebTestBase.php
Normal file
82
core/modules/menu_ui/src/Tests/MenuWebTestBase.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\menu_ui\Tests\MenuWebTestBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\menu_ui\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Base class for menu web tests.
|
||||
*/
|
||||
abstract class MenuWebTestBase extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('menu_ui', 'menu_link_content');
|
||||
|
||||
/**
|
||||
* Fetches the menu item from the database and compares it to expected item.
|
||||
*
|
||||
* @param int $menu_plugin_id
|
||||
* Menu item id.
|
||||
* @param array $expected_item
|
||||
* Array containing properties to verify.
|
||||
*/
|
||||
function assertMenuLink($menu_plugin_id, array $expected_item) {
|
||||
// Retrieve menu link.
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
$menu_link_manager->resetDefinitions();
|
||||
// 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 (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']);
|
||||
}
|
||||
|
||||
if (isset($expected_item['enabled']) && $entity) {
|
||||
$this->assertEqual($entity->enabled->value, $expected_item['enabled']);
|
||||
unset($expected_item['enabled']);
|
||||
}
|
||||
|
||||
foreach ($expected_item as $key => $value) {
|
||||
$this->assertTrue(isset($definition[$key]));
|
||||
$this->assertEqual($definition[$key], $value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue