Deployment appear to fail often for me do to an error like, "Illegal choice primary-links:2867 in Parent item element." - I've garnered some theories why it's happening only for certain nodes.

1. the node's parent isn't a node, rather a just a menu link
2. the node's parent has been imported yet, so it can't establish a connection.
3. the node's parent doesn't exist

Are any of these valid?

CommentFileSizeAuthor
#5 menu_parent_deploy.tar_.gz936 byteslongwave

Comments

gdd’s picture

Any of these could possibly be correct. I do not support the menu system at all, so #1 would definitely break things. #2 and #3 would also break things, buit should be handleable. I've been away from the module for a while but I hope to pick up some development again soon and this is high on the list.

waverate’s picture

I have the same issues. The error show up on the destination server log as type form, severity error, and message Illegal choice menu-name:243 in Parent item element.

I created two new sites to try out the above theories and I have the same results consistent with the parent item not existing:

- if a node is part of a menu on the source server, the menu must be created on the destination server in order for the node to be deployed, and
- if a node is part of a secondary menu item on the source server, the primary menu item must be created on the destination server for the node to be created.

Q1. Why are the menus not able to be copied like other types?

Q2. Can the node be copied anyway and the parent item just be ignored until there is a better solution?

The workaround for the moment is to create the parent items on the destination server prior to deploying from the source server.

waverate’s picture

Small update.

It looks like if you enable the Menu Service (under Services - services) on the destination server the menu will be populated. However, if the menu is not one of the existing menus (navigation, primary-links, secondary-links), you will have to create it on the destination server before deployment.

brad.bulger’s picture

what i seem to be seeing is that the mlid values are different on the destination server from the source server. not to mention the node IDs changing. so if a node's parent item in a menu is another node, the menu value can end up either illegal or just silently wrong.

longwave’s picture

Status: Active » Needs review
StatusFileSize
new936 bytes

The attached module fixes the issues brad describes in #4, by using the menu and node services to discover the correct remote parent item to select when deploying nodes.

This code could be included directly in node_deploy.module but it was easier to keep it separate during development. It may also require the patch from #740836-7: menu_service: menu.get language argument if you are sending menu items in multiple languages, depending on your i18n configuration.

This still has issues when sending over new parent and child nodes as part of the same deployment; if the child nodes are sent first, obviously the parents don't yet exist, so the lookup fails and the items are incorrectly parented. However, this seems difficult to solve fully, especially if you are sending a large menu tree with more than two levels of parent/child items in a single plan - the plan item weight system can't easily cope with this level of complexity, especially if some of those nodes have further dependencies on other nodes. There are seemingly impossible chicken-and-egg corner cases if a parent menu item has a nodereference field to a child menu item, for example.

This development was sponsored by Opsview.

brad.bulger’s picture

i ended up writing a hook_node_deploy_check() function and my own service to get the menu_links record for the parent, and then do requirement checking. the "remove from plan" function in the patch to #766806: Weight between items will break deployment if dependencies are added by hand in wrong order was really useful here, because rather than automatically adding things to the plan, i kick the node out of the plan if the requirements aren't met (the parent menu item has to exist and be enabled, and if the parent is a node, that parent node has to have been deployed and be published on the destination server).

the code that fixes the parent mlid to match the value on the destination server is more or less like what you are doing.

i don't know how much of that would work as a general purpose approach. as you say, the potential complexities can get pretty gnarly.

longwave’s picture

Hmmm, I didn't see that issue before, which is slightly neater than my approach I think, and could be generalised to further dependency cases it seems. It would likely need some protection against circular dependencies though, otherwise I can see deploy getting stuck in an infinite loop, constantly trying to rearrange dependencies before each other.

dixon_’s picture

Status: Needs review » Needs work

What we could do here is to handle the cases where the menu parent is actually a node. Everything else would be quite tough to solve for Deploy at this stage I think.

I will think some more on what's the best approach for this.

dixon_’s picture

To help version 6.x-1.x move forward, please see this issue: #526936: Find best way to proceeding with 6.x-1.x and more specifically this comment: http://drupal.org/node/526936#comment-4931548

kenorb’s picture

As posted in #5:

/**
 * @file
 * Deployment API which enables modules to deploy items between servers.
 *
 * This module manages deployment-related issues regarding menu items
 * and their parents.
 */

/**
 * Implementation of hook_node_deploy(),
 *
 * @param $node
 *   The node we're deploying.
 */
function menu_parent_deploy_node_deploy($node) {
  $item = menu_link_load($node->menu['mlid']);
  if (!empty($item['plid'])) {
    $menu_name = $item['menu_name'];

    // Find the path to the parent item.
    $item = menu_link_load($item['plid']);
    $path = $item['link_path'];

    // If the parent is a node, find the remote node ID and look for the
    // link in the remote menu.
    if (substr($path, 0, 5) == 'node/') {
      $parent_node = node_load(substr($path, 5));
      $remote_key = deploy_get_remote_key($parent_node->uuid, 'node');
      if (isset($remote_key['nid'])) {
        $path = 'node/' . $remote_key['nid'];
      }
    }

    $menu = deploy_send(array('menu.get'), array($menu_name, array('mlid', 'link_path'), $node->language));
    if ($remote_mlid = menu_parent_deploy_find_item($menu, $path)) {
      $node->menu['parent'] = $menu_name . ':' . $remote_mlid;
    }
    else {
      watchdog('deploy', 'not found parent for '.$path);
    }
  }
}

function menu_parent_deploy_find_item($menu, $path) {
  // Search the current level for the path.
  foreach ($menu as $item) {
    if ($item['link_path'] == $path) {
      return $item['mlid'];
    }

    // Search any children.
    if (!empty($item['children'])) {
      if ($mlid = menu_parent_deploy_find_item(&$item['children'], $path)) {
        return $mlid;
      }
    }
  }
}
kenorb’s picture

Created sandbox module for the fixes:
https://drupal.org/sandbox/kenorb/2108059

kenorb’s picture

Priority: Normal » Minor
Issue summary: View changes