Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 31-01-2012 09:53:16

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Questions diverses et bonnes pratiques

Bonjour à tous, toujours dans un soucis d'utiliser les bonnes pratiques, j'ai encore quelques zones d'ombre.

Etant développeur JAVA j'ai pour habitude de créer une classe static avec des méthodes four tout, de calcul etc ... Cependant en PHP je n'ai pas l'impression que ce soit une pratique courante de se fait je me pose plusieurs questions. Je vais prendre l'exemple d'un véhicule pour exposer mes interrogations.

J'ai donc une classe véhicule avec laquelle j'aimerai faire plusieurs calculs :
- Nombre de roues
- Vitesse maximum
- Usure des pneus
- Consommation
etc ...

Si mon véhicule est un camion, il n'aura pas le même nombre de roues qu'une voiture, la même vitesse et n'usera pas forcément ses pneus de la même manière (plus lourd mais moins rapide etc ...)

- Dois-je écrire une classe véhicule abstraite et créer d'autre classe de type voiture, camion étendant la classe véhicule et re-définir les différences qu'il peux y avoir au niveau du calcul ?

- Dois juste étendre ma classe véhicule (pour seulement ses attribut) et écrire les méthodes pour chaque objet de type voiture, camion; ce qui implique de ne manipuler que des objets étendant la classe véhicule et non plus une classe abstraite ?

- Dois je créer simplement une interface (me parait le moins pertinent) implémentant toutes ces méthodes ?

- Dois je simplement créer une classe static ou une classe à tout faire (représentant un fichier function.php dans le php procédurale) avec toutes les fonctions dont j'aurai besoin que j'utiliserais pour faire mes calculs ?

Je me pose ces différentes questions car il existe plusieurs manière de faire la même chose mais il y a forcément une des façons de faire qui est meilleure et permet d'être extensible plus facilement. Pour mon projet je vais avoir plusieurs types de calculs à faire :
- Calcul de combat
- Calcul de points
- Calcul de production de ressources
etc ... Et je me pose donc la question de savoir où placer tout ça et de quelle manière.

============================================================

Une autre série de questions me passent par la tête.

- Est-il possible de définir des fichiers contenant des labels, en JAVA nous avons pour habitude d'utiliser des fichier ressources (*.properties) qui sont au final des fichiers .ini suivant la langue et avec une clé permettent de récupérer le label. Est-ce le principe de Zend\Translate ?

- Pour mon projet, il sera possible d'avoir différentes configuration (activer une trêve pour maintenance, bloquer les attaques, bloquer les productions, augmenter la production générale des ressources, bonus du joueur en fonction de sa race/classe etc ...). Est-il préférable d'avoir toutes ces informations en base de données dans une table de configuration (clé/valeur) avec un panel d'administration permettant de modifier ce genre de paramètres ou un fichier de configuration classique pourrait faire l'affaire ?
Comment dans ZF2 charger ces différents paramètres sachant qu'ils pourront être modifié à la volé, il faut donc charger ça automatiquement dans chaque pages, y a t-il une méthode plus performante que l'autre ? N'est ce pas trop lourd que de faire ce "flot" de requête pour chaque page ?

Merci d'avance pour vos réponse

Orkin

Dernière modification par Orkin (31-01-2012 11:21:54)

Hors ligne

 

#2 31-01-2012 14:25:28

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: Questions diverses et bonnes pratiques

Salut,

Pour ta première question c'est clairement de la conception objet.

Oublie déjà la classe static ou la classe à tout faire. Ca peut toujours sembler pratique au début mais ça devient vite impossible à gérer.

Dans ton exemple, ce n'est pas non plus un cas d'utilisation d'interface. L'interface est plus une sorte de contrat... Regarde les interfaces écrites sur ZF2, par exemple, c'est très instructif. Rien que les noms des interfaces te permettent de comprendre "l'idée" derrière les interfaces : Pluggable, LocatorAware, Dispatchable...

Sur le cas des véhicules, la solution idéale est clairement la classe abstraite. La question à se poser est, compte tenu ton architecture (une classe véhicule puis des classes camions, voiture...) : est-ce qu'il y a un sens à instancier directement des objets véhicule. La réponse est évidemment non. Tu vas instancier des camions, des voitures, des motos... tu ne feras jamais de $vehicule = new Vehicule(). Du coup, Vehicule doit être abstraite.

