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

Symfony PHP Discussion :

Enregistrer l' User_id et relations n-n [1.x]


Sujet :

Symfony PHP

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Par défaut Enregistrer l' User_id et relations n-n
    Mesdames, Messieurs bonjour !

    J'ai un problème qui je pense est commun mais pour lequel je n'arrive pas à trouver une réponse claire sur le web

    Voici mon histoire :

    J'ai trois classes d'objets :
    - User
    - Livre et
    - User_Livre

    Un User peut avoir plusieurs livres, et un livre peut appartenir à plusieurs Users (relation n-n).

    J'aimerais, quand un livre se crée (via un formulaire de création de livre) qu'un objet liaison "User_livre" se crée systématiquement en reprenant l'id du livre et l'id du User.

    Mes questions sont donc les suivantes

    - Comment récupérer l'id du User (en sachant qu'il s'est connecté via SfGuardPlugin) ?
    - Et comment créer l'objet de liaison "User_Livre"?

    J'ai essayé par plusieurs méthodes (surchargement de la méthode save par exemple) mais je n'y arrive vraiment pas.

    Toute aide ou idée est la bienvenue

    Merci beaucoup

    Matthieu

    PS: s'il est possible d'éviter "sfContext::getInstance()->getUser()"...
    PPS : je m'excuse d'avance si j'ouvre un sujet pour rien mais je vous assure que je n'ai rien trouvé dessus !!!

  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
    Si c'est une vrai liaison n-n (la table user_livre de liaison n'a pas d'attribut), c'est géré automatiquement.

    Tu dois avoir un problème dans le shema.yml.

    Donnes ton shema.yml qu'il se fasse relooker !

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Par défaut
    Bonjour Michel,

    tout d'abord merci pour ta réponse

    ensuite voici le schéma :

    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
     
    livre:
      columns:
        nom: { type: string(255) }
     
    user_livre:
      columns:
        livre_id: { type: integer, notnull: true }
        sf_guard_user_id: { type: integer, notnull: true }
      relations:
        livre:
          alias:        livre
          foreignType:  many
          foreignAlias: user
          onDelete:     cascade
        sfGuardUser:
          alias:        sfGuardUser
          foreignType:  many
          foreignAlias: livre
     
    sfGuardUser:
      actAs: [Timestampable]
      columns:
        first_name: string(255)
        last_name: string(255)
        email_address:
          type: string(255)
          notnull: true
          unique: true
        username:
          type: string(128)
          notnull: true
          unique: true
        algorithm:
          type: string(128)
          default: sha1
          notnull: true
        salt: string(128)
        password: string(128)
        is_active:
          type: boolean
          default: 1
        is_super_admin:
          type: boolean
          default: false
        last_login:
          type: timestamp
      indexes:
        is_active_idx:
          fields: [is_active]
      relations:
        Groups:
          class: sfGuardGroup
          local: user_id
          foreign: group_id
          refClass: sfGuardUserGroup
          foreignAlias: Users
        Permissions:
          class: sfGuardPermission
          local: user_id
          foreign: permission_id
          refClass: sfGuardUserPermission
          foreignAlias: Users
    enfin comme j'ai l'impression que tu en sais beaucoup sur le sujet, tu pourrais expliquer un peu ce qui se passe dans Doctrine (puisque je suppose que c'est Doctrine qui se charge de faire les relations...)??? ca me permettra de pecher plutot que d'aller à la poissonnerie

    Merci beaucoup (d'avance ... )

  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
    Le schema revu

    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
     
    livre:
      columns:
        nom: string(255)
      relations:
        users:
          class: sfGuardUser
          refClass: UserLivre
          foreignAlias: livres
     
    UserLivre:
      columns:
        livre_id: 
          type: integer
          primary: true
        sf_guard_user_id: 
          type: integer
          primary: true
      relations:
        livre:
          foreignAlias: UserLivres
          onDelete:     cascade
        user:
          class:        sfGuardUser
          foreignAlias: UserLivres
    Je n'ai volontairement pas repris la table sfGuardUser qui ne doit pas être modifier.

    A noter que pour accéder aux users en relation avec un livre, depuis livre, on utilisera $livre->getUsers()

    Le secret de la relation n-n est dans la rédaction de la table de liaison, qui n'a pas beaucoup à expliquer, si ce n'est la clef primaire double. Et la relation qui "passe a traver" à l'aide du mot clef refClass de la relation définie sur livre chez toi.

    En principe, on ne touche jamais à la table de liaison qui se nourit toute seul.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Par défaut
    Bonsoir Michel

    merci pour ces infos.

    je n'ai pas encore testé, mais avant de le faire j'aimerais un peu comprendre ce que tu as fait :

    D'abord dans la classe "livre" tu indiques la relation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      relations:
        users:
          class: sfGuardUser
          refClass: UserLivre
          foreignAlias: livres
    Autrement dit, tu dis dans le schéma que Livre est relié par une relation "users", qui relie chaque livre à la classe "sfguarduser" via la classe de référence "UserLivre" et que vu de l'autre côté (coté user), cette classe s'appelle "livre".

    -C'est bien ca?

    Ensuite, tu type en clé primaire les 2 colonnes de User livre.
    - quel est le but de cela? faire qu'il n'y ait pas de doublon de même type?

    Enfin, pour la classe "UserLivre", tu indiques cette relation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      relations:
        livre:
          foreignAlias: UserLivres
          onDelete:     cascade
        user:
          class:        sfGuardUser
          foreignAlias: UserLivres
    En revanche pour SfguardUser tu n'indiques rien.

    Ce que je ne comprend pas, c'est qu'à mes yeux, "une relation n-n" veut dire que et Livre et SfguardUser sont "égaux". Puisque chaque user peut avoir plusieurs livres et que chaque livre peut avoir plusieurs users,

    -pourquoi ne donner que les relations dans la classe livre et pas la classe sfGuardUser?
    -et pourquoi cette asymétrie d'information dans la table userLivre? (tu n'indiques pas le onDelete pour le user, ni la classe pour pour le livre)

    Bref j'essaie de comprendre le mécanisme mais cela reste très flou!!!


    D'autre part dans mon sujet je fais part d'un problème pour récupérer le user_id de ma session. aurais tu une idée?

    merci beaucoup pour toutes tes lanternes

    Matthieu

  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
    Citation Envoyé par Mattyman Voir le message
    Autrement dit, tu dis dans le schéma que Livre est relié par une relation "users", qui relie chaque livre à la classe "sfguarduser" via la classe de référence "UserLivre" et que vu de l'autre côté (coté user), cette classe s'appelle "livre".

    -C'est bien ca?
    Presque
    Je dis sur la table "livre", que tu établis une relation avec l'objet "sfGuardUser". Cette relation s'appellera "livres" du côté de "sfGuardUser" et "users" du côté de l'objet "livre". Cette relation passe par une table pivot UserLivre.

    Ne pas oublier le "s" sur les relations qui indique que le retour de l'appel de la relation ( getLivres() ) va retourner une collection, pas un enregistrement.

    Citation Envoyé par Mattyman Voir le message
    Enfin, pour la classe "UserLivre", tu indiques cette relation :
    ...
    En revanche pour SfguardUser tu n'indiques rien.

    Ce que je ne comprend pas, c'est qu'à mes yeux, "une relation n-n" veut dire que et Livre et SfguardUser sont "égaux". Puisque chaque user peut avoir plusieurs livres et que chaque livre peut avoir plusieurs users,

    -pourquoi ne donner que les relations dans la classe livre et pas la classe sfGuardUser?
    -et pourquoi cette asymétrie d'information dans la table userLivre? (tu n'indiques pas le onDelete pour le user, ni la classe pour pour le livre)
    Effectivement, j'ai été un peu rapide sur les ciseaux, les relations pour l'objet "UserLivre" sont :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
      relations:
        livre:
          foreignAlias: UserLivres
          onDelete:     cascade
        user:
          class:        sfGuardUser
          foreignAlias: UserLivres
          onDelete: cascade
    Ce qu'il faut savoir c'est qu'il y a dans les paramètres à définir pour établir une relation. Ciel ! il n'en a indiqué que 2 ou 3 (voir 1 le plus souvent), mes relations ne marcheront pas ! Que nenni, à des valeurs par défaut qui remplissent parfaitement leur offices. Par défaut une relation est 1-n et est déclarée du côté n de la relation. Ce qui est le cas ici, si on dessine le MPD on se retrouve bien avec deux relations 1-n. Pas de paramètre "class:" défini sur la première relation, pas nécessaire, il prend la valeur par défaut qui est le nom de la relation, ne pas l'écrire revient à écrire : "class: livre" ce qui est bien ce que nous cherchons. Pour l'autre, sans le paramètres "class: sfGuardUser", notre relation tenterait de ce lier avec l'objet "user" qui n'existe pas. Si on remonte d'un paragraphe, dans la définition de la vision n-n la relation s'appelle (vu côté de l'objet "livre") : "users" et est en relation avec l'objet "sfGuardUser" grâce au paramètre "class".

    Si nous déroulons tous les paramètres, ceux exprimés et ceux par défaut nous avons bien deux relations de même type.

    Les relations sont bien définie entre "UserLivre" et les deux tables.

    Et le onDelete est remis en place, victime de ciseaux trop rapide !
    Citation Envoyé par Mattyman Voir le message
    D'autre part dans mon sujet je fais part d'un problème pour récupérer le user_id de ma session. aurais tu une idée?
    Tu utilises sfGuard, donc tu as modifier l'objet parent de myUser. Tu peux donc récupérer l'Id de ton objet "sfGuardUser" correspondant à l'utilisateur courant par les méthodes getGuardUser() et getId(). Dans un contrôleur, cela va donner :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $userId = $this->getUser()->getGuardUser()->getId();
    Tu as une autre méthode qui ne nécessite pas de charger l'objet sfGuardUser (une lecture en base de données). sfGuardUser stock l'id dans les attributs de l'objet myUser() sous le nom de "user_id". Tu peux donc aussi faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $userId = $this->getUser()->getAttribute('user_id');

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Par défaut
    Bonjour Michel

    Merci pour ces précisions !

    Donc si je résume la relation many to many doctrine "pour les nuls"

    1. Dans le schéma j'ai
    -mes 2 objets à lier (livre, sfguarduser)
    -mon objet de liaison (UserLivre)

    2. Je renseigne sur l'un des objet à lier (ici livre) le lien qu'il a avec l'autre objet (sfguarduser) et l'objet qui les lie (UserLivre)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    relations:
        users:
          class: sfGuardUser
          refClass: UserLivre
          foreignAlias: livres
    3. Je renseigne mon objet de liaison
    - en mettant des clefs primaires sur les 2 id
    - en indiquant la classe (qui par défaut est le nom de la relation), le foreign alias, et le delete.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    relations:
        livre:
          foreignAlias: UserLivres
          onDelete:     cascade
        user:
          class:        sfGuardUser
          foreignAlias: UserLivres
          onDelete: cascade
    C'est bien ca???

    En tout cas, ca marche nickel !!!

    Donc merci beaucoup


    En revanche pour ce qui est de l'intégration du user en base, j'ai fait ainsi dans mon create :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      public function executeCreate(sfWebRequest $request)
      {	
    	...
            $users = new Doctrine_Collection('sfGuardUser');
    	$users[0] = $this->getUser()->getGuardUser();
     
    	$nouveaulivre = new livre;
    	$this->form = new livreForm($nouveaulivre);
     
    	$nouveaulivre->setUsers($users);
     
    	$this->processForm($request, $this->form);
            ...
      }
    Ce code fonctionne très bien mais je me demande si je ne suis pas un peu un "hérétique" de la philosophie symfony en faisant ca? en effet j'ai l'impression qu'il y a beaucoup de code php dans mon action.class.

    -Ne pourrais (devrais)-je pas déporter une partie de ce code ailleurs?
    -Si oui, où? livreform.class.php? livre.class.php? ailleurs?

    Merci encore !

    Matthieu

  8. #8
    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 ce qui est du "c'est bien ça ?" je dirais presque.

    En fait tu dois avoir dans les 15 paramètres pour une liaison. La majeur partie du temps, le paramètre par défaut est le bon donc tu n'en renseigne qu'un petit nombre. Mais le paramètre class par exemple est utilisé par doctrine dant toutes les relations. Simplement, la plus part du temps, la valeur par défaut est la bonne.

    Pour le reste, on est relativement bon sur la description.


    Pour ton ajout, la liaison dans le modèle entre livre et user permet de sauter une étape. De plus tu passes par Moscou pour aller de Lyon à Avignon pour récupérer le user courant.

    Le code simplifié.
    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
     
      public function executeCreate(sfWebRequest $request)
      {	
    	...	
            // création et enregistrement d'un objet livre
            // il doit être enregistré avant de pouvoir être lié
            // m'est avis que le process form doit prendre place ici
    	$nouveaulivre = new livre;
    	$this->form = new livreForm($nouveaulivre);
    	$this->processForm($request, $this->form); 
     
            // récupération de l'objet user du "en cours"
            // uniquement si les données ont été sauvegardée
            $user = $this->getUser()->getGuardUser();
     
            // liaison entre le curent user et le livre   
    	$user->setLivres( array ( $nouveaulivre ) );
            ...
      }
    Je ne garanti pas le code, je n'ai pas testé et je n'ai jamais procédé ainsi.

    Il faut éclaircir qui sauvegarde l'objet. En principe $nouveaulivre est un pointeur sur l'objet livre lié au form, donc si celui lié au form est sauvegardé, $nouveaulivre aussi.

    Avec cette construction les livres ne sont lié qu'à l'utilisateur qui les créée. Je ne sais pas si c'est ce que tu cherches. Et on est plus dans une relation 1-n que n-n.

    Edit: Après réflexion, je me demande si tu n'aurais pas intérêt à descendre une bonne partie de ce code dans processForm. Mais comme je ne sais pas ce que représente la liaison n-n entre livre et user, je ne sais pas trop où mettre le code.

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Par défaut
    tu dis "je n'ai jamais procédé ainsi."

    comment procèdes tu toi quand tu dois enregistrer le user en base?

    tu passes par le sfcontext?

    si je passe par le process form avant, je pense pas qu'il sauve en base la relation du livre avec le user (ou il faudrait que j'ajoute un ->save() dans l'execute selon moi). d'ailleurs, si je ne mets rien, il me laisse ajouter des livres sans alimenter LivreUser (j'ai en fait une relation 0,n et non 1,n)

    aussi il ne reconnait pas le array (j'ai essayé, j'ai pas reussi). il demandais que l'argument soit un "doctrine_collection" c'est pour cela que j'ai du passer par le new doctrine_collection.

    Ce que je veux en fait, c'est que l'user puisse ajouter un livre à sa bibliothèque (chaque livre a au moins un user, et le user en question est celui qui enregistre le livre). mais s'il souhaite partager un livre par exemple, ou fusionner sa bibliothèque avec un autre, il puisse le faire sans probleme (d'où mon besoin n-n).

  10. #10
    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
    En général j'ai deux tables. Sur le form de modification (pas de création) s'affiche une liste de possibilités à lier. Tu coches le lien. Après la création. C'est une fonction standard de symfony.

    Créer une collection, oui, il faut, j'ai été un peu vite, mais sans tester... c'est moins stable.

    Enregistrer deux fois, oui, je pense que c'est la seul solution.

    Par contre si tu ne veux pas de livre sans user, tu vas devoir rajouter au moins un champ (attribut) sur la relation, pour préciser que c'est une relation primaire qui ne peut être effacée (si non le livre est orphelin). Ce qui fait que tu ne peux plus utiliser pour cette création la relation n-n mais que tu devras construire les deux liaisons 1-n entre livreUser et ces deux copains. Avec un défaut bien placé sur le nouvel attribut, tu peux faire les autres avec l'outil standard.

    Et il faut gérer la disparition d'un user. Que deviennent ses livres ? Et si tu les gardes tant que quelqu'un les as dans ces liaisons, il va falloir vérifier régulièrement soit a chaque suppression, soit régulièrement pour supprimer les livres orphelins.

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 13
    Par défaut
    Merci pour tout en tout cas Michel.

    Dès que je trouve le bouton, je cliquerai sur "résolu" pour ce sujet

  12. #12
    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
    M'est avis que tu l'as trouvé

    Bonne chance.

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

Discussions similaires

  1. Réponses: 18
    Dernier message: 29/10/2008, 10h25
  2. sélectionner les enregistrements sans relation
    Par piotrr dans le forum Requêtes
    Réponses: 1
    Dernier message: 22/07/2008, 21h49
  3. Suppresion d'enregistrement avec relation
    Par Cydonia dans le forum VBA Access
    Réponses: 8
    Dernier message: 25/06/2008, 11h30
  4. pb relations tables + ligne d'enregistrement
    Par Ludo11 dans le forum Modélisation
    Réponses: 1
    Dernier message: 01/06/2007, 17h56
  5. enregistrement, probleme avec les relations
    Par Nelmo dans le forum SQL Procédural
    Réponses: 6
    Dernier message: 27/04/2006, 17h23

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