[PHP - Symfony]Construire une entité à partir de plusieurs tables.

Répondre
Partager Rechercher
Bonjour ! J'ai un souci qui me bloque depuis un moment maintenant, et je vois pas du tout comment faire : J'essaye de créer une entité depuis une DB existante, et j'essaye de mettre plusieurs champs de plusieurs tables dans une seule entité, et je sais même pas si c'est possible en fait

Exemple concret :
  • Dans la table Pokemon j'ai id, name, etc...
  • Dans la table Pokemon_stats j'ai pokemon id, stats_id, base_stats

Est-ce qu'il est possible de créer une entité Pokémon ayant comme attribut :
  • id
  • name
  • stats_id
  • base_stats

A noter que j'ai pas besoin de setter et que je ne vais rien ajouter dans la DB. J'avais pensé à faire une vue regroupant tout ça et faire mon entité dessus, mais c'est pas super super clean qu'on m'a dit, du coup je cherche autre chose

Merci d'avance !
Sauf erreur, ce que tu veux faire correspond au chapitre association de la doc :
http://symfony.com/doc/current/book/...s-associations

Pour ce genre de truc, pense d'abord en terme base de données pour ta recherche google, ce que tu veux faire c'est une jointure relationnelle de type 1 pour n (one to many).
Et de préférence avec les termes anglais : tu aurais trouvé cette doc dans les premiers liens
Nope c'est pas si simple vu que visiblement tu veux pas créer une entité et une relation mais une entité qui couvre 2 tables. Je suis pas un pro de doctrine mais ça me semble pas possible.

Imo il faudrait voir à changer ton modèle de donné qui me semble assez chelou (tu as vraiment besoin d'une table "stats" à part ? Visiblement tuvpeux fusionner l'entité "stats" et l'entité "pokémon"). Si tu veux vraiment séparer les choses dans ton code, peut-être te tourner vers des Value Object et des embed Doctrine : http://doctrine-orm.readthedocs.org/...beddables.html (attention je crois que c'est dans une version de Doctrine supérieure à celle par defaut dans Symfony)

Edit : visiblement c'est pas impossible, http://docs.doctrine-project.org/en/...le-inheritance
C'est une DB complète et pré remplie avec toutes les données nécessaires (les pokémons parents, ceux compatibles en reproduction, les méthodes d'évolution, etc... 20Mo de données environ) mise à jour à chaque nouvelle version et dont le modèle ne change pas, du coup j'aimerai ne pas avoir à re coder le pokédex entièrement à chaque version

Mais merci pour les liens, j'vais regarder en détail !
L'héritage pourrait en effet résoudre ton problème, mais ça me semble un peu bizarre de l'utiliser dans un cas comme ça. En plus, ça va te forcer à modifier la DB pour ajouter la colonne du discriminant.
Pour ce qui est d'embeddable, il semblerait que ça permette de faire l'inverse : 2 classes représentées dans une seule table, donc ça ne te conviendra pas.

Une bête relation 1-1 me semblerait plus adaptée, et tu peux masquer cette indirection via des getters dans ton entité Pokemon.
La vue devrait aussi bien fonctionner, mais c'est plus bas niveau, donc ça risque de te jouer des tours (par exemple si tu dois recréer la db et que tu oublies de refaire la vue).
Citation :
Publié par Metalovichinkov
C'est une DB complète et pré remplie avec toutes les données nécessaires (les pokémons parents, ceux compatibles en reproduction, les méthodes d'évolution, etc... 20Mo de données environ) mise à jour à chaque nouvelle version et dont le modèle ne change pas, du coup j'aimerai ne pas avoir à re coder le pokédex entièrement à chaque version

Mais merci pour les liens, j'vais regarder en détail !
le plus simple imo c'est d'avoir une entité pokemon qui contient une entité pokemonStat. sémantique t cela a plus de sens que l'héritage. un pokemon à des statistiques. il n'est pas la statistique en elle même.
Citation :
Publié par Metalovichinkov
C'est une DB complète et pré remplie avec toutes les données nécessaires (les pokémons parents, ceux compatibles en reproduction, les méthodes d'évolution, etc... 20Mo de données environ) mise à jour à chaque nouvelle version et dont le modèle ne change pas, du coup j'aimerai ne pas avoir à re coder le pokédex entièrement à chaque version
Si le modèle ne change pas, tu ne devrais pas avoir à recoder quoique ce soit si ?
imo il veut dire que la database est fournie par un tiers. Apres ouais si il se retrouve avec un Modele Pokemon qui contient juste un nom, une ID et une relation 1-1 vers la pokemon stat qui correspond, c'est un peu laid comme modele. Ca vaut peut etre le coup d'avoir un petit script de transformation en sql ?
Ben justement si la database est fournie par un tier et que sa structure ne change pas à chaque mise à jour, ça veut dire qu'il code une fois et c'est réglé. Je ne vois pas pourquoi il aurait besoin de recoder si les données sont mises à jour.

