CakePHP-Fr.Org

Forum francophone du Framework CakePHP

Vous n'êtes pas identifié.

#1 22-04-2009 18:57:13

Ziaaa
Crêpe Suzette
Date d'inscription: 22-04-2009
Messages: 7

[RESOLU] Insertion de données HABTM

Bonjour,

Je n'arrive pas à enregistrer des données appartenant à deux modèles liés.
J'ai une table transferts une table plans et une table de jointure plans_transferts
L'idée c'est qu'un transfert peut contenir plusieurs plans et les plans peuvent être contenus dans plusieurs transferts.

Mon problème est le suivant : je n'arrive pas à enregistrer ces données à la fois dans la table transferts plans et plans_transferts. J'ai essayé plusieurs solutions, la méthode save appliquée sur le modèle Transfert et le modèle Plan et j'ai aussi essayé la méthode saveAll mais ça ne fonctionne pas. Quand j'utilise save la table plans_transferts est mise à jour mais les données ne correspondent pas du tout. Avec saveAll c'est la table plans qui n'est pas mise à jour (et il me semble qu'il n'y a pas d'insertion ds la table plans_transferts)

Ci dessous vous trouverez mon code dans l'état actuel des mes tests. Si qqun connait la bonne méthode JE SUIS PRENEUR :)



J'ai donc configuré les relation HABTM ds mes modèles :
ici mon modèle Transfert :

Code: php

  1. class Transfert extends AppModel
  2. {
  3.     var $name = 'Transfert';
  4.     var $belongsTo = array(
  5.         'Projet' => array(
  6.             'className'    => 'Projet',
  7.             'foreignKey'    => 'projet_id'
  8.         ),
  9.         'Affaire' => array(
  10.             'className'   => 'Affaire',
  11.             'foreignKey'  => 'affaire_id'
  12.         ),
  13.         'Destinataire' => array(
  14.             'className'   => 'Destinataire',
  15.             'foreignKey'  => 'destinataire_id'
  16.         ),
  17.         'User' => array(
  18.             'className'   => 'User',
  19.             'foreignKey'  => 'user_id'
  20.         )
  21.     );
  22.     var $hasAndBelongsToMany  = array(
  23.         'Plan' => array(
  24.             'className' => 'Plan',
  25.             'joinTable' => 'plans_transferts',
  26.             'foreignKey' => 'transfert_id',
  27.             'associationForeignKey' => 'plan_id'
  28.         )
  29.     );
  30.      
  31. }

Ici mon modèle Plan :

Code: php

  1. class Plan extends AppModel
  2. {
  3.   var $name = 'Plan';
  4.   var $hasAndBelongsToMany = array(
  5.         'Transfert' => array(
  6.             'className' => 'Transfert',
  7.             'joinTable' => 'plans_transferts',
  8.             'foreignKey' => 'plan_id',
  9.             'associationForeignKey' => 'transfert_id'
  10.         )
  11.     );
  12. }

Ensuite je passe au formulaire. Comme je l'ai dis, un transfert est censé contenir un ou plusieurs plan, au point où j'en suis j'essaie d'enregistrer au moins un plan lié au transfert, je verrai plsu tard pour plusieurs plans.
Au niveau de mon action du contrôleur Transfert voilà ce que j'ai :

Code: php

  1.     function add() {
  2.      
  3.       $this->set('projets', $this->Transfert->Projet->find('list', array('fields'=>'Projet.intitule')));
  4.       $this->set('affaires', $this->Transfert->Affaire->find('list', array('fields'=>'Affaire.intitule')));
  5.       $this->set('destinataires', $this->Transfert->Destinataire->find('list', array('fields'=>'Destinataire.intitule')));
  6.       $this->set('user',$this->Auth->user('id'));
  7.      
  8.       if (!empty($this->data)) {
  9.          //debug($this->data); 
  10.          if ($transfert = $this->Transfert->save($this->data) ) {
  11.                //debug($transfert);
  12.                $this->data['Plan'][0]['Transfert.id'] = $this->Transfert->id;
  13.                debug($this->data);
  14.                $this->Transfert->Plan->save($this->data);  
  15.                $this->flash('Votre transfert a été sauvegardé.','/transferts');
  16.          }
  17.       }
  18.      
  19.  
  20.    }

La vue qui correspond à cette action :

Code: php

  1. echo $form->create('Transfert',array('controller' => 'transferts', 'action' => 'add'));
  2.  
  3. // cette solution fonctionne aussi : echo $form->select('projet_id',$projets);
  4. echo $form->input('projet_id', array('options'=>$projets));
  5. echo $form->input('affaire_id',  array('options'=>$affaires));
  6. echo $form->input('user_id', array('type'=>'hidden', 'value' => $user));
  7. echo $form->input('destinataire_id', array('options'=>$destinataires));
  8. ?>
  9. <h2>Ajouter des plans</h2>
  10. <?php
  11.  
  12. echo $form->input('Plan.0.reference');
  13. echo $form->input('Plan.0.indice');
  14. echo $form->input('Plan.0.logiciel');
  15. echo $form->input('Plan.0.type');
  16.  
  17.  
  18. echo $form->end('Enregistrer');

Hors ligne

 

#2 23-04-2009 10:10:30

avairet
Chef Pâtissier
Date d'inscription: 25-06-2008
Messages: 1320

Re: [RESOLU] Insertion de données HABTM

Salut Ziaaa,

Première chose, dans ton action add(), où settes-tu les Plans pour les passer à la vue et les afficher dans ton formulaire ?

Il devrait y avoir une ligne $this->set('plans',$this->Transfert->Plan->find('list'));
Et dans le formulaire, pour avoir le select multiple avec tous les plans, tu devrais avoir une simple ligne :
echo $form->input('Plans');

Hors ligne

 

#3 23-04-2009 16:34:32

Ziaaa
Crêpe Suzette
Date d'inscription: 22-04-2009
Messages: 7

Re: [RESOLU] Insertion de données HABTM

Salut avairet et merci de t'intéresser à mon pb smile

En fait si je ne "sette" pas mes plans, c'est que j'essaie de les créer "à la volée". C'est à dire que ce formulaire créer un transfert mais crée aussi les plans qui sont liés à ce transfert...et idéalement il met à jour automatiquement ma table de liaison.

Hors ligne

 

#4 23-04-2009 17:00:19

avairet
Chef Pâtissier
Date d'inscription: 25-06-2008
Messages: 1320

Re: [RESOLU] Insertion de données HABTM

Ouh là ! Cela m'a l'air bigrement compliqué ton histoire... roll

Comment veux-tu créer des plans à la volée depuis les transferts ? Tu peux décrire un peu mieux...
Est-ce que c'est :
- j'ai un morceau de formulaire qui crée le Transfert
- un autre morceau de formulaire qui crée le Plan
- quand je valide le tout, un nouvel enregistrement est créé dans Plan, un second dans Transfert et j'ai en plus un enregistrement dans la table plans_transferts correspondant aux 2 ids générés ?

Hors ligne

 

#5 23-04-2009 17:21:47

Ziaaa
Crêpe Suzette
Date d'inscription: 22-04-2009
Messages: 7

Re: [RESOLU] Insertion de données HABTM

avairet a écrit:

Ouh là ! Cela m'a l'air bigrement compliqué ton histoire... roll

Effectivement c'est pas très conventionnel, mais c'est la solution la plus pratique côté utilisateur.

avairet a écrit:

- j'ai un morceau de formulaire qui crée le Transfert
- un autre morceau de formulaire qui crée le Plan
- quand je valide le tout, un nouvel enregistrement est créé dans Plan, un second dans Transfert et j'ai en plus un enregistrement dans la table plans_transferts correspondant aux 2 ids générés ?

C'est exactement ça. Avec le même formulaire, je souhaiterais créer un enregistrement dans la table transferts, créer des enregistrements dans la table plans et ensuite avec les ID générés créer les enregistrement correspondant dans la table de liaison.

Hors ligne

 

#6 23-04-2009 21:55:51

avairet
Chef Pâtissier
Date d'inscription: 25-06-2008
Messages: 1320

Re: [RESOLU] Insertion de données HABTM

mais c'est la solution la plus pratique côté utilisateur

A voir... gérer deux types d'objets en même temps, c'est parfois plus difficile que de créer "en série" des Plans, puis de lister tous ces plans dans le formulaire de création du Transfert où l'on a plus qu'à les cocher par exemple.

En tout cas, pas de magie Cake pour faire çà, il va te falloir décomposer la sauvegarde ! Tu pourrais envisager des validations Ajax indépendantes pour chaque sous-formulaire.

Et le nombre de plans est toujours le même pour chaque transfert ? Comment gères-tu l'affichage des champs pour chaque plan ? Il y a un truc qui me chiffonne tout de même avec ton système : aucun plan ne peut appartenir à plusieurs transferts, dès lors une HABTM est-elle bien nécessaire ? Ou tu prévois de faire çà a posteriori, dans un autre formulaire ? Dans ce cas, on perd à mon avis en souplesse...

Hors ligne

 

#7 24-04-2009 07:45:37

real34
Cooker
Lieu: Toulouse
Date d'inscription: 28-06-2008
Messages: 1810
Site web

Re: [RESOLU] Insertion de données HABTM

Si les modèles sont liés par des relations (hasMany ou HABTM) Cake permet de sauvegarder directement (en créant) tous les modèles liés non ?
Qu'est-ce qui poserait problème ?


Expert CakePHP - Co-gérant du studio web Occitech

Hors ligne

 

#8 24-04-2009 10:42:42

avairet
Chef Pâtissier
Date d'inscription: 25-06-2008
Messages: 1320

Re: [RESOLU] Insertion de données HABTM

Non real34, save ne permet pas de sauvegarder directement tous les modèles liés.
http://book.cakephp.org/fr/view/75/Saving-Your-Data et suivants. C'est toi qui avait traduit je crois... wink

Pour sauvegarder un modèle et les modèles liés par hasMany, hasOne et belongsTo, soit on save le modèle et on récupère l'id généré pour sauver l'autre modèle, soit on utilise saveAll() mais à condition de formater le formulaire correctement.

Par contre, pour sauvegarder un modèle et son HABTM, le formulaire doit contenir les id de l'autre modèle. Or dans l'exemple de Ziaa ceux-ci n'existent pas encore puisqu'il les crée à la volée dans le même formulaire !

Il ne peut donc que décomposer au moins en deux :
1) saveAll pour enregistrer le Transfert et tous les Plans créés en même temps que lui
2) save sur Transfert pour enregistrer l'HABTM, après avoir récupéré les id des Plans créés par le saveAll et en ajoutant l'id du Transfert créé

