3 namespace Drupal\Tests\menu_link_content\Functional;
5 use Drupal\Component\Utility\SafeMarkup;
6 use Drupal\Core\Menu\MenuTreeParameters;
7 use Drupal\menu_link_content\Entity\MenuLinkContent;
8 use Drupal\system\Entity\Menu;
9 use Drupal\Tests\BrowserTestBase;
10 use Drupal\user\Entity\User;
13 * Tests handling of menu links hierarchies.
17 class LinksTest extends BrowserTestBase {
24 public static $modules = ['router_test', 'menu_link_content'];
27 * The menu link plugin manager.
29 * @var \Drupal\Core\Menu\MenuLinkManagerInterface
31 protected $menuLinkManager;
36 protected function setUp() {
39 $this->menuLinkManager = \Drupal::service('plugin.manager.menu.link');
43 'label' => 'Test menu',
44 'description' => 'Description text',
49 * Create a simple hierarchy of links.
51 public function createLinkHierarchy($module = 'menu_test') {
52 // First remove all the menu links in the menu.
53 $this->menuLinkManager->deleteLinksInMenu('menu_test');
55 // Then create a simple link hierarchy:
62 'title' => 'Menu link test',
63 'provider' => $module,
64 'menu_name' => 'menu_test',
67 $parent = $base_options + [
68 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent'],
70 $link = MenuLinkContent::create($parent);
72 $links['parent'] = $link->getPluginId();
74 $child_1 = $base_options + [
75 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child'],
76 'parent' => $links['parent'],
78 $link = MenuLinkContent::create($child_1);
80 $links['child-1'] = $link->getPluginId();
82 $child_1_1 = $base_options + [
83 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child2/child'],
84 'parent' => $links['child-1'],
86 $link = MenuLinkContent::create($child_1_1);
88 $links['child-1-1'] = $link->getPluginId();
90 $child_1_2 = $base_options + [
91 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child2/child'],
92 'parent' => $links['child-1'],
94 $link = MenuLinkContent::create($child_1_2);
96 $links['child-1-2'] = $link->getPluginId();
98 $child_2 = $base_options + [
99 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child'],
100 'parent' => $links['parent'],
102 $link = MenuLinkContent::create($child_2);
104 $links['child-2'] = $link->getPluginId();
110 * Assert that at set of links is properly parented.
112 public function assertMenuLinkParents($links, $expected_hierarchy) {
113 foreach ($expected_hierarchy as $id => $parent) {
114 /* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin */
115 $menu_link_plugin = $this->menuLinkManager->createInstance($links[$id]);
116 $expected_parent = isset($links[$parent]) ? $links[$parent] : '';
118 $this->assertEqual($menu_link_plugin->getParent(), $expected_parent, SafeMarkup::format('Menu link %id has parent of %parent, expected %expected_parent.', ['%id' => $id, '%parent' => $menu_link_plugin->getParent(), '%expected_parent' => $expected_parent]));
123 * Assert that a link entity's created timestamp is set.
125 public function testCreateLink() {
127 'menu_name' => 'menu_test',
128 'bundle' => 'menu_link_content',
129 'link' => [['uri' => 'internal:/']],
130 'title' => 'Link test',
132 $link = MenuLinkContent::create($options);
134 // Make sure the changed timestamp is set.
135 $this->assertEqual($link->getChangedTime(), REQUEST_TIME, 'Creating a menu link sets the "changed" timestamp.');
137 'title' => 'Test Link',
139 $link->link->options = $options;
140 $link->changed->value = 0;
142 // Make sure the changed timestamp is updated.
143 $this->assertEqual($link->getChangedTime(), REQUEST_TIME, 'Changing a menu link sets "changed" timestamp.');
147 * Tests that menu link pointing to entities get removed on entity remove.
149 public function testMenuLinkOnEntityDelete() {
152 $user = User::create(['name' => 'username']);
155 // Create "canonical" menu link pointing to the user.
156 $menu_link_content = MenuLinkContent::create([
157 'title' => 'username profile',
158 'menu_name' => 'menu_test',
159 'link' => [['uri' => 'entity:user/' . $user->id()]],
160 'bundle' => 'menu_test',
162 $menu_link_content->save();
164 // Create "collection" menu link pointing to the user listing page.
165 $menu_link_content_collection = MenuLinkContent::create([
166 'title' => 'users listing',
167 'menu_name' => 'menu_test',
168 'link' => [['uri' => 'internal:/' . $user->toUrl('collection')->getInternalPath()]],
169 'bundle' => 'menu_test',
171 $menu_link_content_collection->save();
173 // Check is menu links present in the menu.
174 $menu_tree_condition = (new MenuTreeParameters())->addCondition('route_name', 'entity.user.canonical');
175 $this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
176 $menu_tree_condition_collection = (new MenuTreeParameters())->addCondition('route_name', 'entity.user.collection');
177 $this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition_collection));
182 // The "canonical" menu item has to be deleted.
183 $this->assertCount(0, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
185 // The "collection" menu item should still present in the menu.
186 $this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition_collection));
190 * Test automatic reparenting of menu links.
192 public function testMenuLinkReparenting($module = 'menu_test') {
193 // Check the initial hierarchy.
194 $links = $this->createLinkHierarchy($module);
196 $expected_hierarchy = [
198 'child-1' => 'parent',
199 'child-1-1' => 'child-1',
200 'child-1-2' => 'child-1',
201 'child-2' => 'parent',
203 $this->assertMenuLinkParents($links, $expected_hierarchy);
205 // Start over, and move child-1 under child-2, and check that all the
206 // children of child-1 have been moved too.
207 $links = $this->createLinkHierarchy($module);
208 /* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin */
209 $this->menuLinkManager->updateDefinition($links['child-1'], ['parent' => $links['child-2']]);
210 // Verify that the entity was updated too.
211 $menu_link_plugin = $this->menuLinkManager->createInstance($links['child-1']);
212 $entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $menu_link_plugin->getDerivativeId());
213 $this->assertEqual($entity->getParentId(), $links['child-2']);
215 $expected_hierarchy = [
217 'child-1' => 'child-2',
218 'child-1-1' => 'child-1',
219 'child-1-2' => 'child-1',
220 'child-2' => 'parent',
222 $this->assertMenuLinkParents($links, $expected_hierarchy);
224 // Start over, and delete child-1, and check that the children of child-1
225 // have been reassigned to the parent.
226 $links = $this->createLinkHierarchy($module);
227 $this->menuLinkManager->removeDefinition($links['child-1']);
229 $expected_hierarchy = [
231 'child-1-1' => 'parent',
232 'child-1-2' => 'parent',
233 'child-2' => 'parent',
235 $this->assertMenuLinkParents($links, $expected_hierarchy);
237 // Try changing the parent at the entity level.
238 $definition = $this->menuLinkManager->getDefinition($links['child-1-2']);
239 $entity = MenuLinkContent::load($definition['metadata']['entity_id']);
240 $entity->parent->value = '';
243 $expected_hierarchy = [
245 'child-1-1' => 'parent',
247 'child-2' => 'parent',
249 $this->assertMenuLinkParents($links, $expected_hierarchy);
251 // @todo Figure out what makes sense to test in terms of automatic
252 // re-parenting. https://www.drupal.org/node/2309531
256 * Tests uninstalling a module providing default links.
258 public function testModuleUninstalledMenuLinks() {
259 \Drupal::service('module_installer')->install(['menu_test']);
260 \Drupal::service('router.builder')->rebuild();
261 \Drupal::service('plugin.manager.menu.link')->rebuild();
262 $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
263 $this->assertEqual(count($menu_links), 1);
264 $menu_link = reset($menu_links);
265 $this->assertEqual($menu_link->getPluginId(), 'menu_test');
267 // Uninstall the module and ensure the menu link got removed.
268 \Drupal::service('module_installer')->uninstall(['menu_test']);
269 \Drupal::service('plugin.manager.menu.link')->rebuild();
270 $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
271 $this->assertEqual(count($menu_links), 0);