A ta place je me casserai pas la tête, tu fais tes entités avec tes relations, tu génères les getters/setters et comme ça dès que tu feras ta requête (findOneBy par exemple) pour récupérer les données d'un pokemon, tu auras les getters dans l'entité pour aller chercher toutes les données qu'il te manque.
Si vous voulez voir, la DB se trouve en bas de page ici

En toute honnêteté, j'ai jamais bossé avec une DB de cette taille, et jamais avec une DB déjà remplie du coup je suis totalement perdu

Dans l'absolu nan, je n'ai rien à recoder, je répondais à Edel qui disait que le modèle est chelou (et ça je l'admet) et c'est aussi pour ça que l'idée de faire une vue me plait moyennement, même si je ne voyais que ça... Ou alors faire beaucoup d'entité, vraiment beaucoup : rien que pour les pokémons (id, numéro pokédex selon les différentes région, pokémon parents, attaques, attaque transmises par reproduction, etc... Y'a beaucoup de trucs dans Pokémon ) ça représente 26 tables.
A ça faut ajouter quelques tables pour les attaques, pour les objets, etc...

Après, si le plus simple (et pas trop sale) est de faire une entité pour chaque table en découpant dans différents bundle (bundle pokémon, attaques, objets, etc...) bah je pense que je peux en être capable, mais je sais pas, je trouvais pas ça bien propre

Je vous ajoute un lien vers la DB en mysql pour ceux qui veulent observer : ici
Citation :
Publié par Metalovichinkov

Après, si le plus simple (et pas trop sale) est de faire une entité pour chaque table en découpant dans différents bundle (bundle pokémon, attaques, objets, etc...) bah je pense que je peux en être capable, mais je sais pas, je trouvais pas ça bien propre

C'est le plus propre meme. C'est semantiquement juste (ce sont des relations A-UN), et ca apporte du decouplage (pas besoin de duplication de donnee, facile de modifier / rajouter une stat sans toucher a la table pokemon). Propre != concis. Au contraire meme, imo.
Les entités c'est une chose, les bundles et la façon de coder le code métier s'en est une autre.

Les entités doivent être faites de façon à :
- pouvoir ressortir les valeurs de tous les champs de ta bdd
- te faciliter la vie en faisant les bonnes relations

Les bundles et le découpage du code métier, c'est appliquer des bonnes pratiques et penser réutilisation et clareté.

Il y a une commande Symfony pour faire du reverse ingeneering et créer les entités à partir de la database, par contre il faudra surement que tu repasses sur certaines entités pour les compléter et améliorer/optimiser.

Je pense que tu devrais y aller étape par étape, déjà tu mets en place ton projet symfony avec un bundle entités par exemple qui contiendra toutes les entités de cette base. Ensuite tu penseras à tes classes et bundles pour t'organiser. Pour moi tes bundles ne doivent pas forcément être liés à une entité, surtout que tu risques, en codant, de te rendre compte que tu as besoin de la même entité dans 2 bundles différents et là ça deviendra moche.

Perso je fais mon controller, par exemple : DisplayPokemonAction() : je veux qu'il affiche un pokemon.
Ce controller appellera les méthodes de la classe Pokemon et cette classe fera appelle aux entités et aux requêtes faites dans les repository de ces entités afin de ressortir les données.

Si tu as peur que ta classe Pokemon soit trop grosse, tu sépares tout ce qui est stat dans PokemonStat et ta classe Pokemon ira appeler des méthodes de PokemonStat pour ressortir tout ce qu'il te faut. Tu peux faire aussi des classes PokemonImage, PokemonSoud, PokemonZone ou whatever pour bien séparer tes méthodes mais au final je pense qu'il faudra que tu récupères la donnée que tu veux de la manière suivante dans ton controller :
$this->Pokemon->getZone($idPokemon) et basta.

Dernière modification par N3o- ; 21/12/2015 à 11h50.
Déjà, merci beaucoup pour vos réponses, ça m'aide pas mal !

Mais y'a juste un truc que j'ai du mal à comprendre
Citation :
Publié par N3o-
Je pense que tu devrais y aller étape par étape, déjà tu mets en place ton projet symfony avec un bundle entités par exemple qui contiendra toutes les entités de cette base. Ensuite tu penseras à tes classes et bundles pour t'organiser.
J'ai un peu peur de passer pour un con en demandant mais... Y'a d'autres classes que les entités dans Symfony?

Avec vos réponses, je voyais un truc type :
  • PokemonBundle
    • Pokemon (entity)
    • PokemonStats (entity)
    • PokemonEggGroups (entity)
    • etc...
  • AbilityBundle
    • Ability (entity)
    • etc...
  • MoveBundle
    • Move (entity)
    • MoveEffect (entity)
    • etc...

J'ai bon? Sachant qu'un Pokémon a 1, 2 ou 3 abilities possibles et une grosse liste de moves
Après, y'a certains trucs ou je ne pense pas avoir besoin d'entités, genre pour récupérer le nom, les tables sont sous la forme ***_names, là je pense pouvoir récupérer le nom directement, le lien est déjà présent sur ***_id
Citation :
Publié par Metalovichinkov
J'ai un peu peur de passer pour un con en demandant mais... Y'a d'autres classes que les entités dans Symfony?
Une classe, c'est une représentation d'un objet. Dans la programmation orienté objet, on ne travaille qu'avec ça.

Donc il n'y a pas que les entités qui sont des classes, les entités sont les objets représentants tes "vraies" tables en bdd.
C'est un peu comme si tu faisais un mysql_fetch_object à l'ancienne.

En gros le MVC et la programmation objet c'est ça :

mvc_couche_service_metier.png
Et "Business" ce sont tes objets PHP (comme Pokemon dans mon exemple du dessus).

Ton controller fait appel à une ou plusieures classes PHP (souvent des services dans Symfony) qui vont récupérer et traiter les infos de la bdd pour les retourner au controller qui renvoient les infos dans une vue pour les afficher.

Imo il te manque des bases de programmation objet avant de te lancer dans Symfony 2. Tu devrais déjà suivre quelques tuto (sur Symfony ou pas) pour te familiariser avec ça et ensuite tu auras une vision plus claire de ce que tu veux faire.
Citation :
Publié par Metalovichinkov
Avec vos réponses, je voyais un truc type :
  • PokemonBundle
  • AbilityBundle
  • MoveBundle
Ne te prends pas la tête avec plusieurs bundles. Comme l'a mentionné N3o-, les bundles servent à faire des composants indépendants et réutilisables (par d'autres projets sans rapport avec le tien). Je doute que ça soit le cas pour ça. Tu peux mettre tes entités dans des namespaces différents (~ des dossiers différents), mais ne va pas chercher plus loin. http://symfony.com/doc/current/best_...cation-bundles
Je compléterai la réponse de N3o- en précisant que dans Symfony TOUT est objet et donc, tu utilises exclusivement des classes.

Une idée d'organisation peut-être à creuser car je l'utilise systématiquement sur l'ensemble de mes projets et j'en suis satisfait :
- une classe entité par table
- une classe repository par entité dans lesquelles tu mets tes requêtes spécifiques (en plus des find dont ces classes héritent)
- une classe manager par entité que tu déclares comme service dans lesquelles tu mets toutes tes actions métiers concernant cette entité
- une classe manager par "multi-entités" (ou hors-usage d'entités mais c'est pas courant) que tu déclares comme service si le besoin s'en fait sentir et que tu ne sais pas vraiment où classer ce manager (bon, ça c'est moche+++ mais ça dépanne)

