Précédent   Forum des professionnels en informatique > PHP > Bibliothèques et frameworks > symfony
symfony Forum d'entraide sur le framework PHP symfony. Avant de poster : cours symfony et FAQ symfony
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 18/11/2010, 18h08   #1
Membre chevronné
 
Avatar de Herode
 
Développeur Web
Inscription : mars 2005
Messages : 766
Détails du profil
Informations personnelles :
Localisation : France, Savoie (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : mars 2005
Messages : 766
Points : 782
Points : 782
Par défaut embedForms 1:n avec table intermédiaire

Ladies and gentlemen,

Soit une gestion de catalogue simplifiée : j'ai des objets Category, Product, Image. Une catégorie ou un produit a 1:n images, une image n'appartient qu'à un seul élément de type donné (produit ou image).

Utiliser une relation 1:n classique en mettant la clé étrangère dans la table Image n'est pas satisfaisant ici car on ne sait pas quelle table va référencer cette clé étrangère.

C'est pourquoi une table intermédiaire est introduite : CategoryImage qui lie une image à sa catégorie, ProductImage qui lie une image à son produit.

Si on ne considère que le côté 'catégorie', cela nous donne un schéma (simplifié) comme ceci :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Category:
  columns:
    name:
      type: string(45)
      notnull: true
  relations:
    Images:
      refClass: CategoryImage
      class: Image
      foreignType: one
 
CategoryImage:
  columns:
    image_id:
      type: integer
      primary: true
    category_id:
      type: integer
      notnull: true
 
Image:
  columns:
    file_name:
      type: string(255)
      notnull: true
      unique: true
Une fois généré le modèle, les cardinalités indiquées dans le code sont correctes :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
BaseCategory::setUp() {
        $this->hasMany('Image as Images', array(
             'refClass' => 'CategoryImage',
             'local' => 'category_id',
             'foreign' => 'image_id'));
}
 
BaseImage::setUp() {
        $this->hasOne('Category', array(
             'refClass' => 'CategoryImage',
             'local' => 'image_id',
             'foreign' => 'category_id'));
}
Tout à coup, l'envie irrépressible me saisit : je veux encapsuler un formulaire sur les Images dans la page de gestion des catégories !

Je prépare aussitôt l'objet Image de la façon la plus banale qui soit :
Code :
1
2
	$img = new Image();
	$img->setCategory($cat);
Et là, soudain, paf ! Le drame :
Citation:
Couldn't call Doctrine_Core::set(), second argument should be an instance of Doctrine_Collection when setting many-to-many references.
Face à cette injustice, je ne suis plus qu'un cri : Pourrrrrrrrrrrrrrrrrrrrrrquoiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii ?

Hein ?
Herode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/11/2010, 14h32   #2
Modérateur
 
Avatar de Michel Rotta
 
Homme Michel Rotta
Responsable d'exploitation informatique
Inscription : septembre 2005
Messages : 4 913
Détails du profil
Informations personnelles :
Nom : Homme Michel Rotta
Âge : 49
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Responsable d'exploitation informatique
Secteur : Distribution

Informations forums :
Inscription : septembre 2005
Messages : 4 913
Points : 7 505
Points : 7 505
Ton schéma et code qui en découlent me semblent compliqué.

Je te propose d'utiliser l'héritage pour simplifier le schéma, le code et ton travail...

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
category:
  columns:
    name:
      type: string(45)
      notnull: true
 
product:
  columns:
    name:
      type: string(45)
      notnull: true
 
image:
  columns:
    file_name:
      type: string(255)
      notnull: true
      unique: true
    link_id: integer
 
image_product
    inheritance:
      extends: image
      type: column_aggregation
      keyField: type
      keyValue: 1
   relations:
      product:
         local: link_id
         foreign: id
         foreignAlias: images
 
image_category
    inheritance:
      extends: image
      type: column_aggregation
      keyField: type
      keyValue: 2
   relations:
      category:
         local: link_id
         foreign: id
         foreignAlias: images
Ce qui va te générer des modèles avec héritages et des forms avec héritage itou.

Il n'y a plus qu'à encapsuler ton form imageProductForm dans le productForm.

Pour retrouver les images d'un produit :
$produit->getImages().

En fait, tu ne vas jamais travailler directement avec le modèle image, mais avec un de deux hérités. Pour retrouver le produits d'une image, tu instancie l'image depuis imageProduct en $prodImage (par exemple) et tu retrouves le produit par :
$prodImage->getProduct()

Code simplifié et maintenance simplifiée que demande le peuple ?
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).
  • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
  • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
  • Une discussion est terminée ? Alors le bouton est votre ami !
Michel Rotta est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 19/11/2010, 16h11   #3
Membre chevronné
 
Avatar de Herode
 
Développeur Web
Inscription : mars 2005
Messages : 766
Détails du profil
Informations personnelles :
Localisation : France, Savoie (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : mars 2005
Messages : 766
Points : 782
Points : 782
Très juste. Je n'avais pas encore utilise les héritages de Doctrine, une bonne occasion de m'y mettre. Ca marche et c'est immensément plus simple en effet !

J'ai juste pris la stratégie 'concrete' plutôt que 'colum-aggregation' car j'aime bien les clés étrangères typées et je n'aime pas les typages par qualifiants (colonne 'type' ici). C'est plus propre côté gestion des clés étrangères & c'est plus proche du modèle orienté objet.

Merci pour la piste !
Herode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/11/2010, 17h44   #4
Modérateur
 
Avatar de Michel Rotta
 
Homme Michel Rotta
Responsable d'exploitation informatique
Inscription : septembre 2005
Messages : 4 913
Détails du profil
Informations personnelles :
Nom : Homme Michel Rotta
Âge : 49
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Responsable d'exploitation informatique
Secteur : Distribution

Informations forums :
Inscription : septembre 2005
Messages : 4 913
Points : 7 505
Points : 7 505
Ce que tu dis n'est pas faux.

Par contre, tu vas te retrouver avec trois tables, une pour chaque liaison et une qui ne sert à rien, mais est, malgré tout, créé.

C'est pour cela, entre autre, que, dans ce type de cas, je prends la solution que j'ai proposé. Toutes les données d'un même type sont dans une table et une seule, et, pour moi, ce type de mise en œuvres est bien conformes aux 5 formes normales (Ah les anciens et leur normes)...
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).
  • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
  • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
  • Une discussion est terminée ? Alors le bouton est votre ami !
Michel Rotta est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 09h15.


 
 
 
 
Partenaires

Hébergement Web