Voilà pourquoi je pense que ce serait plus souple d'avoir la création des Plans d'un côté, puis un select multiple (ou des checkbox) avec tous ces Plans dans le formulaire d'ajout d'un Transfert.

Si tu Bake le modèle de Ziaaa, c'est exactement comme cela que ce sera fait, avec bien sûr un lien dans les deux formulaires qui permet de passer de l'un à l'autre rapidement.

Hors ligne

 

#9 24-04-2009 11:31:19

real34
Cooker
Lieu: Toulouse
Date d'inscription: 28-06-2008
Messages: 1810
Site web

Re: [RESOLU] Insertion de données HABTM

Je vais réviser mes HABTM durant le week-end alors ... je n'ai dû utiliser que des hasMany dans mes projets je pense, car j'étais persuadé qu'un saveAll effectuait les opérations suivantes : créer (ou modifier) l'instance du modèle principal, les instances associées et renseignait la table de relation.

Promis, ce week-end je bosse tout ça et j'essaierai de mettre le code résultant en ligne wink


Expert CakePHP - Co-gérant du studio web Occitech

Hors ligne

 

#10 24-04-2009 14:32:32

Ziaaa
Crêpe Suzette
Date d'inscription: 22-04-2009
Messages: 7

Re: [RESOLU] Insertion de données HABTM

