Relations Zend_Db_TableIntroductionLes tables possèdent des relations entre elles, dans une base de données relationnelle. Une entité d'une table peut être liée à une autre entité d'une autre table, via un procédé appelé contrainte d'intégrité référentielle La classe Zend_Db_Table_Row possède des méthodes pour récupérer des enregistrement dans d'autres tables, liées à celle en cours. Définir ses relationsChaque table doit avoir sa classe étendant Zend_Db_Table_Abstract, comme décrit dans Définir une classe de Table. Voyez aussi La base de données d'exemple pour une description de la base de donnée qui servira d'exemple pour la suite de ce chapitre. Voici les classes correspondantes à ces tables :
Si vous utilisez Zend_Db_Table pour émuler les cascades UPDATE et DELETE, alors déclarez $_dependentTables en tant que tableau dans la classe des tables parentes. Listez ainsi le nom de chaque table dépendante. Utilisez bien le nom des classes, et non les noms physiques des tables.
Déclarez un tableau $_referenceMap dans les classes de chaque table dépendante (qui "reçoit une clé"). C'est un tableau associatif, dit de "rôles". Un rôle définit quelle table est parente dans la relation, et quelle est sa colonne de parenté. Le rôle est utilisé comme index du tableau $_referenceMap. Il est utilisé pour définir la relation, et pourra faire partie du nom de certaines méthodes, comme nous le verrons plus tard. Choisissez ainsi un nom de rôle de manière intelligente.
Dans l'exemple du dessus, les rôles dans la classe Bugs sont :
La valeur de chaque rôle dans le tableau $_referenceMap est aussi un tableau associatif. Les éléments de chaque rôle sont décrits ci-après.
Récupérer des enregistrements dépendants (enfants)
Si vous possédez un enregistrement actif (
Cette méthode retourne un objet instance de
Zend_Db_Table_Rowset_Abstract, qui contient tous les
enregistrements ( Le paramètre $table désigne la table dépendante à utiliser. Ceci peut être une chaîne de caractères aussi bien qu'un objet de la classe de cette table. Example #1 Récupérer des enregistrements dépendants
Cet exemple montre comment obtenir un enregistrement actif (objet
Le second paramètre $rule est optionnel. Il s'agit du nom du rôle à utiliser depuis le tableau $_referenceMap de la classe de la table dépendante. Si vous ne le spécifiez pas, le premier rôle sera utilisé. Il n'y a dans la majorité des cas qu'un seul rôle.
Dans l'exemple ci dessus, nous ne fournissons pas de nom de rôle, le premier est
donc pris en considération, et il s'agit de Example #2 Récupérer des enregistrements dépendants avec un rôle spécifique
Dans cet exemple nous montrons comment obtenir un enregistrement
(
Vous pouvez rajouter des critères à vos relations, comme l'ordre ou la limite,
ceci en utilisant l'objet
Example #3 Récupérer des enregistrements dépendants en utilisant un objet Zend_Db_Table_Select
Dans cet exemple nous montrons comment obtenir un enregistrement
(
Dans les motifs ci-dessus,
Example #4 Récupérer des enregistrements dépendants en utilisant les méthodes magiques Cet exemple a le même effet que le précédent. Il utilise simplement les méthodes magiques pour récupérer les enregistrements dépendants.
Récupérer l'enregistrement parent
Si vous possédez un enregistrement (
La logique veut qu'il ne puisse y avoir qu'un et un seul parent par
enregistrement. Ainsi, cette méthode retourne un objet Le premier paramètre $table désigne la table parente. Ceci peut être une chaîne de caractères, ou un objet instance de la classe de la table parente. Example #5 Récupérer l'enregistrement parent
Cet exemple illustre la récupération d'un enregistrement
Le second paramètre $rule est optionnel. Il s'agit du nom du rôle à utiliser depuis le tableau $_referenceMap de la classe de la table dépendante. Si vous ne le spécifiez pas, le premier rôle sera utilisé. Il n'y a dans la majorité des cas qu'un seul rôle.
Dans l'exemple ci dessus, nous ne fournissons pas de nom de rôle, le premier est
donc pris en considération, et il s'agit de Example #6 Récupérer un enregistrement parent avec un rôle spécifique
Cet exemple va démontrer comment, à partir d'un enregistrement de
Vous pouvez récupérer l'enregistrement parent d'une autre manière. En utilisant les "méthodes magiques". En effet, Zend_Db_Table_Row_Abstract va utiliser la méthode findParentRow('<TableClass>', '<Rule>') si vous appelez sur l'enregistrement une méthode correspondante à un de ces motifs :
Dans les motifs ci-dessus,
Example #7 Récupérer un enregistrement parent en utilisant les méthodes magiques Cet exemple a le même effet que le précédent. Il utilise simplement les méthodes magiques pour récupérer l'enregistrement parent.
Récupérer des enregistrements dans une relation N-N (plusieurs-à-plusieurs ou "many-to-many")Si vous possédez un enregistrement sur une table (appelons la "table d'origine") ayant une relation plusieurs à plusieurs vers une autre table (appelons la "table de destination"), vous pouvez alors accéder aux enregistrements de la table de destination, via une table dite "d'intersection". Utilisez la méthode :
Cette méthode retourne un objet instance de Zend_Db_Table_Rowset_Abstract qui contient les enregistrements de la table $table qui correspondent à la relation plusieurs à plusieurs. L'enregistrement courant de la table courante, $row, est utilisé comme point de départ pour effectuer une jointure vers la table de destination, via la table d'intersection. Le premier paramètre $table peut être soit une chaîne soit un objet instance de la classe de la table de destination dans la relation plusieurs à plusieurs. Le second paramètre $intersectionTable peut être soit une chaîne soit un objet instance de la classe de la table d'intersection dans la relation plusieurs à plusieurs. Example #8 Récupérer des enregistrements dans une relation plusieurs-à-plusieurs
Cet exemple montre comment posséder un enregistrement de la table d'origine
Les troisième et quatrième paramètres, $rule1 et $rule2, sont optionnels. Ce sont des chaînes de caractères qui désignent les rôles à utiliser dans le tableau $_referenceMap de la table d'intersection.
$rule1 nomme le rôle dans la relation entre la table d'origine et la
table d'intersection. Dans notre exemple, il s'agit donc de la relation de
$rule2nomme le rôle dans la relation entre la table d'origine et la
table d'intersection. Dans notre exemple, il s'agit donc de la relation de
Si vous ne spécifiez pas de rôles, alors le premier rôle trouvé pour la table, dans le tableau $_referenceMap, sera utilisé. Dans la grande majorité des cas, il n'y a qu'un rôle.
Dans l'exemple ci-dessus, les rôles ne sont pas spécifiés. Ainsi
$rule1 prend la valeur Example #9 Récupérer des enregistrements dans une relation plusieurs-à-plusieurs avec un rôle spécifique
Cet exemple montre comment à partir d'un enregistrement de
Vous pouvez récupérer l'enregistrement de destination d'une autre manière. En
utilisant les "méthodes magiques". En effet,
Zend_Db_Table_Row_Abstract va utiliser la méthode
Dans les motifs ci dessus,
Example #10 Récupérer des enregistrements dans une relation plusieurs-à-plusieurs avec les méthodes magiques Cet exemple illustre la récupération d'enregistrements dans une table de destination, bugs, depuis un produit, en passant par une table d'intersection, le tout, via des méthodes magiques.
Opérations d'écritures en cascade
Vous pouvez déclarer des opérations de cascade sur un UPDATE ou un DELETE, à appliquer sur les enregistrements dépendants à la table en cours. Example #11 Exemple de DELETE cascade
Cet exemple montre l'effacement d'un enregistrement de
De la même manière, si vous utilisez un UPDATE pour changer la valeur de la clé primaire d'une table parente, vous pourriez nécessiter que les clés étrangères des tables dépendantes soient mises à jour. En général s'il s'agit d'une séquence, il n'est pas nécessaire de mettre à jour les enregistrements dépendants. En revanche concernant les clé dites naturelles , il peut s'avérer nécessaire de propager un changement de valeur.
Afin de déclarer une relation de cascades dans
Zend_Db_Table, éditer les rôles dans $_referenceMap.
Ajoutez les clés Example #12 Exemple de déclaration des opérations de cascade
Dans l'exemple ci-après, les enregistrements de
Pas de mise à jour en cascade en revanche pour cette table, si la clé primaire
de la table parente est changée. En effet, l'élément Notes concernant les opérations de cascadeLes opérations de cascades déclenchées par Zend_Db_Table ne sont pas atomiques. Ceci signifie que si votre SGBD possède un moyen de gérer les cascades, comme l'intégrité référentielle (et les clés étrangères), alors vous ne devriez pas utiliser les cascades INSERT via Zend_Db_Table, car elles vont entrer en conflit avec le système d'intégrité référentielle du SGBD qui lui, est atomique. Le problème est plus mitigé concernant DELETE. Vous pouvez détruire de manière non atomique un enregistrement dépendant, avant de détruire son parent. Cependant, les deux opérations UPDATE et DELETE utilisées de manière non atomique(que), c'est à dire avec le mécanisme de Zend_Db_Table, peuvent laisser la base de données dans un état non désiré, ou état intermédiaire. Supposez que vous supprimiez tous les enregistrements dépendants, pour finir par leur parent unique. A un moment donnée, la base de donnée sera dans un état tel que le parent sera sans enfants, mais toujours bel et bien présent. Si un autre client se connecte exactement à ce moment là, il va pouvoir requêter éventuellement le parent, en croyant que celui-ci n'a plus d'enfant, ce qui normalement n'est pas le cas. Il est alors totalement impossible pour ce client là de se rendre compte qu'il a effectuer une lecture au beau milieu d'une plus vaste opération d'effacement. Les problèmes de changements non-atomique peuvent être anéantis en utilisant les transactions isolantes, c'est d'ailleurs un de leur rôle clé. Cependant certains SGBDs ne supportent pas encore les transactions, et autorisent leurs clients à lire des changements incomplets pas validés en totalité. Les opérations de cascades de Zend_Db_Table ne sont utilisées que par Zend_Db_Table.
Les cascades pour DELETE et UPDATE définies dans vos
classes Zend_Db_Table ne sont utilisées que lors du recours
aux méthodes save() ou delete() sur les enregistrements
Pas d'INSERT en cascade Le support pour les cascades d'INSERT n'est pas assuré. Vous devez explicitement insérer les enregistrements dépendants à un enregistrement parent.
|