Aggiornare in massa l'urlalias dei contenuti

Come utilizzare hook_update_N() e le Batch API.

7 October, 2016

Quest'oggi volevo condividere con voi un post che avevo scritto l'anno scorso su Drupal.org, utile per chi deve eseguire dei processi batch per aggiornare grosse moli di dati. Per evitare che il processo vada in timeout, invece di eseguire l'aggiornamento su tutto in un unica passata, effettueremo più aggiornamenti su porzioni di dati fino a completamento. Quando si deve lavorare con molti dati la soluzione sta sempre nel concetto di divide et impera.

Qui di seguito vedremo i frammenti più significativi dell'intero codice che potete trovare nel mio post.

Utilizzare la variabile $sandbox

Per partizionare l'insieme di dati da aggiornare dobbiamo tenere traccia di alcune informazioni importanti:

  • il numero totale di nodi da aggiornare;
  • il numero di nodi elaborati fino ad ora;
  • messaggi da visualizzare durante l'esecuzione;
  • l'identificativo dell'ultimo nodo aggiornato;

Questi dati vengono memorizzati all'interno della variabile $sandbox passata come parametro ( per riferimento) alla funzione hook_update_N(&$sandbox). Alla prima iterazione si inizializza la variabile con le informazioni di partenza nel modo seguente:

    // Use the sandbox to store the information needed to track progression.
    if (!isset($sandbox['progress'])) {
      // The count of nodes visited so far.
      $sandbox['progress'] = 0;
      // Total nodes that must be visited.
      $sandbox['max'] = $result->rowCount();
      // A place to store messages during the run.
      $sandbox['messages'] = array();
      // Last node read via the query.
      $sandbox['current_node'] = -1;
    } 

Poi ad ogni iterazione successiva, provvederemo ad aggiornare i suoi valori:

  foreach ($result as $row) {
    /*
      Do you jobs...
     */

    // Update our progress information.
    $sandbox['progress']++;
    $sandbox['current_node'] = $row->nid;
  } 

Prima di chiudere la funzione, verificheremo se il processo deve terminare o essere eseguito nuovamente. Per farlo basta confrontare il valore di $sandbox['progress'] con il numero totale degli elementi da aggiornare $sandbox['max'] nel seguente modo:

  // Set the "finished" status, to tell batch engine whether this function
  // needs to run again. If you set a float, this will indicate the progress
  // of the batch so the progress bar will update.
  $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max'])
    ? TRUE
    : ($sandbox['progress'] / $sandbox['max']);

  if ($sandbox['#finished'])
  {
    return t('The batch URL Alias rebuild is finished.');
  } 

Definire la finestra di elaborazione

Dimenticavo, dovete inoltre impostare l'ampiezza della finestra di elaborazione, cioè il numero di elementi da elaborare ad ogni ciclo. Ecco come:

  // Process nodes by groups of 50.
  // When a group is processed, the batch update engine determines
  // whether it should continue processing in the same request or provide
  // progress feedback to the user and wait for the next request.
  $limit = 50;

  // Retrieve the next group of nids.
  $query = db_select('node', 'n')->extend('PagerDefault');

  $result = $query->fields('n', array('nid'))
      ->orderBy('n.nid', 'ASC')
      ->condition('type', array('type_one','type_two','type_three'), 'IN')
      ->condition('n.nid', $sandbox['current_node'], '>')
      ->limit($limit)->execute(); 

Bene questo è tutto. Per vedere il codice completo vi rimando alla pagina del post su Drupal.org.