avairet a écrit:

Et le nombre de plans est toujours le même pour chaque transfert ? Comment gères-tu l'affichage des champs pour chaque plan ?

Non le nombre de plan peut varier. Pour l'affichage se sont de simple input dans lequel l'utilisateur saisit sa référence, et un select pour le type de plan.

Il ne peut donc que décomposer au moins en deux :
1) saveAll pour enregistrer le Transfert et tous les Plans créés en même temps que lui
2) save sur Transfert pour enregistrer l'HABTM, après avoir récupéré les id des Plans créés par le saveAll et en ajoutant l'id du Transfert créé

Ok c'est donc comme ça qu'il faut procéder ! Sous quel format doit se présenter le tableau pour le 2) ? je n'ai rien vu qui traite de cela dans la doc. Ça fait bizarre de devoir faire un save et un saveAll sur Transfert.

Voilà pourquoi je pense que ce serait plus souple d'avoir la création des Plans d'un côté, puis un select multiple (ou des checkbox) avec tous ces Plans dans le formulaire d'ajout d'un Transfert.

Si tu Bake le modèle de Ziaaa, c'est exactement comme cela que ce sera fait, avec bien sûr un lien dans les deux formulaires qui permet de passer de l'un à l'autre rapidement.

Effectivement la solution avec les deux formulaires et possibilité de passer de l'un à l'autre serait idéale (faut vraiment que je jette  un œil sur bake). Mais dans mon cas nous voulons simplifier au maximum la saisie des utilisateurs et éviter qu'ils aient à créer les plans pour ensuite avoir à sélectionner ces plans ds le formulaire de transfert. D'autant plus que le nombre de plan va très vite devenir énorme (qqs centaines, voir milliers) du coup la sélection de plan serait pénible si on devait les cocher ou les sélectionner.



