Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 10-09-2009 10:42:49

Asfaloth
Membre
Lieu: Bruxelles
Date d'inscription: 13-05-2008
Messages: 83
Site web

Quickstart ZF: GuestbookMapper... Question existentielle

Bonjour à tous,

Hier soir j'ai enfin eu le temps de me mettre un peu à jour vis-à-vis du ZF (oui j'ai honte, je travaille toujours en 1.7), j'ai donc télécharger la dernière version, et me suis lancé corps et âme dans le quickstart pour découvrir le magnifique Zend_Application.Et pour lui pas de problème, ça m'a l'air d'être du bon, même du très très bon.

Par contre au cours de ce tuto, m'est apparue la notion de Mapper.  Et oui, étant autodidacte total, et ne travaillant en objet que depuis un peu plus d'un an, c'est quelque chose que j'ai un peu de mal à saisir.  Non pas dans son fonctionnement, qui est, je le suppose dans ce cas ci (et je précise bien, celui-ci) assez simple.  Non la question que je me pose est "pourquoi ?"

Pourquoi utiliser une class, qui va rajouter une couche entre le Db_Table_Abstract et le model ?  Jusqu'a présent, j'avais dans mon projet un dossier models, qui contenait que des class issue de Zend_Db_Table_Abstract, et j'utilisais ces class directement dans mes controllers...  Donc ici j'ai un peu de mal à saisir l'utilité de faire 2 class (le model et le mapperModel) pour acceder à une troisieme (la Db_Table) si ce n'est l'évidente clarté du code au niveau du controller.  En effet, juste faire un new suivis d'un save, c'est joli et très propre.

j'ai bien lu le lien fournis par la doc au moment de creer le mapper qui explique un peu, mais je dois m'avouer vaincu par la subtilité de la langue anglaise dans ce cas ci (pour faire simple, j'ai lu mais j'ai rien compris  roll).

Donc si quelqu'un aurait la gentillesse de m'expliquer, ou de me donner des pistes de documentation, il en sera grandement remercié big_smile


La capacité d'apprendre est un don.
La faculté d'apprendre est un talent.
La volonté d'apprendre est un choix.
-=[ Frank Herbert ]=-

Hors ligne

 

#2 10-09-2009 12:41:46

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Salut,

L'intérêt du mapper est de découpler un peu plus le front de l'application de la persistance.

Dans un monde parfait, les controlleurs ne devraient jamais communiquer directement avec la couche de persistance (pour toi Zend_Db). Ils ne devraient que "contrôler" l'information et transmettre après contrôle à une autre couche pour la suite des opérations.
Le controlleur ne va donc manipuler que des objets entité (Entity Object), ou objets métier (Domain Object/Business Object).

Qu'est-ce qu'un objet métier ?

Ces objets représentent la plupart du temps les entités du domaine métier pour lequel l'application est conçue.

Ils sont pensés et implémentés par les développeurs et non pas par le framework. Ils sont totalement détachés  de la persistance (base de données ou autre).

Par exemple, ton application doit afficher des galeries d'images, et ces galeries appartiennent à des utilisateurs.
Tu vas avoir une entité Utilisateur dans laquelle tu auras des galeries qui sont elle-mêmes des entités Galerie. C'est la définition des entités qui répondent au métier, au domaine abordé.

Le terme "modèle métier" est un peu utilisé à toutes les sauces. Le modèle métier (Domain model) représente l'ensemble des objets métiers, donc des entités, et les relations entre eux. Ni plus, ni moins.

Les objets métiers sont la plupart du temps peuplés avec des données des entités réelles (dans le métier) qu'ils représentent (mais pas toujours).


Le Mapper dans tout ça ?

Les objets métiers sont les seuls éléments qui sont connus dans toutes les couches de l'application.
Les controlleurs ne doivent pas connaitre l'organisation de la persistance, mais connaissent les objets métiers, c'est donc au travers de ceux là qu'ils vont travailler.
Ils assurent un contrôle aller/retour des informations vers le client, la dynamique de l'application (intéractions, etc.).