L'idée, pour simplifier la maintenance du code, est d'écrire le maximum de code dans la classe véhicule et de redéfinir uniquement les fonctions qui changent dans les classes filles, le polymorphisme faisant le reste. Dans ton cas, les variables membres (nombre de roues, vitesse max...) seront dans la classe Vehicule. La fonction getNombreDeRoues() sera également dans la classe véhicule car le code sera dans tous les cas :

return $this->nombreDeRoues;

En revanche, une fonction getUsureDesPneus changera suivant les paramètres du véhicules. Par exemple, imaginons que, à la fin de ta fonction, tu multiplies par deux dans le cas d'un camion (car ça s'use plus vite). Tu auras donc une méthode abstraite dans la classe Vehiucle :

abstract public function getNombreDeRoues();

Puis que tu redéfiniras dans tes classes filles, car le traitement change suivant le type de l'objet.




Pour tes autres questions :

oui, c'est comme ça que fonctionne Zend\Translate.

Hors ligne

 

#3 31-01-2012 15:03:10

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Merci pour tes réponses.

bakura a écrit:

Tu vas instancier des camions, des voitures, des motos... tu ne feras jamais de $vehicule = new Vehicule(). Du coup, Vehicule doit être abstraite.

C'est bien la solution qui me semblait la plus probable là où je parlais d'utiliser la classe véhicule en tant qu'objet c'est plus côté paramètre de fonctions du genre :

Code:

[lang=php]
public function faireLePlein(Vehicule $vehicule) {
$reservoir = $vehicule->getTailleDuReservoir();
$essenceReservoir = $vehicule->getQuantiteReservoir();

$essence = $reservoir - $essenceReservoir;

return "vous avez remis " + $essence + "L dans le reservoir";
}

Du coup en fonction du type de véhicule le réservoir sera différent.

Sinon j'ai une question qui n'a pas été répondu :).

Orkin a écrit:

- Pour mon projet, il sera possible d'avoir différentes configuration (activer une trêve pour maintenance, bloquer les attaques, bloquer les productions, augmenter la production générale des ressources, bonus du joueur en fonction de sa race/classe etc ...). Est-il préférable d'avoir toutes ces informations en base de données dans une table de configuration (clé/valeur) avec un panel d'administration permettant de modifier ce genre de paramètres ou un fichier de configuration classique pourrait faire l'affaire ?
Comment dans ZF2 charger ces différents paramètres sachant qu'ils pourront être modifié à la volé, il faut donc charger ça automatiquement dans chaque pages, y a t-il une méthode plus performante que l'autre ? N'est ce pas trop lourd que de faire ce "flot" de requête pour chaque page ?

Encore merci !

Hors ligne

 

#4 31-01-2012 15:17:58

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: Questions diverses et bonnes pratiques

Oui bien sûr. Si d'autres objets ont besoin de consommer des véhicules (peut importe qu'il s'agisse d'une voiture ou d'un camion), tu leur passe un objet de type "Vehicule", et le polymorphisme appellera la fonction correspondant au "vrai" type de l'instance.

Pour ta deuxième question... tu veux dire quelque chose de similaire aux fichiers ini de ZF1 avec les sections production, development... ?

Hors ligne

 

#5 31-01-2012 15:28:19

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Oui et non. En fait je vais avoir besoin de modifier des paramètres de configuration en live. Par exemple interdire certaines opérations/bloquer des fonctionnalité pendant les fêtes de fin d'années.
J'aurais aussi des paramètres avec des coefficients de calcul, pour fêter tel ou tel événement => production augmenté de 20%, temps de construction diminué de 50% etc ...

Ces paramètres doivent être chargés à chaque page car je souhaite pouvoir faire ces modifications à la volée sans avoir à couper le serveur ou autre. Donc dans un sens c'est à la manière des fichiers ini de ZF1 (si la solution des fichiers est la meilleure) sinon via une table de configuration et/ou pourquoi pas faire un mixte des deux pour des choses qui ne vont pas changer souvent.

Hors ligne

 

#6 01-02-2012 15:14:02

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Désolé pour le double post mais je voulais du coup revenir sur une autre question concernant mes paramètres à charger.

