diff --git a/core/core.services.yml b/core/core.services.yml index 480ef39..f228297 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -787,6 +787,9 @@ services: - { name: backend_overridable } batch.processor: class: Drupal\Core\Batch\BatchProcessor + arguments: ['@batch.queue', '@date.formatter', '@form_submitter', '@batch.storage', '@request_stack'] + batch.queue: + class: Drupal\Core\Batch\BatchQueueHandler replica_database_ignore__subscriber: class: Drupal\Core\EventSubscriber\ReplicaDatabaseIgnoreSubscriber tags: diff --git a/core/includes/form.inc b/core/includes/form.inc index fb9add4..c4b2505 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -3035,26 +3035,12 @@ function &batch_get() { * * @return * The name and class of the queue are added by reference to the batch set. + * + * @deprecated Use \Drupal::service('batch.queue')->populateQueue($batch, $set_id) + * instead. */ 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 \Drupal::service('batch.queue')->populateQueue($batch, $set_id); } /** @@ -3065,23 +3051,11 @@ function _batch_populate_queue(&$batch, $set_id) { * * @return * The queue object. + * + * @deprecated Use \Drupal::service('batch.queue')->getQueue($batch_set) instead. */ function _batch_queue($batch_set) { - static $queues; - - if (!isset($queues)) { - $queues = array(); - } - - if (isset($batch_set['queue'])) { - $name = $batch_set['queue']['name']; - $class = $batch_set['queue']['class']; - - if (!isset($queues[$class][$name])) { - $queues[$class][$name] = new $class($name, Database::getConnection()); - } - return $queues[$class][$name]; - } + return \Drupal::service('batch.queue')->getQueue($batch_set); } /** diff --git a/core/lib/Drupal/Core/Batch/BatchProcessor.php b/core/lib/Drupal/Core/Batch/BatchProcessor.php index 2e9dfd2..56cc7f0 100644 --- a/core/lib/Drupal/Core/Batch/BatchProcessor.php +++ b/core/lib/Drupal/Core/Batch/BatchProcessor.php @@ -9,9 +9,14 @@ use Drupal\Component\Utility\Timer; use Drupal\Component\Utility\UrlHelper; +use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Form\FormState; +use Drupal\Core\Form\FormSubmitterInterface; use Drupal\Core\Url; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\RequestStack; + +require_once DRUPAL_ROOT . '/core/includes/form.inc'; /** * Provides a batch processor. @@ -26,18 +31,57 @@ class BatchProcessor implements BatchProcessorInterface { protected $batch; /** + * The batch queue. + * + * @var \Drupal\Core\Batch\BatchQueueHandlerInterface + */ + protected $batchQueue; + + /** + * The date formatter. + * + * @var \Drupal\Core\Datetime\DateFormatter + */ + protected $dateFormatter; + + /** + * The form submitter. + * + * @var \Drupal\Core\Form\FormSubmitterInterface + */ + protected $formSubmitter; + + /** + * The batch storage service. + * + * @var \Drupal\Core\Batch\BatchStorageInterface + */ + protected $batchStorage; + + /** + * The request stack. + * + * @var \Symfony\Component\HttpFoundation\RequestStack + */ + protected $requestStack; + + /** * Creates a new BatchProcessor. */ - public function __construct() { - $this->batch = array(); + public function __construct(BatchQueueHandlerInterface $batch_queue, DateFormatter $date_formatter, FormSubmitterInterface $form_submitter, BatchStorageInterface $batch_storage, RequestStack $request_stack) { + $this->batchQueue = $batch_queue; + $this->dateFormatter = $date_formatter; + $this->formSubmitter = $form_submitter; + $this->batchStorage = $batch_storage; + $this->requestStack = $request_stack; + $this->batch = array('sets' => array()); } /** * {@inheritdoc} */ public function process() { - $batch = &$this->batch; - $current_set = &$this->currentSet(); + $current_set = $this->currentSet(); // Indicate that this batch set needs to be initialized. $set_changed = TRUE; @@ -45,7 +89,7 @@ public function process() { // drupal_form_submit()), initialize a timer to determine whether we need to // proceed with the same batch phase when a processing time of 1 second has // been exceeded. - if ($batch['progressive']) { + if ($this->batch['progressive']) { Timer::start('batch_processing'); } @@ -53,9 +97,7 @@ public function process() { $current_set['start'] = microtime(TRUE); } - include_once DRUPAL_ROOT . '/form.inc'; - /** @var \Drupal\Core\Queue\QueueInterface $queue */ - $queue = _batch_queue($current_set); + $queue = $this->batchQueue->getQueue($current_set); while (!$current_set['success']) { // If this is the first time we iterate this batch set in the current @@ -108,17 +150,17 @@ public function process() { // At this point, either $current_set contains operations that need to be // processed or all sets have been completed. - $queue = _batch_queue($current_set); + $queue = $this->batchQueue->getQueue($current_set); // If we are in progressive mode, break processing after 1 second. - if ($batch['progressive'] && Timer::read('batch_processing') > 1000) { + if ($this->batch['progressive'] && Timer::read('batch_processing') > 1000) { // Record elapsed wall clock time. $current_set['elapsed'] = round((microtime(TRUE) - $current_set['start']) * 1000, 2); break; } } - if ($batch['progressive']) { + if ($this->batch['progressive']) { // Gather progress information. // Reporting 100% progress will cause the whole batch to be considered @@ -148,9 +190,9 @@ public function process() { '@total' => $total, '@current' => floor($current), '@percentage' => $percentage, - '@elapsed' => \Drupal::service('date.formatter')->formatInterval($elapsed / 1000), + '@elapsed' => $this->dateFormatter->formatInterval($elapsed / 1000), // If possible, estimate remaining processing time. - '@estimate' => ($current > 0) ? \Drupal::service('date.formatter')->formatInterval(($elapsed * ($total - $current) / $current) / 1000) : '-', + '@estimate' => ($current > 0) ? $this->dateFormatter->formatInterval(($elapsed * ($total - $current) / $current) / 1000) : '-', ); $message = strtr($progress_message, $values); if (!empty($task_message)) { @@ -169,6 +211,7 @@ public function process() { * {@inheritdoc} */ public function currentSet() { + $this->batch = &batch_get(); return $this->batch['sets'][$this->batch['current_set']]; } @@ -176,15 +219,14 @@ public function currentSet() { * {@inheritdoc} */ public function nextSet() { - $batch = &$this->batch; - if (isset($batch['sets'][$batch['current_set'] + 1])) { - $batch['current_set']++; + if (isset($this->batch['sets'][$this->batch['current_set'] + 1])) { + $this->batch['current_set']++; $current_set = &$this->currentSet(); if (isset($current_set['form_submit']) && ($callback = $current_set['form_submit']) && is_callable($callback)) { // We use our stored copies of $form and $form_state to account for // possible alterations by previous form submit handlers. - $complete_form = &$batch['form_state']->getCompleteForm(); - call_user_func_array($callback, array(&$complete_form, &$batch['form_state'])); + $complete_form = &$this->batch['form_state']->getCompleteForm(); + call_user_func_array($callback, array(&$complete_form, &$this->batch['form_state'])); } return TRUE; } @@ -194,48 +236,45 @@ public function nextSet() { * {@inheritdoc} */ public function finished() { - $batch = &$this->batch; - // Execute the 'finished' callbacks for each batch set, if defined. - foreach ($batch['sets'] as $batch_set) { + foreach ($this->batch['sets'] as $batch_set) { if (isset($batch_set['finished'])) { // Check if the set requires an additional file for function definitions. if (isset($batch_set['file']) && is_file($batch_set['file'])) { include_once DRUPAL_ROOT . '/' . $batch_set['file']; } if (is_callable($batch_set['finished'])) { - /** @var \Drupal\Core\Queue\QueueInterface $queue */ - $queue = _batch_queue($batch_set); + $queue = $this->batchQueue->getQueue($batch_set); $operations = $queue->getAllItems(); - call_user_func_array($batch_set['finished'], array($batch_set['success'], $batch_set['results'], $operations, \Drupal::service('date.formatter')->formatInterval($batch_set['elapsed'] / 1000))); + call_user_func_array($batch_set['finished'], array($batch_set['success'], $batch_set['results'], $operations, $this->dateFormatter->formatInterval($batch_set['elapsed'] / 1000))); } } } - // Clean up the batch table and unset the static $batch variable. - if ($batch['progressive']) { - \Drupal::service('batch.storage')->delete($batch['id']); - foreach ($batch['sets'] as $batch_set) { - if ($queue = _batch_queue($batch_set)) { + // Clean up the batch table and unset the static $this->batch variable. + if ($this->batch['progressive']) { + $this->batchStorage->delete($this->batch['id']); + foreach ($this->batch['sets'] as $batch_set) { + if ($queue = $this->batchQueue->getQueue($batch_set)) { $queue->deleteQueue(); } } // Clean-up the session. Not needed for CLI updates. if (isset($_SESSION)) { - unset($_SESSION['batches'][$batch['id']]); + unset($_SESSION['batches'][$this->batch['id']]); if (empty($_SESSION['batches'])) { unset($_SESSION['batches']); } } } - $_batch = $batch; - $batch = NULL; + $_batch = $this->batch; + $this->batch = NULL; // Redirect if needed. if ($_batch['progressive']) { // Revert the 'destination' that was saved in batch_process(). if (isset($_batch['destination'])) { - \Drupal::request()->query->set('destination', $_batch['destination']); + $this->requestStack->getCurrentRequest()->query->set('destination', $_batch['destination']); } // Determine the target path to redirect to. @@ -255,7 +294,7 @@ public function finished() { // Use \Drupal\Core\Form\FormSubmitterInterface::redirectForm() to handle // the redirection logic. - $redirect = \Drupal::service('form_submitter')->redirectForm($_batch['form_state']); + $redirect = $this->formSubmitter->redirectForm($_batch['form_state']); if (is_object($redirect)) { return $redirect; } diff --git a/core/lib/Drupal/Core/Batch/BatchQueueHandler.php b/core/lib/Drupal/Core/Batch/BatchQueueHandler.php new file mode 100644 index 0000000..f3c3137 --- /dev/null +++ b/core/lib/Drupal/Core/Batch/BatchQueueHandler.php @@ -0,0 +1,82 @@ +queues = array(); + } + + /** + * {@inheritdoc} + */ + public function getQueue($batch_set) { + if (isset($batch_set['queue'])) { + $name = $batch_set['queue']['name']; + $class = $batch_set['queue']['class']; + + if (!isset($this->queues[$class][$name])) { + $this->queues[$class][$name] = new $class($name, Database::getConnection()); + } + return $this->queues[$class][$name]; + } + } + + /** + * 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. + * + * @param array $batch + * The batch array. + * @param string $set_id + * The id of the set to process. + * + * @return array + * The name and class of the queue are added by reference to the batch set. + */ + public function populateQueue(&$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 = $this->getQueue($batch_set); + $queue->createQueue(); + foreach ($batch_set['operations'] as $operation) { + $queue->createItem($operation); + } + + unset($batch_set['operations']); + } + } + +} diff --git a/core/lib/Drupal/Core/Batch/BatchQueueHandlerInterface.php b/core/lib/Drupal/Core/Batch/BatchQueueHandlerInterface.php new file mode 100644 index 0000000..2334c44 --- /dev/null +++ b/core/lib/Drupal/Core/Batch/BatchQueueHandlerInterface.php @@ -0,0 +1,43 @@ +