Précédent   Forum des professionnels en informatique > PHP > Outils > Zend > Zend Framework > Zend_Db
Zend_Db Forum d'entraide pour le composant Zend_Db du Zend Framework (création de requêtes, abstraction, ORM etc.). Avant de poster -> FAQ Zend_Db.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 29/10/2007, 20h51   #1
ovh
Rédacteur
 
Avatar de ovh
 
Homme
Ingénieur développement logiciels
Inscription : mai 2002
Messages : 3 725
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : mai 2002
Messages : 3 725
Points : 6 310
Points : 6 310
Par défaut [Zend_Db] ORM avec jointures SQL ?

Bonjour

Je débute avec le ZF, et je bute déjà sur un éceuil En effet les possibilités d'ORM sont séduisantes mais... c'est absolument nul point de vue requêtes SQL puisque ça fait un SELECT pour chaque table liée, que ce soit en lazy ou full loading. (la différence entre les 2 modes se situe juste au niveau du moment où on exécute les SELECT secondaires)
C'est pour moi inacceptable sur une base mysql avec des tables comportant des dizaines de milliers de lignes sur un petit serveur.

Je cherche donc le moyen d'optimiser l'ORM basique de ZF en créant mes objets sur base des champs adéquats, que je sélectionnerais au moyen d'une requête SQL propre (et surtout unique ).

Prenons un exemple abstrait, mettons que j'ai 2 tables SQL, t1 et t2. Je crée 2 classes dérivées de Zend_Db_Table_Abstract, et à partir de t1 je voudrais récupérer les informations de la table t2 qui est liée.
En SQL je ferais :
SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ON t2.id_toto = t1.id_toto
Je me vois donc faire une petite fonction genre "myFetch()" dans la classe t1, qui utilise le db adapter pour passer la requête SQL; mais ensuite tout le noeud du problème consiste à lui dire comment transformer le résultat en objets t1 et t2...

Je ne sais pas si je suis clair

Y a-t-il une méthode magique pour fabriquer son mapping objet à la main, ou bien il faut créer des classes t1_ovh et t2_ovh en mettant tous les champs t1 et t2 en attributs "protected" et en gérant tout ça à la main ? Mais alors bénéfice-t-on encore de tous les avantages du ZF pour les opérations élémentaires sur la table (insert, update, delete, etc.) ? De quels types devraient être ces classes ?

Un grand d'avance à ceux qui pourront m'aider
J'ai cherché au préalable ici et sur google, mais je n'ai pas trouvé de réponse satisfaisante
__________________
Tutoriels sur les UPS, e-commerce, PHP, critiques de livres...

Ce forum est fait pour vous et surtout par vous, merci d'en respecter les règles.
Je n'ai rien à voir avec la société www.ovh.com !
ovh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/10/2007, 22h00   #2
ovh
Rédacteur
 
Avatar de ovh
 
Homme
Ingénieur développement logiciels
Inscription : mai 2002
Messages : 3 725
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : mai 2002
Messages : 3 725
Points : 6 310
Points : 6 310
Grâce à un post de gorgo, il semblerait que la méthode magique soit fetchObject Ca vient de PDO apparemment, et je ne connaissais pas

Enfin ça n'a pas l'air si simple que ça quand il s'agit de séparer différents champs d'un même select dans plusieurs objets différents...

Dans ce cas, c'est peut-être plutôt la fonction bindColumn qu'il faut exécuter, pour faire pointer chaque champ du résultat vers un attribut de la classe ?
http://fr.php.net/manual/en/function...bindColumn.php

Suis-je dans la bonne direction ?
__________________
Tutoriels sur les UPS, e-commerce, PHP, critiques de livres...

Ce forum est fait pour vous et surtout par vous, merci d'en respecter les règles.
Je n'ai rien à voir avec la société www.ovh.com !
ovh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/10/2007, 17h45   #3
ovh
Rédacteur
 
Avatar de ovh
 
