Use Drush command with Batch to update Node
In this tutorial, we are going learn how to create/update nodes with the help of the Drush command using Batch API in Drupal. For that, we need to create a custom module. The file structure will be like below:
Example: In the below example, we are updating the article content type Title field with a dummy value by dividing it into chunks of 100, similarly can add your own logic.
To create a custom module, follow the below steps, which will help create a custom Drush Command update:node article.
- Create BatchDrushCommand.php file under the custom module/Commands folder.
<?php namespace Drupal\module_name\Commands; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drush\Commands\DrushCommands; /** * A Drush commandfile for defining the command and callback method to it. */ class BatchDrushCommand extends DrushCommands { /** * Entity type service. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ private $entityTypeManager; /** * Logger service. * * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface */ private $loggerChannelFactory; /** * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * Entity type service. * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerChannelFactory * Logger service. */ public function__construct(EntityTypeManagerInterface$entityTypeManager, LoggerChannelFactoryInterface$loggerChannelFactory) { $this->entityTypeManager = $entityTypeManager; $this->loggerChannelFactory = $loggerChannelFactory; } /** * Update Node. * * @param string $type * Type of node to update * Argument provided to the drush command. * * @command update:node * @aliases update-node * * @usage update:node article */ public functionupdateNode($type = '') { // 1. Log the start of the script. $this->loggerChannelFactory->get('module_name')->info('node update started'); // Check the type of node given as argument, if not, set article as default. if (strlen($type) == 0) { $type = 'article'; } // 2. Retrieve all nodes of this type. try { $storage = $this->entityTypeManager->getStorage('node'); $query = $storage->getQuery() ->condition('type', $type) ->condition('status', '1'); $nidsCount = $query->execute(); $nidsCount = count($nidsCount); } catch (\Exception$e) { $this->output()->writeln($e); $this->loggerChannelFactory->get('module_name')->warning('Error found @e', ['@e' => $e]); } // 3. Create the operations array for the batch. $operations = []; $numOperations = 0; $batchId = 1; if ($nidsCount > 0) { for ($i = 0; $i < $nidsCount;) { $query = $storage->getQuery() ->condition('type', $type) ->range($i, 100) ->condition('status', '1'); $nids = $query->execute(); $articleId = array_keys($nids); $operations[] = [ '\Drupal\module_name\UpdateNode::articleUpdate', [ $batchId, $articleId, ], ]; $batchId++; $numOperations++; $i = $i + 100; } } else { $this->logger()->warning('No nodes of this type @type', ['@type' => $type]); } // 4. Create the batch. $batch = [ 'title' => t('Updating @num node(s)', ['@num' => $numOperations]), 'operations' => $operations, 'finished' => '\Drupal\module_name\UpdateNode::articleUpdateFinished', ]; // 5. Add batch operations as new batch sets. batch_set($batch); // 6. Process the batch sets. drush_backend_batch_process(); } }
- Create a Helper File named UpdateNode.php in which we will write the articleUpdate and articleUpdateFinished function
<?php namespace Drupal\module_name; /** * Class RevisionBatchProcess. */ class UpdateNode { /** * articleUpdate callback. */ public function articleUpdate($id, $articleId, &$context) { foreach ($articleId as $nid) { // Simulate long process by waiting 100 microseconds. usleep(100); $entityService = \Drupal::entityTypeManager(); $articleObject = $entityService->getStorage('node')->loadRevision($nid); $articleObject->set('title', 'update-title'); $articleObject->save(); $context['results'][] = $id; $context['message'] = t('processing "@id" @response', ['@id' => $id, '@response' => $nid] ); } } /** * articleUpdateFinished callback. */ public function articleUpdateFinished($success, array $results, array $operations) { $messenger = \Drupal::messenger(); if ($success) { $messenger->addMessage(t('@count results processed.', ['@count' => count($results)])); } } }
Once the code is added to the module, enable the module or if you are using the existing module, then clear the drupal cache and run the drush update:node article
command.Please add comments if you have any queries or doubts.