diff --git a/includes/menu.inc b/includes/menu.inc index 3a376f2..a9195c3 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -3590,42 +3590,41 @@ 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', - )); + // These placeholders will be used in the SQL queries. + $field_placeholders = array( + 'path' => "'%s'", + 'load_functions' => "'%s'", + 'to_arg_functions' => "'%s'", + 'access_callback' => "'%s'", + 'access_arguments' => "'%s'", + 'page_callback' => "'%s'", + 'page_arguments' => "'%s'", + 'delivery_callback' => "'%s'", // new in D7 + 'fit' => '%d', + 'number_parts' => '%d', + 'context' => "'%s'", // new in D7 + 'tab_parent' => "'%s'", + 'tab_root' => "'%s'", + 'title' => "'%s'", + 'title_callback' => "'%s'", + 'title_arguments' => "'%s'", + 'theme_callback' => "'%s'", // new in D7 + 'theme_arguments' => "'%s'", // new in D7 + 'type' => '%d', + // 'block_callback' => "'%s'", // gone in D7 + 'description' => "'%s'", + 'position' => "'%s'", + 'weight' => '%d', + // 'file' => "'%s'", // gone in D7 + 'include_file' => "'%s'", // new in D7 + ); - $num_records = 0; + $field_names = array_keys($field_placeholders); + // 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'], @@ -3649,17 +3648,83 @@ 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; + + $q = db_select('menu_router') + ->fields('menu_router') + ->execute(); - // 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; + while ($row_old = $q->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 rows that no longer exist. + if ($n_delete = count($delete)) { + db_delete('menu_router') + ->condition('path', array_keys($delete)) + ->execute(); + } + + // Update rows that have changed. + if ($n_update = count($update)) { + foreach ($update as $path => $row_changes) { + db_update('menu_router') + ->fields($row_changes) + ->condition('path', $path) + ->execute(); + } + } + + // Insert new rows, in chunks of 20. + if ($n_insert = count($insert)) { + + // Prepare insert object. + $q = db_insert('menu_router') + ->fields($field_names); + + $num_records = 0; + + foreach ($insert as $path => $item) { + + // Fill in insert object values. + $q->values($item); + + // Execute in batches to avoid the memory overhead of all of those records + // in the query object. + if (++$num_records == 20) { + $q->execute(); + $num_records = 0; + } + } + + // Insert any remaining records. + $q->execute(); } - // Insert any remaining records. - $insert->execute(); + // Store the masks. variable_set('menu_masks', $masks);