diff --git a/core/lib/Drupal/Core/Batch/BatchBuilder.php b/core/lib/Drupal/Core/Batch/BatchBuilder.php index dce669874d..2c4512fd82 100644 --- a/core/lib/Drupal/Core/Batch/BatchBuilder.php +++ b/core/lib/Drupal/Core/Batch/BatchBuilder.php @@ -205,12 +205,17 @@ public function setErrorMessage($message) { * The path should be relative to base_path(), and thus should be built using * drupal_get_path(). Defaults to {module_name}.module. * + * The file needs to be set before using ::addOperation(), + * ::setFinishCallback(), or any other function that uses callbacks from the + * file. This is so that PHP knows about the included functions. + * * @param string $filename * The path to the file. * * @return $this */ public function setFile($filename) { + include_once $filename; $this->file = $filename; return $this; } diff --git a/core/modules/config/src/Form/ConfigSingleImportForm.php b/core/modules/config/src/Form/ConfigSingleImportForm.php index 83e776c0b0..35ff559df2 100644 --- a/core/modules/config/src/Form/ConfigSingleImportForm.php +++ b/core/modules/config/src/Form/ConfigSingleImportForm.php @@ -4,6 +4,7 @@ use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Drupal\config\StorageReplaceDataWrapper; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Config\ConfigImporter; use Drupal\Core\Config\ConfigImporterException; use Drupal\Core\Config\ConfigManagerInterface; @@ -400,19 +401,16 @@ public function submitForm(array &$form, FormStateInterface $form_state) { else { try { $sync_steps = $config_importer->initialize(); - $batch = [ - 'operations' => [], - 'finished' => [ConfigSync::class, 'finishBatch'], - 'title' => $this->t('Importing configuration'), - 'init_message' => $this->t('Starting configuration import.'), - 'progress_message' => $this->t('Completed @current step of @total.'), - 'error_message' => $this->t('Configuration import has encountered an error.'), - ]; + $batch_builder = (new BatchBuilder()) + ->setTitle($this->t('Importing configuration')) + ->setFinishCallback([ConfigSync::class, 'finishBatch']) + ->setInitMessage($this->t('Starting configuration import.')) + ->setProgressMessage($this->t('Completed @current step of @total.')) + ->setErrorMessage($this->t('Configuration import has encountered an error.')); foreach ($sync_steps as $sync_step) { - $batch['operations'][] = [[ConfigSync::class, 'processBatch'], [$config_importer, $sync_step]]; + $batch_builder->addOperation([ConfigSync::class, 'processBatch'], [$config_importer, $sync_step]); } - - batch_set($batch); + batch_set($batch_builder->toArray()); } catch (ConfigImporterException $e) { // There are validation errors. diff --git a/core/modules/config/src/Form/ConfigSync.php b/core/modules/config/src/Form/ConfigSync.php index 44034ddabb..be8e9a0a3d 100644 --- a/core/modules/config/src/Form/ConfigSync.php +++ b/core/modules/config/src/Form/ConfigSync.php @@ -2,6 +2,7 @@ namespace Drupal\config\Form; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Config\ConfigImporterException; use Drupal\Core\Config\ConfigImporter; use Drupal\Core\Config\TypedConfigManagerInterface; @@ -335,19 +336,16 @@ public function submitForm(array &$form, FormStateInterface $form_state) { else { try { $sync_steps = $config_importer->initialize(); - $batch = [ - 'operations' => [], - 'finished' => [get_class($this), 'finishBatch'], - 'title' => t('Synchronizing configuration'), - 'init_message' => t('Starting configuration synchronization.'), - 'progress_message' => t('Completed step @current of @total.'), - 'error_message' => t('Configuration synchronization has encountered an error.'), - ]; + $batch_builder = (new BatchBuilder()) + ->setTitle($this->t('Synchronizing configuration')) + ->setFinishCallback([ConfigSync::class, 'finishBatch']) + ->setInitMessage($this->t('Starting configuration synchronization.')) + ->setProgressMessage($this->t('Completed step @current of @total.')) + ->setErrorMessage($this->t('Configuration synchronization has encountered an error.')); foreach ($sync_steps as $sync_step) { - $batch['operations'][] = [[get_class($this), 'processBatch'], [$config_importer, $sync_step]]; + $batch_builder->addOperation([get_class($this), 'processBatch'], [$config_importer, $sync_step]); } - - batch_set($batch); + batch_set($batch_builder->toArray()); } catch (ConfigImporterException $e) { // There are validation errors. diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc index 69b465b4ae..41e39e131f 100644 --- a/core/modules/locale/locale.bulk.inc +++ b/core/modules/locale/locale.bulk.inc @@ -9,6 +9,7 @@ use Drupal\file\FileInterface; use Drupal\locale\Gettext; use Drupal\locale\Locale; +use Drupal\Core\Batch\BatchBuilder; /** * Prepare a batch to import all translations. @@ -138,28 +139,25 @@ function locale_translate_batch_build(array $files, array $options) { 'finish_feedback' => TRUE, ]; if (count($files)) { - $operations = []; + $batch_builder = (new BatchBuilder()) + ->setTitle(t('Importing interface translations')) + ->setErrorMessage(t('Error importing interface translations')) + ->setFile(drupal_get_path('module', 'locale') . '/locale.bulk.inc'); + foreach ($files as $file) { // We call locale_translate_batch_import for every batch operation. - $operations[] = ['locale_translate_batch_import', [$file, $options]]; + $batch_builder->addOperation('locale_translate_batch_import', [$file, $options]); } // Save the translation status of all files. - $operations[] = ['locale_translate_batch_import_save', []]; + $batch_builder->addOperation('locale_translate_batch_import_save', []); // Add a final step to refresh JavaScript and configuration strings. - $operations[] = ['locale_translate_batch_refresh', []]; - - $batch = [ - 'operations' => $operations, - 'title' => t('Importing interface translations'), - 'progress_message' => '', - 'error_message' => t('Error importing interface translations'), - 'file' => drupal_get_path('module', 'locale') . '/locale.bulk.inc', - ]; + $batch_builder->addOperation('locale_translate_batch_refresh', []); + if ($options['finish_feedback']) { - $batch['finished'] = 'locale_translate_batch_finished'; + $batch_builder->setFinishCallback('locale_translate_batch_finished'); } - return $batch; + return $batch_builder->toArray(); } return FALSE; } @@ -557,9 +555,15 @@ function locale_config_batch_update_components(array $options, array $langcodes */ function locale_config_batch_build(array $names, array $langcodes, array $options = []) { $options += ['finish_feedback' => TRUE]; + + $batch_builder = (new BatchBuilder()) + ->setTitle(t('Updating configuration translations')) + ->setInitMessage(t('Starting configuration update')) + ->setErrorMessage(t('Error updating configuration translations')) + ->setFile(drupal_get_path('module', 'locale') . '/locale.bulk.inc'); + $i = 0; $batch_names = []; - $operations = []; foreach ($names as $name) { $batch_names[] = $name; $i++; @@ -568,24 +572,17 @@ function locale_config_batch_build(array $names, array $langcodes, array $option // request. We batch a small number of configuration object upgrades // together to improve the overall performance of the process. if ($i % 20 == 0) { - $operations[] = ['locale_config_batch_refresh_name', [$batch_names, $langcodes]]; + $batch_builder->addOperation('locale_config_batch_refresh_name', [$batch_names, $langcodes]); $batch_names = []; } } if (!empty($batch_names)) { - $operations[] = ['locale_config_batch_refresh_name', [$batch_names, $langcodes]]; + $batch_builder->addOperation('locale_config_batch_refresh_name', [$batch_names, $langcodes]); } - $batch = [ - 'operations' => $operations, - 'title' => t('Updating configuration translations'), - 'init_message' => t('Starting configuration update'), - 'error_message' => t('Error updating configuration translations'), - 'file' => drupal_get_path('module', 'locale') . '/locale.bulk.inc', - ]; if (!empty($options['finish_feedback'])) { - $batch['completed'] = 'locale_config_batch_finished'; + $batch_builder->setFinishCallback('locale_config_batch_finished'); } - return $batch; + return $batch_builder->toArray(); } /** diff --git a/core/modules/locale/locale.compare.inc b/core/modules/locale/locale.compare.inc index c66af14108..fd6bc4f9bf 100644 --- a/core/modules/locale/locale.compare.inc +++ b/core/modules/locale/locale.compare.inc @@ -6,6 +6,7 @@ */ use Drupal\Core\Utility\ProjectInfo; +use Drupal\Core\Batch\BatchBuilder; /** * Load common APIs. @@ -236,23 +237,23 @@ function locale_translation_batch_status_build($projects = [], $langcodes = []) $langcodes = $langcodes ? $langcodes : array_keys(locale_translatable_language_list()); $options = _locale_translation_default_update_options(); - $operations = _locale_translation_batch_status_operations($projects, $langcodes, $options); + $batch_builder = (new BatchBuilder()) + ->setTitle(t('Checking translations')) + ->setErrorMessage(t('Error checking translation updates.')) + ->setFinishCallback('locale_translation_batch_status_finished') + ->setFile(drupal_get_path('module', 'locale') . '/locale.batch.inc'); + _locale_translation_batch_status_operations($batch_builder, $projects, $langcodes, $options); - $batch = [ - 'operations' => $operations, - 'title' => t('Checking translations'), - 'progress_message' => '', - 'finished' => 'locale_translation_batch_status_finished', - 'error_message' => t('Error checking translation updates.'), - 'file' => drupal_get_path('module', 'locale') . '/locale.batch.inc', - ]; - return $batch; + return $batch_builder->toArray(); } /** - * Helper function to construct batch operations checking remote translation - * status. + * Helper function to construct batch operations. + * + * This checks remote translation status. * + * @param \Drupal\Core\Batch\BatchBuilder $batch_builder + * The batch builder to add the operations to. * @param array $projects * Array of project names to be processed. * @param array $langcodes @@ -260,20 +261,20 @@ function locale_translation_batch_status_build($projects = [], $langcodes = []) * @param array $options * Batch processing options. * - * @return array - * Array of batch operations. + * @internal */ -function _locale_translation_batch_status_operations($projects, $langcodes, $options = []) { - $operations = []; - +function _locale_translation_batch_status_operations(BatchBuilder $batch_builder, $projects, $langcodes, $options = []) { foreach ($projects as $project) { foreach ($langcodes as $langcode) { // Check status of local and remote translation sources. - $operations[] = ['locale_translation_batch_status_check', [$project, $langcode, $options]]; + $batch_builder->addOperation( + 'locale_translation_batch_status_check', + [ + $project, $langcode, $options, + ] + ); } } - - return $operations; } /** diff --git a/core/modules/locale/locale.fetch.inc b/core/modules/locale/locale.fetch.inc index 1de6934473..24b7596eaa 100644 --- a/core/modules/locale/locale.fetch.inc +++ b/core/modules/locale/locale.fetch.inc @@ -5,6 +5,8 @@ * The API for download and import of translations from remote and local sources. */ +use Drupal\Core\Batch\BatchBuilder; + /** * Load the common translation API. */ @@ -33,20 +35,19 @@ function locale_translation_batch_update_build($projects = [], $langcodes = [], $status_options = $options; $status_options['finish_feedback'] = FALSE; + $batch_builder = (new BatchBuilder()) + ->setTitle(t('Updating translations')) + ->setErrorMessage('Error importing translation files') + ->setFile(drupal_get_path('module', 'locale') . '/locale.batch.inc') + ->setFinishCallback('locale_translation_batch_fetch_finished') + ->setErrorMessage(t('Error importing translation files')); + // Check status of local and remote translation files. - $operations = _locale_translation_batch_status_operations($projects, $langcodes, $status_options); + _locale_translation_batch_status_operations($batch_builder, $projects, $langcodes, $status_options); // Download and import translations. - $operations = array_merge($operations, _locale_translation_fetch_operations($projects, $langcodes, $options)); + _locale_translation_fetch_operations($batch_builder, $projects, $langcodes, $options); - $batch = [ - 'operations' => $operations, - 'title' => t('Updating translations'), - 'progress_message' => '', - 'error_message' => t('Error importing translation files'), - 'finished' => 'locale_translation_batch_fetch_finished', - 'file' => drupal_get_path('module', 'locale') . '/locale.batch.inc', - ]; - return $batch; + return $batch_builder->toArray(); } /** @@ -67,20 +68,21 @@ function locale_translation_batch_fetch_build($projects = [], $langcodes = [], $ $projects = $projects ? $projects : array_keys(locale_translation_get_projects()); $langcodes = $langcodes ? $langcodes : array_keys(locale_translatable_language_list()); - $batch = [ - 'operations' => _locale_translation_fetch_operations($projects, $langcodes, $options), - 'title' => t('Updating translations.'), - 'progress_message' => '', - 'error_message' => t('Error importing translation files'), - 'finished' => 'locale_translation_batch_fetch_finished', - 'file' => drupal_get_path('module', 'locale') . '/locale.batch.inc', - ]; - return $batch; + $batch = (new BatchBuilder()) + ->setTitle(t('Updating translations.')) + ->setErrorMessage(t('Error importing translation files')) + ->setFile(drupal_get_path('module', 'locale') . '/locale.batch.inc') + ->setFinishCallback('locale_translation_batch_fetch_finished'); + _locale_translation_fetch_operations($batch, $projects, $langcodes, $options); + + return $batch->toArray(); } /** * Helper function to construct the batch operations to fetch translations. * + * @param \Drupal\Core\Batch\BatchBuilder $batch_builder + * The batch builder to add the operations to. * @param array $projects * Array of project names for which to check the state of translation files. * Defaults to all translatable projects. @@ -89,20 +91,28 @@ function locale_translation_batch_fetch_build($projects = [], $langcodes = [], $ * @param array $options * Array of import options. * - * @return array - * Array of batch operations. + * @internal */ -function _locale_translation_fetch_operations($projects, $langcodes, $options) { - $operations = []; - +function _locale_translation_fetch_operations(BatchBuilder $batch_builder, $projects, $langcodes, $options) { foreach ($projects as $project) { foreach ($langcodes as $langcode) { if (locale_translation_use_remote_source()) { - $operations[] = ['locale_translation_batch_fetch_download', [$project, $langcode]]; + $batch_builder->addOperation( + 'locale_translation_batch_fetch_download', + [ + $project, + $langcode, + ] + ); } - $operations[] = ['locale_translation_batch_fetch_import', [$project, $langcode, $options]]; + $batch_builder->addOperation( + 'locale_translation_batch_fetch_import', + [ + $project, + $langcode, + $options, + ] + ); } } - - return $operations; } diff --git a/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php b/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php index 403ef351f3..0e172b043d 100644 --- a/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php +++ b/core/modules/migrate_drupal_ui/src/Form/ReviewForm.php @@ -2,6 +2,7 @@ namespace Drupal\migrate_drupal_ui\Form; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\State\StateInterface; use Drupal\Core\TempStore\PrivateTempStoreFactory; @@ -376,19 +377,11 @@ public function buildForm(array $form, FormStateInterface $form_state) { */ public function submitForm(array &$form, FormStateInterface $form_state) { $config['source_base_path'] = $this->store->get('source_base_path'); - $batch = [ - 'title' => $this->t('Running upgrade'), - 'progress_message' => '', - 'operations' => [ - [ - [MigrateUpgradeImportBatch::class, 'run'], - [array_keys($this->migrations), $config], - ], - ], - 'finished' => [ - MigrateUpgradeImportBatch::class, 'finished', - ], - ]; + $batch = (new BatchBuilder()) + ->setTitle($this->t('Running upgrade')) + ->addOperation([MigrateUpgradeImportBatch::class, 'run'], [array_keys($this->migrations), $config]) + ->setFinishCallback([MigrateUpgradeImportBatch::class, 'finished']) + ->toArray(); batch_set($batch); $form_state->setRedirect(''); $this->store->set('step', 'overview'); diff --git a/core/modules/node/node.admin.inc b/core/modules/node/node.admin.inc index bd1b6232ad..1beac3be07 100644 --- a/core/modules/node/node.admin.inc +++ b/core/modules/node/node.admin.inc @@ -5,6 +5,8 @@ * Content administration and module settings user interface. */ +use Drupal\Core\Batch\BatchBuilder; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\node\NodeInterface; /** @@ -33,20 +35,16 @@ function node_mass_update(array $nodes, array $updates, $langcode = NULL, $load // We use batch processing to prevent timeout when updating a large number // of nodes. if (count($nodes) > 10) { - $batch = [ - 'operations' => [ - ['_node_mass_update_batch_process', [$nodes, $updates, $langcode, $load, $revisions]], - ], - 'finished' => '_node_mass_update_batch_finished', - 'title' => t('Processing'), - // We use a single multi-pass operation, so the default - // 'Remaining x of y operations' message will be confusing here. - 'progress_message' => '', - 'error_message' => t('The update has encountered an error.'), + $batch = (new BatchBuilder()) + ->addOperation('_node_mass_update_batch_process', [$nodes, $updates, $langcode, $load, $revisions]) + ->setFinishCallback('_node_mass_update_batch_finished') + ->setTitle(t('Processing')) + ->setErrorMessage(t('The update has encountered an error.')) // The operations do not live in the .module file, so we need to // tell the batch engine which file to load before calling them. - 'file' => drupal_get_path('module', 'node') . '/node.admin.inc', - ]; + ->setFile(drupal_get_path('module', 'node') . '/node.admin.inc') + ->toArray(); + batch_set($batch); } else { diff --git a/core/modules/node/node.module b/core/modules/node/node.module index ea27e269b2..f09da02281 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -10,6 +10,7 @@ use Drupal\Component\Utility\Xss; use Drupal\Core\Access\AccessResult; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Cache\Cache; use Drupal\Core\Database\Query\AlterableInterface; use Drupal\Core\Database\Query\SelectInterface; @@ -19,6 +20,7 @@ use Drupal\Core\Render\Element; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Template\Attribute; use Drupal\Core\Url; use Drupal\field\Entity\FieldConfig; @@ -1180,13 +1182,11 @@ function node_access_rebuild($batch_mode = FALSE) { // Only recalculate if the site is using a node_access module. if (count(\Drupal::moduleHandler()->getImplementations('node_grants'))) { if ($batch_mode) { - $batch = [ - 'title' => t('Rebuilding content access permissions'), - 'operations' => [ - ['_node_access_rebuild_batch_operation', []], - ], - 'finished' => '_node_access_rebuild_batch_finished', - ]; + $batch = (new BatchBuilder()) + ->setTitle(t('Rebuilding content access permissions')) + ->addOperation('_node_access_rebuild_batch_operation') + ->setFinishCallback('_node_access_rebuild_batch_finished') + ->toArray(); batch_set($batch); } else { diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module index 4ace6e4594..9a53e5e9b0 100644 --- a/core/modules/simpletest/simpletest.module +++ b/core/modules/simpletest/simpletest.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Asset\AttachedAssetsInterface; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Database\Database; use Drupal\Core\Render\Element; use Drupal\Core\Routing\RouteMatchInterface; @@ -149,17 +150,13 @@ function simpletest_run_tests($test_list) { $first_test = reset($test_list); $info = TestDiscovery::getTestInfo($first_test); - $batch = [ - 'title' => t('Running tests'), - 'operations' => [ - ['_simpletest_batch_operation', [$test_list, $test_id]], - ], - 'finished' => '_simpletest_batch_finished', - 'progress_message' => '', - 'library' => ['simpletest/drupal.simpletest'], - 'init_message' => t('Processing test @num of @max - %test.', ['%test' => $info['name'], '@num' => '1', '@max' => count($test_list)]), - ]; - batch_set($batch); + $batch_builder = (new BatchBuilder()) + ->setTitle(t('Running tests')) + ->addOperation('_simpletest_batch_operation', [$test_list, $test_id]) + ->setFinishCallback('_simpletest_batch_finished') + ->setLibraries(['simpletest/drupal.simpletest']) + ->setInitMessage(t('Processing test @num of @max - %test.', ['%test' => $info['name'], '@num' => '1', '@max' => count($test_list)])); + batch_set($batch_builder->toArray()); \Drupal::moduleHandler()->invokeAll('test_group_started'); diff --git a/core/modules/simpletest/tests/modules/simpletest_test/simpletest_test.install b/core/modules/simpletest/tests/modules/simpletest_test/simpletest_test.install index aabe921f59..90f224d89f 100644 --- a/core/modules/simpletest/tests/modules/simpletest_test/simpletest_test.install +++ b/core/modules/simpletest/tests/modules/simpletest_test/simpletest_test.install @@ -5,6 +5,7 @@ * Install hooks for test module. */ +use Drupal\Core\Batch\BatchBuilder; use Drupal\entity_test\Entity\EntityTest; /** @@ -12,14 +13,15 @@ */ function simpletest_test_install() { $total = 2; - $operations = []; + $batch_builder = (new BatchBuilder()) + ->setProgressive(FALSE); for ($i = 1; $i <= $total; $i++) { - $operations[] = ['_simpletest_test_callback', [$i]]; + $batch_builder->addOperation('_simpletest_test_callback', [$i]); } - $batch = [ - 'operations' => $operations, - ]; - batch_set($batch); + batch_set($batch_builder->toArray()); + // TODO: Remove the following two lines of code when issue #638712 is fixed. + // There is currently a bug with non-progressive batches. See + // https://www.drupal.org/project/drupal/issues/638712 for more details. $batch =& batch_get(); $batch['progressive'] = FALSE; batch_process(); diff --git a/core/modules/system/src/Controller/DbUpdateController.php b/core/modules/system/src/Controller/DbUpdateController.php index 25a2a70891..44ee11b5a1 100644 --- a/core/modules/system/src/Controller/DbUpdateController.php +++ b/core/modules/system/src/Controller/DbUpdateController.php @@ -2,6 +2,7 @@ namespace Drupal\system\Controller; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -576,7 +577,12 @@ protected function triggerBatch(Request $request) { $this->state->set('system.maintenance_mode', TRUE); } - $operations = []; + /** @var \Drupal\Core\Batch\BatchBuilder $batch_builder */ + $batch_builder = (new BatchBuilder()) + ->setTitle($this->t('Updating')) + ->setInitMessage($this->t('Starting updates')) + ->setErrorMessage($this->t('An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.')) + ->setFinishCallback([DbUpdateController::class, 'batchFinished']); // Resolve any update dependencies to determine the actual updates that will // be run and the order they will be run in. @@ -602,7 +608,14 @@ protected function triggerBatch(Request $request) { drupal_set_installed_schema_version($update['module'], $update['number'] - 1); unset($start[$update['module']]); } - $operations[] = ['update_do_one', [$update['module'], $update['number'], $dependency_map[$function]]]; + $batch_builder->addOperation( + 'update_do_one', + [ + $update['module'], + $update['number'], + $dependency_map[$function], + ] + ); } } @@ -611,20 +624,13 @@ protected function triggerBatch(Request $request) { if ($post_updates) { // Now we rebuild all caches and after that execute the hook_post_update() // functions. - $operations[] = ['drupal_flush_all_caches', []]; + $batch_builder->addOperation('drupal_flush_all_caches'); foreach ($post_updates as $function) { - $operations[] = ['update_invoke_post_update', [$function]]; + $batch_builder->addOperation('update_invoke_post_update', [$function]); } } - $batch['operations'] = $operations; - $batch += [ - 'title' => $this->t('Updating'), - 'init_message' => $this->t('Starting updates'), - 'error_message' => $this->t('An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.'), - 'finished' => ['\Drupal\system\Controller\DbUpdateController', 'batchFinished'], - ]; - batch_set($batch); + batch_set($batch_builder->toArray()); // @todo Revisit once https://www.drupal.org/node/2548095 is in. return batch_process(Url::fromUri('base://results'), Url::fromUri('base://start')); diff --git a/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php index 8531653247..b746b89863 100644 --- a/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php @@ -2,6 +2,7 @@ namespace Drupal\system\Form; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; @@ -180,18 +181,13 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $entity_type_id = $form_state->getValue('entity_type_id'); $entity_type_plural = $this->entityTypeManager->getDefinition($entity_type_id)->getPluralLabel(); - $batch = [ - 'title' => t('Deleting @entity_type_plural', [ - '@entity_type_plural' => $entity_type_plural, - ]), - 'operations' => [ - [ - [__CLASS__, 'deleteContentEntities'], [$entity_type_id], - ], - ], - 'finished' => [__CLASS__, 'moduleBatchFinished'], - 'progress_message' => '', - ]; + $batch = (new BatchBuilder()) + ->setTitle($this->t('Deleting @entity_type_plural', ['@entity_type_plural' => $entity_type_plural,])) + ->setProgressMessage('') + ->setFinishCallback([__CLASS__,'moduleBatchFinished']) + ->addOperation([__CLASS__, 'deleteContentEntities'], [$entity_type_id]) + ->toArray(); + batch_set($batch); } diff --git a/core/modules/system/tests/modules/batch_test/batch_test.module b/core/modules/system/tests/modules/batch_test/batch_test.module index 59327de4fe..8e9d5578c4 100644 --- a/core/modules/system/tests/modules/batch_test/batch_test.module +++ b/core/modules/system/tests/modules/batch_test/batch_test.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Form\FormState; +use Drupal\Core\Batch\BatchBuilder; /** * Batch operation: Submits form_test_mock_form(). @@ -20,11 +21,10 @@ function _batch_test_nested_drupal_form_submit_callback($value) { * Batch 0: Does nothing. */ function _batch_test_batch_0() { - $batch = [ - 'operations' => [], - 'finished' => '_batch_test_finished_0', - 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', - ]; + $batch = (new BatchBuilder()) + ->setFile(drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc') + ->setFinishCallback('_batch_test_finished_0') + ->toArray(); return $batch; } @@ -38,16 +38,16 @@ function _batch_test_batch_1() { $total = 10; $sleep = (1000000 / $total) * 2; - $operations = []; + /** @var \Drupal\Core\Batch\BatchBuilder $batch_builder */ + $batch_builder = (new BatchBuilder()) + ->setFile(drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc') + ->setFinishCallback('_batch_test_finished_1'); + for ($i = 1; $i <= $total; $i++) { - $operations[] = ['_batch_test_callback_1', [$i, $sleep]]; + $batch_builder->addOperation('_batch_test_callback_1', [$i, $sleep]); } - $batch = [ - 'operations' => $operations, - 'finished' => '_batch_test_finished_1', - 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', - ]; - return $batch; + + return $batch_builder->toArray(); } /** @@ -60,14 +60,11 @@ function _batch_test_batch_2() { $total = 10; $sleep = (1000000 / $total) * 2; - $operations = [ - ['_batch_test_callback_2', [1, $total, $sleep]], - ]; - $batch = [ - 'operations' => $operations, - 'finished' => '_batch_test_finished_2', - 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', - ]; + $batch = (new BatchBuilder()) + ->setFile(drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc') + ->addOperation('_batch_test_callback_2', [1, $total, $sleep]) + ->setFinishCallback('_batch_test_finished_2') + ->toArray(); return $batch; } @@ -85,21 +82,20 @@ function _batch_test_batch_3() { $total = 10; $sleep = (1000000 / $total) * 2; - $operations = []; + /** @var \Drupal\Core\Batch\BatchBuilder $batch_builder */ + $batch_builder = (new BatchBuilder()) + ->setFile(drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc') + ->setFinishCallback('_batch_test_finished_3'); + for ($i = 1; $i <= round($total / 2); $i++) { - $operations[] = ['_batch_test_callback_1', [$i, $sleep]]; + $batch_builder->addOperation('_batch_test_callback_1', [$i, $sleep]); } - $operations[] = ['_batch_test_callback_2', [1, $total / 2, $sleep]]; + $batch_builder->addOperation('_batch_test_callback_2', [1, $total / 2, $sleep]); for ($i = round($total / 2) + 1; $i <= $total; $i++) { - $operations[] = ['_batch_test_callback_1', [$i, $sleep]]; + $batch_builder->addOperation('_batch_test_callback_1', [$i, $sleep]); } - $operations[] = ['_batch_test_callback_2', [6, $total / 2, $sleep]]; - $batch = [ - 'operations' => $operations, - 'finished' => '_batch_test_finished_3', - 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', - ]; - return $batch; + $batch_builder->addOperation('_batch_test_callback_2', [6, $total / 2, $sleep]); + return $batch_builder->toArray(); } /** @@ -115,20 +111,18 @@ function _batch_test_batch_4() { $total = 10; $sleep = (1000000 / $total) * 2; - $operations = []; + /** @var \Drupal\Core\Batch\BatchBuilder $batch_builder */ + $batch_builder = (new BatchBuilder()) + ->setFile(drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc') + ->setFinishCallback('_batch_test_finished_4'); for ($i = 1; $i <= round($total / 2); $i++) { - $operations[] = ['_batch_test_callback_1', [$i, $sleep]]; + $batch_builder->addOperation('_batch_test_callback_1', [$i, $sleep]); } - $operations[] = ['_batch_test_nested_batch_callback', []]; + $batch_builder->addOperation('_batch_test_nested_batch_callback'); for ($i = round($total / 2) + 1; $i <= $total; $i++) { - $operations[] = ['_batch_test_callback_1', [$i, $sleep]]; + $batch_builder->addOperation('_batch_test_callback_1', [$i, $sleep]); } - $batch = [ - 'operations' => $operations, - 'finished' => '_batch_test_finished_4', - 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', - ]; - return $batch; + return $batch_builder->toArray(); } /** @@ -141,16 +135,14 @@ function _batch_test_batch_5() { $total = 10; $sleep = (1000000 / $total) * 2; - $operations = []; + /** @var \Drupal\Core\Batch\BatchBuilder $batch_builder */ + $batch_builder = (new BatchBuilder()) + ->setFile(drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc') + ->setFinishCallback('_batch_test_finished_5'); for ($i = 1; $i <= $total; $i++) { - $operations[] = ['_batch_test_callback_5', [$i, $sleep]]; + $batch_builder->addOperation('_batch_test_callback_5', [$i, $sleep]); } - $batch = [ - 'operations' => $operations, - 'finished' => '_batch_test_finished_5', - 'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc', - ]; - return $batch; + return $batch_builder->toArray(); } /** diff --git a/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php b/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php index 9a5951e6d3..733865941e 100644 --- a/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php +++ b/core/modules/system/tests/modules/batch_test/src/Controller/BatchTestController.php @@ -2,6 +2,7 @@ namespace Drupal\batch_test\Controller; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Form\FormState; /** @@ -47,9 +48,9 @@ public function testLargePercentage() { */ public function testNestedDrupalFormSubmit($value = 1) { // Set the batch and process it. - $batch['operations'] = [ - ['_batch_test_nested_drupal_form_submit_callback', [$value]], - ]; + $batch = (new BatchBuilder()) + ->addOperation('_batch_test_nested_drupal_form_submit_callback', [$value]) + ->toArray(); batch_set($batch); return batch_process('batch-test/redirect'); } diff --git a/core/modules/update/src/Controller/UpdateController.php b/core/modules/update/src/Controller/UpdateController.php index 6a8ec6abcb..2ca902c724 100644 --- a/core/modules/update/src/Controller/UpdateController.php +++ b/core/modules/update/src/Controller/UpdateController.php @@ -5,6 +5,7 @@ use Drupal\update\UpdateManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\Batch\BatchBuilder; /** * Controller routines for update routes. @@ -59,16 +60,13 @@ public function updateStatus() { */ public function updateStatusManually() { $this->updateManager->refreshUpdateData(); - $batch = [ - 'operations' => [ - [[$this->updateManager, 'fetchDataBatch'], []], - ], - 'finished' => 'update_fetch_data_finished', - 'title' => t('Checking available update data'), - 'progress_message' => t('Trying to check available update data ...'), - 'error_message' => t('Error checking available update data.'), - ]; - batch_set($batch); + $batch = (new BatchBuilder()) + ->setTitle($this->t('Checking available update data')) + ->addOperation(UpdateManagerInterface::class, 'fetchDataBatch') + ->setProgressMessage($this->t('Trying to check available update data ...')) + ->setErrorMessage($this->t('Error checking available update data.')) + ->setFinishCallback('update_fetch_data_finished'); + batch_set($batch->toArray()); return batch_process('admin/reports/updates'); } diff --git a/core/modules/update/src/Form/UpdateManagerUpdate.php b/core/modules/update/src/Form/UpdateManagerUpdate.php index e17d214bb7..ba67dfe531 100644 --- a/core/modules/update/src/Form/UpdateManagerUpdate.php +++ b/core/modules/update/src/Form/UpdateManagerUpdate.php @@ -8,6 +8,7 @@ use Drupal\Core\State\StateInterface; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Batch\BatchBuilder; /** * Configure update settings for this site. @@ -331,14 +332,13 @@ public function submitForm(array &$form, FormStateInterface $form_state) { ], ]; } - $batch = [ - 'title' => $this->t('Downloading updates'), - 'init_message' => $this->t('Preparing to download selected updates'), - 'operations' => $operations, - 'finished' => 'update_manager_download_batch_finished', - 'file' => drupal_get_path('module', 'update') . '/update.manager.inc', - ]; - batch_set($batch); + $batch = (new BatchBuilder()) + ->setTitle($this->t('Downloading updates')) + ->setInitMessage($this->t('Preparing to download selected updates')) + ->addOperation($operations) + ->setFile(drupal_get_path('module', 'update') . '/update.manager.inc') + ->setFinishCallback('update_manager_download_batch_finished'); + batch_set($batch->toArray()); } } diff --git a/core/modules/update/update.authorize.inc b/core/modules/update/update.authorize.inc index 664f25f9c5..b845bfae8c 100644 --- a/core/modules/update/update.authorize.inc +++ b/core/modules/update/update.authorize.inc @@ -12,6 +12,7 @@ use Drupal\Core\Updater\UpdaterException; use Drupal\Core\Url; +use Drupal\Core\Batch\BatchBuilder; /** * Updates existing projects when invoked by authorize.php. @@ -49,13 +50,12 @@ function update_authorize_run_update($filetransfer, $projects) { ]; } - $batch = [ - 'init_message' => t('Preparing to update your site'), - 'operations' => $operations, - 'finished' => 'update_authorize_update_batch_finished', - 'file' => drupal_get_path('module', 'update') . '/update.authorize.inc', - ]; - batch_set($batch); + $batch = (new BatchBuilder()) + ->setInitMessage($this->t('Preparing to update your site')) + ->addOperation($operations) + ->setFinishCallback('update_authorize_update_batch_finished') + ->setFile(drupal_get_path('module', 'update') . '/update.authorize.inc'); + batch_set($batch->toArray()); // Since authorize.php has its own method for setting the page title, set it // manually here rather than passing it in to batch_set() as would normally @@ -102,14 +102,12 @@ function update_authorize_run_install($filetransfer, $project, $updater_name, $l ]; // @todo Instantiate our Updater to set the human-readable title? - $batch = [ - 'init_message' => t('Preparing to install'), - 'operations' => $operations, - // @todo Use a different finished callback for different messages? - 'finished' => 'update_authorize_install_batch_finished', - 'file' => drupal_get_path('module', 'update') . '/update.authorize.inc', - ]; - batch_set($batch); + $batch = (new BatchBuilder()) + ->setInitMessage($this->t('Preparing to install')) + ->addOperation($operations) + ->setFile(drupal_get_path('module', 'update') . '/update.authorize.inc') + ->setFinishCallback('update_authorize_install_batch_finished'); + batch_set($batch->toArray()); // Since authorize.php has its own method for setting the page title, set it // manually here rather than passing it in to batch_set() as would normally diff --git a/core/modules/user/user.module b/core/modules/user/user.module index a2b64648a8..737a0c25e5 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -9,6 +9,7 @@ use Drupal\Component\Render\PlainTextOutput; use Drupal\Component\Utility\Unicode; use Drupal\Core\Asset\AttachedAssetsInterface; +use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Render\Element; @@ -695,13 +696,6 @@ function user_cancel($edit, $uid, $method) { return; } - // Initialize batch (to set title). - $batch = [ - 'title' => t('Cancelling account'), - 'operations' => [], - ]; - batch_set($batch); - // When the 'user_cancel_delete' method is used, user_delete() is called, // which invokes hook_ENTITY_TYPE_predelete() and hook_ENTITY_TYPE_delete() // for the user entity. Modules should use those hooks to respond to the @@ -711,21 +705,19 @@ function user_cancel($edit, $uid, $method) { \Drupal::moduleHandler()->invokeAll('user_cancel', [$edit, $account, $method]); } - // Finish the batch and actually cancel the account. - $batch = [ - 'title' => t('Cancelling user account'), - 'operations' => [ - ['_user_cancel', [$edit, $account, $method]], - ], - ]; + // Initialize batch (to set title). + $batch_builder = (new BatchBuilder()) + ->setTitle(t('Cancelling user account')) + ->addOperation('_user_cancel', [$edit, $account, $method]); // After cancelling account, ensure that user is logged out. if ($account->id() == \Drupal::currentUser()->id()) { // Batch API stores data in the session, so use the finished operation to // manipulate the current user's session id. - $batch['finished'] = '_user_cancel_session_regenerate'; + $batch_builder->setFinishCallback('_user_cancel_session_regenerate'); } + $batch = $batch_builder->toArray(); batch_set($batch); // Batch processing is either handled via Form API or has to be invoked