Homme
Ingénieur développement logiciels
Inscription : mai 2002
Messages : 3 725
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : mai 2002
Messages : 3 725
Points : 6 310
Points : 6 310
Bon hé bien je n'étais pas dans la bonne direction et j'ai trouvé une solution Pour cela j'ai dû regarder le code source du ZF pour voir comment ils font leur mapping, et en adaptant ça à mes propres classes ça marche \o/

Je ferai une doc un de ces jours pour expliciter cela (après avoir un peu joué avec et voir si ça marche bien pour tous les cas, et aussi optimisé un peu le code)
__________________
Tutoriels sur les UPS, e-commerce, PHP, critiques de livres...

Ce forum est fait pour vous et surtout par vous, merci d'en respecter les règles.
Je n'ai rien à voir avec la société www.ovh.com !
ovh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/11/2007, 00h21   #4
Membre à l'essai
 
Inscription : août 2007
Messages : 21
Détails du profil
Informations personnelles :
Âge : 35
Localisation : France, Doubs (Franche Comté)

Informations forums :
Inscription : août 2007
Messages : 21
Points : 24
Points : 24
Oui, tiens-nous au courant.

Ta solution a l'air intéressante. Moi aussi, je trouve innacceptable la charge induite sur le serveur web par le full loading. C'est une des raisons pour lesquelles je n'utilise pas (encore) l'ORM. Mais avec ta méthode, peut-être... ?
megar est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2007, 10h56   #5
Nouveau Membre du Club
 
Inscription : août 2007
Messages : 95
Détails du profil
Informations forums :
Inscription : août 2007
Messages : 95
Points : 34
Points : 34
Bonjour,
Cela fait plusieurs heures que je cherche a faire une jointure entre 2 classes en utilisant l'ORM mais je n'y arrive pas

quelqu'un peut me donner un exemple simple sil vous plait ?
Guillomme est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2007, 15h56   #6
ovh
Rédacteur
 
Avatar de ovh
 
Homme
Ingénieur développement logiciels
Inscription : mai 2002
Messages : 3 725
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : mai 2002
Messages : 3 725
Points : 6 310
Points : 6 310
OK désolé, je n'ai pas abandonné mais j'ai eu d'autres choses à faire au boulot, mais je m'y réattelle parce que j'ai un projet à terminer pour janvier 2008 donc j'ai intérêt à mettre les bouchées doubles

Alors je vais tenter d'expliquer le principe

