2010-06-10 4 views
4

J'ai un dilemme. J'ai utilisé DI (lire: usine) pour fournir des composants de base pour un ORM homebrew. Le conteneur fournit des connexions de base de données, des DAO, des mappeurs et leurs objets de domaine résultants sur demande.Modèle d'injection de dépendances et unité de travail

Voici un aperçu de base des cartographes et des classes d'objets de domaine

class Mapper{ 
    public function __constructor($DAO){ 
     $this->DAO = $DAO; 
     } 

    public function load($id){ 
     if(isset(Monitor::members[$id]){ 
     return Monitor::members[$id]; 

     $values = $this->DAO->selectStmt($id); 
     //field mapping process omitted for brevity 
     $Object = new Object($values); 
     return $Object; 
     } 
    } 

class User(){ 
    public function setName($string){ 
     $this->name = $string; 
     //mark modified by means fair or foul 
    } 
} 

Le ORM contient également une classe (Monitor) basée sur l'unité de modèle de travail à savoir

class Monitor(){ 
    private static array modified; 
    private static array dirty; 
    public function markClean($class); 
    public function markModified($class); 
} 

La classe ORM elle-même coordonne simplement les ressources extraites du conteneur DI. Donc, pour instancier un nouvel objet Utilisateur:

$Container = new DI_Container; 
$ORM = new ORM($Container); 
$User = $ORM->load('user',1); 
//at this point the container instantiates a mapper class 
//and passes a database connection to it via the constructor 
//the mapper then takes the second argument and loads the user with that id 
$User->setName('Rumpelstiltskin');//at this point, User must mark itself as "modified" 

Ma question est. Au moment où un utilisateur définit des valeurs sur une classe d'objets de domaine, je dois marquer la classe comme "sale" dans la classe Monitor. J'ai l'une des trois options que je peux le voir

1: Passer une instance de la classe Monitor à l'objet de domaine. J'ai remarqué que ceci est marqué comme récursif dans FirePHP - c'est-à-dire $ this-> Monitor-> markModified ($ this)

2: Instancier le moniteur directement dans l'objet de domaine - cela brise-t-il DI? 3: Rendre les méthodes Monitor statiques, et les appeler depuis l'intérieur de l'objet de domaine - cela casse aussi DI non?

Quelle serait votre plan d'action recommandé (autre que d'utiliser un ORM existant, je le fais pour le plaisir ...)

+0

L'ORM conserve-t-il une référence de l'objet renvoyé? Si non, pourquoi le moniteur est-il dans l'ORM? Si l'entité possède son propre moniteur, alors quand tout est retransmis à l'ORM pour les opérations CRUD, l'ORM boucle les moniteurs pour les changements? –

+0

Non, le moniteur conserve un enregistrement de toutes les classes chargées - donc $ User1 et $ User2 pointent vers le même objet dans Monitor si ce sont les mêmes enregistrements. L'ORM lui-même est juste une façade pour gérer l'interaction des mappeurs, etc. Boucles ORM Surveiller les modifications en cours d'enregistrement – sunwukung

+0

Je suis confus sur votre utilisation des motifs, principalement parce que ce n'est pas comme cela que je l'aurais paramétré. Mettre le DI * dans * l'ORM brise l'injection de dépendance, n'est-ce pas? L'ORM est alors une usine pour les objets de domaine, plutôt qu'un ORM plus traditionnel. Je ne placerais pas le moniteur dans la fabrique d'objets de domaine.Dans ce scénario, je le rends statique. Si je ne comprends pas ce que vos habitudes accomplissent, je m'excuse. –

Répondre

1

D'accord, je vois. Qu'en est-il:

$user = new User; 
$monitoredUser = new Monitor($user); 

//at update in class Monitor: 
Monitor::markDirty($this); 

Maintenant, vous utilisez le moniteur comme décorateur; il ajoute un shell autour de l'objet utilisateur ou de tout autre objet qui gère les requêtes entrantes. Si un objet est mis à jour il sera marqué sale par le moniteur, mais parce que le moniteur utilise une méthode statique pour cela, il reste dans la portée de la classe actuelle évitant ainsi la récursivité.

+0

C'est un angle intéressant, bien que cela puisse rendre l'API un peu plus difficile. résultat - avoir à mettre à jour le moniteur manuellement. Idéalement, vous voulez simplement obtenir un utilisateur de l'ORM, changer ses propriétés et il est automatiquement surveillé. Les implémentations de UoW que j'ai vues utilisent des appels statiques (externes) - mais c'est mauvais non? – sunwukung

+0

Vous pouvez également utiliser la réflexion pour cela; implémenter une méthode __call() qui achemine la demande à l'utilisateur dans le cas où un accesseur a été appelé. –

+0

Peut-être pour l'inspiration: J'ai proposé un autre modèle UoW: http://www.gabordemooij.com/unit_of_work, et j'ai aussi mon propre ORM: http://www.redbeanphp.com –

0

Je pensais que je ne l'ai fait, votre classe Monitor semble correspondre à un " Observateur "modèle de conception. De cette façon, vous n'avez pas besoin de demander à la classe Monitor de marquer la classe comme sale, mais elle devrait le faire seule.

Comme je l'ai dit je ne l'ai jamais fait en PHP mais je suis assez confiant que vous pouvez regarder sur Google un moyen d'implémenter ce modèle de conception en PHP.

+0

Bien sûr, c'est fondamentalement la même chose que d'utiliser un setter. Mon seul problème est qu'il établit une boucle de récurrence (puisqu'une référence à l'entité réside dans le moniteur, et une référence au moniteur réside dans l'entité). – sunwukung

0

Grande question est; ce qui se passe à l'intérieur de markModified() ..? J'ai copié le code et essayé, mais je n'ai pas l'erreur que vous avez signalé. Donc je suppose qu'il manque un puzzle?

+0

markModified stocke simplement une référence à $ this dans le tableau $ _modified dans Monitor. Ce n'est pas une erreur, mais un drapeau dans FirePHP - si Monitor contient une ref de Entity, et Entity contient une ref de Monitor, c'est une sorte de récursivité – sunwukung

Questions connexes