Je me demande si c'est possible de charger ces informations directement dans un contrôleur "à moi" qui étend ActionController et faire étendre tous mes contrôleur de mon contrôleur "à moi" ou si c'est plus performant de le faire ailleurs sachant qu'il faut que l'instance d'accès à la base de données soient créée.

Au delà de cette question, j'avais pour habitude d'effectuer une série d'action sous ZF1 dans la méthode init() de mon contrôleur (comme par exemple recharger le profil de l'utilisateur et gérer les blocages en cas de ban (plutôt que d'attendre la fin de la session)) cependant avec ZF2 il n'y a plus de méthode init(). J'ai pensé à implémenter mon propre constructeur dans mon contrôleur mais mon Entity Manager me permettant d'avoir les accès à la base de données est null. Dois-je définir un constructeur avec des paramètres ou est-ce qu'il existe une autre méthode à utiliser pour faire ce genre d'action ? (plugin, etc ...) ?

Hors ligne

 

#7 01-02-2012 17:55:53

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: Questions diverses et bonnes pratiques

Salut,

Pour ta question d'étendre le contrôleur, oui c'est évidemment la meilleure solution. Si je comprends bien, ton objectif est "d'injecter" une sorte de config au sein de ton contrôleur ? C'est sûrement possible avec le Di mais j'avoue ne pas trop savoir comment (idéalement, il faudrait pouvoir accéder à la configuration de l'application depuis le contrôleur, je sais pas si c'est possible).

Quant à ta deuxième : oui la meilleure solution est de définir un constructeur qui aura le même rôle que le init. Je viens de vérifier le code source de ActionController, il n'y a pas de constructeur, donc tu n'as même pas besoin d'appeler parent::__construct ;-).

Hors ligne

 

#8 01-02-2012 18:03:24

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Merci bien, le soucis avec le constructeur c'est que mon EntityManager qui est injecté par le DI est null au niveau du constructeur du coup je ne peux pas récupérer les informations renseignées en base de données

Hors ligne

 

#9 01-02-2012 18:07:54

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: Questions diverses et bonnes pratiques

Ca c'est plutôt normal... A la création de ton objet contrôleur tu peux pas avoir magiquement un autre objet déjà construit. Je pense que tu devrais pouvoir t'en sortir en mettant un paramètre à ton constructeur :

public function __construct(EntityManager $em);

Après je crois qu'il faut jouer avec le Di, y'a un truc spécial à écrire dans le fichier de conf pour passer un paramètre au constructeur, il me semble...

Hors ligne

 

#10 01-02-2012 18:25:32

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

D'accord je vais pousser sur ce point et je reviendrais donner mes résultats smile

Hors ligne

 

#11 02-02-2012 14:11:50

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Salut, j'ai un début de réponse. Ca fonctionne mais c'est pas très optimisé donc si quelqu'un peux me donner un coup de pouce pour trouver la solution finale !

Pour re-situer rapidement :
- J'ai un contrôleur GenericController qui étend ActionController. Mon GenericController possède un constructeur comme ceci :

Code:

[lang=php]
public function __construct(EntityManager $em) {
        $this->em = $em;
    }

- Tous mes contrôleurs étendent ma classe GenericController.

Mon but est donc dans le constructeur de faire certains traitement d'initialisation. Je souhaite passer par l'injecteur de dépendance pour injecter l'EntityManager.
Ca fonctionne très bien en passant par un setter mais cette action se fait après celle du constructeur la solution est donc d'injecter l'EntityManager directement dans le contrôleur.

Lorsque je demande au DI d'injecter l'EntityManager directement dans le GenericController j'ai cette erreur :
Fatal error: Uncaught exception 'RuntimeException' with message 'Invalid instantiator' in E:\BPGL5075\Data\wamp\www\quickstartzf2\vendor\ZendFramework\library\Zend\Di\Di.php on line 193
RuntimeException: Invalid instantiator in E:\BPGL5075\Data\wamp\www\quickstartzf2\vendor\ZendFramework\library\Zend\Di\Di.php on line 193


J'ai donc poussé mes recherches et si je demande au DI d'injecter l'EntityManager directement dans une classe fille du GenericController (donc de tous mes contrôleur étendant GenericController) l'injection se passe à merveille.
Le hic de cette solution c'est que je dois ajouter une ligne dans le fichier de configuration du module pour chaque contrôleur ce qui fait répéter énormément de fois la même opération pour un final faire la même chose. L'idéal serait donc d'injecter directement lorsque la classe GenericController est instancié.
J'ai tenté de la passer en abstraite mais ça ne change rien.

Un petit coup de pouce ? :p

Hors ligne

 

#12 03-02-2012 21:52:25

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: Questions diverses et bonnes pratiques

Honnêtement j'en sais trop rien, j'ai pas trop l'occasion de faire de ZF2 en ce moment :'(. Essaye de voir quand même ici : http://doczf.mikaelkael.fr/2.0/en/zend.di.html

Hors ligne

 

#13 05-02-2012 20:46:00

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Hello, je remonte encore ce sujet car j'ai une nouvelle problématique sur la conception orienté objet.

En effet jusqu'à maintenant j'effectuais mes traitement en rapport avec la base de données (requêtes de lecture, création de nouvelles lignes en base etc ...) directement dans les contrôleurs. Ce qui pose problème lorsque l'on a besoin de réutiliser des fonctions qu'on utilise souvent (avec des tests car si c'était que de la lecture ou insertion classique ça irait). Du coup je souhaiterais mettre en place une couche service qui aurait connaissance de l'EntityManager.
Le problème c'est que comme j'ai des actions qui se font lors de l'instanciation de n'importe quel contrôleur du coup je dois les déporter dans la couche service, sauf que ces actions sont répété X fois dans un même contrôleur car plus j'ai de services plus le DI va instancier ma classe Service (dont étant tous mes services) et donc répéter les requêtes présentent dans le constructeur commun.

Je souhaiterais donc avoir des précisions à ce sujet et savoir si vous avez déjà mis en place une couche service avec ZF2 et comment vous avez fait, dans le cas contraire comment vous feriez pour mettre ça en place. Et enfin si c'est réellement nécessaire de faire ça ou si des classes un peu "batarde" pourraient servir pour ce genre de chose en ayant des méthodes prenant tous ce dont elles ont besoin en paramètre ?

Merci d'avance

Orkin

Hors ligne

 

#14 05-02-2012 23:26:29

bakura
Administrateur
Date d'inscription: 30-01-2010
Messages: 353

Re: Questions diverses et bonnes pratiques

La règle veut que les contrôleurs soient les plus "légers" possible et, qu'effectivement, les accès à la base de données se fassent autre part. Pour la base de données, et vu que tu utilises Doctrine, tu devrais regarder du côté des repository. Tu as déjà des repository "par défaut" générés par Doctrine (notamment quand tu fais $em->getRepository('MonEntité')->find(id)).

Afin de créer ton propre repository, tu dois ajouter une annotation : http://docs.doctrine-project.org/projec … ref-entity

Puis créer le repository, qui étend Doctrine\ORM\EntityRepository. Tu pourras par exemple créer tes propres requêtes complexes, et les effectuer directement dans ton contrôleur en récupérant le repository. Par exemple :

Code:

$em->getRepository('monEntité')->getUserByEmail($email);

Ceci te permettra déjà de découpler toute la logique de la base de données de tes contrôleurs.

Quant à la couche service, pour être honnête j'ai toujours trouvé ça très joli sur le papier, mais clairement "overkill" pour un projet de petite/moyenne envergure. Donc j'évite autant que possible.

Hors ligne

 

#15 06-02-2012 10:18:50

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Merci pour tes précision. J'utilise effectivement les repository actuellement mais ça ne me fait pas une belle couche service comme sur le papier. Car ce que je voulais avoir à faire c'est en cas de changement d'ORM (ce qui serait un peu absurde mais sait on jamais) n'avoir qu'à changer la couche service.
Maintenant en y réfléchissant le repository peux jouer cette couche et être la seule à bouger en cas de changement.

Je suis aussi d'accord avec toi sur le fait qu'une couche service fait beau sur le papier, n'est pas toujours facile à mettre en place, donc je vais laisser ça de côté pour l'instant mais sur un CV, ou expérience pro/perso ça fait toujours bien quand tu fais une applications dans les pratiques de développement de grosses applications.

Hors ligne

 

#16 15-02-2012 01:20:20

omega2
Membre
Lieu: Boisbriand, quebec, canada
Date d'inscription: 01-04-2009
Messages: 85
Site web

Re: Questions diverses et bonnes pratiques

Orkin > Bonsoir Orkin,
Pour le stockage des configuration, j'aurais tendance à dire que tout ce qui est configuration serveur aurait d'avantage sa place dans un fichier de config que dans la base de donnée si on n'a pas besoin de préparer les changement à l'avance.

Cependant en pratique ce genre d'information est généralement déporté dans la base de donnée pour les raisons suivantes :
- on n'aura pas de problème de synchro si on monte en charge en rajoutant un ou plusieurs serveurs web
- avec une base de donnée on peut indiquer facilement des intervalles de validité pour un réglage voire des priorités dans les règles des réglages (pas besoin de fermer la règle générale quand on entre dans une période productiion * X wink )
- (cas généralement rare mais à penser éventuellement) avec des systèmes de cryptage de fichiers php comme ioncube, on peut interdire le chargement de fichiers non cryptés à partir des fichiers cryptés et inversement : ça serait moins sécurisé (et plus cher) d'installer un encodeur sur le serveur de production pour encoder le fichier de config à chaque changement et ça serait lourd de devoir faire appel à un serveur externe pour modifier la configuration.

il faut bien réfléchir à ses besoins (souplesse, fiabilité, etc) avant de décider si on met les réglages dans un fichier .ini ou dans une base de donnée.

Hors ligne

 

#17 15-02-2012 09:56:40

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Salut Omega2 et merci pour tes précisions.

J'ai choisi la méthode de stockage en base de données car ça me parait être la méthode la plus souple avec dans une table la clé de la config et la valeur. Ca fonctionne pour l'instant pas mal après à voir plus tard si ça pose des soucis de performances avec du trafic.

Je vise à la fois un service performant, fiable et sûr et c'est pas toujours évident d'avoir les 3 comme on le souhaite smile.

Hors ligne

 

#18 16-02-2012 10:46:31

Orkin
Administrateur
Lieu: Paris
Date d'inscription: 09-12-2011
Messages: 1261

Re: Questions diverses et bonnes pratiques

Salut, je reviens sur ce sujet car je m'aperçois que j'ai d'autre problématiques. En effet pour avoir un gain de performance je stocke directement des objets sérialisé pour certains champs en base de données. Le soucis étant que ces objets sont stockées avec leur attributs. Dans ces attributs certains sont des attributs de configuration.

Le problème étant que lorsque je modifie un des attributs de configuration, il est pris en compte que sur les nouveaux objets stockées et non pas aussi sur les anciens du coup ça pose un déséquilibre entre les paramètres défini à l'instant T et ceux ajustés à l'instant T+1. (c'est Doctrine qui gère tout ça)

Comment puis-je procéder ? Je me demande si stocker uniquement ce dont j'ai besoin sous forme de tableaux sérialisé ou d'un objet sans les paramètres de configuration et effectuer un mapping avant et après chaque traitement en base de données ?

Edit : j'ai trouvé une solution, je ne sais pas si c'est totalement propre mais voici comment j'ai fait :
J'ai remplacé le stockage de l'objet par un array sérialisé. Cet array prend pour clé le code de la classe (attribut que j'ai défini) et en valeur ce que j'ai besoin de stocké.

Lorsque je récupère mon array dé-sérialisé, je boucle sur toutes les clés du tableau et instancie la classe dont j'ai besoin en fonction de la clé qui me permet de retrouver quelle classe appeler.

Voici un exemple :

Code:

[lang=php]
$array = array('MaClasse' => $id, 'MaClasse2' => $id);

foreach ($array as $key => $value) {
$objet = new $key;
$objet->setValue($value);
}

Dernière modification par Orkin (16-02-2012 11:47:28)

Hors ligne

 

#19 23-02-2012 01:31:08

omega2
Membre
Lieu: Boisbriand, quebec, canada
Date d'inscription: 01-04-2009
Messages: 85
Site web

Re: Questions diverses et bonnes pratiques

Salut,
Je pense qu'à l'heure actuelle le mieux pour ce genre de problème, c'est d'utiliser l'interface Serializable. Comme c'est php qui fait la transformation des données, c'est théoriquement plus rapide que la création manuelle d'un tableau. En plus la classe de l'objet est inclus dans la chaine : on a plus besoin de le rajouter à côté.
Avec cette solution là tu peux toujours indiquer quels sont les éléments qu'on stocke et tu peux faire des traitements quand tu recharge les données (comme vérifier/recharger la config)

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