Wednesday, March 2, 2016

Drupal batch process to download or create CSV/XLS

Using below code you can able to download or create CSV/XLS file with huge data (I have used it for around 90,000 records) using batch process.

// Menu callback.
     
$items['url_to_my_batch'] = array(
  'title' => "Batch process to download some huge contents",
  'page callback' => 'my_batch_callback',
  'access arguments' => 'administer users',
  'type' => MENU_CALLBACK,
);
Batch menu call back definition.
     
 function my_batch_callback() {
  // File create.
  $download_folder = 'public://my_folder';
  $file_name = 'my-file-' . date('m-d-Y') . '.csv';
  $header = array('Name', 'age', .....);
  // Append header values.
  if (!file_exists($download_folder)) {
    mkdir($download_folder, 0777, TRUE);
  }
  $fp = fopen($download_folder . '/' . $file_name, 'w');
  fprintf($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
  fwrite($fp, implode(",", $header) . "\n");
  fclose($fp);
  // Batch process starts.
  $total = count_for_batch(); // Get total count. It was 90,000 records in my case.
  $batch = array(
    'title' => t('Batch process to download huge data'),
    'finished' => 'process_finished_batch',
  );
  $i = 0;
  $total = $total +1000;
  while($i <= $total) {
    $batch['operations'][] = array('process_my_batch', array($i, $total));
    $i += 1000 ;
  }
  batch_set($batch);
  batch_process('success/page');
}
I have split 90,000 records into 1000 records each to single batch process.
// Collect table row values
     
function process_my_batch($from, $total, &$context) {
  $download_folder = 'public://my_folder';
  $file_name = 'my-file-' . date('m-d-Y') . '.csv';
  $results = function_to_collect_rows($from, 1000);
  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['max'] = count($results[0]);
  }
  $fwp = fopen($download_folder . '/' . $file_name, 'a');
  if (!empty($results[0])) {
    foreach ($results[0] as $key => $value) {
      if (!empty($value)) {
        fwrite($fwp, implode(",", $value) . "\n");
      }
      //increment our progress
      $context['sandbox']['progress']++;
    }
  }
  fclose($fwp);
  //check if batch is finished and update progress
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
  }
}
// Batch finish.
     
function process_finished_batch($success, $results, $operations) {
  if($success) {
    $message = t('The batch was successful');
    drupal_set_message($message);
  }
  else {
    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
  }
}

Some useful references:
-- Drupal 7 Batch Process Example

No comments:

Post a Comment