Batch Processing To Update Nodes In Drupal And Download Updated Nods In CSV Format
What is Batch Processing:
In Drupal, batch processing is a mechanism that allows you to execute time-consuming operations in smaller, manageable chunks. It helps prevent PHP timeouts and allows long-running processes to be executed successfully. Batch processing is commonly used for tasks such as data migration, large-scale updates, or any operation involving a significant amount of data.
Batch processing is a powerful feature in Drupal that allows you to efficiently update a large number of nodes. In this blog post, we will walk you through implementing batch processing to update nodes in Drupal.
Batch processing for updating nodes and downloading updated nodes in CSV format in your Drupal application:
Step 1:
Create the custom module with the name batch_process, then create the .info.yml File Start by creating a file called batch_process.info.yml
In your custom module’s root directory. The .info.yml file provides metadata about your module to Drupal. Here’s an example of its contents:
name: "Batch Process" type: module description: "Example module demonstrating batch processing in Drupal" package: Custom version: "1.0" core_version_requirement: ^8 || ^9
Step 2:
Create the .module File Next, create a file called batch_process.module
in your custom module’s root directory. The .module file is where you define the module’s functionality and hook implementations. Here’s an example of its contents:
<?php use Drupal\Core\Routing\RouteMatchInterface; /** * Implements hook_help(). */ function batch_process_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { case 'help.page.batch_process': return '<p>' . t('Help text for My Module.') . '</p>'; } } /** * Implements hook_menu(). */ function batch_process_menu() { $items['admin/config/batch-process/update-nodes'] = array( 'title' => 'Update Nodes', 'description' => 'Update nodes using batch processing', 'route_name' => 'batch_process.update_nodes', 'weight' => 0, ); $items['admin/config/batch-process/download-csv'] = array( 'title' => 'Download CSV', 'route_name' => 'batch_process.download_csv', 'weight' => 1, ); return $items; } /** * Implements hook_theme(). */ function batch_process_theme() { return array( 'batch_process_update_nodes_form' => array( 'render element' => 'form', ), ); }
Step 3:
Define the Routing File Create a file called batch_process.routing.yml
in your custom module’s root directory. The routing file defines the URLs and corresponding controller methods for your module. Here’s an example of its contents:
batch_process.update_nodes: path:"/update-nodes" defaults: _form:'\Drupal\batch_process\Form\UpdateNodesForm' _title:"Update Nodes" requirements: _permission:"access content" _access:"TRUE" batch_process.download_csv: path:"/batch-process/download-csv" defaults: _controller:'\Drupal\batch_process\Controller\BatchProcessController::downloadCsv' requirements: _permission:"access content"
Step 4:
BatchProcessController.php
in your custom module’s src/Controller
Directory. This file will handle the batch-processing functionality. Here’s an example of its contents:<?php namespace Drupal\batch_process\Controller; use Drupal\Core\Controller\ControllerBase; use Drupal\batch_process\Batch\BatchProcessUpdateNodes; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Serializer\Encoder\CsvEncoder; /** * Class BatchProcessController. */ class BatchProcessController extends ControllerBase { /** * Download the updated nodes as a CSV file. */ publicfunctiondownloadCsv() { $csvData =BatchProcessUpdateNodes::generateCsvData(); $csvContent =''; if(!empty($csvData)){ $csvEncoder =newCsvEncoder(); $csvContent =$csvEncoder->encode($csvData,'csv'); } $response =newResponse($csvContent); $response->headers->set('Content-Type','text/csv'); $response->headers->set('Content-Disposition','attachment; filename="updated_nodes.csv"'); return$response; }
Step 5:
UpdateNodesForm.php
in your custom module’s src/Form
Directory. This form will include a button “Download Updated Nodes (CSV)” by clicking on the user can download the updated nodes in csv format. Here’s an example of its contents:<?php namespace Drupal\batch_process\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; use Drupal\batch_process\Batch\BatchProcessUpdateNodes; /** * Class UpdateNodesForm. */ class UpdateNodesForm extends FormBase { /** * {@inheritdoc} */ publicfunctiongetFormId() { return'batch_process_update_nodes_form'; } /** * {@inheritdoc} */ publicfunctionbuildForm(array$form,FormStateInterface$form_state) { $form['#title']=$this->t('Update Nodes'); $form['csv_download']=[ '#type'=>'link', '#title'=>$this->t('Download Updated Nodes (CSV)'), '#url'=>Url::fromRoute('batch_process.download_csv'), '#attributes'=>[ 'class'=>['button'], ], ]; $form['submit']=[ '#type'=>'submit', '#value'=>$this->t('Start Batch Processing'), ]; return$form; } /** * {@inheritdoc} */ publicfunctionsubmitForm(array&$form,FormStateInterface$form_state) { $batch =array( 'title'=>t('Updating nodes'), 'init_message'=>t('Starting node update...'), 'progress_message'=>t('Processed @current out of @total nodes.'), 'error_message'=>t('An error occurred during processing.'), 'operations'=>array( array( '\Drupal\batch_process\Batch\BatchProcessUpdateNodes::processBatch', array(), ), ), 'finished'=>'\Drupal\batch_process\Batch\BatchProcessUpdateNodes::finishBatch', ); batch_set($batch); $redirect_url =Url::fromRoute('batch_process.update_nodes')->toString(); $form_state->setRedirectUrl(Url::fromRoute('batch_process.update_nodes')); } }
Step 6:
Implement the Batch Process Now, let’s implement the batch process logic. Create a file called BatchProcessUpdateNodes.php in your custom module’s src/Batch directory. This file will contain the functions responsible for the batch process.
The processBatch() Method: This method is the main batch callback function. It processes nodes in batches by updating their status to “Published” and performing any other necessary updates. It keeps track of the progress and current node count, and when all nodes have been processed, it marks the batch as finished.
ThefinishBatch() Method: This method is called after the batch processing is complete. It displays a success or error message using Drupal’s messenger service, indicating the status of the node update process. It provides feedback to the user regarding the outcome of the batch processing.
ThegenerateCsvData() Method: This method generates CSV data containing information about the updated nodes. It retrieves the published nodes and extracts the required information, such as the node ID, title, and updated status. The method returns the CSV data array, which can be used for further processing or generating reports.
<?php namespace Drupal\batch_process\Batch; use Drupal\Component\Serialization\Csv; use Drupal\Core\Url; use Drupal\node\Entity\Node; use Symfony\Component\HttpFoundation\Response; /** * Class BatchProcessUpdateNodes. */ class BatchProcessUpdateNodes { /** * Batch callback. */ publicstaticfunctionprocessBatch(&$context) { if(empty($context['sandbox'])){ $context['sandbox']['progress']=0; $context['sandbox']['max']=1000;// Total number of nodes to process $context['sandbox']['current_node']=0; } $limit =10;// Number of nodes to process in each batch $query =\Drupal::entityQuery('node') ->condition('status',[0,1],'IN')// Published and unpublished nodes ->range($context['sandbox']['current_node'],$limit)// Process only a limited number of nodes ->sort('nid','ASC');// Sort by node ID in ascending order $nids =$query->execute(); $nodes =Node::loadMultiple($nids); foreach($nodes as$node){ // Update the status of the node to "Processed" $node->set('status',1);// 1 means "Published" $node->save(); // Perform other necessary updates to the newly added nodes // Increment the current node count $context['sandbox']['current_node']++; // Update the progress $context['sandbox']['progress']=($context['sandbox']['current_node']/$context['sandbox']['max'])*100; // If all nodes have been processed, mark the batch as finished if($context['sandbox']['current_node']>=$context['sandbox']['max']){ $context['finished']=1; break; } } // Set the progress message $context['message']=t('Processed @current out of @total nodes.',array( '@current'=>$context['sandbox']['current_node'], '@total'=>$context['sandbox']['max'], )); } /** * Batch finished callback. */ publicstaticfunctionfinishBatch($success,$results,$operations) { if($success){ \Drupal::messenger()->addMessage(t('Node update completed successfully.')); }else{ \Drupal::messenger()->addMessage(t('Node update completed with errors.'),'error'); } } /** * Generate CSV data for updated nodes. */ publicstaticfunctiongenerateCsvData() { $csvData =array( array('Node ID','Title','Updated Status'), ); // Retrieve the updated nodes. $query =\Drupal::entityQuery('node') ->condition('status',1)// Published nodes ->range(0,1000)// Limit the query to the maximum number of nodes ->sort('nid','ASC');// Sort by node ID in ascending order $nids =$query->execute(); $nodes =Node::loadMultiple($nids); // Extract the required information from the updated nodes. foreach($nodes as$node){ $csvData[]=array( $node->id(), $node->label(), 'Published', ); } return$csvData; } }
Step 7:
batch-process-update-nodes-form.html.twig
in your custom module’s templates
directory. This template file will render the form elements defined in the form class.{{ form }} {{ csv_download }}
Go to your drupal site and open the form : /update-nodes
Before Updating the nodes
Click on the “Start Batch Processing” Button and start the batch processing. All the nodes will updated.
After updating the nodes
Now, you can download the updated node by clicking “Download Updated Nodes (CSV)” Button.
You can see the updated nodes in CSV format.
Thank You.