Il y a un truc qui me chiffonne tout de même avec ton système : aucun plan ne peut appartenir à plusieurs transferts, dès lors une HABTM est-elle bien nécessaire ? Ou tu prévois de faire çà a posteriori, dans un autre formulaire ? Dans ce cas, on perd à mon avis en souplesse...

C'est la réflexion que je me faisais effectivement. Vu que les plans sont créés à la volée à chaque fois, un plan est finalement lié à un unique transfert, et donc dans ce cas là pas de HABTM mais un hasmany. Je pense que je vais finalement partir sur cette solution vu la façon dont j'enregistre/traite les données. Mais je veux bien que tu répondes quand même à ma question au dessus stp.

Encore merci à vous d'avoir pris du temps pour m'aider smile

Hors ligne

 

#11 27-04-2009 09:49:18

avairet
Chef Pâtissier
Date d'inscription: 25-06-2008
Messages: 1320

Re: [RESOLU] Insertion de données HABTM

Non le nombre de plan peut varier. Pour l'affichage se sont de simple input dans lequel l'utilisateur saisit sa référence, et un select pour le type de plan.

Et donc tu en affiches X à l'avance ou bien l'utilisateur peut en générer des nouveaux en JS ?

Sous quel format doit se présenter le tableau pour le 2)

data['Plan']['Plan'][]

D'autant plus que le nombre de plan va très vite devenir énorme (qqs centaines, voir milliers) du coup la sélection de plan serait pénible si on devait les cocher ou les sélectionner.

Un petit auto-complete en Ajax dans ce cas !

Hors ligne

 

#12 27-04-2009 10:20:14

Ziaaa
Crêpe Suzette
Date d'inscription: 22-04-2009
Messages: 7

Re: [RESOLU] Insertion de données HABTM

