2012-03-15 57 views
19

我试图访问实体对于给定的嵌入形式,在父CollectionTypeFormBuilderSymfony的形式 - 访问实体内的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', 
     ); 
    } 
} 

虽然这项工作s以正常形式存在,$child将返回为空。如何访问ChildType内部的Child实体?

回答

38

答案在于使用事件监听器其中监听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

要问的明显曲estion,你的父实体中是否有用于表单数据的任何Bars?你可以通过var_dumping从你的父表单类型的数据来检查你的bars集合吗? – user1207727 2012-03-16 21:10:23

+0

太好了,谢谢!这个工作很完美,也让我看到了我忽略的文档中的部分:[如何使用表单事件动态生成表单](http://symfony.com/doc/current/cookbook/form/dynamic_form_generation.html) – Nick 2012-03-16 21:32:28

+0

啊,我在删除它之前就发现了我的评论 - 我懒惰地将你的答案的一部分排除在formfactory之外,试图继续仅仅是建造者本身。然后我决定逐字使用你的解决方案,并且它工作。很抱歉混淆! – Nick 2012-03-16 21:33:45

2

这是一个基于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(), 
    )); 
} 
相关问题