Bonjour,

Je viens ici cherche de l'aide car je ne parviens pas à trouver la solution par moi même. Je cherche à faire une multiple imbrication de formulaire. Je m'explique, je code pour un projet, un système de création d'exercices.

Un exercice doit avoir plusieurs questions (QCM). Un QCM a aussi plusieurs réponses.

J'ai réussi à imbriquer mon formulaire de question dans celui de l'exercice.

Un peu de code saura surement mieux faire comprendre les choses

J'ai une entité Exercice :
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
class Exercice
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
 
    /**
     * @var string
     *
     * @ORM\Column(name="titre", type="string", length=255)
     */
    private $titre;
 
    /**
     * @ORM\OneToMany(targetEntity="Question", mappedBy="exercice")
     */
    protected $questions;
 
    public function __construct()
    {
        $this->questions = new ArrayCollection();
    }
}
Comme on peut le voir, j'ai une collection de questions. Mon entité Question est comme ceci :

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
class Question
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
 
    /**
     * @var string
     *
     * @ORM\Column(name="libelle", type="text")
     */
    protected $libelle;
 
    /**
     * @var integer
     *
     * @ORM\Column(name="numQuestion", type="integer")
     */
    protected $numQuestion;
 
    /**
     * @ORM\OneToMany(targetEntity="ItemQCM", mappedBy="question")
     */
    protected $itemsQCM;
 
    /**
     * @ORM\ManyToOne(targetEntity="Exercice", inversedBy="questions")
     * @ORM\JoinColumn(nullable=false)
     */
    protected $exercice;
 
    public function __construct()
    {
        $this->itemsQCM = new ArrayCollection();
    }
 
}
et mon entité ItemQCM :

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
class ItemQCM
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
 
    /**
     * @var string
     *
     * @ORM\Column(name="libelle", type="text")
     */
    private $libelle;
 
    /**
     * @var boolean
     *
     * @ORM\Column(name="isJuste", type="boolean")
     */
    private $isJuste;
 
    /**
     * @ORM\ManyToOne(targetEntity="Question", inversedBy="itemsQCM")
     * @ORM\JoinColumn(nullable=false)
     */
    private $question;
}
Je n'ai pas copié tous les getter/setter afin de ne pas trop surcharger..

J'ai ensuite trois classes de formulaires :

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
class ExerciceType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
 
        $builder
            ->add('titre')
            ->add('questions', 'collection',
                            array(  'type' => new QuestionType(),
                                    'allow_add' => true,
                                    'by_reference' => false,))
              ;
    }
 
    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Bili\ExerciceBundle\Entity\Exercice',
 
        ));
    }
 
    /**
     * @return string
     */
    public function getName()
    {
        return 'exercice';
    }
}
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
class QuestionType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('libelle', 'textarea', array('label' => "Libelle",
                                'attr' => array('rows' => '10','cols' => '100')))
            ->add('itemsQCM', 'collection', array('type' => new ItemQCMType(),
                                                'allow_add' => true,
                                                'by_reference' => false,
                                                ))
        ;
    }
 
    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Bili\ExerciceBundle\Entity\Question',
 
        ));
    }
 
    /**
     * @return string
     */
    public function getName()
    {
        return 'question';
    }
}
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
class ItemQCMType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('libelle')
            ->add('isJuste')
 
        ;
    }
 
    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Bili\ExerciceBundle\Entity\ItemQCM'
        ));
    }
 
    /**
     * @return string
     */
    public function getName()
    {
        return 'itemqcm';
    }
}
Pour finir, mon fichier twig new.html.twig est de cette forme :

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
<form action="{{ path('exercice_create') }}" method="post" {{ form_enctype(form) }}>
                <table id="exercice_form">
 
                  <tbody>
                    <tr>
                      <th>{{ form_label(form.titre) }}</th>
                      <td>
                        {{ form_errors(form.titre) }}
                        {{ form_widget(form.titre) }}
                      </td>
                    </tr>
 
                  </tbody>
                </table>
 
                <ul class="questions" data-prototype="{{ form_widget(form.questions.vars.prototype)|e }}">
 
                    <ul class="itemsQCM" data-prototype="{{ form_widget(form.questions.vars.itemsQCM.prototype)|e }}">
 
                    </ul>        
                </ul>
 
                {{ form_rest(form) }}
 
              </form>
mon erreur est de la forme :

Key "itemsQCM" for array with keys "value, attr, form, id, name, full_name, disabled, label, multipart, block_prefixes, unique_block_prefix, translation_domain, cache_key, read_only, errors, valid, data, required, max_length, pattern, size, label_attr, compound, method, action, submitted, sonata_admin_enabled, sonata_admin, allow_add, allow_delete, prototype" does not exist in SidesEntrainementBundle:Entrainement:new.html.twig at line 102
Donc ma question est : comment faire pour imbriquer un formulaire dans un formulaire lui même imbriqué dans un autre ?

Et ma deuxième question, comment fait-on pour modifier l'aspect d'un formulaire imbriqué ?

Je me suis inspiré de ce site : http://symfony.com/fr/doc/current/co...llections.html
Très bien fait mais il n'explique pas comment imbriquer plusieurs collections

Merci d'avance pour votre aide

Antoine