phpformssymfonyformflowcraueformflow

Symfony : How to return dynamically a form type depending on a chosen option?


I'm using this bundle https://github.com/craue/CraueFormFlowBundle to handle a multi-step form. I have setted up and it works correctly but I'm struggling with the loadstepsconfig method of my Flow form class. In step 2, I have two forms (form2Type and Form3Type) and should display one depending on an option(2,3) chosen on form1Type.

Here is my Flow Form class :

class CreateAnnonceFlow extends FormFlow
{


    protected function loadStepsConfig()
    {

        return [
            [
                'form_type' => Form1Type::class,

            ],
            [
                'form_type' => CustomFormType::class,
                'skip' => function ($estimatedCurrentStepNumber, FormFlowInterface $flow) {

                    return $estimatedCurrentStepNumber > 2 && !$flow->getFormData();
                },

            ],
            [
                'form_type' => Form4Type::class,
                'skip' => function ($estimatedCurrentStepNumber, FormFlowInterface $flow) {
                    return $estimatedCurrentStepNumber > 3 && !$flow->getFormData();
                },
            ]
    }
}

here I have created a custom class type that looks :

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use App\Entity\Annonce;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormFactoryInterface;

class CustomFormType extends AbstractType
{
    private $formFactory;

    public function __construct(FormFactoryInterface $formFactory)
    {
        $this->formFactory = $formFactory;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Add an event listener to handle the form submission and determine the next form type
        $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
            $form = $event->getForm();
            // dd($form);
            $data = $form->getData();
            $option = $data->getOption();
            //dd($option);
            if ($option === '2') {
                $formType = Form2Type::class;
                //dd($formType);
            } elseif ($option === '3') {

                $formType = Form3Type::class;
                //dd($formType);
            }
        });
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Annonce::class, // Replace with your form data class
        ]);
    }
}

I have chosen option 1 and submitted form 1 but in step 2 I have errors that the fields of the form2 don't exist.


Solution

  • Finally, I have resolved it by modifying the CustomType :

    <?php
    
    namespace App\Form;
    
    use Symfony\Component\Form\AbstractType;
    use App\Entity\Annonce;
    use Symfony\Component\Form\Extension\Core\Type\HiddenType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\Form\FormEvent;
    use Symfony\Component\Form\FormEvents;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\Form\FormFactoryInterface;
    
    class CustomFormType extends AbstractType
    {
        private $formFactory;
    
        public function __construct(FormFactoryInterface $formFactory)
        {
            $this->formFactory = $formFactory;
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            // Add an event listener to handle the form submission and determine the next form type
            $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
                $form = $event->getForm();
                // dd($form);
                $data = $form->getData();
                $option = $data->getOption();
                //dd($option);
                if ($option === '2') {
                   $formType = $form->add('step2', FormType2::class, [
                        'mapped' => false, // This ensures this field is not mapped to your entity
                    ]);
                } elseif ($option === '3') {
    $formType = $form->add('step2', FormTyp3::class, [
                        'mapped' => false, // This ensures this field is not mapped to your entity
                    ]);
                }
            });
        }
    
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults([
                'data_class' => Annonce::class, // Replace with your form data class
            ]);
        }
        public function getBlockPrefix()
        {
            return 'customform_type';
        }
    }