diff --git a/core/modules/menu_link_content/migration_templates/d6_menu_links.yml b/core/modules/menu_link_content/migration_templates/d6_menu_links.yml deleted file mode 100644 index e58b202fdeda6b40edf629f81d50bd318a996fa8..0000000000000000000000000000000000000000 --- a/core/modules/menu_link_content/migration_templates/d6_menu_links.yml +++ /dev/null @@ -1,48 +0,0 @@ -id: d6_menu_links -label: Menu links -migration_tags: - - Drupal 6 -source: - plugin: menu_link - constants: - bundle: menu_link_content -process: - id: mlid - bundle: 'constants/bundle' - title: link_title - description: - plugin: extract - source: - - options - index: - - 0 - - attributes - - title - default: '' - menu_name: - plugin: migration - migration: menu - source: menu_name - 'link/uri': - plugin: internal_uri - source: - - link_path - 'link/options': options - external: external - weight: weight - expanded: expanded - enabled: enabled - parent: - - - plugin: skip_on_empty - method: process - source: plid - - - plugin: migration - migration: d6_menu_links - changed: updated -destination: - plugin: entity:menu_link_content -migration_dependencies: - required: - - menu diff --git a/core/modules/menu_link_content/migration_templates/d7_menu_links.yml b/core/modules/menu_link_content/migration_templates/menu_links.yml similarity index 71% rename from core/modules/menu_link_content/migration_templates/d7_menu_links.yml rename to core/modules/menu_link_content/migration_templates/menu_links.yml index d7b1d87aebe01bca397e9b09c46288547879f7d7..131162ed379f8147a32f69bd331363a319dc58ac 100644 --- a/core/modules/menu_link_content/migration_templates/d7_menu_links.yml +++ b/core/modules/menu_link_content/migration_templates/menu_links.yml @@ -1,6 +1,7 @@ -id: d7_menu_links +id: menu_links label: Menu links migration_tags: + - Drupal 6 - Drupal 7 source: plugin: menu_link @@ -10,19 +11,17 @@ process: id: mlid bundle: 'constants/bundle' title: link_title - description: - plugin: extract - source: - - options - index: - - 0 - - attributes - - title - default: '' + description: description menu_name: - plugin: migration - migration: menu - source: menu_name + - + plugin: migration + migration: menu + source: menu_name + - + plugin: static_map + map: + management: admin + bypass: true 'link/uri': plugin: internal_uri source: @@ -42,16 +41,15 @@ process: expanded: expanded enabled: enabled parent: - - - plugin: skip_on_empty - method: process - source: plid - - - plugin: migration - migration: d7_menu_links + plugin: menu_link_parent + source: + - plid + - @menu_name + - parent_link_path changed: updated destination: plugin: entity:menu_link_content + no_stub: true migration_dependencies: required: - menu diff --git a/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php b/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php index 93cf5836f316128ad8409d377725d37cfcda73d8..54c9a201177f26b0e9d47f4d3623a148743e9fad 100644 --- a/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php +++ b/core/modules/menu_link_content/src/Plugin/migrate/source/MenuLink.php @@ -7,6 +7,7 @@ namespace Drupal\menu_link_content\Plugin\migrate\source; +use Drupal\Component\Utility\Unicode; use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase; use Drupal\migrate\Row; @@ -23,12 +24,20 @@ class MenuLink extends DrupalSqlBase { * {@inheritdoc} */ public function query() { - return $this->select('menu_links', 'ml') - ->fields('ml') - ->orderby('ml.depth') - ->orderby('ml.mlid') - ->condition('module', 'menu') - ->condition('customized', 1); + $query = $this->select('menu_links', 'ml') + ->fields('ml'); + $and = $query->andConditionGroup() + ->condition('ml.module', 'menu') + ->condition('ml.router_path', ['admin/build/menu-customize/%', 'admin/structure/menu/manage/%'], 'NOT IN'); + $condition = $query->orConditionGroup() + ->condition('ml.customized', 1) + ->condition($and); + $query->condition($condition); + $query->leftJoin('menu_links', 'pl', 'ml.plid = pl.mlid'); + $query->addField('pl', 'link_path', 'parent_link_path'); + $query->orderBy('ml.depth'); + $query->orderby('ml.mlid'); + return $query; } /** @@ -70,6 +79,7 @@ public function fields() { public function prepareRow(Row $row) { $row->setSourceProperty('options', unserialize($row->getSourceProperty('options'))); $row->setSourceProperty('enabled', !$row->getSourceProperty('hidden')); + $row->setSourceProperty('description', Unicode::truncate($row->getSourceProperty('options/attributes/title'), 255)); return parent::prepareRow($row); } @@ -79,6 +89,7 @@ public function prepareRow(Row $row) { */ public function getIds() { $ids['mlid']['type'] = 'integer'; + $ids['mlid']['alias'] = 'ml'; return $ids; } diff --git a/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php b/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php index f6346fc53cd6b4302c39389d1036b97e289f5de0..8fc22ef0c7a86228dc43976aca54af591f824b37 100644 --- a/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php +++ b/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php @@ -29,7 +29,7 @@ protected function setUp() { parent::setUp(); $this->installSchema('system', ['router']); $this->installEntitySchema('menu_link_content'); - $this->executeMigrations(['menu', 'd6_menu_links']); + $this->executeMigrations(['menu', 'menu_links']); } /** diff --git a/core/modules/menu_link_content/src/Tests/Migrate/d7/MigrateMenuLinkTest.php b/core/modules/menu_link_content/src/Tests/Migrate/d7/MigrateMenuLinkTest.php index 6b9814a26903ed9b4f17c67d708ac6fbee567ad2..68c6d7aa7e04ca35b3f40a123a4e34f35d74abbe 100644 --- a/core/modules/menu_link_content/src/Tests/Migrate/d7/MigrateMenuLinkTest.php +++ b/core/modules/menu_link_content/src/Tests/Migrate/d7/MigrateMenuLinkTest.php @@ -8,6 +8,8 @@ namespace Drupal\menu_link_content\Tests\Migrate\d7; use Drupal\Core\Database\Database; +use Drupal\Core\Menu\MenuTreeParameters; +use Drupal\Core\Url; use Drupal\menu_link_content\Entity\MenuLinkContent; use Drupal\menu_link_content\MenuLinkContentInterface; use Drupal\migrate_drupal\Tests\d7\MigrateDrupal7TestBase; @@ -18,6 +20,7 @@ * @group menu_link_content */ class MigrateMenuLinkTest extends MigrateDrupal7TestBase { + const MENU_NAME = 'menu-test-menu'; /** * {@inheritdoc} @@ -32,6 +35,7 @@ protected function setUp() { $this->installSchema('system', ['router']); $this->installEntitySchema('menu_link_content'); $this->executeMigration('menu'); + \Drupal::service('router.builder')->rebuild(); } /** @@ -70,16 +74,44 @@ protected function assertEntity($id, $title, $menu, $description, $enabled, $exp $this->assertIdentical($attributes, $menu_link->link->options); $this->assertIdentical($uri, $menu_link->link->uri); $this->assertIdentical($weight, $menu_link->getWeight()); + return $menu_link; } /** * Tests migration of menu links. */ public function testMenuLinks() { - $this->executeMigration('d7_menu_links'); - $this->assertEntity(467, 'Google', 'menu-test-menu', 'Google', TRUE, FALSE, ['attributes' => ['title' => 'Google']], 'http://google.com', 0); - $this->assertEntity(468, 'Yahoo', 'menu-test-menu', 'Yahoo', TRUE, FALSE, ['attributes' => ['title' => 'Yahoo']], 'http://yahoo.com', 0); - $this->assertEntity(469, 'Bing', 'menu-test-menu', 'Bing', TRUE, FALSE, ['attributes' => ['title' => 'Bing']], 'http://bing.com', 0); + $this->executeMigration('menu_links'); + $this->assertEntity(469, 'Bing', static::MENU_NAME, 'Bing', TRUE, FALSE, ['attributes' => ['title' => 'Bing']], 'http://bing.com', 0); + $this->assertEntity(467, 'Google', static::MENU_NAME, 'Google', TRUE, FALSE, ['attributes' => ['title' => 'Google']], 'http://google.com', 0); + $this->assertEntity(468, 'Yahoo', static::MENU_NAME, 'Yahoo', TRUE, FALSE, ['attributes' => ['title' => 'Yahoo']], 'http://yahoo.com', 0); + $menu_link_tree_service = \Drupal::service('menu.link_tree'); + $parameters = new MenuTreeParameters(); + $tree = $menu_link_tree_service->load(static::MENU_NAME, $parameters); + $this->assertEqual(2, count($tree)); + $children = 0; + $google_found = FALSE; + foreach ($tree as $menu_link_tree_element) { + $children += $menu_link_tree_element->hasChildren; + if ($menu_link_tree_element->link->getUrlObject()->toString() == 'http://bing.com') { + $this->assertEqual(reset($menu_link_tree_element->subtree)->link->getUrlObject()->toString(), 'http://google.com'); + $google_found = TRUE; + } + } + $this->assertEqual(1, $children); + $this->assertTrue($google_found); + // Now find the custom link under a system link. + $parameters->root = 'system.admin_structure'; + $tree = $menu_link_tree_service->load(static::MENU_NAME, $parameters); + $found = FALSE; + foreach ($tree as $menu_link_tree_element) { + $this->pass($menu_link_tree_element->link->getUrlObject()->toString()); + if ($menu_link_tree_element->link->getTitle() == 'custom link test') { + $found = TRUE; + break; + } + } + $this->assertTrue($found); } /** @@ -94,8 +126,8 @@ public function testUndefinedLinkTitle() { ->condition('mlid', 467) ->execute(); - $this->executeMigration('d7_menu_links'); - $this->assertEntity(467, 'Google', 'menu-test-menu', NULL, TRUE, FALSE, [], 'http://google.com', 0); + $this->executeMigration('menu_links'); + $this->assertEntity(467, 'Google', static::MENU_NAME, NULL, TRUE, FALSE, [], 'http://google.com', 0); } } diff --git a/core/modules/menu_link_content/tests/src/Unit/Plugin/migrate/source/MenuLinkSourceTest.php b/core/modules/menu_link_content/tests/src/Unit/Plugin/migrate/source/MenuLinkSourceTest.php index 4ec1f096e9afdd68ea714dacc71c3f917e52f844..372452de4a06743f81ebc2924eb812f15e8c2fc2 100644 --- a/core/modules/menu_link_content/tests/src/Unit/Plugin/migrate/source/MenuLinkSourceTest.php +++ b/core/modules/menu_link_content/tests/src/Unit/Plugin/migrate/source/MenuLinkSourceTest.php @@ -6,6 +6,7 @@ */ namespace Drupal\Tests\menu_link_content\Unit\Plugin\migrate\source; +use Drupal\Component\Utility\Unicode; use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase; /** @@ -25,6 +26,92 @@ class MenuLinkSourceTest extends MigrateSqlSourceTestCase { ); protected $expectedResults = array( + array( + // Customized menu link, provided by system module. + 'menu_name' => 'menu-test-menu', + 'mlid' => 140, + 'plid' => 0, + 'link_path' => 'admin/config/system/cron', + 'router_path' => 'admin/config/system/cron', + 'link_title' => 'Cron', + 'options' => array(), + 'module' => 'system', + 'hidden' => 0, + 'external' => 0, + 'has_children' => 0, + 'expanded' => 0, + 'weight' => 0, + 'depth' => 0, + 'customized' => 1, + 'p1' => '0', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', + ), + array( + // D6 customized menu link, provided by menu module. + 'menu_name' => 'menu-test-menu', + 'mlid' => 141, + 'plid' => 0, + 'link_path' => 'node/141', + 'router_path' => 'node/%', + 'link_title' => 'Node 141', + 'options' => array(), + 'module' => 'menu', + 'hidden' => 0, + 'external' => 0, + 'has_children' => 0, + 'expanded' => 0, + 'weight' => 0, + 'depth' => 0, + 'customized' => 1, + 'p1' => '0', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', + 'description' => '', + ), + array( + // D6 non-customized menu link, provided by menu module. + 'menu_name' => 'menu-test-menu', + 'mlid' => 142, + 'plid' => 0, + 'link_path' => 'node/142', + 'router_path' => 'node/%', + 'link_title' => 'Node 142', + 'options' => array(), + 'module' => 'menu', + 'hidden' => 0, + 'external' => 0, + 'has_children' => 0, + 'expanded' => 0, + 'weight' => 0, + 'depth' => 0, + 'customized' => 0, + 'p1' => '0', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', + 'description' => '', + ), array( 'menu_name' => 'menu-test-menu', 'mlid' => 138, @@ -51,6 +138,7 @@ class MenuLinkSourceTest extends MigrateSqlSourceTestCase { 'p8' => '0', 'p9' => '0', 'updated' => '0', + 'description' => 'Test menu link 1', ), array( 'menu_name' => 'menu-test-menu', @@ -78,6 +166,7 @@ class MenuLinkSourceTest extends MigrateSqlSourceTestCase { 'p8' => '0', 'p9' => '0', 'updated' => '0', + 'description' => 'Test menu link 2', ), ); @@ -85,10 +174,47 @@ class MenuLinkSourceTest extends MigrateSqlSourceTestCase { * {@inheritdoc} */ public function setUp() { - foreach ($this->expectedResults as $k => $row) { + $this->databaseContents['menu_links'] = $this->expectedResults; + + // Add long link title attributes. + $title = $this->getRandomGenerator()->string('500'); + $this->databaseContents['menu_links'][0]['options']['attributes']['title'] = $title; + $this->expectedResults[0]['description'] = Unicode::truncate($title, 255); + + // D6 menu link to a custom menu, provided by menu module. + $this->databaseContents['menu_links'][] = [ + 'menu_name' => 'menu-user', + 'mlid' => 143, + 'plid' => 0, + 'link_path' => 'admin/build/menu-customize/navigation', + 'router_path' => 'admin/build/menu-customize/%', + 'link_title' => 'Navigation', + 'options' => array(), + 'module' => 'menu', + 'hidden' => 0, + 'external' => 0, + 'has_children' => 0, + 'expanded' => 0, + 'weight' => 0, + 'depth' => 0, + 'customized' => 0, + 'p1' => '0', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', + 'description' => '', + ]; + + array_walk($this->databaseContents['menu_links'], function (&$row) { $row['options'] = serialize($row['options']); - $this->databaseContents['menu_links'][$k] = $row; - } + }); + parent::setUp(); } diff --git a/core/modules/migrate/src/Entity/Migration.php b/core/modules/migrate/src/Entity/Migration.php index 8209d9b7196d867bfcf9538c0f4229ae4537a3e0..9e509f486da3a1ee09e3877a01f4c96536fc87e6 100644 --- a/core/modules/migrate/src/Entity/Migration.php +++ b/core/modules/migrate/src/Entity/Migration.php @@ -320,10 +320,10 @@ protected function getProcessNormalized(array $process) { * {@inheritdoc} */ public function getDestinationPlugin($stub_being_requested = FALSE) { + if ($stub_being_requested && !empty($this->destination['no_stub'])) { + throw new MigrateSkipRowException; + } if (!isset($this->destinationPlugin)) { - if ($stub_being_requested && !empty($this->destination['no_stub'])) { - throw new MigrateSkipRowException; - } $this->destinationPlugin = \Drupal::service('plugin.manager.migrate.destination')->createInstance($this->destination['plugin'], $this->destination, $this); } return $this->destinationPlugin; diff --git a/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php b/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php new file mode 100644 index 0000000000000000000000000000000000000000..78fbd14a5619b14a8b91b66179dc44775331992e --- /dev/null +++ b/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php @@ -0,0 +1,109 @@ +migrationPlugin = $migration_plugin; + $this->menuLinkManager = $menu_link_manager; + $this->menuLinkStorage = $menu_link_storage; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) { + $migration_configuration['migration'][] = $migration->id(); + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.migrate.process')->createInstance('migration', $migration_configuration, $migration), + $container->get('plugin.manager.menu.link'), + $container->get('entity.manager')->getStorage('menu_link_content') + ); + } + + /** + * {@inheritdoc} + * + * Find the parent link GUID. + */ + public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { + $parent_id = array_shift($value); + if (!$parent_id) { + // Top level item. + return ''; + } + try { + $already_migrated_id = $this + ->migrationPlugin + ->transform($parent_id, $migrate_executable, $row, $destination_property); + if ($already_migrated_id && ($link = $this->menuLinkStorage->load($already_migrated_id))) { + return $link->getPluginId(); + } + } + catch (MigrateSkipRowException $e) { + + } + if (isset($value[1])) { + list($menu_name, $parent_link_path) = $value; + $url = Url::fromUserInput("/$parent_link_path"); + if ($url->isRouted()) { + $links = $this->menuLinkManager->loadLinksByRoute($url->getRouteName(), $url->getRouteParameters(), $menu_name); + if (count($links) == 1) { + /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ + $link = reset($links); + return $link->getPluginId(); + } + } + } + throw new MigrateSkipRowException; + } + +} diff --git a/core/modules/migrate_drupal/tests/fixtures/drupal7.php b/core/modules/migrate_drupal/tests/fixtures/drupal7.php index ef7e2bfc643eb1379766a61075207ce9ffb8553f..0e94e8f9bac7ced150959680f10ef1a03547303a 100644 --- a/core/modules/migrate_drupal/tests/fixtures/drupal7.php +++ b/core/modules/migrate_drupal/tests/fixtures/drupal7.php @@ -18871,7 +18871,7 @@ ->values(array( 'menu_name' => 'menu-test-menu', 'mlid' => '467', - 'plid' => '0', + 'plid' => '469', 'link_path' => 'http://google.com', 'router_path' => '', 'link_title' => 'Google', @@ -18882,10 +18882,10 @@ 'has_children' => '0', 'expanded' => '0', 'weight' => '0', - 'depth' => '1', + 'depth' => '2', 'customized' => '1', - 'p1' => '467', - 'p2' => '0', + 'p1' => '469', + 'p2' => '467', 'p3' => '0', 'p4' => '0', 'p5' => '0', @@ -19057,6 +19057,33 @@ 'p9' => '0', 'updated' => '0', )) +->values(array( + 'menu_name' => 'management', + 'mlid' => '478', + 'plid' => '20', + 'link_path' => 'admin/content/book', + 'router_path' => 'admin/content/book', + 'link_title' => 'custom link test', + 'options' => 'a:1:{s:10:"attributes";a:1:{s:5:"title";s:0:"";}}', + 'module' => 'menu', + 'hidden' => '0', + 'external' => '0', + 'has_children' => '0', + 'expanded' => '0', + 'weight' => '0', + 'depth' => '3', + 'customized' => '1', + 'p1' => '1', + 'p2' => '20', + 'p3' => '478', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', +)) ->execute(); $connection->schema()->createTable('menu_router', array( diff --git a/core/modules/shortcut/migration_templates/d7_shortcut.yml b/core/modules/shortcut/migration_templates/d7_shortcut.yml index da3d894940ff526a90fbf75eaacf1c4326f51174..ba986eb85300b695414eaac9cc7dc1e176455894 100644 --- a/core/modules/shortcut/migration_templates/d7_shortcut.yml +++ b/core/modules/shortcut/migration_templates/d7_shortcut.yml @@ -23,4 +23,4 @@ destination: migration_dependencies: required: - d7_shortcut_set - - d7_menu_links + - menu_links diff --git a/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetTest.php b/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetTest.php index a1fb995c920f2ecf7263e0b1500dda0f47e75b9a..ff2cd8f0667d2d9c1165f0c43994a8811941eca4 100644 --- a/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetTest.php +++ b/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetTest.php @@ -38,9 +38,10 @@ protected function setUp() { $this->installSchema('system', array('router')); $this->installEntitySchema('shortcut'); $this->installEntitySchema('menu_link_content'); + \Drupal::service('router.builder')->rebuild(); $this->executeMigration('d7_shortcut_set'); $this->executeMigration('menu'); - $this->executeMigration('d7_menu_links'); + $this->executeMigration('menu_links'); $this->executeMigration('d7_shortcut'); } diff --git a/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetUsersTest.php b/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetUsersTest.php index c6d4530f1c6298c4f2fb2967f922b6dbae416360..ed63ac031f6519059d5f72ac7865d351f18b5fad 100644 --- a/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetUsersTest.php +++ b/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutSetUsersTest.php @@ -38,11 +38,12 @@ protected function setUp() { $this->installEntitySchema('shortcut'); $this->installEntitySchema('menu_link_content'); $this->installSchema('shortcut', ['shortcut_set_users']); + \Drupal::service('router.builder')->rebuild(); $this->executeMigration('d7_user_role'); $this->executeMigration('d7_user'); $this->executeMigration('d7_shortcut_set'); $this->executeMigration('menu'); - $this->executeMigration('d7_menu_links'); + $this->executeMigration('menu_links'); $this->executeMigration('d7_shortcut'); $this->executeMigration('d7_shortcut_set_users'); } diff --git a/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutTest.php b/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutTest.php index 8bf10ee0909dca1b6e4ea0d5b657263fa302c483..0d333fe5bfc15a94574cafbb4cf913666b86f997 100644 --- a/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutTest.php +++ b/core/modules/shortcut/src/Tests/Migrate/d7/MigrateShortcutTest.php @@ -38,9 +38,10 @@ protected function setUp() { $this->installSchema('system', array('router')); $this->installEntitySchema('shortcut'); $this->installEntitySchema('menu_link_content'); + \Drupal::service('router.builder')->rebuild(); $this->executeMigration('d7_shortcut_set'); $this->executeMigration('menu'); - $this->executeMigration('d7_menu_links'); + $this->executeMigration('menu_links'); $this->executeMigration('d7_shortcut'); }