Sauf que, comment faire persister un objet métier, ou comment récupérer les données pour peupler un objet métier si le controlleur ne connait pas la persistance ? Et bien il passe par le mapper.

Le rôle du mapper, tel que Zend l'introduit, est de savoir comment récupérer les informations nécessaires dans la persistance pour peupler un objet métier. Ou bien de savoir comment demander à la persistance d'enregistrer un objet métier.

Le controlleur saura donc créer un objet métier, le peupler (depuis un formulaire par ex.) et demandera au mapper de faire persister cette objet. Ou dans l'autre sens, le controlleur a besoin d'un objet métier déjà peuplé, il demandera au mapper de lui retourner.

Si demain, la couche de persistance change, tu n'auras rien à refactoriser dans tes controlleurs, seuls les mappers vont changer.

Mais aussi, si tes mappers sont prêts, tu peux développer le front indépendamment du back et tu n'es pas obligé d'attendre après la conception de la base de données pour commencer ton dév.

Après, tout dépend de la dimension de l'application, beaucoup de développeurs décident qu'un Zend_Db_Table_Row = un objet métier, et ceci leur convient.

Pour moi ce n'est pas satisfaisant pour plusieurs raisons.
D'abord, une entité n'est pas forcément égale à une table, elle peut être construite à partir de plusieurs tables dans la BDD.
Ensuite, tout ceci lie très fortement ton front à une persistance type base de données. Si demain tu dois récupérer tes données depuis un webservice en XML ou depuis un annuaire il faudra tout refactoriser.

Enfin, la solution proposée par Zend dans le Quickstart est, selon moi, insuffisante. Par exemple, pour faire persister un objet métier, ils ont implémenté la méthode save() dans l'objet métier, ce qui, à mon sens est une abérration. Mais plus loin encore, pour un découplage réel de toutes les couches, la notion de mapper est plus qu'insuffisante et n'est qu'une brique de toute l'architecture.

Celà fait quelques jours que je me penche sur le sujet du découplage et d'une architecture découpées en Controlleurs/Services/ORM avec inversion de contrôles (IOC ou Di = injection de dépendances). Je vais très bientôt faire un retour de ce que j'en ai tiré sur le forum, ça pourra peut-être te donner des idées, sachant qu'il n'y a pas LA bonne solution, d'autres personnes t'en proposeront, parfois tout aussi efficaces, d'autres insuffisantes. Tout ceci demande beaucoup de réflexion.


A+ benjamin.


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

#3 10-09-2009 13:12:26

Asfaloth
Membre
Lieu: Bruxelles
Date d'inscription: 13-05-2008
Messages: 83
Site web

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Tout d'abord merci Delprog !!
Ça c'est de l'explication, et j'y vois effectivement beaucoup plus clair.

La seule chose qui me turlupine dans ton explication, c'est

Enfin, la solution proposée par Zend dans le Quickstart est, selon moi, insuffisante. Par exemple, pour faire persister un objet métier, ils ont implémenté la méthode save() dans l'objet métier, ce qui, à mon sens est une abérration.

Tu pourrais me dire, pourquoi de ton point de vue c'est une abérration ?

Sinon oui, il est clair qu'un objet métier n'est pas égale à une seule table, celà à d'ailleur souvent été un problème dans mon cas, car travaillant sur un intranet de société (dont les informations doivent justement être accessible en webservices), il n'est pas rare d'avoir des requetes avec 5 jointures, et si traiter les données en sortie est assez facile, pour faire un enregistrement c'est parfois plus délicat, et me retrouvais donc avec toutes ces notions directement dans le controller.  Je vois que la notion de mapper, et de découplage en général est la réponses à une question que je ne m'étais pas clairement posée.

J'ai asisté lors du forum php à la session d'information sur l'injection de dépendance (présenée par le createur de symphony) et m'étais promis d'approfondir le sujet, malheureusement mon employeur s'obstine à me faire travailler sans me laisser le temps d'en apprendre d'avantage ^^.

J'atendrai donc avec impatience (et ne serai surement pas le seul) ton retour d'expérience là-dessus.


Merci Encore


