IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 PHP Discussion :

Formulaire et relation many to many [1.x]


Sujet :

PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 155
    Par défaut Formulaire et relation many to many
    Bonjour,

    Je suis en train de développer une petite appli de gestion des compétences pour des organismes de formation.

    Une compétence (capacite dans le schéma ci-dessous) pour être sélectionnée pour plusieurs territoires (lieu) et bien sûr un lieu peut être lié à plusieurs compétences. Il me semble donc que nous sommes dans une relation many to many. Or donc après moult recherches, j'en suis arrivé au schéma suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    capacite:
      actAs: { Timestampable: ~ }
      columns:
        text:               { type: string(4000), notnull: true }
        deleted:            { type: boolean, notnull: true, default: false }
        id_formateur:       { type: integer, notnull: true }
        id_ech_exp:         { type: integer, notnull: true }
        id_domaine:         { type: integer, notnull: true }
      relations:
        formateur:          { onDelete: CASCADE, local: id_formateur, foreign: id, foreignAlias: formateursCapacites }
        echelle_experience: { onDelete: CASCADE, local: id_ech_exp, foreign: id, foreignAlias: expCapacites }
        sous_domaine:       { onDelete: CASCADE, local: id_domaine, foreign: id, foreignAlias: domainesCapacites }
        lieux:
            foreignAlias:     CapacitesZoneGeoAccept
            class:            Lieu
            refClass:         ZoneGeoAccept
            local:            id_capacite
            foreign:          id_lieu
     
     
    lieu:
      columns:
        nom:                { type: string(255), notnull: true }
        type:               { type: enum, length: 3, values: ['aca','dep','gre'], notnull: true }
     
    zone_geo_accept:
      columns:
        id_capacite:        { type: integer, primary: true, notnull: true }
        id_lieu:            { type: integer, primary: true, notnull: true }
      relations:
        capacite:           { onDelete: CASCADE, local: id_capacite, foreign: id, foreignAlias: zonesGeoAcceptees }
        lieu:               { onDelete: CASCADE, local: id_lieu, foreign: id, foreignAlias: zonesGeoAcceptees }
    Maintenant, lorsque j'arrive sur le editSuccess pour modifier une compétence, les champs ne sont pas générés automatiquement. J'ai lu quelque part sur un forum que ce devrait être le cas. L'information est-elle erronée ? Dans le baseCapaciteForm je n'ai aucun widget qui fasse référence à cette relation. Le problème viendrait-il d'une mauvaise écriture du schéma ?

    Donc j'ai commencé à contruire ça moi-même, et j'y suis bien parvenu côté vue :

    capaciteForm.php :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    $this->setWidget( 'zonesGeoAccept' , new sfWidgetFormDoctrineChoice(array(
              'model'           =>  'Lieu',
              'add_empty'       =>  false,
              'multiple'        =>  true,
              'expanded'        =>  true
          )));
     
          $this->widgetSchema->setLabels( array(
     
              'text'            => 'Compétence',
              'id_formateur'    => 'Formateur',
              'id_ech_exp'      => 'Expérience',
              'id_domaine'      => 'Sous-domaine',
              'zonesGeoAccept'  => 'Mobilité'
     
          ));
          $this->widgetSchema['text']->setAttribute('cols',60);
          $this->widgetSchema['domaine']->setDefault( $this->getObject()->getSousDomaine()->getIdDomaine() );
     
          $zones_records = $this->getObject()->getZonesGeoAcceptees();
             foreach($zones_records as $key=>$value)
             {
                 $default_zones[]=$value->getIdLieu();
             }
          $this->widgetSchema['zonesGeoAccept']->setDefault( $default_zones );
     
     
          $this->setValidator('domaine', new sfValidatorDoctrineChoice(array(
              'model'           =>  'Domaine'
          )));
          $this->setValidator('zonesGeoAccept', new sfValidatorDoctrineChoice(array(
              'model'           =>  'Lieu',
              'multiple'        =>  true
          )));
    J'ai bien sûr rajouté le bon renderRow dans le partial _form.php.

    Mon problème c'est comment sauvegarder les modifications relatives à cette relation... Faut-il faire quelque chose dans le fichier actions.class.php au niveau du processForm ? Faut-il réécrire la méthode save() du modèle ?

  2. #2
    Expert confirmé
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Par défaut
    Bonjour,

    Le modèle n'est pas viable, il y a des problèmes dans les liaisons, notamment sur la table capacite.

    J'ai réécris "comme pour moi"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    capacite:
      actAs:
        Timestampable: ~ 
      columns:
        text:               
          type:         string(4000)
          notnull:      true
        deleted:
          type:         boolean
          default:      false
        formateur_id:   integer
        experience_id:  integer
        domaine_id:     integer
      relations:
        formateur:       
          onDelte:      CASCADE
          foreignAlias: capacites
        experience: 
          onDelete:     CASCADE
          foreignAlias: capacites
        domaine:  
          onDelete:     CASCADE
          foreignAlias: capacites
        lieux:
            foreignAlias:     CapaciteLieu
            class:            Lieu
            refClass:         ZoneGeoAccept
     
    lieu:
      columns:
        nom:                
          type:         string(255)
          notnull:      true 
        type: 
              // les champs de type enum sont des plaies à maintenir
              // un integer et un tableau dans l'objet modèle 
              // permettent de récupérer le texte et de faire des listes
              // avec un minium de code et sans avoir à modifier la structure
              // si on veut rajouter des informations.
          type:         enum
          length:       3
          values:       ['aca','dep','gre']
     
    CapaciteLieu:
      columns:
        id_capacite:        
          type:         integer,
          primary:      true
        id_lieu:     
          type:         integer
          primary:      true
      relations:
        capacite: 
          onDelete: CASCADE
          foreignAlias: CapaciteLieux
        lieu:
          onDelete: CASCADE
          foreignAlias: CapaciteLieux
     
    formateur:
      columns:
        ...
     
    experience:
      columns:
        ...
     
    domaine:
      columns:
        ...
        // pas de relation pour ces tables, elles sont définies dans
        // la table capacite
    En cherchant un peu sur le forum, tu trouveras de nombreux sujets sur les structures de shema.yml où j'explique le pourquoi des différentes modifications faites.

    Modifie ton schéma, régénère les forms, ensuite on devrait être plus à l'aise.

    Juste une chose, je suis passé très vite sur le reste du code. Pour information, il n'est pas possible dans le cadre d'une liaison n-n d'avoir un formulaire qui affiche les capacité d'un gugus et qui permette de saisir de nouveaux lieux. Il faut que les lieux existent avant d'être rattachés aux capacités. Du moins, ce n'est pas réalisable avec les outils de base. Après, on peut toujours broder et triturer...

  3. #3
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 155
    Par défaut
    Merci encore une fois Michel pour ton aide. Je verrai donc ça mardi puisque je ne rebosse que mardi sur ce projet. Je te tiendrai au courant.

    PS. Comment fais-tu pour répondre à autant de billets ?

  4. #4
    Expert confirmé
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Par défaut
    Je passe mes journées à lancer de long process...

    Non, je tape vite, je répond sans exemple ou rare, a vous de chercher, c'est plus un guide de recherche qu'une réponse complète. Enfin souvent.

    Donc c'est rapide à taper.

    Et il n'y a pas tant de billet par jour...

  5. #5
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 155
    Par défaut
    Bon voilà, c'est mardi, j'ai réattaqué. J'ai donc réécris mon schéma en suivant ton modèle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    Formateur:
      actAs: { Timestampable: ~ }
      columns:
        nom:
          type:             string(255)
          notnull:          true
        prenom:
          type:             string(255)
          notnull:          true
        telephone:
          type:             string(14)
        email:
          type:             string(255)
          notnull:          true
        deleted:
          type:             boolean
          default:          false
        statut_id:          integer
        lieu_id:            integer
      relations:
        Statut:
          onDelete:         CASCADE
          foreignAlias:     formateurs
        Lieu:
          onDelete:         CASCADE
          foreignAlias:     formateurs
     
    Capacite:
      actAs: { Timestampable: ~ }
      columns:
        text:
          type:             string(4000)
          notnull:          true
        deleted:
          type:             boolean
          default:          false
        formateur_id:       integer
        experience_id:      integer
        sousdomaine_id:     integer
      relations:
        Formateur:
          onDelete:         CASCADE
          foreignAlias:     capacites
        Experience:
          onDelete:         CASCADE
          foreignAlias:     capacites
        Sousdomaine:
          onDelete:         CASCADE
          foreignAlias:     capacites
        Lieux:
            foreignAlias:   CapaciteLieux
            class:          Lieu
            refClass:       CapaciteLieu
     
    CapaciteLieu:
      columns:
        capacite_id:
          type:             integer
          primary:          true
        lieu_id:
          type:             integer
          primary:          true
      relations:
        Capacite:
          onDelete:         CASCADE
          foreignAlias:     CapaciteLieux
        Lieu:
          onDelete:         CASCADE
          foreignAlias:     CapaciteLieux
     
    Statut:
      columns:
        nom:
           type:            string(255)
           notnull:         true
     
    Experience:
      columns:
        nom:
          type:             string(255)
          notnull:          true
     
    Domaine:
      columns:
        nom:
          type:             string(255)
          notnull:          true
     
    Sousdomaine:
      columns:
        nom:
          type:             string(255)
          notnull:          true
        domaine_id:         integer
      relations:
        Domaine:
          onDelete:         CASCADE
          foreignAlias:     SousDomaines
     
    Lieu:
      columns:
        nom:
          type:             string(255)
          notnull:          true
        type:
          type:             integer
          notnull:          true
    mais au moment d'importer les fixtures, j'obtiens de nouveau :
    SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`geco`.`capacite`, CONSTRAINT `capacite_formateur_id_formateur_id` FOREIGN KEY (`formateur_id`) REFERENCES `formateur` (`id`) ON DELETE CASCADE)
    Mon fichier fixtures correspondant se présente ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    45
    46
    47
    48
    49
    50
    Formateur:
      1:
        nom:                  ******
        prenom:              ******
        telephone:           "0123456789"
        email:                mon.email@fai.net
        statut_id:            3
        lieu_id:              6
      2:
        nom:                  ******
        prenom:               Pierre
        telephone:            "0123456789"
        email:                son.email@fai.fr
        statut_id:            1
        lieu_id:              7
      3:
        nom:                  ******
        prenom:             ******
        email:                ses.email@fai.fr
        statut_id:            1
        lieu_id:              8
     
    Capacite:
      1:
        text:                 |
                              Plein 
                              de
                              texte
        formateur_id:         1
        experience_id:        1
        sousdomaine_id:       24
      2:
        text:                 |
                              Encore
                              du 
                              texte
        formateur_id:         2
        experience_id:        2
        sousdomaine_id:       20
     
    CapaciteLieu:
      1:
        lieu_id:              6
        capacite_id:          1
      2:
        lieu_id:              3
        capacite_id:          1
      3:
        lieu_id:              2
        capacite_id:          2
    Si je place la ligne formateur_id des fixtures capacite, cela fonctionne... Là je ne vois pas pourquoi j'ai ce souci ! Y-a-t-il encore une erreur quelque part ?

  6. #6
    Expert confirmé
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Par défaut
    Pour les fixatures. Chaque fixature doit avoir un nom unique. Donc "1:" ne peut être utilisé deux fois. Remplace par "fac001".

    Pour les liaisons il faut utilisé les noms créés avec relations dans le shéma et lier avec le nom de la fixature et pas la clef (elle est auto-générée, rien ne permet de présager de la valeur.

    En résumé :
    Code yaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Formateur:
      for001:
        nom:                  ******
        prenom:              ******
        telephone:           0123456789
        email:                mon.email@fai.net
        statut:            statut003
        lieu:              lieu006

    En principe doctrine réarrange pour avoir les clefs même si elles sont déclarées après.

    Tu peux aussi pour les côté n des liaisons faire des tableaux

    Code yaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    lieu:
      lieu001:
        nom: coucoulelieu
        formateurs: [ for001, for005, for008 ]

    Tu peux aussi, pour des enfants multiple (relation 1-n) et toujours unique créer dans la relation

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    parent:
      par001:
        nom: Dupond
        prenom: avecD
        enfants:
          enf001:
            prenom: pierre
          enf002:
            prenom: gustave
    A noter que, même là, les noms enf001 doivent être unique dans toutes les fixatures.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. PGSQL-EclipseLink Relation One To Many et Many To One
    Par faitor1 dans le forum Persistance des données
    Réponses: 0
    Dernier message: 30/01/2015, 19h46
  2. [1.x] Formulaire imbriqué Relation many to many
    Par Ontolingua dans le forum Symfony
    Réponses: 13
    Dernier message: 03/08/2012, 21h34
  3. Réponses: 0
    Dernier message: 30/05/2012, 21h05
  4. [MVC] Spring, formulaire, et relation one-to-many
    Par andlio dans le forum Spring Web
    Réponses: 1
    Dernier message: 21/06/2011, 09h39
  5. Un peu de mal a comprendre le concepte "one-to-many" et "many-to-many"
    Par chriscoolletoubibe dans le forum Hibernate
    Réponses: 4
    Dernier message: 29/03/2007, 18h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo