Symfony2 "This form should not contain extra fields"集合和动态字段错误



所以,进入故障排除的第 5 天,仍然无法解决。我什至创建了一个特殊的表单来解决此问题,但仍然无法取得任何进展。基本问题:我有一个通过FormBuilderInterface构建的Symfony2表单,使用表单修饰符根据用户对表单中第一个实体的选择动态填充字段。表单中还有 3 个集合(表示与表单主类的一对一关联)。

无论我做什么,在if ($form->isValid())上,我都会收到非常熟悉和有趣的"错误:此表单不应包含额外的字段",表单提交错误(3 次,每个集合 1 次)。

值得注意且可能与修复有关:如果我从表单中删除集合实体,它会正确验证。对于表单中的任何集合,或 3 个集合中的 2 个的任意组合(我已经尝试了所有集合),它会抛出"此表单不应包含额外的字段"错误。

以下是表单类型的代码:

class ThisDataClassType extends AbstractType
{
protected $user_id;
public function __construct($user_id) {
    $this->user_id = $user_id;
}
/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $user_id = $this->user_id;
    $builder->add('firstChoice', 'entity', array(
            'class' => 'MyBundle:FirstChoice',
            'query_builder' => function(firstChoiceRepository $repository) use ($user_id) {
                    return $repository->createQueryBuilder('f')
                        ->where('f.user = ?1')
                        ->andWhere('f.isActive = 1')
                        ->setParameter(1, $user_id);
                },
            'property' => 'firstChoice_name',
            'required' => true,
            'mapped' => false,
            'label' => 'block.firstChoice.name'
        ))
        ->add('sub_block_name','text', array(
            'label' => 'subblock.block.name',
            'max_length' => 50,
            'required' => true,
            'attr' => array(
                'placeholder' => 'subblock.phv.name',
                'pattern' => 'alpha_numeric'
            )
        ))
        // ... bunch of other standard form types (text, etc.) ... //
        ->add('subdata1', 'collection', array(
            'type' => new SubData1Type()
        ))
        ->add('subdata2', 'collection', array(
            'type' => new SubData2Type()
        ))
        ->add('subdata3', 'collection', array(
            'type' => new SubData3Type()
        ));
    $formModifier = function(FormInterface $form, $firstChoice_id) {
        $form->add('secondChoice', 'entity', array(
            'class'         => 'MyBundle:SecondChoice',
            'query_builder' => function(secondChoiceRepository $S_repository) use ($firstChoice_id) {
            return $S_repository->createQueryBuilder('s')
                ->where('s.firstChoice_id = ?1')
                ->andWhere('s.isActive = 1')
                ->setParameter(1, $firstChoice_id);
            },
            'property'    => 'secondChoice_name',
            'label'       => 'block.secondChoice.name'
        ));
    };
    $builder->addEventListener(
        FormEvents::PRE_SET_DATA,
        function(FormEvent $event) use ($formModifier) {
            $data = $event->getData()->getId();
            $formModifier($event->getForm(), $data);
        }
    );
    $builder->get('firstChoice')->addEventListener(
        FormEvents::POST_SUBMIT,
        function(FormEvent $event) use ($formModifier) {
            $data = $event->getForm()->getData();
            $formModifier($event->getForm()->getParent(), $data->getId());
        }
    );
    $builder->setMethod('POST');
}
/**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'MyBundleEntityThisDataClass',
        'user_id' => null,
        'translation_domain' => 'block',
        'cascade_validation' => true
    ));
}
/**
 * @return string
 */
public function getName()
{
    return 'ThisDataForm';
}
}

。和基本控制器(目前仅用于测试):

public function TestFormAction(Request $request, $whichSize)
{
    $user_id = $this->getUser()->getId();
    $success = 'Not submitted';
    $dataclass = new EntityThisDataClass();
    $subdata1 = new EntitySubData1();
    $subdata2 = new EntitySubData2();
    $subdata3 = new EntitySubData3();
    if (!$request->isMethod('POST')) {
        $dataclass->getSubData1()->add($subdata1);
        $dataclass->getSubData2()->add($subdata2);
        $dataclass->getSubData3()->add($subdata3);
    }
    $form = $this->createForm(new FormThisDataClassType($user_id), $dataclass, array(
        'action' => $this->generateUrl('my_custom_test_route', array('whichSize' => $whichSize)),
        'user_id' => $user_id
    ));
    $form->handleRequest($request);
    if ($form->isValid()) {
        $success = 'Success!!';
        return $this->render('MyBundle:DataClassTestForm.html.twig', array('dataClassTestForm' => $form->createView(), 'whichSize' => $whichSize, 'success' => $success));
    } else {
        $success = $form->getErrorsAsString();
    }
        return $this->render('MyBundle:DataClassTestForm.html.twig', array('dataClassTestForm' => $form->createView(), 'whichSize' => $whichSize, 'success' => $success));
}

提及其他几个要点:

  • 窗体正确显示(所有实体都显示正确的值并根据需要进行更新)
  • 所有预期的POST变量都在POST数据中(通过Firebug和Symfony的Profiler检查)
  • POST 数据中没有未映射到类(除了设置'mapped' => false的第一选择字段,以及CSRF _token,但无论我是否显式启用 CSRF _token,我都会收到错误或者不是,当我删除集合时,错误再次消失)

非常感谢任何人对我所缺少的见解。

在休息了一天半并离开后,当我坐下时,答案突然出现,而且很明显。编写的控制器仅在首次创建时(即未发生提交/POST 事件时)将子数据类添加到表单中。因此,在提交事件之后创建的表单具有所有发布数据,但类不与之关联。控制器现已重写如下,表单现在按预期进行验证:

public function TestFormAction(Request $request, $whichSize)
{
    $user_id = $this->getUser()->getId();
    $success = 'Not submitted';
    $dataclass = new EntityThisDataClass();
    $subdata1 = new EntitySubData1();
    $subdata2 = new EntitySubData2();
    $subdata3 = new EntitySubData3();
    $dataclass->getSubData1()->add($subdata1);
    $dataclass->getSubData2()->add($subdata2);
    $dataclass->getSubData3()->add($subdata3);
    $form = $this->createForm(new FormThisDataClassType($user_id), $dataclass, array(
        'action' => $this->generateUrl('my_custom_test_route', array('whichSize' => $whichSize)),
        'user_id' => $user_id
    ));
    $form->handleRequest($request);
    if ($form->isValid()) {
        $success = 'Success!!';
    } else {
        $success = 'Invalid!!';
    }
} // RESULT::Success!!

最新更新