La capacité d'apprendre est un don.
La faculté d'apprendre est un talent.
La volonté d'apprendre est un choix.
-=[ Frank Herbert ]=-

Hors ligne

 

#4 10-09-2009 13:41:26

philippe
Administrateur
Lieu: Grenoble
Date d'inscription: 01-03-2007
Messages: 1624

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Merci Delprog pour cette analyse !

J'ajoute un article intéressant (téléchargez le PDF) vers une conf sur les différents types d'ORM en PHP (bon, Zend_Db_Mapper n'était pas encore sorti...).
http://maggienelson.com/2009/05/orm-in-the-php-world/
et le PDF :
http://maggienelson.com/conferences/php … _World.pdf

A+, Philippe


twitter : @plv ; kitpages.fr : Création de sites internet à Grenoble et Paris

Hors ligne

 

#5 10-09-2009 13:41:38

Julien
Membre
Date d'inscription: 16-03-2007
Messages: 501

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Si je peux te donner un conseil : va voir ce qu'il se passe coté Java : Hibernate, Spring et autres EJB, et si t'as l'occasion d'attaquer un projet Ruby avec Rails, prend le vite vite vite. Après tu ne verras plus jamais PHP de la même manière.

Aussi, renseigne-toi sur les patterns (et des bouquins sur ça .... il en existe des tonnes et des tonnes, les meilleurs sont en anglais), c'est la base de tout développement informatique "moderne", quel que soit le langage.

Hors ligne

 

#6 10-09-2009 14:36:01

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Asfaloth a écrit:

La seule chose qui me turlupine dans ton explication, c'est

Enfin, la solution proposée par Zend dans le Quickstart est, selon moi, insuffisante. Par exemple, pour faire persister un objet métier, ils ont implémenté la méthode save() dans l'objet métier, ce qui, à mon sens est une abérration.

Tu pourrais me dire, pourquoi de ton point de vue c'est une abérration ?

En fait, un objet métier peut avoir plusieurs "status". Il peut être une "entité" (c'est grossier mais je vais utiliser ce terme) et doit donc pouvoir être persisté. Il peut être un simple objet volatile (calculs par ex.), qui n'est donc pas persisté et ne représente pas d'entité en terme de métier.

Dans tous les cas, ces objets, quels qu'ils soient ne déterminent pas eux même leurs "status" et le save() n'est surement pas de leur ressort. Implémenter un save() dans l'objet métier revient à faire connaitre à l'objet autre chose que le métier. Dans le quickstart, l'objet métier fait appel au Mapper, c'est très "sale" :p

Julien a écrit:

Si je peux te donner un conseil : va voir ce qu'il se passe coté Java : Hibernate, Spring et autres EJB, et si t'as l'occasion d'attaquer un projet Ruby avec Rails, prend le vite vite vite. Après tu ne verras plus jamais PHP de la même manière.

Pour moi, hibernate et spring MVC sont la crème. Dans ce que je proposerai bientôt, je me suis inspiré sans retenue de leurs fonctionnement en essayant de l'adapter à un environnement script. Seule chose qui me laisse dubitatif dans leurs dernières versions, c'est l'utilisation des annotations, bien que pratique, je ne sais pas ça me dérange.

Sinon, JAVA est un langage très mûre, et Spring MVC couplé à Hibernate implémentent des patterns très très efficaces (Factory, Proxy, Service Layer, DAO, ORM pour ne citer que ceux là).

Julien a écrit:

Aussi, renseigne-toi sur les patterns (et des bouquins sur ça .... il en existe des tonnes et des tonnes, les meilleurs sont en anglais), c'est la base de tout développement informatique "moderne", quel que soit le langage.

big_smile Et si tu es passionné, chaque fois que tu découvriras ce que tu peux faire d'un pattern tu t'illumineras :p


A+ benjamin.


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

#7 10-09-2009 16:09:41

Asfaloth
Membre
Lieu: Bruxelles
Date d'inscription: 13-05-2008
Messages: 83
Site web

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Merci à tous pour ces réponses, c'est pour ça que j'adore la progra, on arrete jamais de découvrir de nouvelles choses, et il faut constamment se remettre en question, certains diront qu'on est mazo big_smile

@Delprog

Et si tu es passionné, chaque fois que tu découvriras ce que tu peux faire d'un pattern tu t'illumineras :p

Ça c'est certain, et chaques fois on se dit, mais pourquoi j'ai pas connu ça plus tôt, et on a envie de refactorisé tout ce qu'on a déjà fait ^^ (et encore plus quand cela fait à peine plus d'un an qu'on est sortis du fonctionnel tongue)

Par contre, désolé d'insister mais j'aime bien aller au fond des choses, le fameux save de la doc, tu l'aurais placer où et comment ?


@philippe
J'ai parcouru en vitesse, ça éclaire pas mal de chose aussi, merci

@Julien
Promis dès que j'ai 10 min j'apprend le java et le ruby pour voir ce qui se fait de l'autre coté ^^
Sinon pour les bouquins si tu as un ouvrage ou une maison d'édition à me conseiller en particulier, je suis preneur (en attendant je vai voir si ya pas qqch qui traine chez o'reilly et eyrolle)


La capacité d'apprendre est un don.
La faculté d'apprendre est un talent.
La volonté d'apprendre est un choix.
-=[ Frank Herbert ]=-

Hors ligne

 

#8 10-09-2009 16:25:25

philippe
Administrateur
Lieu: Grenoble
Date d'inscription: 01-03-2007
Messages: 1624

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Par contre, désolé d'insister mais j'aime bien aller au fond des choses, le fameux save de la doc, tu l'aurais placer où et comment ?

L'idée serait de placer le save dans le mapper, on aurait :

Code:

$mapper->save($objetMetier);

au lieu de

Code:

$objetMetier->save();

Sur le principe je suis plutôt d'accord avec Delprog. C'est particulièrement choquant pour un delete : quand tu fais $objetMetier->delete(), ton instance a disparu en base et tu continues à avoir un $objetMetier un peu zombi... c'est pas à l'objet métier de se détruire lui même, c'est plutôt au mappeur...

Cependant d'un point de vue pragmatique, je trouve que c'est souvent bien pratique d'avoir ces méthodes dans l'objet métier... Sur le principe ça me choque un peu, mais dans un code c'est tellement pratique que je suis un peu plus mesuré sur ce point... (il faut s'appuyer sur les principes, ils finiront bien par céder smile )

