Dynamically add fields to CollectionType

555 views Asked by At

I have to create a school manager. When a teacher has to submit the results of an evaluation, he has to assess given skills by a scoring grade.

Evaluation ------OneToMany------ Scale ------ManyToOne------ Skill

EvaluationType

class EvaluationType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('scales', CollectionType::class, [
                'entry_type' => ScaleType::class
            ]);
    }
}

ScaleType

class ScaleType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('value');
    }
}

I want to dynamically add ScaleType children to EvaluationType::scales form child for a given collection of Skills.

Here is what I've tried so far in my controller action :

public function newEvaluation(Classroom $classroom, Subject $subject, Period $period)
{
    $evaluation = new Evaluation();
    $evaluation->setClassroom($classroom);
    $evaluation->setSubject($subject);
    $evaluation->setPeriod($period);

    $form = $this->createForm(EvaluationType::class, $evaluation);
    $skills =$this->getDoctrine()->getRepository('AppBundle:Skill')->findAll();
    foreach($skills as $skill) {
        $scale = new Scale();
        $scale->setEvaluation($evaluation);
        $scale->setSkill($skill);
        $form['scales']->add($this->createForm(ScaleType::class, $scale, [
            'auto_initialize' => false
        ]));
    }

    return $this->render('classrooms/newEvaluation.html.twig', [
        'form' => $form->createView(),
        'classroom' => $classroom,
        'subject' => $subject
    ]);
}

The problem is that I only get a single sub-form in the scales field on rendering, looks like when I add a children to $form['scales'] it overwrites the previous children.

I suppose I'm doing it totally wrong. How can I achieve that ?

I'm also pointing out the fact that I can't create the Evaluation first and then, on another page, create all the Scales. It needs to be done in the same controller/page.

Edit: I'll add the fact that I don't want the children of scales to be extensible, they have to be fixed by the server, and not being fetched by the client.

1

There are 1 answers

0
DarkChipolata On BEST ANSWER

Solved it, thanks to Artamiel, here is my new controller action :

public function newEvaluation(Classroom $classroom, Subject $subject, Period $period)
{
    $evaluation = new Evaluation();
    $evaluation->setClassroom($classroom);
    $evaluation->setSubject($subject);
    $evaluation->setPeriod($period);

    $skills = $this->getDoctrine()->getRepository('AppBundle:Skill')->findAll();
    foreach ($skills as $skill) {
        $scale = new Scale();
        $scale->setSkill($skill);
        $scale->setEvaluation($evaluation);
    }

    $form = $this->createForm(EvaluationType::class, $evaluation);

    return $this->render('classrooms/newEvaluation.html.twig', [
        'form' => $form->createView(),
        'classroom' => $classroom,
        'subject' => $subject
    ]);
}