Using Batch API in Drupal 7 - Batch API Tutorial

Drupal's batch API processing is awesome and offers two great benefits: -

  1. You can break long tasks into smaller batches, preventing max_execution_time errors
  2. You can give the visitor (or more likely administration or developer) some feedback

Building a batch routine in a custom module requires a minimum of 4 function including the batch function call: -

  1. Call the batch API and tell it which function to build the batch instructions.
  2. The batch builder loop which builds a list of operations for the batch routine to perform. It doesn't call the operation code at this point but purely makes the list of operations.
  3. The function to perform 1 operation in the batch.
  4. A "Finished" function to notify the user when we're finished, or if there is an error.

Let's look through a working example, with some of the actual work code removed as it's not important here. This code was mostly adapted from the excellent "Examples" module collection.

Step 1 - Call the batch API function

This just passes a function name to the batch API. The referenced function should build the array which tells batch API what to do. In our example we have it on a form submit handler.

<?php
/*
* Form Submit handler
*/
function drupology_form_submit($form, $form_state) {
 
batch_set(drupology_associate_audio_tiles_to_songs());
}
?>


Step 2 - Create the list of operations to call when the batch starts

Here we essentially build an array of future function calls, with arguments, and a finished function.

The important thing here is the $operations array so look at that closely. When the batch starts it will loop through that array calling those function names with those arguments.

<?php
/**
* Batch operation: associate audio tiles to each song node.
*/
function drupology_associate_audio_tiles_to_songs() {
 
drupal_set_message('Updating Song Nodes');
 
// load all the "Song Story" nodes
 
$nodes = node_load_multiple(array(), array('type' => "story_song"));
 
$node_count = count($nodes);
 
// build the list of operation functions and function arguments
 
foreach($nodes as $nid=>$node) {
   
// $operations[] = array(<function name>, <array of arguments to pass to function>);
   
$operations[] = array('drupology_associate_audio_tiles_to_song', array($node));
  }
 
// build the batch instructions
 
$batch = array(
   
'operations' => $operations,
   
'finished' => 'drupology_associate_audio_tiles_to_songs_finished',
  );
  return
$batch;
}
?>


Step 3 - Create the operation code

This is the actual operation part - the thing that does the work. The arguments it receives will have come from the $operations[] loop in step 2 above. Note the additional $context argument. This is in additional to the ones we provided in step 2 and lets us converse with the batch. This is useful for passing back status messages, etc.

<?php
/**
* Batch operation: associate audio tiles to 1 node.
* This is the function that is called on each operation in the above.
*/
function drupology_associate_audio_tiles_to_song($node, &$context) {
 
$context['results'][] = $node->nid . ' : ' . check_plain($node->title);
 
// Optional message displayed under the progressbar.
 
$context['message'] = t('Processing song "@title"', array('@title' => $node->title));
 
$updated = FALSE;
 
// .... do the actual work - code removed in this example
 
if ($updated) {
   
node_save($node);
   
$path = drupal_lookup_path("alias", "node/" . $node->nid);
   
drupal_set_message("<a href='/$path'>" . $node->title . "</a> updated.");
  }
}
?>


Step 4 - Create the "Finished" code

Here we let the user know when we've finished and also if there were any errors.

<?php
function drupology_associate_audio_tiles_to_songs_finished($success, $results, $operations) {
  if (
$success) {
   
// Here we could do something meaningful with the results.
    // We just display the number of nodes we processed...
   
drupal_set_message(t('@count songs  processed.', array('@count' => count($results))));
  } else {
   
// An error occurred.
    // $operations contains the operations that remained unprocessed.
   
$error_operation = reset($operations);
   
drupal_set_message(t('An error occurred while processing @operation with arguments : @args', array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE))));
  }
}
?>

Get in touch

This form collects your name, telephone number (optionally) and email address only so we can contact you back about your enquiry. We do not and will never use your data for any other purposes other than contacting you regarding this enquiry and no data is shared with any third-party.