/** * {@inheritdoc} */ public function menuItemAccess(AccountInterface $account, MenuLinkContent $menu_link_content = NULL) { $permission = 'administer ' . $menu_link_content->getMenuName() . ' menu items'; $permissions = $this::getPerMenuPermissions($account); if ($account->hasPermission('administer menu') || isset($permissions[$permission])) { return AccessResult::allowed(); } return AccessResult::neutral(); }
/** * Tests the rediscovering. */ public function testRediscover() { \Drupal::state()->set('menu_link_content_dynamic_route.routes', ['route_name_1' => new Route('/example-path')]); \Drupal::service('router.builder')->rebuild(); // Set up a custom menu link pointing to a specific path. MenuLinkContent::create(['title' => '<script>alert("Welcome to the discovered jungle!")</script>', 'link' => [['uri' => 'internal:/example-path']], 'menu_name' => 'tools'])->save(); $menu_tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual(1, count($menu_tree)); /** @var \Drupal\Core\Menu\MenuLinkTreeElement $tree_element */ $tree_element = reset($menu_tree); $this->assertEqual('route_name_1', $tree_element->link->getRouteName()); // Change the underlying route and trigger the rediscovering. \Drupal::state()->set('menu_link_content_dynamic_route.routes', ['route_name_2' => new Route('/example-path')]); \Drupal::service('router.builder')->rebuild(); // Ensure that the new route name / parameters are captured by the tree. $menu_tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual(1, count($menu_tree)); /** @var \Drupal\Core\Menu\MenuLinkTreeElement $tree_element */ $tree_element = reset($menu_tree); $this->assertEqual('route_name_2', $tree_element->link->getRouteName()); $title = $tree_element->link->getTitle(); $this->assertFalse($title instanceof TranslationWrapper); $this->assertIdentical('<script>alert("Welcome to the discovered jungle!")</script>', $title); $this->assertFalse(SafeMarkup::isSafe($title)); }
/** * Prepare a node to get suggestions from. * * Creates a node with two file fields. The first one is not translatable, * the second one is. Both fields got two files attached, where one has * translatable content (title and atl-text) and the other one not. * * @return object * The node which is prepared with all needed fields for the suggestions. */ protected function prepareTranslationSuggestions() { // Create a content type with fields. // Only the first field is a translatable reference. $type = NodeType::create(['type' => $this->randomMachineName()]); $type->save(); $content_translation_manager = \Drupal::service('content_translation.manager'); $content_translation_manager->setEnabled('node', $type->id(), TRUE); $field1 = FieldStorageConfig::create(array('field_name' => 'field1', 'entity_type' => 'node', 'type' => 'entity_reference', 'cardinality' => -1, 'settings' => array('target_type' => 'node'))); $field1->save(); $field2 = FieldStorageConfig::create(array('field_name' => 'field2', 'entity_type' => 'node', 'type' => 'entity_reference', 'cardinality' => -1, 'settings' => array('target_type' => 'node'))); $field2->save(); // Create field instances on the content type. FieldConfig::create(array('field_storage' => $field1, 'bundle' => $type->id(), 'label' => 'Field 1', 'translatable' => FALSE, 'settings' => array()))->save(); FieldConfig::create(array('field_storage' => $field2, 'bundle' => $type->id(), 'label' => 'Field 2', 'translatable' => TRUE, 'settings' => array()))->save(); // Create a translatable body field. node_add_body_field($type); $field = FieldConfig::loadByName('node', $type->id(), 'body'); $field->setTranslatable(TRUE); $field->save(); // Create 4 nodes to be referenced. $references = array(); for ($i = 0; $i < 4; $i++) { $references[$i] = Node::create(array('title' => $this->randomMachineName(), 'body' => $this->randomMachineName(), 'type' => $type->id())); $references[$i]->save(); } // Create a node with two translatable and two non-translatable references. $node = Node::create(array('title' => $this->randomMachineName(), 'type' => $type->id(), 'language' => 'en', 'body' => $this->randomMachineName(), $field1->getName() => array(array('target_id' => $references[0]->id()), array('target_id' => $references[1]->id())), $field2->getName() => array(array('target_id' => $references[2]->id()), array('target_id' => $references[3]->id())))); $node->save(); $link = MenuLinkContent::create(['link' => [['uri' => 'entity:node/' . $node->id()]], 'title' => 'Node menu link', 'menu_name' => 'main']); $link->save(); $node->link = $link; return $node; }
/** * Test that menu links using menu_link_content as parent are visible. */ public function testHierarchicalMenuLinkVisibility() { $this->drupalLogin($this->adminUser); $node = $this->drupalCreateNode(['type' => 'page']); // Create a primary level menu link to the node. $link = MenuLinkContent::create(['title' => 'Primary level node', 'menu_name' => 'main', 'bundle' => 'menu_link_content', 'parent' => '', 'link' => [['uri' => 'entity:node/' . $node->id()]]]); $link->save(); $parent_menu_value = 'main:menu_link_content:' . $link->uuid(); // Alter the view's menu link in view page to use the menu link from the // node as parent. $this->drupalPostForm("admin/structure/views/nojs/display/test_menu_link/page_1/menu", ['menu[type]' => 'normal', 'menu[title]' => 'Secondary level view page', 'menu[parent]' => $parent_menu_value], 'Apply'); // Save view which has pending changes. $this->drupalPostForm(NULL, [], 'Save'); // Test if the node as parent menu item is selected in our views settings. $this->drupalGet('admin/structure/views/nojs/display/test_menu_link/page_1/menu'); $this->assertOptionSelected('edit-menu-parent', $parent_menu_value); $this->drupalGet(''); // Test if the primary menu item (node) is visible, and the secondary menu // item (view) is hidden. $this->assertText('Primary level node'); $this->assertNoText('Secondary level view page'); // Go to the node page and ensure that both the first and second level items // are visible. $this->drupalGet($node->urlInfo()); $this->assertText('Primary level node'); $this->assertText('Secondary level view page'); }
/** * {@inheritdoc} */ protected function setUp() { parent::setUp(); $account = $this->drupalCreateUser(); $this->drupalLogin($account); $menu_link_content = MenuLinkContent::create(['title' => 'Link to front page', 'menu_name' => 'tools', 'link' => ['uri' => 'route:<front>']]); $menu_link_content->save(); $this->drupalPlaceBlock('system_menu_block:tools'); }
/** * Ensure that a translate link can be found on the menu edit form. */ public function testTranslationLinkOnMenuEditForm() { $this->drupalGet('admin/structure/menu/manage/tools'); $this->assertNoLink(t('Translate')); $menu_link_content = MenuLinkContent::create(['menu_name' => 'tools', 'link' => ['uri' => 'internal:/admin/structure/menu']]); $menu_link_content->save(); $this->drupalGet('admin/structure/menu/manage/tools'); $this->assertLink(t('Translate')); }
/** * Ensures that a menu link does not cause an XSS issue. */ public function testMenuLink() { $menu_link_content = MenuLinkContent::create(['title' => '<script>alert("Wild animals")</script>', 'menu_name' => 'tools', 'link' => ['uri' => 'route:<front>']]); $menu_link_content->save(); $this->drupalPlaceBlock('system_menu_block:tools'); $this->drupalGet('<front>'); $this->assertNoRaw('<script>alert("Wild animals")</script>'); $this->assertNoRaw('<script>alert("Even more wild animals")</script>'); $this->assertEscaped('<script>alert("Wild animals")</script>'); $this->assertEscaped('<script>alert("Even more wild animals")</script>'); }
/** * Tests bubbleable metadata of menu links' outbound route/path processing. */ public function testOutboundPathAndRouteProcessing() { \Drupal::service('router.builder')->rebuild(); $request_stack = \Drupal::requestStack(); /** @var \Symfony\Component\Routing\RequestContext $request_context */ $request_context = \Drupal::service('router.request_context'); $request = Request::create('/'); $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<front>'); $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/')); $request_stack->push($request); $request_context->fromRequest($request); $menu_tree = \Drupal::menuTree(); $renderer = \Drupal::service('renderer'); $default_menu_cacheability = (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheTags(['config:system.menu.tools'])->setCacheContexts(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']); User::create(['uid' => 1, 'name' => $this->randomString()])->save(); User::create(['uid' => 2, 'name' => $this->randomString()])->save(); // Five test cases, four asserting one outbound path/route processor, and // together covering one of each: // - no cacheability metadata, // - a cache context, // - a cache tag, // - a cache max-age. // Plus an additional test case to verify that multiple links adding // cacheability metadata of the same type is working (two links with cache // tags). $test_cases = [['uri' => 'route:<current>', 'cacheability' => (new BubbleableMetadata())->setCacheContexts(['route'])], ['uri' => 'route:outbound_processing_test.route.csrf', 'cacheability' => (new BubbleableMetadata())->setCacheContexts(['session'])->setAttachments(['placeholders' => []])], ['uri' => 'internal:/', 'cacheability' => new BubbleableMetadata()], ['uri' => 'internal:/user/1', 'cacheability' => (new BubbleableMetadata())->setCacheTags(User::load(1)->getCacheTags())], ['uri' => 'internal:/user/2', 'cacheability' => (new BubbleableMetadata())->setCacheTags(User::load(2)->getCacheTags())]]; // Test each expectation individually. foreach ($test_cases as $expectation) { $menu_link_content = MenuLinkContent::create(['link' => ['uri' => $expectation['uri']], 'menu_name' => 'tools']); $menu_link_content->save(); $tree = $menu_tree->load('tools', new MenuTreeParameters()); $build = $menu_tree->build($tree); $renderer->renderRoot($build); $expected_cacheability = $default_menu_cacheability->merge($expectation['cacheability']); $this->assertEqual($expected_cacheability, BubbleableMetadata::createFromRenderArray($build)); $menu_link_content->delete(); } // Now test them all together in one menu: the rendered menu's cacheability // metadata should be the combination of the cacheability of all links, and // thus of all tested outbound path & route processors. $expected_cacheability = new BubbleableMetadata(); foreach ($test_cases as $expectation) { $menu_link_content = MenuLinkContent::create(['link' => ['uri' => $expectation['uri']], 'menu_name' => 'tools']); $menu_link_content->save(); $expected_cacheability = $expected_cacheability->merge($expectation['cacheability']); } $tree = $menu_tree->load('tools', new MenuTreeParameters()); $build = $menu_tree->build($tree); $renderer->renderRoot($build); $expected_cacheability = $expected_cacheability->merge($default_menu_cacheability); $this->assertEqual($expected_cacheability, BubbleableMetadata::createFromRenderArray($build)); }
/** * 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 = Menu::create(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', '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 = MenuLinkContent::create(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', 'config:user.role.anonymous', 'rendered']); }
/** * Tests the rediscovering. */ public function testRediscover() { \Drupal::state()->set('menu_link_content_dynamic_route.routes', ['route_name_1' => new Route('/example-path')]); \Drupal::service('router.builder')->rebuild(); // Set up a custom menu link pointing to a specific path. $parent = MenuLinkContent::create(['title' => '<script>alert("Welcome to the discovered jungle!")</script>', 'link' => [['uri' => 'internal:/example-path']], 'menu_name' => 'tools']); $parent->save(); $menu_tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual(1, count($menu_tree)); /** @var \Drupal\Core\Menu\MenuLinkTreeElement $tree_element */ $tree_element = reset($menu_tree); $this->assertEqual('route_name_1', $tree_element->link->getRouteName()); // Change the underlying route and trigger the rediscovering. \Drupal::state()->set('menu_link_content_dynamic_route.routes', ['route_name_2' => new Route('/example-path')]); \Drupal::service('router.builder')->rebuild(); // Ensure that the new route name / parameters are captured by the tree. $menu_tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual(1, count($menu_tree)); /** @var \Drupal\Core\Menu\MenuLinkTreeElement $tree_element */ $tree_element = reset($menu_tree); $this->assertEqual('route_name_2', $tree_element->link->getRouteName()); $title = $tree_element->link->getTitle(); $this->assertFalse($title instanceof TranslatableMarkup); $this->assertIdentical('<script>alert("Welcome to the discovered jungle!")</script>', $title); $this->assertFalse(SafeMarkup::isSafe($title)); // Create a hierarchy. \Drupal::state()->set('menu_link_content_dynamic_route.routes', ['route_name_1' => new Route('/example-path'), 'route_name_2' => new Route('/example-path/child')]); $child = MenuLinkContent::create(['title' => 'Child', 'link' => [['uri' => 'entity:/example-path/child']], 'menu_name' => 'tools', 'parent' => 'menu_link_content:' . $parent->uuid()]); $child->save(); $parent->set('link', [['uri' => 'entity:/example-path']]); $parent->save(); $menu_tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual(1, count($menu_tree)); /** @var \Drupal\Core\Menu\MenuLinkTreeElement $tree_element */ $tree_element = reset($menu_tree); $this->assertTrue($tree_element->hasChildren); $this->assertEqual(1, count($tree_element->subtree)); // Edit child element link to use 'internal' instead of 'entity'. $child->set('link', [['uri' => 'internal:/example-path/child']]); $child->save(); \Drupal::service('plugin.manager.menu.link')->rebuild(); $menu_tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual(1, count($menu_tree)); /** @var \Drupal\Core\Menu\MenuLinkTreeElement $tree_element */ $tree_element = reset($menu_tree); $this->assertTrue($tree_element->hasChildren); $this->assertEqual(1, count($tree_element->subtree)); }
/** * Asserts various aspects of a menu link entity. * * @param string $id * The link ID. * @param string $title * The expected title of the link. * @param string $menu * The expected ID of the menu to which the link will belong. * @param string $description * The link's expected description. * @param bool $enabled * Whether the link is enabled. * @param bool $expanded * Whether the link is expanded * @param array $attributes * Additional attributes the link is expected to have. * @param string $uri * The expected URI of the link. * @param int $weight * The expected weight of the link. */ protected function assertEntity($id, $title, $menu, $description, $enabled, $expanded, array $attributes, $uri, $weight) { /** @var \Drupal\menu_link_content\MenuLinkContentInterface $menu_link */ $menu_link = MenuLinkContent::load($id); $this->assertTrue($menu_link instanceof MenuLinkContentInterface); $this->assertIdentical($title, $menu_link->getTitle()); $this->assertIdentical($menu, $menu_link->getMenuName()); // The migration sets the description of the link to the value of the // 'title' attribute. Bit strange, but there you go. $this->assertIdentical($description, $menu_link->getDescription()); $this->assertIdentical($enabled, $menu_link->isEnabled()); $this->assertIdentical($expanded, $menu_link->isExpanded()); $this->assertIdentical($attributes, $menu_link->link->options); $this->assertIdentical($uri, $menu_link->link->uri); $this->assertIdentical($weight, $menu_link->getWeight()); }
/** * Tests the MenuLinkContentDeleteForm class. */ public function testMenuLinkContentDeleteForm() { // Add new menu item. $this->drupalPostForm('admin/structure/menu/manage/admin/add', ['title[0][value]' => t('Front page'), 'link[0][uri]' => '<front>'], t('Save')); $this->assertText(t('The menu link has been saved.')); $menu_link = MenuLinkContent::load(1); $this->drupalGet($menu_link->urlInfo('delete-form')); $this->assertRaw(t('Are you sure you want to delete the custom menu link %name?', ['%name' => $menu_link->label()])); $this->assertLink(t('Cancel')); // Make sure cancel link points to link edit $this->assertLinkByHref($menu_link->url('edit-form')); \Drupal::service('module_installer')->install(['menu_ui']); // Make sure cancel URL points to menu_ui route now. $this->drupalGet($menu_link->urlInfo('delete-form')); $menu = Menu::load($menu_link->getMenuName()); $this->assertLinkByHref($menu->url('edit-form')); $this->drupalPostForm(NULL, [], t('Delete')); $this->assertRaw(t('The menu link %title has been deleted.', ['%title' => $menu_link->label()])); }
public function testMenuLinksInDifferentWorkspaces() { MenuLinkContent::create(['menu_name' => 'main', 'link' => 'route:user.page', 'title' => 'Pineapple'])->save(); $this->drupalGet('user/2'); $this->assertLink('Pineapple'); $this->drupalGet('user/2', ['query' => ['workspace' => $this->new_workspace->id()]]); $this->assertNoLink('Pineapple'); // The previous page request only changed workspace for the session of the // request. We have to switch workspace in the test context as well. $this->workspaceManager->setActiveWorkspace($this->new_workspace); // Save another menu link. MenuLinkContent::create(['menu_name' => 'main', 'link' => 'route:user.page', 'title' => 'Pear'])->save(); $this->drupalGet('user/2'); $this->assertNoLink('Pineapple'); $this->assertLink('Pear'); // Switch back to the default workspace and ensure the menu links render // as expected. $this->drupalGet('user/2', ['query' => ['workspace' => 1]]); $this->assertLink('Pineapple'); $this->assertNoLink('Pear'); }
/** * Tests migration of menu links. */ public function testMenuLinks() { $menu_link = MenuLinkContent::load(138); $this->assertIdentical('Test 1', $menu_link->getTitle()); $this->assertIdentical('secondary-links', $menu_link->getMenuName()); $this->assertIdentical('Test menu link 1', $menu_link->getDescription()); $this->assertIdentical(TRUE, $menu_link->isEnabled()); $this->assertIdentical(FALSE, $menu_link->isExpanded()); $this->assertIdentical(['attributes' => ['title' => 'Test menu link 1']], $menu_link->link->options); $this->assertIdentical('internal:/user/login', $menu_link->link->uri); $this->assertIdentical(-50, $menu_link->getWeight()); $menu_link = MenuLinkContent::load(139); $this->assertIdentical('Test 2', $menu_link->getTitle()); $this->assertIdentical('secondary-links', $menu_link->getMenuName()); $this->assertIdentical('Test menu link 2', $menu_link->getDescription()); $this->assertIdentical(TRUE, $menu_link->isEnabled()); $this->assertIdentical(TRUE, $menu_link->isExpanded()); $this->assertIdentical(['query' => 'foo=bar', 'attributes' => ['title' => 'Test menu link 2']], $menu_link->link->options); $this->assertIdentical('internal:/admin', $menu_link->link->uri); $this->assertIdentical(-49, $menu_link->getWeight()); $menu_link = MenuLinkContent::load(140); $this->assertIdentical('Drupal.org', $menu_link->getTitle()); $this->assertIdentical('secondary-links', $menu_link->getMenuName()); $this->assertIdentical(NULL, $menu_link->getDescription()); $this->assertIdentical(TRUE, $menu_link->isEnabled()); $this->assertIdentical(FALSE, $menu_link->isExpanded()); $this->assertIdentical(['attributes' => ['title' => '']], $menu_link->link->options); $this->assertIdentical('https://www.drupal.org', $menu_link->link->uri); $this->assertIdentical(-50, $menu_link->getWeight()); // assert that missing title attributes don't stop or break migration. $menu_link = MenuLinkContent::load(393); $this->assertIdentical('Test 3', $menu_link->getTitle()); $this->assertIdentical('secondary-links', $menu_link->getMenuName()); $this->assertIdentical(NULL, $menu_link->getDescription()); $this->assertIdentical(TRUE, $menu_link->isEnabled()); $this->assertIdentical(FALSE, $menu_link->isExpanded()); $this->assertIdentical([], $menu_link->link->options); $this->assertIdentical('internal:/user/login', $menu_link->link->uri); $this->assertIdentical(-47, $menu_link->getWeight()); }
/** * Tests the path aliasing changing. */ public function testPathAliasChange() { \Drupal::service('router.builder')->rebuild(); /** @var \Drupal\Core\Path\AliasStorageInterface $path_alias_storage */ $path_alias_storage = \Drupal::service('path.alias_storage'); $alias = $path_alias_storage->save('/test-page', '/my-blog'); $pid = $alias['pid']; $menu_link_content = MenuLinkContent::create(['title' => 'Menu title', 'link' => ['uri' => 'internal:/my-blog'], 'menu_name' => 'tools']); $menu_link_content->save(); $tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual('test_page_test.test_page', $tree[$menu_link_content->getPluginId()]->link->getPluginDefinition()['route_name']); // Saving an alias should clear the alias manager cache. $path_alias_storage->save('/test-render-title', '/my-blog', LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid); $tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertEqual('test_page_test.render_title', $tree[$menu_link_content->getPluginId()]->link->getPluginDefinition()['route_name']); // Delete the alias. $path_alias_storage->delete(['pid' => $pid]); $tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $this->assertTrue(isset($tree[$menu_link_content->getPluginId()])); $this->assertEqual('', $tree[$menu_link_content->getPluginId()]->link->getRouteName()); // Verify the plugin now references a path that does not match any route. $this->assertEqual('base:my-blog', $tree[$menu_link_content->getPluginId()]->link->getUrlObject()->getUri()); }
/** * 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 (['Save and unpublish' => FALSE, 'Save and keep unpublished' => FALSE, 'Save and publish' => TRUE, '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:'); }
/** * Tests language switcher links for session based negotiation. */ public function testLanguageSessionSwitchLinks() { // Add language. $edit = array('predefined_langcode' => 'fr'); $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language')); // Enable session language detection and selection. $edit = array('language_interface[enabled][language-url]' => FALSE, 'language_interface[enabled][language-session]' => TRUE); $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings')); // Enable the language switching block. $this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, array('id' => 'test_language_block')); // Enable the main menu block. $this->drupalPlaceBlock('system_menu_block:main', array('id' => 'test_menu')); // Add a link to the homepage. $link = MenuLinkContent::create(['title' => 'Home', 'menu_name' => 'main', 'bundle' => 'menu_link_content', 'link' => [['uri' => 'entity:user/2']]]); $link->save(); // Go to the homepage. $this->drupalGet(''); // Click on the French link. $this->clickLink(t('French')); // There should be a query parameter to set the session language. $this->assertUrl('user/2', ['query' => ['language' => 'fr']]); // Click on the 'Home' Link. $this->clickLink(t('Home')); // There should be no query parameter. $this->assertUrl('user/2'); // Click on the French link. $this->clickLink(t('French')); // There should be no query parameter. $this->assertUrl('user/2'); }
/** * Creates a menu link. * * Used to create menu links for og menu instances. * The $item data is an array ready to be passed to the * MenuLinkContent::create method. * * @code * * $item_data = [ * 'title' => 'My label for the menu', * 'link' => [ * 'uri' => '/path/of/menu/item', * ], * 'menu_name' => menu_machine_name, * 'weight' => 1, * 'expanded' => TRUE, * ]; * * @end_code * * @param array $item_data * The item data. * * @see \Drupal\menu_link_content\Entity\MenuLinkContent::create() */ public function createOgMenuItem($item_data) { $menu_link = MenuLinkContent::create($item_data); $menu_link->save(); }
/** * Tests the regression in https://www.drupal.org/node/2532490. */ public function testDefaultMenuTabRegression() { $this->container->get('module_installer')->install(['menu_ui', 'menu_link_content', 'toolbar', 'system']); $admin_user = $this->drupalCreateUser(['administer views', 'administer blocks', 'bypass node access', 'access user profiles', 'view all revisions', 'administer permissions', 'administer menu', 'link to any page', 'access toolbar']); $this->drupalLogin($admin_user); $edit = ['title[0][value]' => 'Menu title', 'link[0][uri]' => '/admin/foo', 'menu_parent' => 'admin:system.admin']; $this->drupalPostForm('admin/structure/menu/manage/admin/add', $edit, t('Save')); $menu_items = \Drupal::entityManager()->getStorage('menu_link_content')->getQuery()->sort('id', 'DESC')->pager(1)->execute(); $menu_item = end($menu_items); /** @var \Drupal\menu_link_content\MenuLinkContentInterface $menu_link_content */ $menu_link_content = MenuLinkContent::load($menu_item); $edit = []; $edit['label'] = $this->randomMachineName(16); $view_id = $edit['id'] = strtolower($this->randomMachineName(16)); $edit['description'] = $this->randomMachineName(16); $edit['page[create]'] = TRUE; $edit['page[path]'] = 'admin/foo'; $this->drupalPostForm('admin/structure/views/add', $edit, t('Save and edit')); $parameters = new MenuTreeParameters(); $parameters->addCondition('id', $menu_link_content->getPluginId()); $result = \Drupal::menuTree()->load('admin', $parameters); $plugin_definition = end($result)->link->getPluginDefinition(); $this->assertEqual('view.' . $view_id . '.page_1', $plugin_definition['route_name']); $this->clickLink(t('No menu')); $this->drupalPostForm(NULL, ['menu[type]' => 'default tab', 'menu[title]' => 'Menu title'], t('Apply')); $this->assertText('Default tab options'); $this->drupalPostForm(NULL, ['tab_options[type]' => 'normal', 'tab_options[title]' => 'Parent title'], t('Apply')); $this->drupalPostForm(NULL, [], t('Save')); // Assert that saving the view will not cause an exception. $this->assertResponse(200); }
public function createMenuLink($title, $link, $menu_name, $expanded, $parent) { $menu_link = MenuLinkContent::create(['title' => $title, 'link' => ['uri' => $link], 'menu_name' => $menu_name, 'expanded' => $expanded, 'parent' => $parent]); $menu_link->save(); return $menu_link; }
/** * Assert that a link entity's created timestamp is set. */ public function testCreateLink() { $options = array('menu_name' => 'menu_test', 'bundle' => 'menu_link_content', 'link' => [['uri' => 'internal:/']]); $link = MenuLinkContent::create($options); $link->save(); // Make sure the changed timestamp is set. $this->assertEqual($link->getChangedTime(), REQUEST_TIME, 'Creating a menu link sets the "changed" timestamp.'); $options = array('title' => 'Test Link'); $link->link->options = $options; $link->changed->value = 0; $link->save(); // Make sure the changed timestamp is updated. $this->assertEqual($link->getChangedTime(), REQUEST_TIME, 'Changing a menu link sets "changed" timestamp.'); }
/** * Test creating, editing, deleting menu links via node form widget. */ function testMenuNodeFormWidget() { // 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'))); // 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); // 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'); // 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('route_name' => 'entity.node.canonical', 'route_parameters' => array('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('route_name' => 'entity.node.canonical', 'route_parameters' => array('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:'); }
/** * Test automatic reparenting of menu links. */ function testMenuLinkReparenting($module = 'menu_test') { // Check the initial hierarchy. $links = $this->createLinkHierarchy($module); $expected_hierarchy = array('parent' => '', 'child-1' => 'parent', 'child-1-1' => 'child-1', 'child-1-2' => 'child-1', 'child-2' => 'parent'); $this->assertMenuLinkParents($links, $expected_hierarchy); // Start over, and move child-1 under child-2, and check that all the // children of child-1 have been moved too. $links = $this->createLinkHierarchy($module); /* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin */ $this->menuLinkManager->updateDefinition($links['child-1'], array('parent' => $links['child-2'])); // Verify that the entity was updated too. $menu_link_plugin = $this->menuLinkManager->createInstance($links['child-1']); $entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $menu_link_plugin->getDerivativeId()); $this->assertEqual($entity->getParentId(), $links['child-2']); $expected_hierarchy = array('parent' => '', 'child-1' => 'child-2', 'child-1-1' => 'child-1', 'child-1-2' => 'child-1', 'child-2' => 'parent'); $this->assertMenuLinkParents($links, $expected_hierarchy); // Start over, and delete child-1, and check that the children of child-1 // have been reassigned to the parent. $links = $this->createLinkHierarchy($module); $this->menuLinkManager->removeDefinition($links['child-1']); $expected_hierarchy = array('parent' => FALSE, 'child-1-1' => 'parent', 'child-1-2' => 'parent', 'child-2' => 'parent'); $this->assertMenuLinkParents($links, $expected_hierarchy); // Try changing the parent at the entity level. $definition = $this->menuLinkManager->getDefinition($links['child-1-2']); $entity = MenuLinkContent::load($definition['metadata']['entity_id']); $entity->parent->value = ''; $entity->save(); $expected_hierarchy = array('parent' => '', 'child-1-1' => 'parent', 'child-1-2' => '', 'child-2' => 'parent'); $this->assertMenuLinkParents($links, $expected_hierarchy); // @todo Figure out what makes sense to test in terms of automatic // re-parenting. https://www.drupal.org/node/2309531 }
/** * 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 menu link parents token. */ public function testMenuLinkParentsToken() { // Create a menu with a simple link hierarchy : // - parent // - child-1 // - child-1-1 Menu::create(array('id' => 'menu_test', 'label' => 'Test menu'))->save(); $base_options = ['provider' => 'menu_test', 'menu_name' => 'menu_test']; $parent = $base_options + ['title' => 'parent title', 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent']]; $parent = MenuLinkContent::create($parent); $parent->save(); $child_1 = $base_options + ['title' => 'child_1 title', 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child_1'], 'parent' => $parent->getPluginId()]; $child_1 = MenuLinkContent::create($child_1); $child_1->save(); $child_1_1 = $base_options + ['title' => 'child_1_1 title', 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child_1/child_1_1'], 'parent' => $child_1->getPluginId()]; $child_1_1 = MenuLinkContent::create($child_1_1); $child_1_1->save(); $this->assertTokens('menu-link', ['menu-link' => $child_1_1], ['parents' => 'parent title, child_1 title']); // Change the parent of child_1_1 to 'parent' at the entity level. $child_1_1->parent->value = $parent->getPluginId(); $child_1_1->save(); $this->assertTokens('menu-link', ['menu-link' => $child_1_1], ['parents' => 'parent title']); // Change the parent of child_1_1 to 'main', at the entity level. $child_1_1->parent->value = ''; $child_1_1->save(); // The token shouldn't have been generated; the menu link has no parent. $this->assertNoTokens('menu-link', ['menu-link' => $child_1_1], ['parents']); }