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() {
150 $user = User::create(['name' => 'username']);
152 $menu_link_content = MenuLinkContent::create([
153 'title' => 'username profile',
154 'menu_name' => 'menu_test',
155 'link' => [['uri' => 'entity:user/' . $user->id()]],
156 'bundle' => 'menu_test',
158 $menu_link_content->save();
159 $menu_tree_condition = (new MenuTreeParameters())->addCondition('route_name', 'entity.user.canonical');
160 $this->assertCount(1, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
163 $this->assertCount(0, \Drupal::menuTree()->load('menu_test', $menu_tree_condition));
167 * Test automatic reparenting of menu links.
169 public function testMenuLinkReparenting($module = 'menu_test') {
170 // Check the initial hierarchy.
171 $links = $this->createLinkHierarchy($module);
173 $expected_hierarchy = [
175 'child-1' => 'parent',
176 'child-1-1' => 'child-1',
177 'child-1-2' => 'child-1',
178 'child-2' => 'parent',
180 $this->assertMenuLinkParents($links, $expected_hierarchy);
182 // Start over, and move child-1 under child-2, and check that all the
183 // children of child-1 have been moved too.
184 $links = $this->createLinkHierarchy($module);
185 /* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin */
186 $this->menuLinkManager->updateDefinition($links['child-1'], ['parent' => $links['child-2']]);
187 // Verify that the entity was updated too.
188 $menu_link_plugin = $this->menuLinkManager->createInstance($links['child-1']);
189 $entity = \Drupal::entityManager()->loadEntityByUuid('menu_link_content', $menu_link_plugin->getDerivativeId());
190 $this->assertEqual($entity->getParentId(), $links['child-2']);
192 $expected_hierarchy = [
194 'child-1' => 'child-2',
195 'child-1-1' => 'child-1',
196 'child-1-2' => 'child-1',
197 'child-2' => 'parent',
199 $this->assertMenuLinkParents($links, $expected_hierarchy);
201 // Start over, and delete child-1, and check that the children of child-1
202 // have been reassigned to the parent.
203 $links = $this->createLinkHierarchy($module);
204 $this->menuLinkManager->removeDefinition($links['child-1']);
206 $expected_hierarchy = [
208 'child-1-1' => 'parent',
209 'child-1-2' => 'parent',
210 'child-2' => 'parent',
212 $this->assertMenuLinkParents($links, $expected_hierarchy);
214 // Try changing the parent at the entity level.
215 $definition = $this->menuLinkManager->getDefinition($links['child-1-2']);
216 $entity = MenuLinkContent::load($definition['metadata']['entity_id']);
217 $entity->parent->value = '';
220 $expected_hierarchy = [
222 'child-1-1' => 'parent',
224 'child-2' => 'parent',
226 $this->assertMenuLinkParents($links, $expected_hierarchy);
228 // @todo Figure out what makes sense to test in terms of automatic
229 // re-parenting. https://www.drupal.org/node/2309531
233 * Tests uninstalling a module providing default links.
235 public function testModuleUninstalledMenuLinks() {
236 \Drupal::service('module_installer')->install(['menu_test']);
237 \Drupal::service('router.builder')->rebuild();
238 \Drupal::service('plugin.manager.menu.link')->rebuild();
239 $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
240 $this->assertEqual(count($menu_links), 1);
241 $menu_link = reset($menu_links);
242 $this->assertEqual($menu_link->getPluginId(), 'menu_test');
244 // Uninstall the module and ensure the menu link got removed.
245 \Drupal::service('module_installer')->uninstall(['menu_test']);
246 \Drupal::service('plugin.manager.menu.link')->rebuild();
247 $menu_links = $this->menuLinkManager->loadLinksByRoute('menu_test.menu_test');
248 $this->assertEqual(count($menu_links), 0);