2008-10-24 8 views
7

La situation est la suivante: J'ai 2 modèles: 'Action' et 'Utilisateur'. Ces modèles se réfèrent aux tableaux «actions» et «utilisateurs», respectivement.Assembler automatiquement des tables sans rompre le comportement par défaut dans Zend Framework

Ma table d'action contient une colonne user_id. À ce stade, j'ai besoin d'un aperçu de toutes les actions et des utilisateurs auxquels elles sont affectées. Lorsque j'utilise $action->fetchAll(), je n'ai que l'ID utilisateur, donc je veux être en mesure de joindre les données du modèle de l'utilisateur, de préférence sans faire un appel à findDependentRowset().

Je pensais créer des méthodes personnalisées fetchAll(), fetchRow() et find() dans mon modèle, mais cela romprait le comportement par défaut.

Quelle est la meilleure façon de résoudre ce problème? Toute aide serait grandement appréciée.

+0

Quel est le problème avec Zend_Db_Table_Row :: findDependentRowset()? –

+1

Une objection à findDependentRowset() et findParentRow() est qu'il est moins efficace de charger les lignes reliées une par une que d'interroger les deux tables avec un JOIN lorsque vous savez depuis le début que vous avez besoin de toutes les lignes associées. –

Répondre

14

J'ai conçu et mis en œuvre la table des relations fonctionnalité dans Zend Framework.

Mon premier commentaire est que vous n'utiliserez pas findDependentRowset() de toute façon - vous utiliseriez findParentRow() si l'action a une référence de clé étrangère à l'utilisateur.

$actionTable = new Action(); 
$actionRowset = $actionTable->fetchAll(); 
foreach ($actionRowset as $actionRow) { 
    $userRow = $actionRow->findParentRow('User'); 
} 

Edit: Dans la boucle, vous avez maintenant une actionRow $ et un objet de userRow $. Vous pouvez écrire des modifications dans la base de données via l'un des objets en modifiant les champs d'objet et en appelant save() sur l'objet.

Vous pouvez également utiliser la classe Zend_Db_Table_Select (qui a été implémentée après avoir quitté le projet) pour récupérer un Rowset basé sur une jointure entre Action et Utilisateur.

$actionTable = new Action(); 
$actionQuery = $actionTable->select() 
    ->setIntegrityCheck(false) // allows joins 
    ->from($actionTable) 
    ->join('user', 'user.id = action.user_id'); 
$joinedRowset = $actionTable->fetchAll($actionQuery); 
foreach ($joinedRowset as $joinedRow) { 
    print_r($joinedRow->toArray()); 
} 

Notez qu'un tel Rowset basé sur une requête de jointure est en lecture seule. Vous ne pouvez pas définir les valeurs de champ dans les objets Ligne et appeler save() pour publier les modifications dans la base de données.

Editer: Il est impossible de rendre accessible en écriture un ensemble de résultats joint arbitraire. Prenons un exemple simple en fonction du résultat joint défini ci-dessus:

action_id action_type user_id user_name 
    1   Buy   1  Bill 
    2   Sell   1  Bill 
    3   Buy   2  Aron 
    4   Sell   2  Aron 

suivant pour la ligne avec action_id = 1, je change un des champs qui sont venus de l'objet utilisateur:

$joinedRow->user_name = 'William'; 
$joinedRow->save(); 

Questions: quand je vois la ligne suivante avec action_id = 2, devrais-je voir 'Bill' ou 'William'? Si 'William', cela signifie-t-il que la sauvegarde de la ligne 1 doit automatiquement mettre 'Bill' à 'William' dans toutes les autres lignes de cet ensemble de résultats? Ou cela signifie-t-il que save() réexécute automatiquement la requête SQL pour obtenir un jeu de résultats actualisé à partir de la base de données? Que faire si la requête prend du temps?

Considérez également la conception orientée objet. Chaque ligne est un objet distinct. Est-il approprié qu'appeler save() sur un objet ait l'effet secondaire de changer des valeurs dans un objet séparé (même si elles font partie de la même collection d'objets)? Cela me semble être une forme de Content Coupling.

L'exemple ci-dessus est une requête relativement simple, mais des requêtes beaucoup plus complexes sont également autorisées. Zend_Db ne peut pas analyser les requêtes avec l'intention de dire les résultats en écriture à partir des résultats en lecture seule. C'est aussi pourquoi les vues MySQL ne peuvent pas être mises à jour.

+0

Merci, votre explication clarifie la situation; Je vais simplement aller avec une méthode personnalisée qui retourne un objet en lecture seule. –

+0

Oui, c'est une bonne solution. –

+0

+1 et merci, je cherchais quelque chose comme ça aussi. Serait cool si ZF avait quelque chose comme RoR 'find (: all,: includes)' si – Gordon

2

Vous pouvez toujours créer une vue dans votre base de données qui fait la jointure pour vous.

CREATE OR REPLACE VIEW VwAction AS 
SELECT [columns] 
    FROM action 
    LEFT JOIN user 
    ON user.id = action.user_id 

Ensuite, il suffit d'utiliser

$vwAction->fetchAll(); 

Rappelez-vous simplement que les vues de MySQL sont en lecture seule (en supposant que cela est MySQL)

1

ne crée pas une vue sql table une bonne solution pour faire joint? et après une simple classe de table pour y accéder

Je pense qu'il vaut mieux si votre logique est sql que dans php

Questions connexes