Más con Symfony

8.3. Creando un hydrator de Doctrine

Una de las principales características de Doctrine en su habilidad para transformar un objeto de tipo Doctrine_Query en resultados con diferentes estructuras. Esta tarea la realizan los hydrators de Doctrine y hasta la versión 1.2 de Doctrine los programadores no podían crear sus propios hydrators. Ahora que ya es posible hacerlo, se puede desarrollar un hydrator propio para crear cualquier tipo de estructura a partir de los resultados obtenidos mediante Doctrine_Query.

El siguiente ejemplo muestra cómo crear un hydrator muy sencillo y fácil de entender, pero a la vez muy útil. El funcionamiento del hydrator consiste en seleccionar un par de columnas y transformarlas en un array asociativo en el que la clave de cada elemento del array es el valor de la primera columna y el valor de cada elemento del array es el valor de la segunda columna.

8.3.1. El esquema y los datos de prueba

Para realizar las pruebas se va a utilizar el siguiente esquema de un modelo sencillo llamado User:

# config/doctrine/schema.yml
User:
  columns:
    username: string(255)
    is_active: string(255)

Como también son necesarios algunos datos de prueba, se va a hacer uso de los siguientes:

# data/fixtures/data.yml
User:
  user1:
    username: jwage
    password: changeme
    is_active: 1
  user2:
    username: jonwage
    password: changeme
    is_active: 0

A continuación ejecuta la siguiente tarea para crear todas las clases:

$ php symfony doctrine:build --all --and-load

8.3.2. Creando el hydrator

Para crear un hydrator sólo es necesario crear una nueva clase que herede de Doctrine_Hydrator_Abstract y que implemente un método llamado hydrateResultSet($stmt). Este método recibe como argumento una instancia del PDOStatement utilizado para ejecutar la consulta. Por tanto, se puede utilizar este objeto para obtener los resultados de la consulta directamente del PDO y transformarlos en la estructura deseada.

Se crea una nueva clase llamada KeyValuePairHydrator y se coloca en el directorio lib/ para que symfony pueda cargarla automáticamente:

// lib/KeyValuePairHydrator.class.php
class KeyValuePairHydrator extends Doctrine_Hydrator_Abstract
{
  public function hydrateResultSet($stmt)
  {
    return $stmt->fetchAll(Doctrine_Core::FETCH_NUM);
  }
}

El código anterior por el momento sólo devuelve los datos tal y como los devuelve PDO. Esto no es lo que queremos, ya que queremos transformar los datos en una estructura de tipo clave => valor. Modifica por tanto el método hydrateResultSet() para completar su funcionalidad:

// lib/KeyValuePairHydrator.class.php
class KeyValuePairHydrator extends Doctrine_Hydrator_Abstract
{
  public function hydrateResultSet($stmt)
  {
    $results = $stmt->fetchAll(Doctrine_Core::FETCH_NUM);
    $array = array();
    foreach ($results as $result)
    {
      $array[$result[0]] = $result[1];
    }
 
    return $array;
  }
}

¡Ha sido bastante fácil! El código del hydrator ya está terminado y hace exactamente lo que queríamos, así que vamos a probarlo.

8.3.3. Utilizando el hydrator

Antes de utilizar el hydrator es necesario registrarlo en Doctrine para que esté disponible cuando se ejecuten las consultas. Para ello, regístralo en la instancia del Doctrine_Manager en la clase ProjectConfiguration:

// config/ProjectConfiguration.class.php
 
// ...
class ProjectConfiguration extends sfProjectConfiguration
{
  // ...
 
  public function configureDoctrine(Doctrine_Manager $manager)
  {
    $manager->registerHydrator('key_value_pair', 'KeyValuePairHydrator');
  }
}

Ahora que el hydrator ya está registrado, se puede utilizar en cualquier instancia de Doctrine_Query, tal y como muestra el siguiente ejemplo:

$q = Doctrine_Core::getTable('User')
  ->createQuery('u')
  ->select('u.username, u.is_active');
 
$results = $q->execute(array(), 'key_value_pair');
print_r($results);

Si se ejecuta el código anterior con los datos de prueba mostrados anteriormente, el resultado es el siguiente:

Array
(
    [jwage] => 1
    [jonwage] => 0
)

¡Y eso es todo! Bastante fácil, ¿verdad? Esperamos que te haya sido útil y que te animes a crear hydrators interesantes y los compartas con el resto de la comunidad.