A+, Philippe


twitter : @plv ; kitpages.fr : Création de sites internet à Grenoble et Paris

Hors ligne

 

#9 10-09-2009 16:39:47

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Quickstart ZF: GuestbookMapper... Question existentielle

philippe a écrit:

Cependant d'un point de vue pragmatique, je trouve que c'est souvent bien pratique d'avoir ces méthodes dans l'objet métier... Sur le principe ça me choque un peu, mais dans un code c'est tellement pratique que je suis un peu plus mesuré sur ce point... (il faut s'appuyer sur les principes, ils finiront bien par céder smile )

A ce moment là, il faut utiliser le pattern proxy.

Exemple:

Model_Entity_User = objet métier pure
Model_User = Proxy, étend Model_Entity_User et implémente la méthode save().

Dans ton code tu instancies toujours le proxy, dans les tests unitaires tu instancies l'entité :p


A+ benjamin.


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

#10 14-09-2009 10:41:54

Eureka
Membre
Date d'inscription: 18-07-2009
Messages: 81

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Bonjour,

Delprog a écrit:

Par exemple, ton application doit afficher des galeries d'images, et ces galeries appartiennent à des utilisateurs.
Tu vas avoir une entité Utilisateur dans laquelle tu auras des galeries qui sont elle-mêmes des entités Galerie. C'est la définition des entités qui répondent au métier, au domaine abordé.

