diff --git a/core/includes/form.inc b/core/includes/form.inc
index c8d9b14..4382723 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -7,6 +7,7 @@
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Batch\Batch;
+use Drupal\Core\Batch\BatchQueueController;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Element\RenderElement;
use Drupal\Core\Template\Attribute;
@@ -752,7 +753,7 @@ function batch_set($batch_definition) {
* an existing Batch object.
*/
function batch_process($redirect = NULL, Url $url = NULL, $redirect_callback = NULL) {
- return Batch::process($redirect, $url, $redirect_callback);
+ return BatchQueueController::process($redirect, $url, $redirect_callback);
}
/**
@@ -765,41 +766,7 @@ function &batch_get() {
// that are part of the Batch API and need to reset the batch information may
// call batch_get() and manipulate the result by reference. Functions that are
// not part of the Batch API can also do this, but shouldn't.
- return Batch::getBatches();
-}
-
-/**
- * Populates a job queue with the operations of a batch set.
- *
- * Depending on whether the batch is progressive or not, the
- * Drupal\Core\Queue\Batch or Drupal\Core\Queue\BatchMemory handler classes will
- * be used. The name and class of the queue are added by reference to the
- * batch set.
- *
- * @param $batch
- * The batch array.
- * @param $set_id
- * The id of the set to process.
- */
-function _batch_populate_queue(&$batch, $set_id) {
- $batch_set = &$batch['sets'][$set_id];
-
- if (isset($batch_set['operations'])) {
- $batch_set += array(
- 'queue' => array(
- 'name' => 'drupal_batch:' . $batch['id'] . ':' . $set_id,
- 'class' => $batch['progressive'] ? 'Drupal\Core\Queue\Batch' : 'Drupal\Core\Queue\BatchMemory',
- ),
- );
-
- $queue = _batch_queue($batch_set);
- $queue->createQueue();
- foreach ($batch_set['operations'] as $operation) {
- $queue->createItem($operation);
- }
-
- unset($batch_set['operations']);
- }
+ return BatchQueueController::getBatches();
}
/**
diff --git a/core/lib/Drupal/Core/Batch/Batch.php b/core/lib/Drupal/Core/Batch/Batch.php
index eb45a1a..80f804d 100644
--- a/core/lib/Drupal/Core/Batch/Batch.php
+++ b/core/lib/Drupal/Core/Batch/Batch.php
@@ -2,21 +2,13 @@
namespace Drupal\Core\Batch;
-use Drupal\Core\Database\Database;
use Drupal\Core\Url;
-use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Stores a domain object for a batch process.
- *
- * This object contains the same information than a batch array.
- *
- * @see batch_set()
*/
class Batch {
- private static $batch = array();
-
protected $operations = [];
protected $title;
protected $init_message;
@@ -36,10 +28,10 @@ class Batch {
* The title.
*/
public function __construct($title = NULL) {
- $this->setTitle(is_null($title) ? t('Processing') : $title);
- $this->setInitMessage(t('Initializing.'));
- $this->setProgressMessage(t('Completed @current of @total.'));
- $this->setErrorMessage(t('An error has occurred.'));
+ $this->setTitle(is_null($title) ? 'Processing' : $title);
+ $this->setInitMessage('Initializing.');
+ $this->setProgressMessage('Completed @current of @total.');
+ $this->setErrorMessage('An error has occurred.');
}
/**
@@ -267,47 +259,7 @@ public function addCss($filename) {
* @return $this
*/
public function enqueue() {
- // Initialize the batch if needed.
- if (empty(self::$batch)) {
- self::$batch = array(
- 'sets' => array(),
- 'has_form_submits' => FALSE,
- );
- }
-
- $init = [
- 'sandbox' => [],
- 'results' => [],
- 'success' => FALSE,
- 'start' => 0,
- 'elapsed' => 0,
- ];
- $batch_set = $init + $this->toArray();
-
- // Tweak init_message to avoid the bottom of the page flickering down after
- // init phase.
- $batch_set['init_message'] .= '
';
-
- // The non-concurrent workflow of batch execution allows us to save
- // numberOfItems() queries by handling our own counter.
- $batch_set['total'] = count($batch_set['operations']);
- $batch_set['count'] = $batch_set['total'];
- // Add the set to the batch.
- if (empty(self::$batch['id'])) {
- // The batch is not running yet. Simply add the new set.
- self::$batch['sets'][] = $batch_set;
- }
- else {
- // The set is being added while the batch is running. Insert the new set
- // right after the current one to ensure execution order, and store its
- // operations in a queue.
- $index = self::$batch['current_set'] + 1;
- $slice1 = array_slice(self::$batch['sets'], 0, $index);
- $slice2 = array_slice(self::$batch['sets'], $index);
- self::$batch['sets'] = array_merge($slice1, array($batch_set), $slice2);
- _batch_populate_queue(self::$batch, $index);
- }
-
+ BatchQueueController::enqueue($this);
return $this;
}
@@ -337,90 +289,9 @@ public function enqueue() {
* @return \Symfony\Component\HttpFoundation\RedirectResponse|null
* A redirect response if the batch is progressive. No return value
* otherwise.
- *
- * @deprecated as of Drupal 8.2.x, will be removed in Drupal 9.0.0. Use
- * \Drupal\Core\Batch\Batch::process() instead or the process() function on
- * an existing Batch object.
*/
public static function process($redirect = NULL, Url $url = NULL, $redirect_callback = NULL) {
- if (isset(self::$batch)) {
-
- // Add process information.
- $process_info = [
- 'current_set' => 0,
- 'progressive' => TRUE,
- 'url' => isset($url) ? $url : Url::fromRoute('system.batch_page.html'),
- 'source_url' => Url::fromRouteMatch(\Drupal::routeMatch()),
- 'batch_redirect' => $redirect,
- 'theme' => \Drupal::theme()->getActiveTheme()->getName(),
- 'redirect_callback' => $redirect_callback,
- ];
- self::$batch += $process_info;
-
- // The batch is now completely built. Allow other modules to make changes
- // to the batch so that it is easier to reuse batch processes in other
- // environments.
- \Drupal::moduleHandler()->alter('batch', self::$batch);
-
- // Assign an arbitrary id: don't rely on a serial column in the 'batch'
- // table, since non-progressive batches skip database storage completely.
- self::$batch['id'] = Database::getConnection()->nextId();
-
- // Move operations to a job queue. Non-progressive batches will use a
- // memory-based queue.
- foreach (self::$batch['sets'] as $key => $batch_set) {
- _batch_populate_queue(self::$batch, $key);
- }
-
- // Initiate processing.
- if (self::$batch['progressive']) {
- // Now that we have a batch id, we can generate the redirection link in
- // the generic error message.
- /** @var \Drupal\Core\Url $batch_url */
- $batch_url = self::$batch['url'];
- /** @var \Drupal\Core\Url $error_url */
- $error_url = clone $batch_url;
- $query_options = $error_url->getOption('query');
- $query_options['id'] = self::$batch['id'];
- $query_options['op'] = 'finished';
- $error_url->setOption('query', $query_options);
-
- self::$batch['error_message'] = t('Please continue to the error page', array(':error_url' => $error_url->toString(TRUE)->getGeneratedUrl()));
-
- // Clear the way for the redirection to the batch processing page, by
- // saving and un-setting the 'destination', if there is any.
- $request = \Drupal::request();
- if ($request->query->has('destination')) {
- self::$batch['destination'] = $request->query->get('destination');
- $request->query->remove('destination');
- }
-
- // Store the batch.
- \Drupal::service('batch.storage')->create(self::$batch);
-
- // Set the batch number in the session to guarantee that it will stay
- // alive.
- $_SESSION['batches'][self::$batch['id']] = TRUE;
-
- // Redirect for processing.
- $query_options = $error_url->getOption('query');
- $query_options['op'] = 'start';
- $query_options['id'] = self::$batch['id'];
- $batch_url->setOption('query', $query_options);
- if (($function = self::$batch['redirect_callback']) && function_exists($function)) {
- $function($batch_url->toString(), ['query' => $query_options]);
- }
- else {
- return new RedirectResponse($batch_url->setAbsolute()->toString(TRUE)->getGeneratedUrl());
- }
- }
- else {
- // Non-progressive execution: bypass the whole progressbar workflow
- // and execute the batch in one pass.
- require_once DRUPAL_ROOT . '/core/includes/batch.inc';
- _batch_process();
- }
- }
+ return BatchQueueController::process($redirect, $url, $redirect_callback);
}
/**
@@ -448,11 +319,4 @@ public function toArray() {
return $array;
}
- /**
- * Retrieves the current batch.
- */
- public static function &getBatches() {
- return Batch::$batch;
- }
-
}
diff --git a/core/lib/Drupal/Core/Batch/BatchQueueController.php b/core/lib/Drupal/Core/Batch/BatchQueueController.php
new file mode 100644
index 0000000..ff2f637
--- /dev/null
+++ b/core/lib/Drupal/Core/Batch/BatchQueueController.php
@@ -0,0 +1,228 @@
+ array(),
+ 'has_form_submits' => FALSE,
+ );
+ }
+
+ $init = [
+ 'sandbox' => [],
+ 'results' => [],
+ 'success' => FALSE,
+ 'start' => 0,
+ 'elapsed' => 0,
+ ];
+ $batch_set = $init + $batch->toArray();
+
+ // Make strings translatable.
+ if (is_string($batch_set['title'])) {
+ $batch_set['title'] = new TranslatableMarkup($batch_set['title']);
+ }
+ if (is_string($batch_set['init_message'])) {
+ $batch_set['init_message'] = new TranslatableMarkup($batch_set['init_message']);
+ }
+ if (is_string($batch_set['progress_message'])) {
+ $batch_set['progress_message'] = new TranslatableMarkup($batch_set['progress_message']);
+ }
+ if (is_string($batch_set['error_message'])) {
+ $batch_set['error_message'] = new TranslatableMarkup($batch_set['error_message']);
+ }
+
+ // The non-concurrent workflow of batch execution allows us to save
+ // numberOfItems() queries by handling our own counter.
+ $batch_set['total'] = count($batch_set['operations']);
+ $batch_set['count'] = $batch_set['total'];
+ // Add the set to the batch.
+ if (empty(self::$batches['id'])) {
+ // The batch is not running yet. Simply add the new set.
+ self::$batches['sets'][] = $batch_set;
+ }
+ else {
+ // The set is being added while the batch is running. Insert the new set
+ // right after the current one to ensure execution order, and store its
+ // operations in a queue.
+ $index = self::$batches['current_set'] + 1;
+ $slice1 = array_slice(self::$batches['sets'], 0, $index);
+ $slice2 = array_slice(self::$batches['sets'], $index);
+ self::$batches['sets'] = array_merge($slice1, array($batch_set), $slice2);
+ self::populateQueue($index);
+ }
+
+ }
+
+ /**
+ * Processes the batch.
+ *
+ * This function is generally not needed in form submit handlers;
+ * Form API takes care of batches that were set during form submission.
+ *
+ * @param \Drupal\Core\Url|string $redirect
+ * (optional) Either path or Url object to redirect to when the batch has
+ * finished processing. Note that to simply force a batch to (conditionally)
+ * redirect to a custom location after it is finished processing but to
+ * otherwise allow the standard form API batch handling to occur, it is not
+ * necessary to call batch_process() and use this parameter. Instead, make
+ * the batch 'finished' callback return an instance of
+ * \Symfony\Component\HttpFoundation\RedirectResponse, which will be used
+ * automatically by the standard batch processing pipeline (and which takes
+ * precedence over this parameter).
+ * @param \Drupal\Core\Url $url
+ * (optional) URL of the batch processing page.
+ * Should only be used for separate scripts like update.php.
+ * @param string $redirect_callback
+ * (optional) Specify a function to be called to redirect to the progressive
+ * processing page.
+ *
+ * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
+ * A redirect response if the batch is progressive. No return value
+ * otherwise.
+ */
+ public static function process($redirect = NULL, Url $url = NULL, $redirect_callback = NULL) {
+ if (isset(self::$batches)) {
+
+ // Add process information.
+ $process_info = [
+ 'current_set' => 0,
+ 'progressive' => TRUE,
+ 'url' => isset($url) ? $url : Url::fromRoute('system.batch_page.html'),
+ 'source_url' => Url::fromRouteMatch(\Drupal::routeMatch()),
+ 'batch_redirect' => $redirect,
+ 'theme' => \Drupal::theme()->getActiveTheme()->getName(),
+ 'redirect_callback' => $redirect_callback,
+ ];
+ self::$batches += $process_info;
+
+ // The batch is now completely built. Allow other modules to make changes
+ // to the batch so that it is easier to reuse batch processes in other
+ // environments.
+ \Drupal::moduleHandler()->alter('batch', self::$batches);
+
+ // Assign an arbitrary id: don't rely on a serial column in the 'batch'
+ // table, since non-progressive batches skip database storage completely.
+ self::$batches['id'] = Database::getConnection()->nextId();
+
+ // Move operations to a job queue. Non-progressive batches will use a
+ // memory-based queue.
+ foreach (self::$batches['sets'] as $key => $batch_set) {
+ self::populateQueue($key);
+ }
+
+ // Initiate processing.
+ if (self::$batches['progressive']) {
+ // Now that we have a batch id, we can generate the redirection link in
+ // the generic error message.
+ /** @var \Drupal\Core\Url $batch_url */
+ $batch_url = self::$batches['url'];
+ /** @var \Drupal\Core\Url $error_url */
+ $error_url = clone $batch_url;
+ $query_options = $error_url->getOption('query');
+ $query_options['id'] = self::$batches['id'];
+ $query_options['op'] = 'finished';
+ $error_url->setOption('query', $query_options);
+
+ self::$batches['error_message'] = t('Please continue to the error page', array(':error_url' => $error_url->toString(TRUE)->getGeneratedUrl()));
+
+ // Clear the way for the redirection to the batch processing page, by
+ // saving and un-setting the 'destination', if there is any.
+ $request = \Drupal::request();
+ if ($request->query->has('destination')) {
+ self::$batches['destination'] = $request->query->get('destination');
+ $request->query->remove('destination');
+ }
+
+ // Store the batch.
+ \Drupal::service('batch.storage')->create(self::$batches);
+
+ // Set the batch number in the session to guarantee that it will stay
+ // alive.
+ $_SESSION['batches'][self::$batches['id']] = TRUE;
+
+ // Redirect for processing.
+ $query_options = $error_url->getOption('query');
+ $query_options['op'] = 'start';
+ $query_options['id'] = self::$batches['id'];
+ $batch_url->setOption('query', $query_options);
+ if (($function = self::$batches['redirect_callback']) && function_exists($function)) {
+ $function($batch_url->toString(), ['query' => $query_options]);
+ }
+ else {
+ return new RedirectResponse($batch_url->setAbsolute()->toString(TRUE)->getGeneratedUrl());
+ }
+ }
+ else {
+ // Non-progressive execution: bypass the whole progressbar workflow
+ // and execute the batch in one pass.
+ require_once DRUPAL_ROOT . '/core/includes/batch.inc';
+ _batch_process();
+ }
+ }
+
+ return NULL;
+ }
+
+ /**
+ * Retrieves the current batch.
+ */
+ public static function &getBatches() {
+ return self::$batches;
+ }
+
+ /**
+ * Populates a job queue with the operations of a batch set.
+ *
+ * Depending on whether the batch is progressive or not, the
+ * Drupal\Core\Queue\Batch or Drupal\Core\Queue\BatchMemory handler classes
+ * will be used. The name and class of the queue are added by reference to the
+ * batch set.
+ *
+ * @param int $set_id
+ * The id of the set to process.
+ */
+ protected static function populateQueue($set_id = 0) {
+ $batch = &self::$batches;
+ $batch_set = &$batch['sets'][$set_id];
+
+ if (isset($batch_set['operations'])) {
+ $batch_set += array(
+ 'queue' => array(
+ 'name' => 'drupal_batch:' . $batch['id'] . ':' . $set_id,
+ 'class' => $batch['progressive'] ? 'Drupal\Core\Queue\Batch' : 'Drupal\Core\Queue\BatchMemory',
+ ),
+ );
+
+ $queue = _batch_queue($batch_set);
+ $queue->createQueue();
+ foreach ($batch_set['operations'] as $operation) {
+ $queue->createItem($operation);
+ }
+
+ unset($batch_set['operations']);
+ }
+ }
+
+}