Commit ef4e932d authored by alexpott's avatar alexpott

Issue #2301313 by pwolanin, dawehner, Wim Leers, effulgentsia, kgoel, YesCT,...

Issue #2301313 by pwolanin, dawehner, Wim Leers, effulgentsia, kgoel, YesCT, glide: MenuLinkNG part3 (no conversions): MenuLinkContent UI.
parent 49f4fddb
menu_link.static.overrides:
type: mapping
label: 'Menu link overrides'
mapping:
definitions:
type: sequence
label: Definitions
sequence:
- type: mapping
label: Definition
mapping:
menu_name:
type: string
label: 'Menu name'
parent:
type: string
label: 'Parent'
weight:
type: integer
label: 'Weight'
expanded:
type: boolean
label: 'Expanded'
hidden:
type: boolean
label: 'Hidden'
......@@ -301,6 +301,11 @@ services:
parent: default_plugin_manager
plugin.cache_clearer:
class: Drupal\Core\Plugin\CachedDiscoveryClearer
paramconverter.menu_link:
class: Drupal\Core\ParamConverter\MenuLinkPluginConverter
tags:
- { name: paramconverter }
arguments: ['@plugin.manager.menu.link']
menu.tree_storage:
class: Drupal\Core\Menu\MenuTreeStorage
arguments: ['@database', '@cache.menu', 'menu_tree']
......
<?php
/**
* @file
* Contains \Drupal\Core\Menu\Form\MenuLinkDefaultForm.
*/
namespace Drupal\Core\Menu\Form;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\Core\Menu\MenuLinkManagerInterface;
use Drupal\Core\Menu\MenuParentFormSelectorInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides an edit form for static menu links.
*
* @see \Drupal\Core\Menu\MenuLinkDefault
*/
class MenuLinkDefaultForm implements MenuLinkFormInterface, ContainerInjectionInterface {
use StringTranslationTrait;
/**
* The edited menu link.
*
* @var \Drupal\Core\Menu\MenuLinkInterface
*/
protected $menuLink;
/**
* The menu link manager.
*
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
*/
protected $menuLinkManager;
/**
* The parent form selector service.
*
* @var \Drupal\Core\Menu\MenuParentFormSelectorInterface
*/
protected $menuParentSelector;
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The module data from system_get_info().
*
* @var array
*/
protected $moduleData;
/**
* Constructs a new \Drupal\Core\Menu\Form\MenuLinkDefaultForm.
*
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
* The menu link manager.
* @param \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector
* The menu parent form selector service.
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
* The string translation.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler;
*/
public function __construct(MenuLinkManagerInterface $menu_link_manager, MenuParentFormSelectorInterface $menu_parent_selector, TranslationInterface $string_translation, ModuleHandlerInterface $module_handler) {
$this->menuLinkManager = $menu_link_manager;
$this->menuParentSelector = $menu_parent_selector;
$this->stringTranslation = $string_translation;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.menu.link'),
$container->get('menu.parent_form_selector'),
$container->get('string_translation'),
$container->get('module_handler')
);
}
/**
* {@inheritdoc}
*/
public function setMenuLinkInstance(MenuLinkInterface $menu_link) {
$this->menuLink = $menu_link;
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, array &$form_state) {
$form['#title'] = $this->t('Edit menu link %title', array('%title' => $this->menuLink->getTitle()));
$provider = $this->menuLink->getProvider();
$form['info'] = array(
'#type' => 'item',
'#title' => $this->t('This link is provided by the @name module. The title and path cannot be edited.', array('@name' => $this->getModuleName($provider))),
);
$link = array(
'#type' => 'link',
'#title' => $this->menuLink->getTitle(),
) + $this->menuLink->getUrlObject()->toRenderArray();
$form['path'] = array(
'link' => $link,
'#type' => 'item',
'#title' => $this->t('Link'),
);
$form['enabled'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Enable menu link'),
'#description' => $this->t('Menu links that are not enabled will not be listed in any menu.'),
'#default_value' => !$this->menuLink->isHidden(),
);
$form['expanded'] = array(
'#type' => 'checkbox',
'#title' => t('Show as expanded'),
'#description' => $this->t('If selected and this menu link has children, the menu will always appear expanded.'),
'#default_value' => $this->menuLink->isExpanded(),
);
$menu_parent = $this->menuLink->getMenuName() . ':' . $this->menuLink->getParent();
$form['menu_parent'] = $this->menuParentSelector->parentSelectElement($menu_parent, $this->menuLink->getPluginId());
$form['menu_parent']['#title'] = $this->t('Parent link');
$form['menu_parent']['#description'] = $this->t('The maximum depth for a link and all its children is fixed. Some menu links may not be available as parents if selecting them would exceed this limit.');
$form['menu_parent']['#attributes']['class'][] = 'menu-title-select';
$delta = max(abs($this->menuLink->getWeight()), 50);
$form['weight'] = array(
'#type' => 'number',
'#min' => -$delta,
'#max' => $delta,
'#default_value' => $this->menuLink->getWeight(),
'#title' => $this->t('Weight'),
'#description' => $this->t('Link weight among links in the same menu at the same depth. In the menu, the links with high weight will sink and links with a low weight will be positioned nearer the top.'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function extractFormValues(array &$form, array &$form_state) {
$new_definition = array();
$new_definition['hidden'] = $form_state['values']['enabled'] ? 0 : 1;
$new_definition['weight'] = (int) $form_state['values']['weight'];
$new_definition['expanded'] = $form_state['values']['expanded'] ? 1 : 0;
list($menu_name, $parent) = explode(':', $form_state['values']['menu_parent'], 2);
if (!empty($menu_name)) {
$new_definition['menu_name'] = $menu_name;
}
if (isset($parent)) {
$new_definition['parent'] = $parent;
}
return $new_definition;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, array &$form_state) {
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, array &$form_state) {
$new_definition = $this->extractFormValues($form, $form_state);
return $this->menuLinkManager->updateDefinition($this->menuLink->getPluginId(), $new_definition);
}
/**
* Gets the name of the module.
*
* @param string $module
* The machine name of a module.
*
* @todo This function is horrible, but core has nothing better until we add a
* a method to the ModuleHandler that handles this nicely.
* https://drupal.org/node/2281989
*
* @return string
* The human-readable, localized module name, or the machine name passed in
* if no matching module is found.
*/
protected function getModuleName($module) {
// Gather module data.
if (!isset($this->moduleData)) {
$this->moduleData = system_get_info('module');
}
// If the module exists, return its human-readable name.
if (isset($this->moduleData[$module])) {
return $this->t($this->moduleData[$module]['name']);
}
// Otherwise, return the machine name.
return $module;
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Menu\Form\MenuLinkFormInterface.
*/
namespace Drupal\Core\Menu\Form;
use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\Core\Plugin\PluginFormInterface;
/**
* Defines an interface for edit forms of menu links.
*
* All menu link plugins use the same interface for their configuration or
* editing form, but the implementations may differ.
*
* @see \Drupal\Core\Menu\MenuLinkInterface::getFormClass()
*/
interface MenuLinkFormInterface extends PluginFormInterface {
/**
* Injects the menu link plugin instance.
*
* @param \Drupal\Core\Menu\MenuLinkInterface $menu_link
* A menu link plugin instance.
*/
public function setMenuLinkInstance(MenuLinkInterface $menu_link);
/**
* Extracts a plugin definition from form values.
*
* @param array $form
* An associative array containing the structure of the form.
* @param array $form_state
* An associative array containing the current state of the form.
*
* @return array
* The new plugin definition values taken from the form values.
*/
public function extractFormValues(array &$form, array &$form_state);
}
<?php
/**
* @file
* Contains \Drupal\Core\ParamConverter\MenuLinkPluginConverter.
*/
namespace Drupal\Core\ParamConverter;
use Drupal\Core\Menu\MenuLinkManagerInterface;
use Drupal\Component\Plugin\Exception\PluginException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* Parameter converter for upcasting entity ids to full objects.
*/
class MenuLinkPluginConverter implements ParamConverterInterface {
/**
* Plugin manager which creates the instance from the value.
*
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
*/
protected $menuLinkManager;
/**
* Constructs a new MenuLinkPluginConverter.
*
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
* The menu link plugin manager.
*/
public function __construct(MenuLinkManagerInterface $menu_link_manager) {
$this->menuLinkManager = $menu_link_manager;
}
/**
* {@inheritdoc}
*/
public function convert($value, $definition, $name, array $defaults, Request $request) {
if ($value) {
try {
return $this->menuLinkManager->createInstance($value);
}
catch (PluginException $e) {
// Suppress the error.
}
}
}
/**
* {@inheritdoc}
*/
public function applies($definition, $name, Route $route) {
return (!empty($definition['type']) && $definition['type'] === 'menu_link_plugin');
}
}
menu_link_content.link_edit:
route_name: menu_link_content.link_edit
base_route: menu_link_content.link_edit
title: Edit
menu_link_content.link_add:
path: '/admin/structure/menu/manage/{menu}/add'
defaults:
_content: '\Drupal\menu_link_content\Controller\MenuController::addLink'
_title: 'Add menu link'
requirements:
_entity_create_access: 'menu_link_content'
menu_link_content.link_edit:
path: '/admin/structure/menu/item/{menu_link_content}/edit'
defaults:
_entity_form: 'menu_link_content.default'
_title: 'Edit menu link'
requirements:
_entity_access: 'menu_link_content.update'
menu_link_content.link_delete:
path: '/admin/structure/menu/item/{menu_link_content}/delete'
defaults:
_entity_form: 'menu_link_content.delete'
_title: 'Delete menu link'
requirements:
_entity_access: 'menu_link_content.delete'
<?php
/**
* @file
* Contains \Drupal\menu_link_content\Controller\MenuController.
*/
namespace Drupal\menu_link_content\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\system\MenuInterface;
/**
* Defines a route controller for a form for menu link content entity creation.
*/
class MenuController extends ControllerBase {
/**
* Provides the menu link creation form.
*
* @param \Drupal\system\MenuInterface $menu
* An entity representing a custom menu.
*
* @return array
* Returns the menu link creation form.
*/
public function addLink(MenuInterface $menu) {
$menu_link = $this->entityManager()->getStorage('menu_link_content')->create(array(
'id' => '',
'parent' => '',
'menu_name' => $menu->id(),
'bundle' => 'menu_link_content',
));
return $this->entityFormBuilder()->getForm($menu_link);
}
}
......@@ -41,6 +41,7 @@
* links = {
* "canonical" = "menu_link_content.link_edit",
* "edit-form" = "menu_link_content.link_edit",
* "delete-form" = "menu_link_content.link_delete",
* }
* )
*/
......@@ -336,30 +337,9 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
->setDescription(t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'))
->setSetting('default_value', FALSE);
// The form widget doesn't work yet for core fields, so we skip the
// for display and manually create form elements for the boolean fields.
// @see https://drupal.org/node/2226493
// @see https://drupal.org/node/2150511
$fields['expanded'] = FieldDefinition::create('boolean')
->setLabel(t('Expanded'))
->setDescription(t('Flag for whether this link should be rendered as expanded in menus - expanded links always have their child links displayed, instead of only when the link is in the active trail (1 = expanded, 0 = not expanded).'))
->setSetting('default_value', FALSE)
->setDisplayOptions('view', array(
'label' => 'hidden',
'type' => 'boolean',
'weight' => 0,
));
// We manually create a form element for this, since the form logic is
// is inverted to show enabled.
$fields['hidden'] = FieldDefinition::create('boolean')
->setLabel(t('Hidden'))
->setDescription(t('A flag for whether the link should be hidden in menus or rendered normally.'))
->setSetting('default_value', FALSE);
$fields['weight'] = FieldDefinition::create('integer')
->setLabel(t('Weight'))
->setDescription(t('Link weight among links in the same menu at the same depth.'))
->setDescription(t('Link weight among links in the same menu at the same depth. In the menu, the links with high weight will sink and links with a low weight will be positioned nearer the top.'))
->setSetting('default_value', 0)
->setDisplayOptions('view', array(
'label' => 'hidden',
......@@ -368,9 +348,31 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
))
->setDisplayOptions('form', array(
'type' => 'integer',
'weight' => 20,
));
$fields['expanded'] = FieldDefinition::create('boolean')
->setLabel(t('Show as expanded'))
->setDescription(t('If selected and this menu link has children, the menu will always appear expanded.'))
->setSetting('default_value', FALSE)
->setDisplayOptions('view', array(
'label' => 'hidden',
'type' => 'boolean',
'weight' => 0,
))
->setDisplayOptions('form', array(
'settings' => array('display_label' => TRUE),
'weight' => 0,
));
// @todo We manually create a form element for this, since the form logic is
// is inverted to show enabled. Flip this to a status field and use the
// normal entity Boolean widget. https://www.drupal.org/node/2305707
$fields['hidden'] = FieldDefinition::create('boolean')
->setLabel(t('Hidden'))
->setDescription(t('A flag for whether the link should be hidden in menus or rendered normally.'))
->setSetting('default_value', FALSE);
$fields['langcode'] = FieldDefinition::create('language')
->setLabel(t('Language code'))
->setDescription(t('The node language code.'));
......
<?php
/**
* @file
* Contains \Drupal\menu_link_content\Form\MenuLinkContentDeleteForm.
*/
namespace Drupal\menu_link_content\Form;
use Drupal\Core\Entity\ContentEntityConfirmFormBase;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a delete form for content menu links.
*/
class MenuLinkContentDeleteForm extends ContentEntityConfirmFormBase {
/**
* Logger channel.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* Constructs a MenuLinkContentDeleteForm object.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
* The logger channel factory.
*/
public function __construct(EntityManagerInterface $entity_manager, LoggerChannelFactoryInterface $logger_factory) {
parent::__construct($entity_manager);
$this->logger = $logger_factory->get('menu');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('logger.factory')
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to delete the custom menu link %item?', array('%item' => $this->entity->getTitle()));
}
/**
* {@inheritdoc}
*/
public function getCancelRoute() {
return new Url('menu_ui.menu_edit', array('menu' => $this->entity->getMenuName()));
}
/**
* {@inheritdoc}
*/
public function submit(array $form, array &$form_state) {
$t_args = array('%title' => $this->entity->getTitle());
$this->entity->delete();
drupal_set_message($this->t('The menu link %title has been deleted.', $t_args));
$this->logger->notice('Deleted menu link %title.', $t_args);
$form_state['redirect_route'] = array(
'route_name' => '<front>',
);
}
}
<?php
/**
* @file
* Contains \Drupal\menu_link_content\Tests\MenuLinkContentUITest.
*/
namespace Drupal\menu_link_content\Tests;
use Drupal\content_translation\Tests\ContentTranslationUITest;
/**
* Tests the menu link content UI.
*
* @group Menu
*/
class MenuLinkContentUITest extends ContentTranslationUITest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'language',
'content_translation',
'menu_link_content',
'menu_ui',
);
/**
* {@inheritdoc}
*/
public function setUp() {
$this->entityTypeId = 'menu_link_content';
$this->bundle = 'menu_link_content';
$this->fieldName = 'title';
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function getTranslatorPermissions() {
return array_merge(parent::getTranslatorPermissions(), array('administer menu'));
}
/**
* {@inheritdoc}
*/
protected function createEntity($values, $langcode, $bundle_name = NULL) {
$values['menu_name'] = 'tools';
$values['route_name'] = 'menu_ui.overview_page';
$values['title'] = 'Test title';
return parent::createEntity($values, $langcode, $bundle_name);
}
}
<?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\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, array &$form_state, MenuLinkInterface $menu_link_plugin = NULL) {
$form['menu_link_id'] = array(
'#type' => 'value',
'#value' => $menu_link_plugin->getPluginId(),
);