diff --git a/core/includes/batch.inc b/core/includes/batch.inc index afe2d6e..f26c73f 100644 --- a/core/includes/batch.inc +++ b/core/includes/batch.inc @@ -23,8 +23,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * Loads a batch from the database. * * @param $id - * The ID of the batch to load. When a progressive batch is being processed, - * the relevant ID is found in $_REQUEST['id']. + * The ID of the batch to load. * * @return * An array representing the batch, or FALSE if no batch was found. @@ -42,28 +41,23 @@ function batch_load($id) { } /** + * Access callback for the batch processing page. + * + * @param $batch + * A loaded batch record, as returned by batch_load(). + */ +function _batch_page_access($batch) { + return isset($batch['token']) && $batch['token'] === drupal_get_token($batch['id']); +} + +/** * Renders the batch processing page based on the current state of the batch. * * @see _batch_shutdown() */ -function _batch_page() { +function _batch_page($loaded_batch) { $batch = &batch_get(); - - if (!isset($_REQUEST['id'])) { - throw new NotFoundHttpException(); - } - - // Retrieve the current state of the batch. - if (!$batch) { - $batch = batch_load($_REQUEST['id']); - if (!$batch) { - drupal_set_message(t('No active batch.'), 'error'); - drupal_goto(); - } - if (!isset($batch['token']) || $batch['token'] !== drupal_get_token($_REQUEST['id'])) { - throw new AccessDeniedHttpException(); - } - } + $batch = $loaded_batch; // Register database update for the end of processing. drupal_register_shutdown_function('_batch_shutdown'); diff --git a/core/includes/form.inc b/core/includes/form.inc index 6a747b6..ab35019 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -4835,6 +4835,11 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'd // table, since non-progressive batches skip database storage completely. $batch['id'] = db_next_id(); + // Append the batch ID to the path for the default /batch callback. + if ($batch['url'] == 'batch') { + $batch['url'] = $batch['url'] . '/' . $batch['id']; + } + // Move operations to a job queue. Non-progressive batches will use a // memory-based queue. foreach ($batch['sets'] as $key => $batch_set) { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 889dbe2..f4458dd 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -487,8 +487,16 @@ function install_run_task($task, &$install_state) { // If we are in the middle of processing this batch, keep sending back // any output from the batch process, until the task is complete. elseif ($current_batch == $function) { + // The task is complete when we are at a URL without a batch ID. + if (empty($_REQUEST['id'])) { + // Return nothing so the next task will run in the same request. + variable_del('install_current_batch'); + return; + } + include_once DRUPAL_ROOT . '/core/includes/batch.inc'; - $output = _batch_page(); + $batch = batch_load($_REQUEST['id']); + $output = _batch_page($batch); // Because Batch API now returns a JSON response for intermediary steps, // but the installer doesn't handle Response objects yet, just send the // output here and emulate the old model. @@ -498,21 +506,16 @@ function install_run_task($task, &$install_state) { $output->send(); $output = NULL; } - // The task is complete when we try to access the batch page and receive - // FALSE in return, since this means we are at a URL where we are no - // longer requesting a batch ID. - if ($output === FALSE) { - // Return nothing so the next task will run in the same request. - variable_del('install_current_batch'); - return; - } - else { - // We need to force the page request to end if the task is not - // complete, since the batch API sometimes prints JSON output - // rather than returning a themed page. - $install_state['task_not_complete'] = $install_state['stop_page_request'] = TRUE; - return $output; + elseif (is_array($output)) { + // _batch_page() sets the page content and returns a #type page. + $output = drupal_set_page_content(); + // If the actual page output is NULL, then the batch is complete. + $output = drupal_render($output); } + // Force the page request to end if the task is not complete, since Batch + // API might return JSON output instead of themed page content. + $install_state['task_not_complete'] = $install_state['stop_page_request'] = TRUE; + return $output; } } diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 5677369..9a54f00 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -501,6 +501,9 @@ function _menu_load_objects(&$item, &$map) { if (!is_array($load_functions)) { $load_functions = unserialize($load_functions); } + if (!empty($item['include_file'])) { + include_once DRUPAL_ROOT . '/' . $item['include_file']; + } $path_map = $map; foreach ($load_functions as $index => $function) { if ($function) { @@ -3465,6 +3468,12 @@ function _menu_router_build($callbacks) { $menu = array(); $masks = array(); foreach ($callbacks as $path => $item) { + // Load the defined include file, if any, so callbacks are defined. + if (!empty($item['file'])) { + $file_path = !empty($item['file path']) ? $item['file path'] : drupal_get_path('module', $item['module']); + include_once DRUPAL_ROOT . '/' . $file_path . '/' . $item['file']; + } + $load_functions = array(); $to_arg_functions = array(); $fit = 0; diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 5fe55b0..f882267 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1114,10 +1114,13 @@ function system_menu() { ); // Default page for batch operations. - $items['batch'] = array( + $items['batch/%batch'] = array( 'page callback' => '_batch_page', - 'access callback' => TRUE, + 'page arguments' => array(1), + 'access callback' => '_batch_page_access', + 'access arguments' => array(1), 'theme callback' => '_system_batch_theme', + 'theme arguments' => array(1), 'type' => MENU_CALLBACK, 'file path' => 'core/includes', 'file' => 'batch.inc', @@ -1193,13 +1196,7 @@ function system_cron_access($key) { /** * Theme callback for the default batch page. */ -function _system_batch_theme() { - // Retrieve the current state of the batch. - $batch = &batch_get(); - if (!$batch && isset($_REQUEST['id'])) { - require_once DRUPAL_ROOT . '/core/includes/batch.inc'; - $batch = batch_load($_REQUEST['id']); - } +function _system_batch_theme($batch) { // Use the same theme as the page that started the batch. if (!empty($batch['theme'])) { return $batch['theme'];