Astuce [D7] Effectuer des traitements en masse

Pour effectuer des traitements en masse et limiter les problèmes de mémoire, on peut demander à Drupal de les gérer par lots.

Supposons par exemple que l'on souhaite supprimer tous les nœuds de type article, et qu'il y en ait une dizaine de milliers.

// Récupération des nid des nœuds de type article
$results = db_select('node', 'n')
  ->fields('n', array('nid'))
  ->condition('type', 'article', '=')
  ->execute()
  ->fetchCol();

Pour éviter de tout supprimer en une fois, on peut effectuer des suppressions par lots de 500 nœuds.

$nb_op = 500;
$nb_total = count($results);
 
// Découpage des traitements en lots
foreach (array_chunk($results, $nb_op) as $nids) {
  $operations[] = array('_my_module_batch_delete_nodes', array($nids, $nb_total));
}
 
// Construction du tableau de paramètre pour le batch
$batch = array(
  'operations' => $operations,
  'title' => t('Delete batch'),
  'init_message' => t('Initializing'),
  'error_message' => t('An error occurred'),
  'finished' => 'my_module_my_custom_end_function'
);
 
// Exécution du batch
batch_set($batch);
drush_backend_batch_process();

La fonction qui va effectuer la suppression est _my_module_batch_delete_nodes() :

/**
 * Custom batch function to delete multiple nodes.
 *
 * @param $nids Nids of nodes that must be deleted
 * @param $nb_total Number of nodes already deleted
 * @param $context Context to display the progression
 */
function _my_module_batch_delete_nodes($nids, $nb_total, &$context) {
 
  if (empty($context['results']['progress_d'])) {
    $context['results']['progress_d'] = 0;
  }

  node_delete_multiple($nids);

  // Affichage de la progression
  $context['results']['progress_d'] += count($nids);
  $context['message'] = 'Deleted ' . $context['results']['progress_d'] . '/' . $total;
}