Finding a good tutorial about the batch API can be a little difficult. When you do, it may be a little difficult to understand. So here is my shot to try a simple tutorial. 4 simple functions you will need as a minimum:
- hook_menu to create the page
- callback function to run when page is hit (sets up the batch jobs)
- actual function to run multiple times during the batch
- function to run after job is complete (catches success and error messages)
That’s it, here we go:
// mymodule_import.module // menu_hook to create a page function mymodule_import_menu() { $items['admin/mymodule-import'] = array( 'title' => 'Import stuff', 'page callback' => 'mymodule_import_stuff', 'access arguments' => array('access administration pages'), 'type' => MENU_NORMAL_ITEM, ); return $items; } // menu callback function - sets up the batch function mymodule_import_stuff() { $batch = array( 'operations' => array(), 'finished' => 'mymodule_import_batch_finished', // runs after batch is finished 'title' => t('Processing Import'), 'init_message' => t('Import is starting.'), 'progress_message' => t('Processed @current out of @total.'), 'error_message' => t('Import has encountered an error.'), ); $progress = 0; // where to start $limit = 100; // how many to process for each run $max = 1000; // how many records to process until stop - can do query here to get max times to run while ($progress <= $max) { $batch['operations'][] = array('mymodule_import_stuff_process', array($progress, $limit)); $progress = $progress + $limit; } batch_set($batch); batch_process('admin/mymodule-import'); // page to return to after complete } // this is what runs multiple times per batch // progress and limit and is updated during each run function mymodule_import_stuff_process($progress, $limit, &$context) { // use $progress and $limit to only run that amount of records // example using db_select $query = db_select('node', 'n'); $query->fields('n.nid'); $query->orderBy('n.nid', 'ASC'); $query->range($progress, $limit); $nodes = $query->execute()->fetchAll(); foreach ($nodes as $node) { // processing } // update progress for message $progress = $progress + $limit; // update message during each run so you know where you are in the process $context['message'] = 'Now processing ' . $progress . ' - ' . $context['results'][0] . ' imported'; } function mymodule_import_batch_finished($success, $results, $operations) { if ($success) { drupal_set_message('Import is complete'); } else { $error_operation = reset($operations); $message = t('An error occurred while processing %error_operation with arguments: @arguments', array( '%error_operation' => $error_operation[0], '@arguments' => print_r($error_operation[1], TRUE) )); drupal_set_message($message, 'error'); } }
Little tip: if you want to keep track of records updated or inserted (or any other kind of persistent value), you can latch onto $context[‘results’]. So that would look like:
// add to bottom of mymodule_import_stuff_process()
$context['results']['updated'] = $context['results']['updated'] + $updated_count;
$context['results']['inserted'] = $context['results']['inserted'] + $new_count;
//retrieve final number in mymodule_import_batch_finished()
if ($success) {
drupal_set_message($results['updated'] . ' updated');
drupal_set_message($results['inserted'] . ' inserted');
}