Symfony表单 - 在CollectionType中的子条目类型中访问实体

27

我试图在FormBuilder中访问父级CollectionType中给定嵌入表单的实体:

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',
        );
    }
}

尽管这在普通表单中有效,但$child被返回为null。如何在ChildType内访问Child实体?

2个回答

45
答案:

答案在使用监听PRE_SET_DATA事件的事件监听器中。

它将传递一个FormEvent类给您的闭包,其中包含绑定到表单上的数据和表单本身。

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

            }
        }
    );
}

1
问一个显而易见的问题,你的父实体中是否肯定有任何条形图用于表单数据?你能通过对父表单类型中的 bars 集合进行 var_dump 检查吗? - user1207727
1
太好了!我很高兴它对你有用。与Symfony 1相比,其中一些东西可能会显得很神秘,但是我正在慢慢地看到隧道尽头的光明 :) - user1207727
有没有人能简单解释一下为什么我不能在匿名函数内部简单地使用$builder->add() - Waiting for Dev...
3
这在Symfony2.6中不起作用。没有DataEvent类(你仍然可以搜索并找到一个详细介绍该类的页面,但是该类未包含在Symfony2中)。 - AntonioCS
2
在Symfony 2.6中,事件类是Symfony\Component\Form\FormEvent - Pavel Dubinin
显示剩余3条评论

4
这是基于 user1207727 的更详细的解决方案。
父类型
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
        ));
    }
}

子类型

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',
        ));
    }

}

在控制器中创建表单

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(),
    ));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接