Oui l'autocomplétion est une solution pratique, mais il faut quand même avoir créé les plans à l'avance.
Je suis finalement parti sur la solution hasmany (en créant les plans directement) plutôt que HABTM.
Pour le nombre de plan, effectivement je vais essayer de faire un formulaire dynamique en JS, je suis en train de me documenter.

Hors ligne

 

#13 27-04-2009 10:33:47

avairet
Chef Pâtissier
Date d'inscription: 25-06-2008
Messages: 1320

Re: [RESOLU] Insertion de données HABTM

Ok, happy baking ! wink

Hors ligne

 

#14 16-03-2016 10:19:26

koukou
Crêpe Suzette
Date d'inscription: 15-11-2015
Messages: 8

Re: [RESOLU] Insertion de données HABTM

bonjour , j'ai le mm probleme que Ziaa , donc moi j'ai une table bon et une autre produit et une table jointure produit-bon dans ma vue ajouter bon je veux afficher un produit au début puis l'utilisateur ajoute le nombre de produit kil veulent (les produit sont déja créé ) voici mon controller

Code: php

  1.    
  2. public function add() {
  3.      
  4.         if ($this->request->is('post')) {
  5.            
  6.             $this->Bill->create();
  7.             if ($this->Bill->save($this->request->data)) {
  8.                 $flashContent = $this->getSuccessFlashContent(__('The bill has been saved.'));
  9.                 $this->Session->setFlash($flashContent);
  10.                 return $this->redirect(array('action' => 'index'));
  11.             } else {
  12.                 $flashContent = $this->getFailedFlashContent(__('The bill could not be saved. Please, try again.'));
  13.                 $this->Session->setFlash($flashContent);
  14.             }
  15.         }
  16.         $products = $this->Bill->Product->find('list');
  17.        
  18.         $this->set(compact('products'));
  19.     }

et voici ma vue

Code: php

  1. <?php echo $this->Form->create('Bill'); ?>
  2.         <div class="box-body">
  3.             <?php
  4.  
  5.                 echo "<div class='form-group'>" . $this->Form->input('amount', array(
  6.                     'label' => __('Amount'),
  7.  
  8.                     'class' => 'form-control'
  9.                 )) . "</div>";
  10.            
  11.  
  12.            
  13.             ?>
  14. <div>
  15. <?php
  16.                 echo "<div >" . $this->Form->input('products', array(
  17.                     'label' => __('Product Name'),
  18.                     'class' => 'form-control',
  19.                     'empty' => '',
  20.                     'id' =>'products'
  21.                 )) . "</div>";
  22.                 echo "<div >" . $this->Form->input('Product.quantity', array(
  23.                     'label' => __('Quantity'),
  24.                     'class' => 'form-control',
  25.                     'empty' => ''
  26.                 )) . "</div>";
  27.                  echo "<div >" . $this->Form->input('Product.last_price', array(
  28.                     'label' => __('Price'),
  29.                     'class' => 'form-control',
  30.                     'empty' => ''
  31.                 )) . "</div>";
  32. ?>
  33. </div>
  34.         </div>

voici mes modeles

Code: php

  1. class Bill extends AppModel {
  2.  public $hasAndBelongsToMany = array(
  3.         'Product' => array(
  4.             'className' => 'Product',
  5.             'joinTable' => 'bill_product',
  6.             'foreignKey' => 'bill_id',
  7.             'associationForeignKey' => 'product_id',
  8.             'with' => 'ProductsBill',
  9.         )
  10.         );
  11. }
  12.  
  13. class Product extends AppModel {
  14.    public $hasAndBelongsToMany = array(
  15.         'Bill' => array(
  16.             'className' => 'Bill',
  17.             'joinTable' => 'bill_product',
  18.             'foreignKey' => 'product_id',
  19.             'associationForeignKey' => 'bill_id',
  20.             'with' => 'ProductsBill',
  21.         )
  22.         );
  23. }

comment faire pour afficher et sauvegarder plusieurs produit dans add bill
merci d'avance

Hors ligne

 

Pied de page des forums

Propulsé par FluxBB
Traduction par FluxBB.fr