Symfony form - Access Entity inside child entry Type in a CollectionType

26,835

Solution 1

The answer lies in using Event Listeners which listen for the PRE_SET_DATA event.

It will pass your closure a FormEvent class which contains both the form and the data being bound to it.

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->addEventListener(FormEvents::PRE_SET_DATA,
        function (FormEvent $event) use ($builder)
        {
            $form = $event->getForm();
            $child = $event->getData();

            if ($child instanceof Child) {

                // Do what ever you like with $child entity data

            }
        }
    );
}

Solution 2

This is a more detailed solution based on user1207727.

Parent Type

class FrontentStatsInputFormType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('records', CollectionType::class, array(
                'entry_type' => FrontendStatsRecordType::class,
                'allow_add' => false,
                'allow_delete' => false,
                'label' => null,
            ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => null
        ));
    }
}

Child Type

class FrontendStatsRecordType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addEventListener(FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($builder)
            {
                $form = $event->getForm();
                $child = $event->getData();

                if ($child instanceof StatsRecord) {

                    // Do what ever you like with $child entity data
                    // $child->getSomeValue();

                    $form->add('value', TextType::class);
                }
            }
        );

    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\StatsRecord',
        ));
    }

}

Create form in controller

public function indexAction(Request $request, InputForm $inputForm) {

    $data = array();

    foreach ($inputForm->getStatsTemplates() as $template) {
        $statsRecord = new StatsRecord();
        $data['records'][] = $statsRecord;
    }


    $form = $this->createForm('AppBundle\Form\FrontentStatsInputFormType', $data);
    $form->handleRequest($request);


    if ($form->isSubmitted() && $form->isValid()) {

        $em = $this->getDoctrine()->getManager();

        // Get entries and persist them in the database
        $records = $form->get('records')->getData();
        foreach ($records as $record) {
            $em->persist($record);
        }

        $em->flush();

        return $this->redirectToRoute('frontend_index');
    }

    return $this->render('frontend/showInputForm.html.twig', array(
        'inputForm' => $inputForm,
        'form' => $form->createView(),
    ));
}
Share:
26,835

Related videos on Youtube

Nick
Author by

Nick

Updated on July 22, 2020

Comments

  • Nick
    Nick almost 4 years

    I'm trying to access the entity for a given embedded form in the parent CollectionType inside FormBuilder:

    ParentType

    Class ParentType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('children', CollectionType::class, array(
                'entry_type' => ChildType::class
            );
        }
    }
    

    ChildType

    class ChildType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $child = $builder->getData(); // this returns null
        }
    
        public function getDefaultOptions(array $options)
        {
            return array(
                'data_class' => 'Vendor\Bundle\Entity\Child',
            );
        }
    }
    

    While this works in a normal form, $child is being returned as null. How can I access the Child entity inside ChildType?

  • user1207727
    user1207727 about 12 years
    To ask the obvious question, do you definitely have any Bars in your parent entity that's used for the form's data? Can you check by var_dumping your bars collection from the data in your parent form type?
  • Nick
    Nick about 12 years
    Wonderful, thanks! This worked perfectly, and also led me to the part in the docs I overlooked: How to Dynamically Generate Forms Using Form Events
  • Nick
    Nick about 12 years
    Ah, you caught my comment before I deleted it -- I lazily excluded the part of your answer with the formfactory, trying to continue with just the builder itself. I then decided to use your solution verbatim, and it worked. Sorry to confuse!
  • user1207727
    user1207727 about 12 years
    Fantastic! I'm glad it worked for you. Some of this stuff can seem quite mysterious in comparison to symfony 1, but slowly I'm starting to see the light at the end of the tunnel :)
  • nni6
    nni6 over 11 years
    Great example. Thanks. But when I add fields in the function as it was previously discussed, the fields are not included in the prototype of collection. I need these fields in the prototype.. Is it real? How should I fix this?
  • Waiting for Dev...
    Waiting for Dev... over 11 years
    Does anybody have a simple explanation about why couldn't I do simply $builder->add() inside the anonymous function?
  • AntonioCS
    AntonioCS about 9 years
    This will not work in Symfony2.6. There is no DataEvent (you can still google and find a page with details of the class but the class is not included in Symfony2)
  • Pavel Dubinin
    Pavel Dubinin over 8 years
    On symfony 2.6. event class is Symfony\Component\Form\FormEvent