read

hook_update_N con multipass

Cuando tenemos que realizar un hook_update_N que por su naturaleza es muy posible que rompa los timeouts de PHP; es recomendable utilizar la técnica de multipass; es decir, realizar un sólo hook_update_N pero en varias pasadas. Para ello, utilizamos el parámetro opcional del hook llamado &$sandbox y podemos realizarlo de la siguiente manera.

/**
 * Poner de autor al user 1 para los nodos creados por anonymous.
 */
 function demo_update_7000(&$sandbox) {
   if (!isset($sandbox['progress'])) {
     $sandbox['progress'] = 0;
     // Cantidad total de nodos.
     $sandbox['max'] = db_select('node', 'n')
       ->fields('n', array('nid'))
       ->condition('n.uid', 0)
       ->countQuery()
       ->execute()
       ->fetchField();
     // Aquí almacenaremos mensajes si fuera necesario.
     $sandbox['messages'] = array();
     // Aquí llevamos control del nodo actual.
     $sandbox['current_node'] = -1; 
   }
   // Cuántos nodos visitaremos por cada pasada (valor arbitrario).
   $limit = 100;
   // Traer sólo los nodos mayores al nodo actual.
   $result = db_select('node', 'n')
     ->fields('n', array('nid'))
     ->orderBy('n.nid', 'ASC')
     ->condition('n.nid', $sandbox['current_node'], '>')
     ->condition('n.uid', 0)
     ->extend('PagerDefault')
     ->limit($limit)
     ->execute();

   foreach ($result as $row) {
     $nid = $row->nid;
     // Llamamos a una función que realice la acción (o podemos hacerla aquí).
     $return = demo_node_set_uid($nid, 1);
     if ($return) {
       $sandbox['messages'][] = t('Updated author for node @nid: @title', array('@nid' => $nid, '@title' => $return));
     }
     // Actualizar la información de progreso..
     $sandbox['progress']++;
     $sandbox['current_node'] = $nid;
  }
  // Después de esta pasada actualizamos #finished. Si es 1 implica que terminó;
  // sino, actualiza el progreso.
  $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']);

  // Si ya terminó.
  if ($sandbox['#finished']) {
    if (!count($sandbox['messages'])) {
      $sandbox['messages'][] = t('No messages');
    }
    // Crear el mensaje final que vamos a imprimir al usuario.
    $final_message = '<ul><li>' . implode('</li><li>', $sandbox['messages']) . '</li></ul>';
    return t('Finished updating node authors. Messages: @message', array('@message' => $final_message));
  }
 }

Como podemos ver; aunque es un poco más complejo que el update_N normal; en realidad sigue siendo sencillo y útil para procesos que podrían tomar mucho tiempo y que posiblemente alcanzarían los timeouts de php.

Blog Logo

Kevin Jesús Porras Zumbado

Drupal Backend Developer y un poco de site-builder. Me gustan los retos con las tecnologías y siempre aprender cosas nuevas.


Published

blog comments powered by Disqus
Image

Blog de Kporras07

Un intento personal de documentación

Back to Overview