diff --git a/core/includes/menu.inc b/core/includes/menu.inc index f23eb0d..a5e6c8e 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -3677,42 +3677,10 @@ function _menu_router_build($callbacks) { * Helper function to save data from menu_router_build() to the router table. */ function _menu_router_save($menu, $masks) { - // Delete the existing router since we have some data to replace it. - db_truncate('menu_router')->execute(); - - // Prepare insert object. - $insert = db_insert('menu_router') - ->fields(array( - 'path', - 'load_functions', - 'to_arg_functions', - 'access_callback', - 'access_arguments', - 'page_callback', - 'page_arguments', - 'delivery_callback', - 'fit', - 'number_parts', - 'context', - 'tab_parent', - 'tab_root', - 'title', - 'title_callback', - 'title_arguments', - 'theme_callback', - 'theme_arguments', - 'type', - 'description', - 'position', - 'weight', - 'include_file', - )); - - $num_records = 0; + // rewrite some field values foreach ($menu as $path => $item) { - // Fill in insert object values. - $insert->values(array( + $menu[$path] = array( 'path' => $item['path'], 'load_functions' => $item['load_functions'], 'to_arg_functions' => $item['to_arg_functions'], @@ -3736,17 +3704,105 @@ function _menu_router_save($menu, $masks) { 'position' => $item['position'], 'weight' => $item['weight'], 'include_file' => $item['include file'], - )); + ); + } + + // Determine the diff of new and old table contents. + $delete = array(); + $update = array(); + $insert = $menu; - // Execute in batches to avoid the memory overhead of all of those records - // in the query object. - if (++$num_records == 20) { - $insert->execute(); - $num_records = 0; + $query = db_query('SELECT * FROM {menu_router}'); + + while ($row_old = $query->fetchAssoc()) { + $path = $row_old['path']; + if (!isset($menu[$path])) { + $delete[$path] = TRUE; + } + else { + // Compare the old row with the new row. + $row_changes = array(); + foreach ($row_old as $key => $value_old) { + if ($menu[$path][$key] != $value_old) { + $row_changes[$key] = $menu[$path][$key]; + } + } + if (count($row_changes)) { + $update[$path] = $row_changes; + } + } + unset($insert[$path]); + } + + // Save the changes. + + // Delete router items that no longer exist. + if ($delete) { + db_delete('menu_router') + ->condition('path', array_keys($delete)) + ->execute(); + } + + // Update router items that have changed. + if ($update) { + foreach ($update as $path => $row_changes) { + db_update('menu_router') + ->fields($row_changes) + ->condition('path', $path) + ->execute(); } } - // Insert any remaining records. - $insert->execute(); + + // Insert new router items, in chunks of 20. + if ($insert) { + + // Prepare the insert object. + $query = db_insert('menu_router') + ->fields(array( + 'path', + 'load_functions', + 'to_arg_functions', + 'access_callback', + 'access_arguments', + 'page_callback', + 'page_arguments', + 'delivery_callback', + 'fit', + 'number_parts', + 'context', + 'tab_parent', + 'tab_root', + 'title', + 'title_callback', + 'title_arguments', + 'theme_callback', + 'theme_arguments', + 'type', + 'description', + 'position', + 'weight', + 'include_file', + )); + + $num_records = 0; + + foreach ($insert as $path => $item) { + + // Fill in insert object values. + $query->values($item); + + // Execute in batches, to avoid the memory overhead of all of those + // records in the query object. + if (++$num_records == 20) { + $query->execute(); + $num_records = 0; + } + } + + // Insert any remaining records. + $query->execute(); + } + // Store the masks. variable_set('menu_masks', $masks);