diff --git a/core/modules/node/config/install/views.view.glossary.yml b/core/modules/node/config/install/views.view.glossary.yml index 64541c603b95239f3397cca7fa82a444a813d625..f7ccaef8fc1920ab9dd2867a3f8752abc1a2f1be 100644 --- a/core/modules/node/config/install/views.view.glossary.yml +++ b/core/modules/node/config/install/views.view.glossary.yml @@ -369,6 +369,8 @@ display: type: normal title: Glossary weight: 0 + menu_name: main + parent: '' field_langcode: '***LANGUAGE_language_content***' field_langcode_add_to_query: null attachment_1: diff --git a/core/modules/views/config/schema/views.display.schema.yml b/core/modules/views/config/schema/views.display.schema.yml index 212941bb750bc1f15a5d64abd3eb46edbbcd0c68..6531990a18f29ecd12843dd58e1b71e717803d26 100644 --- a/core/modules/views/config/schema/views.display.schema.yml +++ b/core/modules/views/config/schema/views.display.schema.yml @@ -37,6 +37,9 @@ views.display.page: menu_name: type: string label: 'Menu name' + parent: + type: string + label: 'Parent' context: type: string label: 'Context' diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php index 1ad685a23e7027e0f7a65b07c2c946536ce5b132..ea3664e6bf40830fc59263d80584909209d40b97 100644 --- a/core/modules/views/src/Entity/View.php +++ b/core/modules/views/src/Entity/View.php @@ -345,6 +345,23 @@ public function postCreate(EntityStorageInterface $storage) { $this->mergeDefaultDisplaysOptions(); } + /** + * {@inheritdoc} + */ + public static function preDelete(EntityStorageInterface $storage, array $entities) { + parent::preDelete($storage, $entities); + + // Call the remove() hook on the individual displays. + /** @var \Drupal\views\ViewStorageInterface $entity */ + foreach ($entities as $entity) { + $executable = Views::executableFactory()->get($entity); + foreach ($entity->get('display') as $display_id => $display) { + $executable->setDisplay($display_id); + $executable->getDisplay()->remove(); + } + } + } + /** * {@inheritdoc} */ diff --git a/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php index a07862f301f27cd5c2484b9919eef3a62fe0b56e..85c2350af22b2ce49bed1223386e39d8f8147c4f 100644 --- a/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php +++ b/core/modules/views/src/Plugin/Menu/ViewsMenuLink.php @@ -154,4 +154,17 @@ public function updateLink(array $new_definition_values, $persist) { return $this->pluginDefinition; } + /** + * {@inheritdoc} + */ + public function isDeletable() { + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function deleteLink() { + } + } diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php index 1b66bdc9f6dec0ccb000a496b12ecd634c8188cb..17f39e11d736fe2ee0631e7e8b2de8f7918c3d34 100644 --- a/core/modules/views/src/Plugin/views/PluginBase.php +++ b/core/modules/views/src/Plugin/views/PluginBase.php @@ -92,7 +92,14 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor /** - * Constructs a Plugin object. + * Constructs a PluginBase 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. */ public function __construct(array $configuration, $plugin_id, $plugin_definition) { parent::__construct($configuration, $plugin_id, $plugin_definition); diff --git a/core/modules/views/src/Plugin/views/display/Block.php b/core/modules/views/src/Plugin/views/display/Block.php index ffb40b6a51c894c6e720baff3c8742306ecb51da..5986381c7e83ed0a6150073c697591e1369647d2 100644 --- a/core/modules/views/src/Plugin/views/display/Block.php +++ b/core/modules/views/src/Plugin/views/display/Block.php @@ -8,8 +8,10 @@ namespace Drupal\views\Plugin\views\display; use Drupal\Component\Utility\String; +use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\Block\ViewsBlock; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * The plugin that handles a block. @@ -39,6 +41,46 @@ class Block extends DisplayPluginBase { */ protected $usesAttachments = TRUE; + /** + * The entity manager. + * + * @var \Drupal\Core\Entity\EntityManagerInterface + */ + protected $entityManager; + + /** + * Constructs a new Block instance. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + $this->entityManager = $entity_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('entity.manager') + ); + } + + /** + * {@inheritdoc} + */ protected function defineOptions() { $options = parent::defineOptions(); @@ -316,14 +358,16 @@ public function usesExposed() { } /** - * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::remove(). + * {@inheritdoc} */ public function remove() { parent::remove(); - $plugin_id = 'views_block:' . $this->view->storage->id() . '-' . $this->display['id']; - foreach (entity_load_multiple_by_properties('block', array('plugin' => $plugin_id)) as $block) { - $block->delete(); + if ($this->entityManager->hasDefinition('block')) { + $plugin_id = 'views_block:' . $this->view->storage->id() . '-' . $this->display['id']; + foreach ($this->entityManager->getStorage('block')->loadByProperties(['plugin' => $plugin_id]) as $block) { + $block->delete(); + } } } diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 5348df19f0cacf7ce707e239a939e0bcf1389d50..0dd89bb6f162fbc4c1818a5be4220985ff7c4d80 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -134,6 +134,13 @@ abstract class DisplayPluginBase extends PluginBase { * * @todo Replace DisplayPluginBase::$display with * DisplayPluginBase::$configuration to standardize with other plugins. + * + * @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. */ public function __construct(array $configuration, $plugin_id, $plugin_definition) { parent::__construct(array(), $plugin_id, $plugin_definition); @@ -2389,6 +2396,12 @@ public function newDisplay() { * Reacts on deleting a display. */ public function remove() { + $menu_links = $this->getMenuLinks(); + /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */ + $menu_link_manager = \Drupal::service('plugin.manager.menu.link'); + foreach ($menu_links as $menu_link_id => $menu_link) { + $menu_link_manager->removeDefinition("views_view:$menu_link_id"); + } } /** diff --git a/core/modules/views/src/Plugin/views/display/Page.php b/core/modules/views/src/Plugin/views/display/Page.php index 08da0a22b143b70e2e03c0d844072e0e37694f2d..5234f2c387c01160b074db01a633b6fbdb600064 100644 --- a/core/modules/views/src/Plugin/views/display/Page.php +++ b/core/modules/views/src/Plugin/views/display/Page.php @@ -50,7 +50,7 @@ protected function defineOptions() { 'title' => array('default' => '', 'translatable' => FALSE), 'description' => array('default' => '', 'translatable' => FALSE), 'weight' => array('default' => 0), - 'menu_name' => array('default' => 'navigation'), + 'menu_name' => array('default' => 'main'), 'parent' => array('default' => ''), 'context' => array('default' => ''), ), @@ -62,7 +62,7 @@ protected function defineOptions() { 'title' => array('default' => '', 'translatable' => FALSE), 'description' => array('default' => '', 'translatable' => FALSE), 'weight' => array('default' => 0), - 'menu_name' => array('default' => 'navigation'), + 'menu_name' => array('default' => 'main'), ), ); @@ -338,11 +338,11 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { ); // Only display the menu selector if Menu UI module is enabled. if (\Drupal::moduleHandler()->moduleExists('menu_ui')) { - $form['tab_options']['name'] = array( + $form['tab_options']['menu_name'] = array( '#title' => $this->t('Menu'), '#type' => 'select', '#options' => menu_ui_get_menus(), - '#default_value' => $tab_options['name'], + '#default_value' => $tab_options['menu_name'], '#description' => $this->t('Insert item into an available menu.'), '#states' => array( 'visible' => array( diff --git a/core/modules/views/src/Tests/ViewTestBase.php b/core/modules/views/src/Tests/ViewTestBase.php index 82e42e20227e885f9849ba490c4e1f15d27e3d14..6aa899d41be7dcfa488c838600d928fd20d55049 100644 --- a/core/modules/views/src/Tests/ViewTestBase.php +++ b/core/modules/views/src/Tests/ViewTestBase.php @@ -33,12 +33,6 @@ abstract class ViewTestBase extends WebTestBase { protected function setUp() { parent::setUp(); - // Views' Page displays put menu links in the 'navigation' menu by default. - entity_create('menu', array( - 'id' => 'navigation', - 'label' => 'Navigation', - ))->save(); - // Ensure that the plugin definitions are cleared. foreach (ViewExecutable::getPluginTypes() as $plugin_type) { $this->container->get("plugin.manager.views.$plugin_type")->clearCachedDefinitions(); diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml index cd812f236ee58a80a82f204302f3118399950abc..7b6efae016544a9ef579a637b161c0581e571b85 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml @@ -97,6 +97,24 @@ display: display_title: Page id: page_4 position: 0 + page_5: + display_options: + path: test-path + title: 'Tests a menu with a non-existing parent' + menu: + type: normal + title: 'Test child' + parent: 'system.admin' + description: '' + name: not-existing-menu-name + weight: '0' + context: '0' + defaults: + title: '0' + display_plugin: page + display_title: Page + id: page_4 + position: 0 label: 'Test page menu' id: test_page_display_menu tag: '' diff --git a/core/modules/views_ui/src/Tests/DisplayPathTest.php b/core/modules/views_ui/src/Tests/DisplayPathTest.php index 38f662e9ce331929a60691473434eb1f1b84e0c3..7e553e3807ee26a804e538116fb6bee66a088f12 100644 --- a/core/modules/views_ui/src/Tests/DisplayPathTest.php +++ b/core/modules/views_ui/src/Tests/DisplayPathTest.php @@ -15,13 +15,21 @@ */ class DisplayPathTest extends UITestBase { + /** + * {@inheritdoc} + */ + public static $modules = array('menu_ui'); + /** * Views used by this test. * * @var array */ - public static $testViews = array('test_view'); + public static $testViews = array('test_view', 'test_page_display_menu'); + /** + * Runs the tests. + */ public function testPathUI() { $this->doBasicPathUITest(); $this->doAdvancedPathsValidationTest(); @@ -96,6 +104,25 @@ public function testMenuOptions() { $this->assertLink(t('Tab: @title', array('@title' => 'Test tab title'))); // If it's a default tab, it should also have an additional settings link. $this->assertLinkByHref('admin/structure/views/nojs/display/test_view/page_1/tab_options'); + + // Ensure that you can select a parent in case the parent does not exist. + $this->drupalGet('admin/structure/views/nojs/display/test_page_display_menu/page_5/menu'); + $this->assertResponse(200); + $menu_parent = $this->xpath('//select[@id="edit-menu-parent"]'); + $menu_options = (array) $menu_parent[0]->option; + unset($menu_options['@attributes']); + + $this->assertEqual([ + '', + '-- My account', + '-- Log out', + '', + '