diff --git a/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php b/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php index 5716790cd7dd15e463238f4278d18ccd25ac5106..a9a98f5c71e6f06f7b1d029151a6ea2f540e3a05 100644 --- a/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php +++ b/core/modules/migrate/src/Plugin/migrate/process/MenuLinkParent.php @@ -36,7 +36,12 @@ * - parent_link_path: The Drupal path or external URL the parent of this menu * link points to. * - * Example: + * There is one configuration option: + * - lookup_migrations: (optional) An array of migration IDs. If missing or + * null, then the current migration is used to look up parent_id. If provided, + * then use just the listed migrations for that look-up. + * + * Examples: * * @code * process: @@ -52,6 +57,35 @@ * combination of a menu name (e.g., 'management') and a parent menu link path * (e.g., 'admin/structure'). * + * @code + * process: + * parent: + * plugin: menu_link_parent + * source: + * - plid + * - menu_name + * - parent_link_path + * lookup_migrations: [] + * @endcode + * In this example, skip the migration lookup and find the parent item using + * just the menu name and the link path. + * + * @code + * process: + * parent: + * plugin: menu_link_parent + * source: + * - plid + * - menu_name + * - parent_link_path + * lookup_migrations: + * - this_migration + * - another_migration + * @endcode + * In this example, use this_migration and another_migration (in that order) to + * look up plid. When lookup_migrations is provided, the current migration is + * not added by default. If you want to use it, then include it in the list. + * * @see https://www.drupal.org/docs/8/api/menu-api * @see \Drupal\migrate\Plugin\MigrateProcessInterface */ @@ -86,6 +120,13 @@ class MenuLinkParent extends ProcessPluginBase implements ContainerFactoryPlugin */ protected $menuLinkStorage; + /** + * The migration IDs to use for looking up the parent link. + * + * @var string[] + */ + protected array $lookupMigrations; + /** * Constructs a MenuLinkParent object. * @@ -111,6 +152,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition $this->migrateLookup = $migrate_lookup; $this->menuLinkManager = $menu_link_manager; $this->menuLinkStorage = $menu_link_storage; + $this->lookupMigrations = $this->configuration['lookup_migrations'] ?? [$this->migration->id()]; } /** @@ -141,9 +183,12 @@ public function transform($value, MigrateExecutableInterface $migrate_executable return ''; } - $lookup_result = $this->migrateLookup->lookup($this->migration->id(), [$parent_id]); - if ($lookup_result) { - $already_migrated_id = $lookup_result[0]['id']; + foreach ($this->lookupMigrations as $migration_id) { + $lookup_result = $this->migrateLookup->lookup($migration_id, [$parent_id]); + if ($lookup_result) { + $already_migrated_id = $lookup_result[0]['id']; + break; + } } if (!empty($already_migrated_id) && ($link = $this->menuLinkStorage->load($already_migrated_id))) { diff --git a/core/modules/migrate/tests/src/Unit/process/MenuLinkParentTest.php b/core/modules/migrate/tests/src/Unit/process/MenuLinkParentTest.php index bc77d09ce8f38d163d60a3bf3427dbfa4e5b6613..495d7e4f381ab11af1ed13c84cae8c5f94d4749c 100644 --- a/core/modules/migrate/tests/src/Unit/process/MenuLinkParentTest.php +++ b/core/modules/migrate/tests/src/Unit/process/MenuLinkParentTest.php @@ -79,6 +79,55 @@ protected function setUp(): void { \Drupal::setContainer($container); } + /** + * Tests that an exception is thrown for invalid options. + * + * @param array $configuration + * The plugin configuration being tested. + * @param bool $is_valid + * TRUE if the configuration is valid, FALSE if not. + * + * @dataProvider providerConstructorException + */ + public function testConstructorException(array $configuration, bool $is_valid): void { + if (!$is_valid) { + $this->expectException('TypeError'); + $this->expectExceptionMessage('Cannot assign string to property ' . MenuLinkParent::class . '::$lookupMigrations of type array'); + } + $plugin = new MenuLinkParent($configuration, 'map', [], $this->migrateLookup->reveal(), $this->menuLinkManager->reveal(), $this->menuLinkStorage->reveal(), $this->migration->reveal()); + if ($is_valid) { + $this->assertInstanceOf(MenuLinkParent::class, $plugin); + } + } + + /** + * Provides data for testConstructorException(). + */ + public static function providerConstructorException(): array { + return [ + 'default configuration is valid' => [ + 'configuration' => [], + 'is_valid' => TRUE, + ], + 'lookup_migrations = null is valid' => [ + 'configuration' => ['lookup_migrations' => NULL], + 'is_valid' => TRUE, + ], + 'bypass migration lookup is valid' => [ + 'configuration' => ['lookup_migrations' => []], + 'is_valid' => TRUE, + ], + 'a list of migrations is valid' => [ + 'configuration' => ['lookup_migrations' => ['this_migration', 'another_migration']], + 'is_valid' => TRUE, + ], + 'a single string is not valid' => [ + 'configuration' => ['lookup_migrations' => 'this_migration'], + 'is_valid' => FALSE, + ], + ]; + } + /** * Tests that an exception is thrown when the parent menu link is not found. * @@ -225,4 +274,68 @@ public function doTransform(array $source_value, $plugin_id) { return $plugin->transform($source_value, $this->migrateExecutable, $this->row, 'destination'); } + /** + * Tests the lookup_migrations option. + * + * @param int $plid + * The ID of the parent menu link. + * @param array $configuration + * The plugin configuration being tested. + * @param string $expected_result + * The expected value(s) of the migration process plugin. + * + * @dataProvider providerLookupMigrations + */ + public function testLookupMigrations(int $plid, array $configuration, string $expected_result): void { + $source_value = [$plid, 'some_menu', 'https://www.example.com']; + + $this->migration->id() + ->willReturn('this_migration'); + $this->migrateLookup->lookup('this_migration', [1]) + ->willReturn([['id' => 101]]); + $this->migrateLookup->lookup('some_migration', [2]) + ->willReturn([['id' => 202]]); + $this->migrateLookup->lookup('some_migration', [3]) + ->willReturn([]); + $this->migrateLookup->lookup('another_migration', [3]) + ->willReturn([['id' => 303]]); + + $menu_link_content_this = $this->prophesize(MenuLinkContent::class); + $menu_link_content_this->getPluginId()->willReturn('menu_link_content:this_migration'); + $this->menuLinkStorage->load(101)->willReturn($menu_link_content_this); + $menu_link_content_some = $this->prophesize(MenuLinkContent::class); + $menu_link_content_some->getPluginId()->willReturn('menu_link_content:some_migration'); + $this->menuLinkStorage->load(202)->willReturn($menu_link_content_some); + $menu_link_content_another = $this->prophesize(MenuLinkContent::class); + $menu_link_content_another->getPluginId()->willReturn('menu_link_content:another_migration'); + $this->menuLinkStorage->load(303)->willReturn($menu_link_content_another); + + $plugin = new MenuLinkParent($configuration, 'menu_link', [], $this->migrateLookup->reveal(), $this->menuLinkManager->reveal(), $this->menuLinkStorage->reveal(), $this->migration->reveal()); + $result = $plugin->transform($source_value, $this->migrateExecutable, $this->row, 'destination'); + $this->assertSame($expected_result, $result); + } + + /** + * Provides data for testLookupMigrations(). + */ + public static function providerLookupMigrations(): array { + return [ + 'default configuration' => [ + 'plid' => 1, + 'configuration' => [], + 'expected_result' => 'menu_link_content:this_migration', + ], + 'some migration' => [ + 'plid' => 2, + 'configuration' => ['lookup_migrations' => ['some_migration', 'another_migration']], + 'expected_result' => 'menu_link_content:some_migration', + ], + 'another migration' => [ + 'plid' => 3, + 'configuration' => ['lookup_migrations' => ['some_migration', 'another_migration']], + 'expected_result' => 'menu_link_content:another_migration', + ], + ]; + } + }