Du coup ici on aurait deux objets metier, Utilisateur et Gallerie ? Dès lors l'appel au mapper pour récupérer  un objet métier Utilisateur opèrerait (dans le cas d'une base de données avec 2 tables user/gallery) un select en base pour récupérer l'utilisateur (sur user), injectant les données dans un objet métier Utilisateur, puis ensuite un select pour récupérer toutes les galleries de l'utilisateur (sur gallery), les injectant chacune dans un objet métier Gallerie et ensuite injectant ces objets métier Gallerie dans une propriété (tableau) de l'objet métier Utilisateur (array galleries contenant donc les objets métiers gallerie) ?

Si c'est ainsi, est-ce qu'il convient que des mappers puissent communiquer entre eux ? A savoir que pour récupérer les galleries le mapper Utilisateur pourrait appeler le mapper Gallerie qui lui renverrait tous les objets Gallerie peuplés ?

Et lors d'une modification/ajout/suppression d'une gallerie à partir d'un objet métier Utilisateur le mapper Utilisateur passerait au mapper Gallerie les objets contenu dans l'objet métier l'Utilisateur pour qu'il les ajoute/modifie/supprime en base ?

Hors ligne

 

#11 14-09-2009 10:57:37

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Salut,

Ce que tu décris s'appelle en fait du full loading. C'est à dire que toutes les dépendances sont peuplées dès le départ.

De mon côté j'ai tout implémenté en Lazy-load, c'est à dire que les dépendances ne sont chargées (comprendre requête + création et peuplage de/des entité(s)) que lorsqu'elles sont réclamées pour la première fois.

J'ai voulu conservé quelque chose du type $user->galleries[0]->name, et le pattern proxy a été la solution.

Du côté mapper, j'ai laissé tombé la solution un objet = un mapper, de même que j'ai laissé tomber le pattern Gateway et je n'ai plus de Zend_Db_Table pour chaque table.

J'ai un unique Mapper, un adapter Db et des DAO, les proxy, qui étendents les entités construisent eux-mêmes les requêtes et s'adressent directement au mapper. Après réflexion j'ai pris cette décision car j'ai implémenté un générateur de classes, qui génère aussi les proxy, et si la persistance change, je n'aurai à modifier que mon générateur.

J'essaie de trouver du temps pour expliquer tout ça en détail.


A+ benjamin.

Dernière modification par Delprog (14-09-2009 10:58:22)


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

#12 14-09-2009 16:46:39

Eureka
Membre
Date d'inscription: 18-07-2009
Messages: 81

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Delprog a écrit:

J'essaie de trouver du temps pour expliquer tout ça en détail.

Merci, comme d'habitude enrichissant.

La solution que tu étudies/testes semble relativement performante et facilement maintenable, bien pratique en soit.

A l'époque où tu utilisaient les mappers par objet, te souciais-tu du fait qu'une propriété d'un objet avait pu être modifiée ou non ?
Je pense à un Utilisateur ayant 100 objets Gallerie, au moment d'opérer un save de l'Utilisateur, comment savoir si tout ou partie des galleries devaient être également modifiées dans la persistance ? (éventuellement une notion de propriété (tableau) "$_modified" par objet, recensant les propriétés modifiées au sein d'un objet ?)

Hors ligne

 

#13 14-09-2009 16:56:21

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Quickstart ZF: GuestbookMapper... Question existentielle

Salut,

J'ai commencé à donner quelques indications ici : http://www.z-f.fr/forum/viewtopic.php?id=4027

Je donnerai des exemples de code un peu plus tard. Gardez à l'esprit que c'est une implémentation parmis d'autres, bien qu'éprouvée par d'autres langages, ce n'est pas LA solution ni l'unique possibilité.

Eureka a écrit:

A l'époque où tu utilisaient les mappers par objet, te souciais-tu du fait qu'une propriété d'un objet avait pu être modifiée ou non ?
Je pense à un Utilisateur ayant 100 objets Gallerie, au moment d'opérer un save de l'Utilisateur, comment savoir si tout ou partie des galleries devaient être également modifiées dans la persistance ? (éventuellement une notion de propriété (tableau) "$_modified" par objet, recensant les propriétés modifiées au sein d'un objet ?)

Je n'ai pas encore implémenté le save en cascade, uniquement le Lazy Load pour l'instant. C'est à l'étude smile


A+ benjamin.


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages