Bla bla blog

Aller au contenu | Aller au menu | Aller à la recherche

Tag - Zend_Db_Table

Fil des billets - Fil des commentaires

jeudi 16 avril 2009

Zend_Db : Utilisation du mapping

Après avoir vu comment définir le mapping dans ce précédent article, nous allons voir comment utiliser les classes de ce mapping pour faire du CRUD (Create, Read, Update, Delete) sur nos tables.

Gestion des connexions

Attention Zend_Db_Table utilise l'interface PDO (présente de la version 5.1 de PHP) pour se connecter votre base de données, pensez donc à activer les extensions correspondantes dans le fichier php.in (ie php_pdo.dll et php_pdo_mysql.dll pour une base de données MySql).

Ensuite dans le code il suffit de paramétrer l'adaptateur qui permettra d'établir les connexion de la manière suivante :

    $params = array(
        'host'     => '127.0.0.1',
        'username' => 'root',
        'password' => 'MY_PASSWORD',
        'dbname'   => 'test'
    );
    
    $db = Zend_Db::factory('Pdo_Mysql', $params);
    Zend_Db_Table::setDefaultAdapter($db);

On voit que la méthode static setDefaultAdapter() permet d'enregistrer l'adapteur auprès de la classe Zend_Db_Table, ainsi les connexions/déconnexions seront établies à la demande par cette dernière.

Créations

Pour effectuer une insertion en base de données, il suffit d'instancier la classe mappée sur la table correspondante (la classe Topic pour la table Topics dans notre exemple), puis appeler la méthode createRow() héritée de la classe Zend_Db_Table

$topic = new Topic();
$topic = $topic->createRow();

Vient ensuite l'affectation des différents champs de la table. Ces affectations peuvent s'effectuer en simulant des appels aux attributs de l'objet $topic :

$topic->name=$name;
$topic->forum_id=$id;
$topic->save();

ou en passant un tableau de paramètre à la méthode createRow

$data=array("title"=>$title,"topic_id"=>$id);
$post = $post->createRow($data);
$post->save();

Sans oublier la sauvegarde pour que les modifications soient commitées.

Sélections

Pour les sélections le mécanisme est exactement le même, c'est à dire que l'on commence par instancier la classe correspondant au nom de la table que l'on veut interroger avant d'utiliser les méthodes suivantes :

  • find() pour faire une recherche en filtrant sur la clé primaire
  • fetchAll() pour récupérer plusieurs résultats (RowSet) en ayant la possibilité de filtrer via les paramètres de la méthode
  • fecth() identique au fetchAll() sauf qu'un seul enregistrement (Row) sera retourné
$forum = new Forum();
$all = $forum->fetchAll(); //FetchAll retourne un RowSet donc parcours
foreach($all as $item){
     echo "id:{$item->id}, name:{$item->name}";
}

On voit dans cet exemple qu'en présence d'un RowSet, il faudra le parcourir de manière à récupérer les enregistrement un à un, ce sont en fait des objets Row qui permettent la lecture des valeurs de l'enregistrement.

Pour aller plus loin, comme nous avons défini des relations entre nos table Forum <1_n> Topic <1_n> Post, il est possible d'utiliser ces relations lors d'une selection via les méthode findDependentRowSet("Topic") ou findTopic() pour récupérer tous les enregistrements référençant un Forum. Cette technique est très appréciable pour naviguer dans la structure d'une base de données relationnelle sans ce soucier du SQL et des jointures.

$forum = new Forum();
$forums = $forum->find($pk);
$forum = $forums->current();//on récupère un seul enregistrement forum
echo "FORUM id:{$forum->id}, name:{$forum->name}\n";
$topics = $forum->findDependentRowset("Topic"); //recherche de tous les topics relatifs
foreach($topics as $topic){
    echo "\t TOPIC id:{$topic->id}, name:{$topic->name}\n";
    $posts = $topic->findPost(); //recherche de tous les posts relatifs
    foreach($posts as $post){
                echo "\t\t POST id:{$post->id}, title:{$post->title}\n";
    }
}