Avant d'attaquer le code il faut comprendre basiquement le fonctionnement de l'ORM du ZF. Lorsqu'on fait appel aux méthodes findXX(), findParentRow() etc. pour récupérer un objet lié (jointure), le framework effectue une requête SQL, et sur base de l'array du résultat (renvoyé par l'objet Zend_Db), ZF va créer un objet Zend_Db_Table_Rowset contenant un ensemble d'objets Zend_Db_Table_Row pour chaque ligne de résultat.
Ceci est expliqué dans l'excellent tuto de Julien.

Notre but est de ne plus devoir faire appel aux méthodes findXX(), sans non plus faire du full loading puisque cette dernière méthode ne résoud pas notre problème (effectue autant de requêtes select qu'il y a de jointures, donc très gourmand en ressources). Pour y arriver, nous créerons manuellement notre rowset de résultats. Détails ci-dessous.

Considérons pour notre exemple un modèle en 2 tables : Document et Auteur. Pour simplifier, on considérera qu'un document ne peut avoir qu'un seul auteur et un auteur peut avoir plusieurs documents bien sûr, donc la table Document aura une clé étrangère id_auteur pointant sur la table Auteur.

Nous allons créer une classe Document de manière classique, donc dérivée de Zend_Db_Table_Abstract. Dans cette classe nous pouvons définir les liens ORM au moyen du tableau $_referenceMap au cas où nous aurions besoin d'utiliser l'ORM de base du framework dans certaines situations. Mais pour faire son ORM personnalisé, ce n'est pas nécessaire. Par contre, ce qui est absolument vital c'est de remplacer la classe résultat par défaut par une que nous allons créer, ce qui se fait en renseignant l'attribut $_rowClass (par défaut = Zend_Db_Table_Row).

Code php :
1
2
3
4
5
6
7
8
9
10
11
12
13
class Document extends Zend_Db_Table_Abstract {
 
	protected $_name = "document";
	protected $_schema = "mabelledb";   // schema = nom de la db (facultatif, uniquement si différente de celle par défaut dans $db)
	protected $_rowClass = "DocumentRow";
 
	protected $_referenceMap = array (
			"auteur" => array(
				"columns" => array("id_auteur"),
				"refTableClass" => "Auteur",
				"refColumns" => "id_auteur"
			)
		);

Ensuite dans notre classe Document nous allons créer une fonction pour extraire les résultats qui nous intéressent, appelons-la liste(). Là en considérant que nous construisons la requête SQL dans la variable $sql voici le code intéressant qui va générer les résultats sous forme d'objets :
Code php :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function liste() {
		$db = $this->getAdapter();
		// ici : on génère la requête SQL dans $query
		$sql = $db->quoteInto($query, null);
		$result = $db->query($sql)->fetchAll();
 
		// crée une classe avec tous les résultats (rowset)
		$data  = array(
         'table'    => $this,
         'data'     => $result,
         'rowClass' => $this->_rowClass,
         'stored'   => true
      );
 
      Zend_Loader::loadClass($this->_rowsetClass);
      return new $this->_rowsetClass($data);
	}
Ceci crée un objet classique Zend_Db_Table_Rowset, mais qui au lieu de contenir des Zend_Db_Table_Row contient une classe dérivée de celle-ci pour chaque ligne. Et c'est dans cette classe (plus précisément dans le constructeur) que nous allons créer les objets nécessaires sur base des champs provenant de la jointure SQL.
Le chargement explicite de la classe n'est pas nécessaire si vous utilisez l'auto-loader de ZF.
Illustration :
Code php :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class DocumentRow extends Zend_Db_Table_Row {
 
	public $auteur;
 
	public function __construct($param) {
		// constructeur par défaut
		parent::__construct($param);
 
		// crée une classe pour l'auteur :
		$fields["id_auteur"] = $this->id_auteur;
		$fields["nom"] = $this->anom;
		$data  = array(
         'table'    => $this,
         'data'     => $fields,
         'stored'   => true
      );
      $this->auteur = new Zend_Db_Table_Row($data);
	}
 
};
Je crée un tableau $fields qui contient uniquement les champs constituant un auteur (ici id_auteur et nom), et je les passe en paramètre pour créer un Zend_Db_Table_Row normal que j'associe à l'attribut "auteur" de ma classe. "anom" est le nom de l'auteur tel que je l'ai nommé dans ma jointure SQL. A noter que l'objet Document contient tous les champs accessibles directement ($objet->attribut), même ceux provenant de la jointure.

Si on veut créer d'autres liaisons, on peut procéder de la même manière, en prenant soin de réinitialiser à chaque fois le tableau $fields.
Code php :
1
2
3
4
5
6
7
8
9
// crée une classe pour le fournisseur :
      unset($fields);
		$fields["nom"] = $this->fnom;
		$data  = array(
         'table'    => $this,
         'data'     => $fields,
         'stored'   => true
      );
      $this->fourn = new Zend_Db_Table_Row($data);

Voyons maintenant l'utilisation :
Code php :
1
2
3
4
5
$doc = new Document();
$listedoc = $doc->liste();
foreach ($listedoc as $undoc) {
  echo 'Doc '$undoc->id_doc.' écrit par '.$undoc->auteur->nom.'<br>';
}

Voilà j'espère que j'ai été +/- clair ?

Dites-moi quoi, que je puisse améliorer s'il le faut, et en faire probablement une Q/R de FAQ ou un mini-article.

__________________
Tutoriels sur les UPS, e-commerce, PHP, critiques de livres...

Ce forum est fait pour vous et surtout par vous, merci d'en respecter les règles.
Je n'ai rien à voir avec la société www.ovh.com !
ovh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2007, 20h51   #7
Nouveau Membre du Club
 
Inscription : août 2007
Messages : 95
Détails du profil
Informations forums :
Inscription : août 2007
Messages : 95
Points : 34
Points : 34
Pour ma part ca me semble assez clair, meme si je suis debutant et que certains procédés m'echappent encore dans le Zend
Guillomme est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 17/11/2007, 22h27   #8
Rédacteur
 
Avatar de Yogui
 
Homme Guillaume Rossolini
Directeur technique
Inscription : février 2004
Messages : 13 720
Détails du profil
Informations personnelles :
Nom : Homme Guillaume Rossolini
Localisation : France

Informations professionnelles :
Activité : Directeur technique

Informations forums :
Inscription : février 2004
Messages : 13 720
Points : 17 355
Points : 17 355
Salut

Je viens de tomber là-dessus, au cas où l'idée t'intéresse : What is new in PHP 5.3 - part 2: late static binding
__________________
Mes articles - Zend Certified Engineer (PHP + Zend Framework)
Ressources PHP - Ressources Zend Framework
Yogui est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2007, 13h53   #9
Expert Confirmé
 
Avatar de sekaijin
 
Femme
Urbaniste
Inscription : juillet 2004
Messages : 1 428
Détails du profil
Informations personnelles :
Sexe : Femme
Âge : 48
Localisation : France, Yvelines (Île de France)

Informations professionnelles :
Activité : Urbaniste
Secteur : Santé

Informations forums :
Inscription : juillet 2004
Messages : 1 428
Points : 2 815
Points : 2 815
je viens de regarder ta proposition
il faut la prendre pour l'exemple mais avec des pincettes

beau boulot pour décortiquer le principe mais quelques petites réserves

attention à la création d'un auteur dans le constructeur du doccument
ce constructeur est appelé par diverses méthodes et pas seulement la méthode liste avec sont fetchall il y a là un potentiel problème en effet un find($id) sur ta table va remonter un document sans auteur et ton constructeur n'en tient pas compte.

ensuite ton constructeur construit lui même un auteur mais ne l'attache pa à la table auteur mais à la table document donc finalement ça ne peut pas te servir
pourquoi ne pas simplement en faite un StdClass object

en faire un auteur est intéressant si c'est effectivement un objet auteur complet comme si on l'avait sortit de la table auteur et dans ce cas il convient de l'attacher à la bonne table.

enfin il ne faut pas utiliser ton document pour faire un $document->save() car tu vas avoir des pbs avec l'auteur

bref tout n'est pas fini et ton post mets l'accent sur l'essentiel.

A+JYT
sekaijin est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/11/2007, 14h46   #10
ovh
Rédacteur
 
Avatar de ovh
 
Homme
Ingénieur développement logiciels
Inscription : mai 2002
Messages : 3 725
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : mai 2002
Messages : 3 725
Points : 6 310
Points : 6 310
Merci pour ce commentaire très instructif, je vais à regarder à cela de plus près dès que possible
__________________
Tutoriels sur les UPS, e-commerce, PHP, critiques de livres...

Ce forum est fait pour vous et surtout par vous, merci d'en respecter les règles.
Je n'ai rien à voir avec la société www.ovh.com !
ovh est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/11/2007, 11h52   #11
Futur Membre du Club
 
Inscription : octobre 2007
Messages : 13
Détails du profil
Informations personnelles :
Localisation : France, Haute Savoie (Rhône Alpes)

Informations forums :
Inscription : octobre 2007
Messages : 13
Points : 16
Points : 16
Je me pose actuellement les mêmes questions... Pendant mes recherches je suis tombé sur ce post :

http://fashion.hosmoz.net/post/2007/...-relationships

Ça a l'aire de bouger du coté de chez Zend aussi :

http://www.nabble.com/New-ideas-ques...html#a13756929
http://www.nabble.com/Re%3A--fw-gene...html#a13757451
__2mx est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 04h26.


 
 
 
 
Partenaires

Hébergement Web