0

I am migrating nodes from D7 to D8. For various reasons I am writing my own code to do this. The migration will run on a couple dozen different sites so the solution needs to be as generic as possible. I have implemented a custom RestAPI to do this. Part of the process is to transfer (custom) menu items.

In a menu with multiple levels, I have to check if all of the parents exist before I create the actual menu item being migrated. Assume you have a menu tree with three levels

Main Menu -> Level 1 -> Level 2 -> Menu 1 Item being Migrated.

I am migrating the node that will be linked to Menu 1 Item being Migrated. If Level 2 does not exist on the Drupal 8 site, I have to create this 'parent' menu, before adding Menu Item being Migrated.

This part was easy. The problem is, when I process the next node (and its menu item), say:

Main Menu -> Level 1 -> Level 2 -> Menu 2 Item being Migrated

Then Level 2 should now exist - I created it during the first call. However, when I try to load Level 2 - it is not found, so the code ends up creating Level 2 again.

This is the code that creates the parent menu item:

    $title = (trim($menu['title']) !== '') ? $menu['title'] : $menu['link_title'];
    $menuStorage = \Drupal::entityTypeManager()
      ->getStorage('menu_link_content');
    $menuItem = $menuStorage->loadByProperties(['title' => $title, 'menu_name' => self::MAIN_MENU]);
    if (is_array($menuItem) && !empty($menuItem)) {
      $menuItem = array_pop($menuItem);
    }

    if (!$menuItem) {
      $data = [
        'title'    => $title,
        'link'     => 'internal:' . $this->fixPath($menu['link_path']),
        'expanded' => $menu['expanded'],
      ];

      if (!$parent) {
        $data['menu'] = self::MAIN_MENU;
      }
      else {
        $data['parent'] = $parent->getPluginId();
      }

      $menuItem = $menuStorage->create($data);
      $menuItem->save();
    }

    return $menuItem;
  }

On the second pass, the second node / menu item being created, this line of code returns an empty array

$menuItem = $menuStorage->loadByProperties(['title' => $title, 'menu_name' => self::MAIN_MENU]);

So basically the menu item I created during the first pass, was not found.

What makes this strange is that if I execute the code once and then load the menu in the admin area (admin/structure/menu/manage/main)- I can see it was created - so its not a caching thing, and its not about rebuilding the menu-tree (I tried various ways of rebuilding the menu tree before calling loadByProperties

I even tried clearing all caches from the admin area between the two calls: I am fairly sure its not a caching thing - its just that the menu is not found.

It is worth pointing out that if Level 2 exists before I start migrating the nodes, it finds Level 2 every time and the menu gets created correctly.

Main Menu
  Level 2
    Menu 1 Item being Migrated
    Menu 2 Item being Migrated

If Level 2 does not exist at the onset of the migration, I land up with:

Main Menu
  Level 2
    Menu 1 Item being Migrated
  Level 2
    Menu 2 Item being Migrated

Needless to say I am frustrated and fresh out of ideals so any hints or pointers would be great.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.