Injection de dépendances et LazyLoading, comment faire ?
Bonjour,
Voilà, je trouve des tartines et tartines d'explications et exemples sur les bienfaits de l'injection de dépendances, mais absolument rien sur l'opération inverse...
Je m'explique. Admettons que nous ayons une classe CUtilisateur que l'on stockerait dans une BDD MySQL dans une table appelé utilisateur (au hasard).
On aurait alors un lien assez direct entre la classe CUtilisateur et la table utilisateur, mais en tant que gens bien élevé, on construirait une classe intermédiaire (disons RUtilisateur) pour renseigner la class CUtilisateur à partir d'utilisateur et inversement.
Ces utilisateurs auraient parmis leur propriété un pays d'origine, faisant lui même l'objet d'une class CPays, d'une table pays (lié par une clef étrangère à utilisateur) et d'un RPays pour assurer le lien entre la table et class du même nom.
Edit : RPays est donc un genre de Mapper... Moi, j'ai appelé ça un répository, d'où le R
Sur ce principe, pour faire de l'injection de dépendance, l'action de spécifier un pays pour un utilisateur devrait ressembler à quelque chose un peu comme ça :
Code:
1 2 3 4 5 6 7 8 9
| $bdd = PDOConnect(...); // ma connexion à la BDD
$r_pays = new RPays($bdd);
$pays = $r_pays->load('Belgique'); // pays est une instance de CPays retournée et remplies par RPays
$r_u = new RUtilisateur($bdd);
$u = $r_u->Load(3758); // on charge l'utilisateur 3758 de la BDD dans l'instance de class CUser retournée par RUser.
$u->setPays($pays); // affectation d'un nouveau pays
$r_u->Save($u, $bdd); // sauvegarde de l'information |
Autant que je sache, j'ai donc respecté les principes d'injection de dépendance et n'ai pas fortement liée mes class entre elles.
Dans la pratique, la class CUtilisateur devrait s'écrire :
Code:
1 2 3 4 5 6
| class CUtilisateur {
private $_pays = NULL;
public function setPays(IPays $pays) { // tant qu'a faire, on réclame une interface plutôt qu'une class, donc IPays qu'on supposera déclaré
$this->_pays = $pays;
}
} |
Arrêtez moi si je fais erreur quelque part.
C'est maintenant que ça se complique
En effet, Pays est lui même relié à une class CLangue elle même reliée à une class CAlphabet etc... toutes ces class existante elles aussi sous forme de tables dans la base de données.
Il est bien entendu inconcevable qu'au moment où je charge un utilisateur, je charge également toutes les class associées, donc je souhaite opter pour une solution de LazyLoading, à savoir que pour chaque class que j'instancie et charge à partir de la BDD, je ne charge/instancie les class liées qu'au moment où j'en ai besoin.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class CUtilisateur {
private $_pays = NULL;
private $_id_pays = 0;
public function setPays(IPays $pays) { // tant qu'a faire, on réclame une interface plutôt qu'une class, donc IPays qu'on supposera déclaré
$this->_pays = $pays;
$this->_id_pays = $pays->GetId();
}
public function GetPays() {
if(!is_object($this->_pays))
{
// tout ce que je sais ici, c'est que je suis associé au pays dont l'ID est contenu dans $this->_id_pays.
// Cette données à été renseignée par RUtilisateur->load();
// QUESTION : COMMENT JE FAIS ICI ????
}
return $this->_pays;
}
} |
La question est donc comment je fait pour que mon getter qui ne connait que l'ID du pays associé me retourne une instance de CPays sans briser mes efforts pour de pas faire interdépendre mes class ?
J'avais d'abord pensé injecter une instance de RPays à CUtilisateur::GetPays(), mais il me semble que ça serait une erreur dans la mesure où tout est fait en amont pour que CUtilisateur ignore l’existence des class destinées à assurer la persistance des données.
Votre avis ?
En vous remerciant.