Bonjour,
J'ai deux formulaires imbriqués; comment procéder pour récupérer l'entité parente dans le formulaire imbriqué ?
Merci.
Bonjour,
J'ai deux formulaires imbriqués; comment procéder pour récupérer l'entité parente dans le formulaire imbriqué ?
Merci.
Si tu regarde la DTD, tu verra que les formulaires ne s'imbriquent pas en HTML.
Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 <!--================ Forms ===============================================--> <!ELEMENT form %form.content;> <!-- forms shouldn't be nested --> <!ATTLIST form %attrs; action %URI; #REQUIRED method (get|post) "get" enctype %ContentType; "application/x-www-form-urlencoded" onsubmit %Script; #IMPLIED onreset %Script; #IMPLIED accept %ContentTypes; #IMPLIED accept-charset %Charsets; #IMPLIED >
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter
N'oubliez pas de vous servir des bouttons , et
Bonjour,
Je parlais juste de formulaire avec Symfony 2 :
http://symfony.com/doc/current/book/...embedded-forms
Merci.
désolé, j'avais pas remarqué...
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter
N'oubliez pas de vous servir des bouttons , et
ça dépend de ce que l'on appelle un formulaire avec SymfonyJ'ai deux formulaires imbriqués; comment procéder pour récupérer l'entité parente dans le formulaire imbriqué ?
si c'est une instance de
- Symfony\Component\Form\FormBuilder ->on le manipule dans la méthode buildForm de notre classe EntityType, à ce moment il n'y a pas forcément d'entité, il est préférable de passer par un form Listener
- Symfony\Component\Form\Form ->que l'on manipule généralement dans le controller
- Symfony\Component\Form\FormView ->dans les templates
s'il s'agit d'un formView, on accède à l'entité dans twig de cette façon
donc on peut accéder à l'entité lié au formulaire parent comme ceci
Code : Sélectionner tout - Visualiser dans une fenêtre à part {{form.vars.value}}
Code : Sélectionner tout - Visualiser dans une fenêtre à part {{form.parent.vars.value}} ou {{form.vars.value.monParent}}
Merci, mais je me suis mal exprimé.
pour traiter les variables de mon formulaire, j'ai cette fonction :
Voici l'affichage du print_r() :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 public function onSuccess(Activity $activity) { echo '<pre>'.print_r($activity,true).'</pre>'; $this->em->persist($activity); $this->em->flush(); }
Et le message d'erreur:
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 Mapping\TestBundle\Entity\Activity Object ( [id:protected] => [name:protected] => test 1 [siteactivities:Mapping\TestBundle\Entity\Activity:private] => Doctrine\Common\Collections\ArrayCollection Object ( [_elements:Doctrine\Common\Collections\ArrayCollection:private] => Array ( [0] => Mapping\TestBundle\Entity\Siteactivity Object ( [activity:Mapping\TestBundle\Entity\Siteactivity:private] => [nbemployees:Mapping\TestBundle\Entity\Siteactivity:private] => 6 ) ) ) )
L'Id de la table Activity est généré automatiquement. Il faudrait que je fasse un persist et un flush puis que je recupère l'id pour faire un persist et un flush sur la table Siteactivity
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Entity of type Mapping\TestBundle\Entity\Siteactivity is missing an assigned ID. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.
Merci.
Lorsque l'on fait un flush cela sauvegarde en BDD toutes les entités qui ont été modifié dans une seule transaction (néammoins ce comportement a été un peu modifié sur Doctrine2.2).L'Id de la table Activity est généré automatiquement. Il faudrait que je fasse un persist et un flush puis que je recupère l'id pour faire un persist et un flush sur la table Siteactivity
pourquoi as tu besoin de l'id de Activity?
pourquoi Siteactivity n'as pas de clé auto généré?
Doctrine gére seul les relations entre les entités, pas besoin de préciser toi-même les clés étrangères en revanche il faut comprendre la notion de owning et inverse side pour que tout fonctionne bien (http://www.developpez.net/forums/d11...y/#post6408197).
Merci Arnooo,
En fait, Siteactivity contient une clé primaire sur deux colonnes: activity correspond à l'id de l'entité Activity et site correspond à l'id l'entité Site
J'ai essayé avec mappedBy, inversedBy, sans succes
voici ce que j'ai fais :
Si quelqu'un a solution plus simple, je suis ouvert à toutes suggestions.
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 public function createAction() { $activity = new Activity(); $request = $this->getRequest(); $data = $request->request->get('activity'); $form = $this->createForm(new ActivityType(), $activity); $form->bindRequest($request); if ($form->isValid()) { // echo '<pre>'.print_r($request,true).'</pre>'; // exit(); $em = $this->getDoctrine()->getEntityManager(); $em->getConnection()->beginTransaction(); try { $em->persist($activity); $em->flush(); foreach ($data['siteactivities'] as $value) { $siteactivity = new Siteactivity(); $siteactivity->setNbemployees($value['nbemployees']); $siteactivity->setSite($value['site']); $siteactivity->setActivity($activity->getId()); $em->persist($siteactivity); } $em->flush(); $em->getConnection()->commit(); return $this->redirect($this->generateUrl('activity_show', array('id' => $activity->getId()))); } catch (Exception $e) { $em->getConnection()->rollback(); $em->close(); throw $e; } } return $this->render('MappingTestBundle:Activity:new.html.twig', array( 'entity' => $activity, 'form' => $form->createView() )); }
Il ne reste plus qu'à faire la validation.
Merci.
Ton mapping est suspect:
activity correspond à l'id de l'entité Activity et site correspond à l'id l'entité Sitel'entité siteActivity a une relation avec l'entité Activity, son attribut $activity est un objet de classe Activity, la gestion des clés c'est Doctrine qui s'en occupe.
Code : Sélectionner tout - Visualiser dans une fenêtre à part $siteactivity->setActivity($activity->getId());
tu devrais plutôt avoir:
Revoit ton mapping, et à partir de là l'intégration avec les formulaires Symfony se fera bien plus facilement (et avec moins de code).
Code : Sélectionner tout - Visualiser dans une fenêtre à part $siteactivity->setActivity($activity);
Il te manque des bases sur ce qu'est un ORM, consultes la doc Doctrine et notamment la gestion des clés composés:
http://docs.doctrine-project.org/en/...rived-identity
ok, merci, je vais voir ca.
J'ai recommencé mais j'ai le message d'erreur suivant :
Activity
Code : Sélectionner tout - Visualiser dans une fenêtre à part Catchable Fatal Error: Argument 1 passed to Mapping\TestBundle\Entity\Siteactivity::__construct() must be an instance of Mapping\TestBundle\Entity\Activity, none given,
Siteactivity
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 <?php namespace Mapping\TestBundle\Entity; use Doctrine\ORM\Mapping as ORM, Doctrine\Common\Collections\ArrayCollection; /** * Mapping\TestBundle\Entity\Activity * * @ORM\Table(name="activity") * @ORM\Entity */ class Activity { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\generatedValue(strategy="AUTO") */ protected $id; /** * @var string $name * * @ORM\Column(name="name", type="string", length=100, nullable=true) * */ protected $name; /** * @ORM\OneToMany(targetEntity="Mapping\TestBundle\Entity\Siteactivity", mappedBy="Activity") */ private $siteactivities; public function __construct() { $this->siteactivities = new ArrayCollection(); } /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set name * * @param string $name */ public function setName($name) { $this->name = $name; } /** * Get name * * @return string */ public function getName() { return $this->name; } /** * Add siteactivities * * @param Mapping\TestBundle\Entity\Siteactivity $siteactivities */ public function addSiteactivity(\Mapping\TestBundle\Entity\Siteactivity $siteactivities) { $this->siteactivities[] = $siteactivities; } /** * Get siteactivities * * @return Doctrine\Common\Collections\Collection */ public function getSiteactivities() { return $this->siteactivities; } }
Site
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 <?php namespace Mapping\TestBundle\Entity; use Doctrine\ORM\Mapping as ORM, Doctrine\Common\Collections\ArrayCollection; /** * Mapping\TestBundle\Entity\Siteactivity * * @ORM\Table(name="siteactivity") * @ORM\Entity */ class Siteactivity { /** * @ORM\Id * @ORM\ManyToOne(targetEntity="Activity",inversedBy="siteactivities") */ private $activity; /** * @ORM\Id * @ORM\ManyToOne(targetEntity="Site" ) */ private $site; /** * @var integer $nbemployees * * @ORM\Column(name="nbemployees", type="integer", nullable=true) */ private $nbemployees; public function __construct(Activity $Activity, Site $site) { $this->activity = $activity; $this->site = $site; } /** * Set activity * * @param integer $activity */ public function setActivity($activity) { $this->activity = $activity; } /** * Get activity * * @return integer */ public function getActivity() { return $this->activity; } /** * Set site * * @param string $site */ public function setSite($site) { $this->site = $site; } /** * Get site * * @return string */ public function getSite() { return $this->site; } /** * Set nbemployees * * @param integer $nbemployees */ public function setNbemployees($nbemployees) { $this->nbemployees = $nbemployees; } /** * Get nbemployees * * @return integer */ public function getNbemployees() { return $this->nbemployees; } }
ActivityController
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 <?php namespace Mapping\TestBundle\Entity; use Doctrine\ORM\Mapping as ORM, Doctrine\Common\Collections\ArrayCollection; /** * Mapping\TestBundle\Entity\Site * * @ORM\Entity * @ORM\Table(name="site") */ class Site { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\generatedValue(strategy="AUTO") */ private $id; /** * @var string $name * * @ORM\Column(name="name", type="string", length=100, nullable=true) * */ private $name; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set name * * @param string $name */ public function setName($name) { $this->name = $name; } /** * Get name * * @return string */ public function getName() { return $this->name; } }
Je sèche là
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 public function createAction() { $activity = new Activity(); $request = $this->getRequest(); $data = $request->request->get('activity'); $form = $this->createForm(new ActivityType(), $activity); $form->bindRequest($request); if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); $em->getConnection()->beginTransaction(); try { $em->persist($activity); $em->flush(); foreach ($data['sites'] as $value) { $site = $em->getRepository('MappingTestBundle:Site')->find($activity->getId()); $siteactivity = new Siteactivity($activity,$site); $siteactivity->setNumberemployee($value['numberemployee']); $siteactivity->setSite($value['site']); $siteactivity->setActivity($activity); $em->persist($siteactivity); } $em->flush(); $em->getConnection()->commit(); return $this->redirect($this->generateUrl('activity_show', array('id' => $activity->getId()))); } catch (Exception $e) { $em->getConnection()->rollback(); $em->close(); throw $e; } } return $this->render('MappingTestBundle:Activity:new.html.twig', array( 'entity' => $activity, 'form' => $form->createView() )); }
le message est assez clair, enlève les contraintes dans ton constructeur
Ton code devrait ressembler à cela:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 public function __construct($Activity,$site){ $this->activity = $activity; $this->site = $site; }
controller
ActivityType
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 public function createAction() { $activity = new Activity(); $request = $this->getRequest(); $form = $this->createForm(new ActivityType(), $activity); $form->bindRequest($request); if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); foreach ($activity->getSiteActivity() as $site){//on inverse manuellement la relation pour que Doctrine persiste correctement les entités $site->setActivity($activity); } $em->persist($activity); $em->flush(); return $this->redirect($this->generateUrl('activity_show', array('id' => $activity->getId()))); } return $this->render('MappingTestBundle:Activity:new.html.twig', array( 'entity' => $activity, 'form' => $form->createView() )); }
SiteActivityType
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 public function buildForm($builder,$options){ $builder->add('name') ->add('siteActivity','collection',array('type'=>new SiteActivityType(),'allow_add'=>true)); }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 public function buildForm($builder,$options){ $builder->add('nbemployees') ->add('site'); }
Me voilà revenu au point de départ, je ne vois pas comment faire.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2Entity of type Mapping\TestBundle\Entity\Siteactivity has identity through a foreign entity Mapping\TestBundle\Entity\Activity, however this entity has no ientity itself. You have to call EntityManager#persist() on the related entity and make sure it an identifier was generated before trying to persist 'Mapping\TestBundle\Entity\Siteactivity'. In case of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call EntityManager#flush() between both persist operations.
Bon j'ai peut-être été un peu optimiste sur la capacité de Doctrine à gérer tout les cas du SQL.
Pourtant normalement si tu n'as pas configuré de cascade persist sur la relation Activity<->SiteActivity, il ne devrait s'occuper que de l'entité Activity.
On peut également détacher des entités pour qu'elles ne soit plus prise en compte par l'entityManager (et donc dans le flush)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 $em = $this->getDoctrine()->getEntityManager(); $sitesActivity=$activity->getSiteActivity()->toArray();//on conserve une références des objets sites activity $em->persist($activity); $em->flush();//requete insert de activity et génération de l'id foreach ($sitesActivity as $siteActivity){ $site->setActivity($siteActivity);//théoriquement $activity a désormais un id $em->persist($siteActivity); } $em->flush();//requetes insert dans siteActivity
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 $em = $this->getDoctrine()->getEntityManager(); $sitesActivity=$activity->getSiteActivity(); foreach ($sitesActivity as $siteActivity){ $em->detach($siteActivity);//on détache l'entité SiteActivity } $em->persist($activity); $em->flush(); foreach ($sitesActivity as $siteActivity){ $siteActivity->setActivity($activity); $em->persist($siteActivity); } $em->flush();
Merci Arnooo, mais, dans les deux cas :
Je pense que le plus simple serait que l'id de activity ne soit pas en auto-incrément. Je vais chercher comment récupérer le dernier id inséré dans la table
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Entity of type Mapping\TestBundle\Entity\Siteactivity is missing an assigned ID. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly
Merci.
EDIT :
oops
http://docs.doctrine-project.org/pro...composite-keys
Au final :
ActivityController
ActivityManager
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 public function createAction() { $activity = new Activity(); $request = $this->getRequest(); $form = $this->createForm(new ActivityType(), $activity); $form->bindRequest($request); if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); $id = $this->get('mapping.activity_manager')->generateId(); $activity->setId($id); foreach ($activity->getSiteActivities() as $site){//on inverse manuellement la relation pour que Doctrine persiste correctement les entités $site->setActivity($activity); } $em->persist($activity); $em->flush(); return $this->redirect($this->generateUrl('activity_show', array('id' => $activity->getId()))); } return $this->render('MappingTestBundle:Activity:new.html.twig', array( 'entity' => $activity, 'form' => $form->createView() )); }
ActivityRepository
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 public function generateId() { $entity = $this->getRepository()->findLastId(); $id = $entity->getId() + 1; return $id; }
Voilà, ça fonctionne !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 public function findLastId() { return $this->createQueryBuilder('a') ->add('orderBy', 'a.id DESC') ->setMaxResults(1) ->getQuery() ->getSingleResult(); }
Merci aux contributeurs !
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager