diff --git a/core/core.services.yml b/core/core.services.yml index 4634033..3bfea9a 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1239,7 +1239,7 @@ services: lazy: true batch.processor: class: Drupal\Core\Batch\BatchProcessor - arguments: ['@batch.queue', '@date.formatter', '@form_submitter', '@batch.storage', '@request_stack'] + arguments: ['@app.root', '@batch.queue', '@date.formatter', '@form_submitter', '@batch.storage', '@request_stack'] batch.queue: class: Drupal\Core\Batch\BatchQueueHandler replica_database_ignore__subscriber: diff --git a/core/lib/Drupal/Core/Batch/BatchProcessor.php b/core/lib/Drupal/Core/Batch/BatchProcessor.php index 1b65da5..13b0b98 100644 --- a/core/lib/Drupal/Core/Batch/BatchProcessor.php +++ b/core/lib/Drupal/Core/Batch/BatchProcessor.php @@ -36,14 +36,14 @@ class BatchProcessor implements BatchProcessorInterface { protected $batchQueue; /** - * The date formatter. + * The date formatter used to calculate the needed time for the batch. * * @var \Drupal\Core\Datetime\DateFormatter */ protected $dateFormatter; /** - * The form submitter. + * The form submitter used to redirect at the end of the batch. * * @var \Drupal\Core\Form\FormSubmitterInterface */ @@ -64,15 +64,36 @@ class BatchProcessor implements BatchProcessorInterface { protected $requestStack; /** + * The app root. + * + * @var string + */ + protected $root; + + /** * Creates a new BatchProcessor. + * + * @param string $root + * The app root. + * @param \Drupal\Core\Batch\BatchQueueHandlerInterface $batch_queue + * The batch queue. + * @param \Drupal\Core\Datetime\DateFormatter $date_formatter + * The date formatter used to calculate the needed time for the batch. + * @param \Drupal\Core\Form\FormSubmitterInterface $form_submitter + * The form submitter used to redirect at the end of the batch. + * @param \Drupal\Core\Batch\BatchStorageInterface $batch_storage + * The batch storage. + * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack + * The request stack. */ - public function __construct(BatchQueueHandlerInterface $batch_queue, DateFormatter $date_formatter, FormSubmitterInterface $form_submitter, BatchStorageInterface $batch_storage, RequestStack $request_stack) { + public function __construct($root, BatchQueueHandlerInterface $batch_queue, DateFormatter $date_formatter, FormSubmitterInterface $form_submitter, BatchStorageInterface $batch_storage, RequestStack $request_stack) { + $this->root = $root; $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()); + $this->batch = ['sets' => []]; } /** @@ -114,13 +135,13 @@ public function process() { list($callback, $args) = $item->data; // Build the 'context' array and execute the function call. - $batch_context = array( + $batch_context = [ 'sandbox' => &$current_set['sandbox'], 'results' => &$current_set['results'], 'finished' => &$finished, 'message' => &$task_message, - ); - call_user_func_array($callback, array_merge($args, array(&$batch_context))); + ]; + call_user_func_array($callback, array_merge($args, [&$batch_context])); if ($finished >= 1) { // Make sure this step is not counted twice when computing $current. @@ -128,7 +149,7 @@ public function process() { // Remove the processed operation and clear the sandbox. $queue->deleteItem($item); $current_set['count']--; - $current_set['sandbox'] = array(); + $current_set['sandbox'] = []; } } @@ -197,7 +218,7 @@ public function process() { $label = $task_message; } - return array($percentage, $message, $label); + return [$percentage, $message, $label]; } else { // If we are not in progressive mode, the entire batch has been processed. @@ -224,7 +245,7 @@ public function nextSet() { // We use our stored copies of $form and $form_state to account for // possible alterations by previous form submit handlers. $complete_form = &$this->batch['form_state']->getCompleteForm(); - call_user_func_array($callback, array(&$complete_form, &$this->batch['form_state'])); + call_user_func_array($callback, [&$complete_form, &$this->batch['form_state']]); } return TRUE; } @@ -239,12 +260,18 @@ public function finished() { 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']; + include_once $this->root . '/' . $batch_set['file']; } if (is_callable($batch_set['finished'])) { $queue = $this->batchQueue->getQueue($batch_set); $operations = $queue->getAllItems(); - call_user_func_array($batch_set['finished'], array($batch_set['success'], $batch_set['results'], $operations, $this->dateFormatter->formatInterval($batch_set['elapsed'] / 1000))); + $batch_set_result = call_user_func_array($batch_set['finished'], array($batch_set['success'], $batch_set['results'], $operations, $this->dateFormatter->formatInterval($batch_set['elapsed'] / 1000))); + // If a batch 'finished' callback requested a redirect after the batch + // is complete, save that for later use. If more than one batch set + // returned a redirect, the last one is used. + if ($batch_set_result instanceof RedirectResponse) { + $batch_finished_redirect = $batch_set_result; + } } } } @@ -281,12 +308,21 @@ public function finished() { } if ($_batch['form_state']->getRedirect() === NULL) { $redirect = $_batch['batch_redirect'] ?: $_batch['source_url']; - $options = UrlHelper::parse($redirect); - if (!UrlHelper::isExternal($options['path'])) { - $options['path'] = $GLOBALS['base_url'] . '/' . $options['path']; + // Any path with a scheme does not correspond to a route. + if (!$redirect instanceof Url) { + $options = UrlHelper::parse($redirect); + if (parse_url($options['path'], PHP_URL_SCHEME)) { + $redirect = Url::fromUri($options['path'], $options); + } + else { + $redirect = \Drupal::pathValidator()->getUrlIfValid($options['path']); + if (!$redirect) { + // Stay on the same page if the redirect was invalid. + $redirect = Url::fromRoute(''); + } + $redirect->setOptions($options); + } } - $redirect = Url::createFromPath($options['path']); - $redirect->setOptions($options); $_batch['form_state']->setRedirectUrl($redirect); } @@ -304,16 +340,17 @@ public function finished() { $_SESSION['batch_form_state'] = $_batch['form_state']; } $callback = $_batch['redirect_callback']; + /** @var \Drupal\Core\Url $source_url */ + $source_url = $_batch['source_url']; if (is_callable($callback)) { - $callback($_batch['source_url'], array('query' => array('op' => 'finish', 'id' => $_batch['id']))); + $callback($_batch['source_url'], ['query' => ['op' => 'finish', 'id' => $_batch['id']]]); } elseif ($callback === NULL) { // Default to RedirectResponse objects when nothing specified. - $url = url($_batch['source_url'], array( - 'absolute' => TRUE, - 'query' => array('op' => 'finish', 'id' => $_batch['id']), - )); - return new RedirectResponse($url); + $url = $source_url + ->setAbsolute() + ->setOption('query', ['op' => 'finish', 'id' => $_batch['id']]); + return new RedirectResponse($url->toString()); } } }