symfony : hydrater un objet à la main

En utilisant symfony, on ne fait plus réellement de sql du fait de la couche d'abstraction ORM (Propel ou Doctrine). On ne travaille qu'avec des objets. Cela facilite grandement la vie et contribue pour une grande part à la rapidité de développement. Mais cela ne répond pas toujours à tous les besoins...

Imaginons un modèle Script ayant une propriété category qui permet de classifier les différents scripts par catégorie. Si je veux récupérer toutes les catégories de scripts, le code que je vais écrire pourrait ressembler à ça :


public static function getCategories() {
   $criteria = new Criteria();
   $criteria->addGroupByColumn(self::CATEGORY);
   
   return self::doSelect($criteria);
}

J'aurais pu aussi faire un "select distinct catgeory" mais pour les besoins suivants j'ai préféré faire un "group by". Je voudrais maintenant pour chaque catégorie de scripts savoir combien de scripts y sont associés pour afficher dans un menu. Toute ressemblance avec un menu existant n'est pas purement fortuite; mais c'est une autre histoire !

La requête sql serait toute simple :
select category, count(*) as c from scripts group by category;

Il n'est pas possible de faire la même chose en tout objet. Il va falloir hydrater les objets résultats "à la main". On va commencer par ajouter la propriété count à notre object Script, ainsi que les méthodes pour renseigner (setCount) et récupérer (getCount) cette nouvelle propriété:


class Script extends BaseScript
{
  protected $count = 0;

  public function setCount($n) {
    $this->count = $n;
  }

  public function getCount() {
    return $this->count;
  }  
}

Voici maintenant le code pour symfony 1.2.* qui va permettre d'hydrater (c'est-à-dire de transformer chaque ligne de résultat en un objet Script :


  public static function getCategories() {
    $criteria = new Criteria();
    self::addSelectColumns($criteria);
    $criteria->addGroupByColumn(self::CATEGORY);
    $criteria->addAsColumn('cnt', 'COUNT(*)');
    
    $stmt = self::doSelectStmt($criteria);    
    $scripts = array();

    while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
      $script = new Script;
      $col = $script->hydrate($row);
      $script->setCount(($row[$col] !== null) ? (int) $row[$col] : null);
      $scripts[] = $script;
    }

    return $scripts;
  }

Le code pour symfony 1.0.* et plus généralement les versions inférieures à 1.2 est légèrement différents car symopfy 1.2 se base désormais sur PDO:

Il va falloir remplacer la ligne :

$stmt = self::doSelectStmt($criteria);

par

$row = self::doSelectRs($criteria);

Et la ligne :

while ($row = $stmt->fetch(PDO::FETCH_NUM)) {

par

while ($row->next()) {

Haut de page