diff --git a/includes/batch.inc b/includes/batch.inc index 16a5326caed59496cb19053ad27d513a5ac4f425..3f93bcbbcea4d5c48ab5fdd4e51be5e5ff7c46b4 100644 --- a/includes/batch.inc +++ b/includes/batch.inc @@ -22,13 +22,14 @@ function _batch_page() { register_shutdown_function('_batch_shutdown'); $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : ''; + $output = NULL; switch ($op) { case 'start': $output = _batch_start(); break; case 'do': - $output = _batch_do(); + _batch_do(); break; case 'do_nojs': @@ -97,9 +98,7 @@ function _batch_do() { list($percentage, $message) = _batch_process(); - drupal_set_header('Content-Type: text/plain; charset=utf-8'); - print drupal_to_js(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message)); - exit(); + drupal_json(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message)); } /** @@ -159,6 +158,10 @@ function _batch_process() { $batch =& batch_get(); $current_set =& _batch_current_set(); + if ($batch['progressive']) { + timer_start('batch_processing'); + } + while (!$current_set['success']) { $finished = 1; $task_message = ''; @@ -169,33 +172,51 @@ function _batch_process() { } if ($finished == 1) { - // Make sure this step isn't counted double. + // Make sure this step isn't counted double when computing $current. $finished = 0; - // Remove the operation, and clear the sandbox to reduce the stored data. + // Remove the operation and clear the sandbox. array_shift($current_set['operations']); $current_set['sandbox'] = array(); } - // Make sure we display progress information about a batch set that - // actually has operations, and not about a 'control' set (form submit - // handler). - $remaining = count($current_set['operations']); - $progress_message = $current_set['progress_message']; - $total = $current_set['total']; - - // If the batch set is completed, browse through the remaining sets - // until we find one that actually has operations. + // If the batch set is completed, browse through the remaining sets, + // executing 'control sets' (stored submit handlers) along the way - this + // might in turn insert new batch sets. Stop when we find a set that + // actually has operations. + $set_changed = FALSE; + $old_set = $current_set; while (empty($current_set['operations']) && ($current_set['success'] = TRUE) && _batch_next_set()) { $current_set =& _batch_current_set(); + $set_changed = TRUE; } + // At this point, either $current_set is a 'real' batch set (has operations), + // or all sets have been completed. - // Progressive mode : stop after 1 second - if ($batch['progressive'] && timer_read('page') > 1000) { + // Progressive mode : stop after 1 second. + if ($batch['progressive'] && timer_read('batch_processing') > 1000) { break; } } if ($batch['progressive']) { + // Gather progress information. + + // Reporting 100% progress will cause the whole batch to be considered + // processed. If processing was paused right after moving to a new set, + // we have to use the info from the new one. + if ($set_changed && isset($current_set['operations'])) { + // Processing will continue with a fresh batch set. + $remaining = count($current_set['operations']); + $total = $current_set['total']; + $progress_message = $current_set['init_message']; + $task_message = ''; + } + else { + $remaining = count($old_set['operations']); + $total = $old_set['total']; + $progress_message = $old_set['progress_message']; + } + $current = $total - $remaining + $finished; $percentage = $total ? floor($current / $total * 100) : 100; $values = array( @@ -258,7 +279,9 @@ function _batch_finished() { } // Cleanup the batch table and unset the global $batch variable. - db_query("DELETE FROM {batch} WHERE bid = %d", $batch['id']); + if ($batch['progressive']) { + db_query("DELETE FROM {batch} WHERE bid = %d", $batch['id']); + } $_batch = $batch; $batch = NULL; diff --git a/includes/form.inc b/includes/form.inc index 92d4fe4016a9beeeb728f9c5b7f3c8df6f4b9178..865c1fecdee887e57b7658a789d2e83b87e888f1 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -1398,6 +1398,8 @@ function expand_date($element) { $options = drupal_map_assoc(range(1900, 2050)); break; } + $parents = $element['#parents']; + $parents[] = $type; $element[$type] = array( '#type' => 'select', '#value' => $element['#value'][$type], @@ -2027,7 +2029,7 @@ function batch_set($batch_definition) { * isses a drupal_goto and thus ends page execution. * * This function is not needed in form submit handlers; Form API takes care - * of batches issued during form submission. + * of batches that were set during form submission. * * @param $redirect * (optional) Path to redirect to when the batch has finished processing. @@ -2040,7 +2042,6 @@ function batch_process($redirect = NULL, $url = NULL) { if (isset($batch)) { // Add process information - $t = get_t(); $url = isset($url) ? $url : 'batch'; $process_info = array( 'current_set' => 0, @@ -2048,13 +2049,13 @@ function batch_process($redirect = NULL, $url = NULL) { 'url' => isset($url) ? $url : 'batch', 'source_page' => $_GET['q'], 'redirect' => $redirect, - 'error_message' => $t('Please continue to <a href="@error_url">the error page</a>', array('@error_url' => url($url, array('query' => array('id' => $batch['id'], 'op' => 'error'))))), ); $batch += $process_info; if ($batch['progressive']) { - // Save and unset the destination if any. drupal_goto looks for redirection - // in $_REQUEST['destination'] and $_REQUEST['edit']['destination']. + // Clear the way for the drupal_goto redirection to the batch processing + // page, by saving and unsetting the 'destination' if any, on both places + // drupal_goto looks for it. if (isset($_REQUEST['destination'])) { $batch['destination'] = $_REQUEST['destination']; unset($_REQUEST['destination']); @@ -2063,9 +2064,20 @@ function batch_process($redirect = NULL, $url = NULL) { $batch['destination'] = $_REQUEST['edit']['destination']; unset($_REQUEST['edit']['destination']); } - db_query('INSERT INTO {batch} (timestamp) VALUES (%d)', time()); + + // Initiate db storage in order to get a batch id. We have to provide + // at least an empty string for the (not null) 'token' column. + db_query("INSERT INTO {batch} (token, timestamp) VALUES ('', %d)", time()); $batch['id'] = db_last_insert_id('batch', 'bid'); + + // Now that we have a batch id, we can generate the redirection link in + // the generic error message. + $t = get_t(); + $batch['error_message'] = $t('Please continue to <a href="@error_url">the error page</a>', array('@error_url' => url($url, array('query' => array('id' => $batch['id'], 'op' => 'finished'))))); + + // Actually store the batch data and the token generated form the batch id. db_query("UPDATE {batch} SET token = '%s', batch = '%s' WHERE bid = %d", drupal_get_token($batch['id']), serialize($batch), $batch['id']); + drupal_goto($batch['url'], 'op=start&id='. $batch['id']); } else { diff --git a/modules/system/system.module b/modules/system/system.module index 59a13ee1d3ab48c9d6c42e999283e2f664535b03..0ebaaea517b107b10d195d44ab184f09c4b82adf 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -2808,7 +2808,7 @@ function system_batch_page() { if ($output === FALSE) { drupal_access_denied(); } - else { + elseif (isset($output)) { // Force a page without blocks or messages to // display a list of collected messages later. print theme('page', $output, FALSE, FALSE);