Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.431
diff -u -r1.431 menu.inc
--- includes/menu.inc	4 Jan 2011 06:20:30 -0000	1.431
+++ includes/menu.inc	20 Jan 2011 18:32:15 -0000
@@ -2488,6 +2488,51 @@
 }
 
 /**
+ * Load multiple menu links, access checked and link translated for rendering.
+ *
+ * This function should never be called from within node_load() or any other
+ * function used as a menu object load function since an infinite recursion may
+ * occur.
+ *
+ * @param $mlids
+ *   An array of menu link IDs.
+ * @param $conditions
+ *   An associative array of conditions on the {menu_links}
+ *   table, where the keys are the database fields and the values are the
+ *   values those fields must have.
+ *
+ * @return
+ *   An array of menu links indexed by mlid.
+ *
+ * @see menu_link_load()
+ */
+function menu_link_load_multiple(array $mlids, array $conditions = array()) {
+  $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
+  $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
+  $query->fields('ml');
+  // Weight should be taken from {menu_links}, not {menu_router}.
+  $query->addField('ml', 'weight', 'link_weight');
+  $query->fields('m');
+
+  if (!empty($mlids)) {
+    $query->condition('ml.mlid', $mlids, 'IN');
+  }
+  if (!empty($conditions)) {
+    foreach ($conditions as $field => $value) {
+      $query->condition('ml.' . $field, $value);
+    }
+  }
+
+  $items = array();
+  foreach ($query->execute() as $item) {
+    $item['weight'] = $item['link_weight'];
+    $items[$item['mlid']] = $item;
+    _menu_link_translate($items[$item['mlid']]);
+  }
+  return $items;
+}
+
+/**
  * Get a menu link by its mlid, access checked and link translated for rendering.
  *
  * This function should never be called from within node_load() or any other
@@ -2503,18 +2548,7 @@
  */
 function menu_link_load($mlid) {
   if (is_numeric($mlid)) {
-    $query = db_select('menu_links', 'ml');
-    $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
-    $query->fields('ml');
-    // Weight should be taken from {menu_links}, not {menu_router}.
-    $query->addField('ml', 'weight', 'link_weight');
-    $query->fields('m');
-    $query->condition('ml.mlid', $mlid);
-    if ($item = $query->execute()->fetchAssoc()) {
-      $item['weight'] = $item['link_weight'];
-      _menu_link_translate($item);
-      return $item;
-    }
+    return reset(menu_link_load_multiple(array($mlid)));
   }
   return FALSE;
 }
@@ -2852,6 +2886,89 @@
 }
 
 /**
+ * Delete multiple menu links.
+ *
+ * @param $mlids
+ *   An array of menu link IDs.
+ * @param $force
+ *   Forces deletion. Internal use only, setting to TRUE is discouraged.
+ *
+ * @see menu_link_delete()
+ */
+function menu_link_delete_multiple(array $mlids, $force = FALSE) {
+  if (!empty($mlids)) {
+    $query = db_select('menu_links')
+      ->fields('menu_links')
+      ->condition('mlid', $mlids, 'IN');
+    if (!$force) {
+      // Exclude links belonging to system module except if they are marked
+      // updated (generated during update from Drupal 5).
+      $query->condition(db_or()->condition('module', 'system', '<>')->condition('updated', 0, '<>'));
+    }
+    $links_to_delete = $query->execute()->fetchAllAssoc('mlid', PDO::FETCH_ASSOC);
+
+    if (!empty($links_to_delete)) {
+      $links_with_children = array();
+      $parent_mlids = array();
+      $affected_menus = array();
+      foreach ($links_to_delete as $item) {
+        if ($item['has_children']) {
+          $links_with_children[$item['mlid']] = $item['mlid'];
+        }
+        $parent_mlids[$item['plid']] = $item['plid'];
+        $affected_menus[$item['menu_name']] = $item['menu_name'];
+      }
+      $parent_mlids = array_diff_key($parent_mlids, array(0 => 0) + array_keys($links_to_delete));
+
+      // Re-parent any children to it's closest parent that is not deleted.
+      if (!empty($links_with_children)) {
+        $children = menu_link_load_multiple(array(), array('plid' => $links_with_children));
+        foreach ($children as $item) {
+          while (isset($links_to_delete[$item['plid']])) {
+            $item['plid'] = $links_to_delete[$item['plid']]['plid'];
+          }
+          menu_link_save($item);
+        }
+      }
+
+      db_delete('menu_links')->condition('mlid', array_keys($links_to_delete), 'IN')->execute();
+
+      foreach ($links_to_delete as $item) {
+        // Notify modules we have deleted the item.
+        module_invoke_all('menu_link_delete', $item);
+
+        // Update the has_children status of the parent.
+        //_menu_update_parental_status($item);
+      }
+
+      // Update the has_children status of parents of deleted links.
+      // @todo fix query und use this instead of _menu_update_parental_status($item);
+      if (!empty($parent_mlids)) {
+        $exists_query = db_select('menu_links', 'child')
+          ->fields('child', array('mlid'))
+          ->condition('child.hidden', 0)
+          ->where('child.plid = menu_links.mlid')
+          ->where('child.menu_name = menu_links.menu_name')
+          ->range(0, 1);
+
+        db_update('menu_links')
+          ->fields(array('has_children' => 0))
+          ->condition('has_children', 1)
+          ->condition('mlid', $parent_mlids, 'IN')
+          ->notExists($exists_query)
+          ->execute();
+      }
+
+      // Clear caches.
+      foreach ($affected_menus as $menu_name) {
+        menu_cache_clear($menu_name);
+      }
+      _menu_clear_page_cache();
+    }
+  }
+}
+
+/**
  * Delete one or several menu links.
  *
  * @param $mlid
@@ -2861,13 +2978,11 @@
  */
 function menu_link_delete($mlid, $path = NULL) {
   if (isset($mlid)) {
-    _menu_delete_item(db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $mlid))->fetchAssoc());
+    menu_link_delete_multiple(array($mlid));
   }
   else {
-    $result = db_query("SELECT * FROM {menu_links} WHERE link_path = :link_path", array(':link_path' => $path));
-    foreach ($result as $link) {
-      _menu_delete_item($link);
-    }
+    $mlids = db_query("SELECT mlid FROM {menu_links} WHERE link_path = :link_path", array(':link_path' => $path))->fetchCol();
+    menu_link_delete_multiple(array($mlids));
   }
 }
 