Avec cette organisation, tu réunis dans ces classes l'ensemble de ton code métier.

Ainsi, dans ton controller, tu as juste à faire :
$entiteManager = $this->get('monManager');
puis pour faire un select sur ta base :
$mesResultats = $entiteManager->findMesInfosAvecUneRequeteHyperCompliqueQueJaiEcritDansUnRepository();
ou pour modifier tes données :
$entiteManager->lanceSuperAttaque($assaillant, $victime, array $pleinDOptions);

Cette méthode est très bien détaillée sur la page ci-dessous et me semble éminemment pratique :
http://www.lafermeduweb.net/tutorial...fony2-p99.html
Je plussoie les posts précédent de toute ma force pour l'organisation.

La documentation de Sf2 est très bien faite, tu devrais la lire.

C'est les vacances. A la limite, si tu m'expliques ce que tu veux faire, je veux bien te lancer et écrire la structure de ton appli (si ça me prend pas trop de temps - c'est vite chronophage quand on tombe sur des problèmes imprévus) dans un dépôt git. A partir de là ça devrait te débloquer en partie car tu n'as "qu'à recopier".
Déjà, merci beaucoup pour vos réponses !

Y'a certains trucs que vous dites qui me paraissent logique (le découpage en bundle) mais j'ai pas du tout appris comme ça du coup j'ai un peu de mal à bien visualiser.
[ML]Pendant le BTS, on a appris PHP, puis PHP objet, puis on nous a demandé de faire pour les PPE un projet avec un framework PHP, du coup on a appris Symfony 2* en se démerdant comme on pouvait, et les cours servaient essentiellement à répondre aux problématiques des différents groupe : l'essentiel du fonctionnement, je l'ai vu sur le site du zéro, la doc et stack overflow.
Du coup je sais faire un bundle, je sais faire des entités, un controller, du routing, etc... Mais c'est le niveau 0.5 de l'utilisation quoi, avec des trucs pas bien propre dedans.
*On avait le choix : soit on connaissez déjà un framework (dans n'importe quel langage), soit on avait le droit à Symfony parce que le prof ne faisait des cours que dessus.[/ML]

Du coup les repo, les services et tout, bah j'en ai jamais vu. Enfin si, j'ai utilisé les services déjà dedans mais sans jamais cherché à en faire un moi même.
Donc là j'me met à lire tout ce que vous me donnez et j'essaye de voir ce que ça donne.

D'ailleurs si j'ai bien compris, le controller se retrouve être l'équivalent du main en java, c'est ça?
Pas exactement, le main ce serait plutôt le web/app.php ou web/app_dev.php. C'est ce qu'on appelle le point d'entrée.

Le contrôleur te permet de résoudre une "request" (via une route) en vue de retourner une "response". Idéalement, son rôle devrait se limiter strictement à ça et tout le reste devrait être codé dans des services, le contrôleur n'étant que le chef d'orchestre qui appelle tout ton code. Tu peux très bien écrire un formulaire dans un contrôleur mais c'est dommage de ne pas utiliser un Form/type.

Si tu vises une organisation "propre" (et c'est ce qui est le plus formateur et le plus simple à maintenir à l'avenir), essaies de conserver la règle des 5/10/20 dans chacun de tes contrôleurs c'est à dire :
- 5 variables maximum par méthode
- 10 méthodes maximum par contrôleur
- 20 lignes maximum par méthode
- (je rajouterai : 3 niveaux d'imbrication (if, for, ...) maximum par méthode mais ça c'est personnel)
http://symfony.com/doc/current/best_...ces/index.html

Si tu as un peu de temps et que ça t'intéresses, je t'invite à suivre les vidéos de dev&click qui a su vulgariser Symfony 2 :
https://www.youtube.com/playlist?lis...weDKNMNQhHDbTT

Je pense que tu focalises un peu trop sur les bundles et pour le coup, je me dis que tu devrais plutôt focaliser sur ce qu'ils contiennent et n'utiliser qu'un seul bundle pour ton application. Je te rappelle ce qu'en disent les bonnes pratiques Symfony 2 :
Citation :
A bundle is meant to be something that can be reused as a stand-alone piece of software. If UserBundle cannot be used "as is" in other Symfony apps, then it shouldn't be its own bundle. Moreover, if InvoiceBundle depends on ProductBundle, then there's no advantage to having two separate bundles.
Autrement dit, si deux bundles sont trop liés, peut-être vaut-il mieux n'en écrire qu'un seul.

Sache également qu'on peut très bien utiliser Symfony 2 de manière très organisée tout comme mettre tout en vrac dans ton contrôleur. Lorsqu'on me confie un petit projet, il m'arrive assez régulièrement de nettement surcharger le code de mes contrôleurs de façon à pisser la ligne et de sortir rapidement la maquette attendue par mes clients. Il ne faut pas en avoir honte, ça fonctionne parfaitement, c'est juste plus difficile à lire, à réutiliser et à maintenir. Lorsque tu développes comme ça, très rapidement tu vas sortir un voter, un form et des actions métiers et tu les rangeras naturellement dans des classes spécifiques dès que le besoin de réutilisation se fera sentir. Dans tous les cas, la mise en production devra passer par la rationalisation du code sous peine de passer quelques nuits blanches dans 6 mois quand ton client te demanderas de modifier un comportement

Comme je le dis souvent à mes stagiaires : "Quand tu pisses la ligne, selon les contraintes imposées, il y a toujours énormément de façon de coder : la bonne et les autres"
Wow ! Ca c'est du cadeau de noël ! Depuis que j'ai posté je me tape toute la doc possible, j'ai compris certains trucs (l'architecture à adopter) et d'autres beaucoup moins (enregistrer un service)
Avec ça ça devrait être bon, en tout cas merci énormément !
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés