function _menu_navigation_links_rebuild

Builds menu links for the items in the menu router.

@todo This function should be removed/refactored.

Related topics

1 call to _menu_navigation_links_rebuild()
menu_router_rebuild in drupal/core/includes/menu.inc
Populates the database tables used by various menu functions.

File

drupal/core/includes/menu.inc, line 2805
API for the Drupal menu system.

Code

function _menu_navigation_links_rebuild($menu) {
  if (module_exists('menu_link')) {
    $menu_link_controller = Drupal::entityManager()
      ->getStorageController('menu_link');
  }
  else {

    // The Menu link module is not available at install time, so we need to
    // hardcode the default storage controller.
    $menu_link_controller = new MenuLinkStorageController('menu_link', Drupal::service('database'), Drupal::service('router.route_provider'));
  }

  // Add normal and suggested items as links.
  $router_items = array();
  foreach ($menu as $path => $router_item) {
    if ($router_item['_visible']) {
      $router_items[$path] = $router_item;
      $sort[$path] = $router_item['_number_parts'];
    }
  }
  if ($router_items) {

    // Keep an array of processed menu links, to allow
    // Drupal\menu_link\MenuLinkStorageController::save() to check this for
    // parents instead of querying the database.
    $parent_candidates = array();

    // Make sure no child comes before its parent.
    array_multisort($sort, SORT_NUMERIC, $router_items);
    foreach ($router_items as $key => $router_item) {

      // For performance reasons, do a straight query now and convert to a menu
      // link entity later.
      // @todo revisit before release.
      $existing_item = db_select('menu_links')
        ->fields('menu_links')
        ->condition('link_path', $router_item['path'])
        ->condition('module', 'system')
        ->execute()
        ->fetchAll();
      if ($existing_item) {
        $existing_item = reset($existing_item);
        $existing_item->options = unserialize($existing_item->options);
        $router_item['mlid'] = $existing_item->mlid;
        $router_item['uuid'] = $existing_item->uuid;

        // A change in hook_menu may move the link to a different menu
        if (empty($router_item['menu_name']) || $router_item['menu_name'] == $existing_item->menu_name) {
          $router_item['menu_name'] = $existing_item->menu_name;
          $router_item['plid'] = $existing_item->plid;
        }
        else {

          // It moved to a new menu.
          // Let Drupal\menu_link\MenuLinkStorageController::save() try to find
          // a new parent based on the path.
          unset($router_item['plid']);
        }
        $router_item['has_children'] = $existing_item->has_children;
        $router_item['updated'] = $existing_item->updated;

        // Convert the existing item to a typed object.
        $existing_item = $menu_link_controller
          ->create(get_object_vars($existing_item));
      }
      else {
        $existing_item = NULL;
      }
      if ($existing_item && $existing_item->customized) {
        $parent_candidates[$existing_item->mlid] = $existing_item;
      }
      else {
        $menu_link = MenuLink::buildFromRouterItem($router_item);
        $menu_link->original = $existing_item;
        $menu_link->parentCandidates = $parent_candidates;
        $menu_link_controller
          ->save($menu_link);
        $parent_candidates[$menu_link
          ->id()] = $menu_link;
        unset($router_items[$key]);
      }
    }
  }
  $paths = array_keys($menu);

  // Updated and customized items whose router paths are gone need new ones.
  $menu_links = $menu_link_controller
    ->loadUpdatedCustomized($paths);
  foreach ($menu_links as $menu_link) {
    $router_path = _menu_find_router_path($menu_link->link_path);
    if (!empty($router_path) && ($router_path != $menu_link->router_path || $menu_link->updated)) {

      // If the router path and the link path matches, it's surely a working
      // item, so we clear the updated flag.
      $updated = $menu_link->updated && $router_path != $menu_link->link_path;
      $menu_link->router_path = $router_path;
      $menu_link->updated = (int) $updated;
      $menu_link_controller
        ->save($menu_link);
    }
  }

  // Find any item whose router path does not exist any more.
  $query = Drupal::entityQuery('menu_link')
    ->condition('router_path', $paths, 'NOT IN')
    ->condition('external', 0)
    ->condition('updated', 0)
    ->condition('customized', 0)
    ->sort('depth', 'DESC');
  $result = $query
    ->execute();

  // Remove all such items. Starting from those with the greatest depth will
  // minimize the amount of re-parenting done by the menu link controller.
  if (!empty($result)) {
    menu_link_delete_multiple($result, TRUE);
  }
}