Tous les sources de cette démo sont en pièce jointe, il vous faudra simplement créer une base de données "test" ainsi que les trois tables Forums, Topics et Posts. Bon courage et merci pour vos éventuels retours.

Zend_Db : Définition d'un mapping objet relationnel

Dans ZF (Zend Framework) le mapping objet relationnel a été défini via les design patterns "table data gateway" et "row data gateway" inventés par Martin Fowler. Ces patterns permettent d'accéder ou de manipuler le contenu de table via des objets, ici ces objets seront de simples wrapper de notre structure relationnelle, donc chaque table est associée à une classe qui sera définie par le développeur en respectant un certain nombre de règles (héritage, redéfinition, etc) que nous verrons ici.

Un exemple de modèle relationnel

Pour illustrer les possibilités offertes par ce framework, nous prendrons un exemple simple : le forum de discussion, dont le modèle relationnel simplifié serait le suivant :
Forum modele relationnel
Donc simplement trois tables, avec une clé primaire id auto incrémentée sur chaque table et des clés étrangères de posts vers topics et de topics vers forums.

Définition du mapping

En respectant les principes des patterns précités, nous obtenons donc trois classes qui héritent de la classe Zend_Db_Table (fournie par ZF)
Mapping forum definition

Personnalisation du mapping

Toutefois ce mapping ne fonctionnera qu'à condition que votre table porte exactement le même nom que votre classe et que la clé primaire soit le champ ID et qu'elle soit auto-incrémentée. Pour tout autre cas de figure il faudra redéfinir les attributs $_name, $_id et $_sequence dans votre classe. Ainsi pour la classe Topic, nous aurons le code suivant :

<?php
require_once("Zend/Db/Table.php");

class Topic extends Zend_Db_Table{
    
    protected $_primary="id"; //clé primaire 
    protected $_sequence=true; //true est la valeur par défaut, pour une clé primaire auto-incrémentée
                                              //false entraîne l'obligation pour le développeur de renseigner la valeur de sa clé
                                              //une chaîne de caractère, pour les PK de type séquence (uniquement sur certains type de SGBDR)
    protected $_name="topics"; //nom de la table correspondant à cette classe

}
?>

Définition des relations

Dans ZF, la définition des relations doit être faite dans chaque classe. Elle s'appuie sur les relations définies au niveau de la base de données, c'est à dire les clés étrangères. Cette définition est importante car elle permet de "naviguer" dans la grappe d'objets récupérée, par exemple récupérer tous les posts relatifs à un topic, ou à partir d'un post retrouver son topic.

Prenons l'exemple de la table TOPICS, chaque enregistrement dans cette table doit référencer via une clé étrangère une entrée dans la table FORUMS, tout comme les enregistrements dans la table POSTS doivent référencer les entrées dans la table TOPICS. Voyons comment matérialiser ces relations au niveau de la classe Topic :

<?php
require_once("Zend/Db/Table.php");

class Topic extends Zend_Db_Table{
   [...]  

   //$_refernceMap est un tableau associatif qui représente toutes les clés étrangères ou relations de la 
   //table TOPICS avec d'autre tables
   protected $_referenceMap=array("forumKey"=>array(                 //forumKey est l'identifiant de cette relation, utile pour requêter la structure objet lorsqu'il y a plusieurs relations
                                                     "columns"=>array("forum_id"),  //Nom de la colonne portant la clé étrangère
                                                     "refTableClass"=>"Forum",       //Nom de la table référencée
                                                     "refColumns"=>array("id")));     //Nom de la colonne référencée (PK)

  //Noms de toutes les tables qui ont des relations avec la table TOPICS  
  protected $_dependentTables=array("Post");

}
?>

Nous venons de voir comment définir un mapping objet relationnel avec le module Zend_Db de ZF. Pour aller plus loin je vous propose la documentation de ZF.