首页 文章

无法将现有实体映射到symfony2中的嵌入表单

提问于
浏览
6

我有一个实体,它与三个一对一映射相反 . 实体 FittingStepFittingStepSingleValue 等映射. FittingStep 有一个字段 fittingStepType ,用于标识 FittingStep 应查找的三个实体中的哪一个 . 我想在 FittingStep 编辑表单中嵌入该对象 .

我已经为每个子表单定义了表单作为服务:

services:
    ihear.form.fitting_step_single_value:
        class: Ihear\FittingBundle\Form\FittingStepSingleValueType
        arguments: [@security.context]
        tags:
            -   
                name: form.type
                alias: ihear_fittingbundle_fittingstepsinglevaluetype
    ihear.form.fitting_step_double_value:
        class: Ihear\FittingBundle\Form\FittingStepDoubleValueType
        arguments: [@security.context]
        tags:
            -   
                name: form.type
                alias: ihear_fittingbundle_fittingstepdoublevaluetype
    ihear.form.fitting_step_option:
        class: Ihear\FittingBundle\Form\FittingStepOptionType
        arguments: [@security.context]
        tags:
            -   
                name: form.type
                alias: ihear_fittingbundle_fittingstepoptiontype

这些服务类看起来像这样(非常基本)

class FittingStepSingleValueType extends AbstractType
{
    private $securityContext;

    public function __construct(SecurityContext $securityContext)
    {   
        $this->securityContext = $securityContext;
    }   

    public function buildForm(FormBuilderInterface $builder, array $options)
    {   
        $builder
            ->add('max1')
            ->add('description1')
            ->add('fittingStep', 'hidden')
        ;   
    }   

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Ihear\FittingBundle\Entity\FittingStepSingleValue'
        ));
    }

    public function getName()
    {
        return 'ihear_fittingbundle_fittingstepsinglevaluetype';
    }
}

我的表单在PRE_SET_DATA上使用EventListener来添加适当的嵌入表单字段:

class FittingStepType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {   
        $builder
            ->add('name')
            ->add('abbreviation')
            ->add('description')
            ->add('fittingStepType',
                'choice',
                ['choices' => ['SingleValue' => 'SingleValue',
                               'DoubleValue' => 'DoubleValue',
                               'Option' => 'Option'],
                 'empty_value' => 'select one please'])
        ;   

        $formModifier = function(FormInterface $form, $fittingStepType) {
            switch ($fittingStepType) {
                case 'SingleValue':
                    $form->add('fittingStepSingleValue',
                        'ihear_fittingbundle_fittingstepsinglevaluetype');
                    if ($form->has('fittingStepDoubleValue'))
                        $form->remove('fittingStepDoubleValue');
                    if ($form->has('fittingStepOption'))
                        $form->remove('fittingStepOption');
                    break;
                case 'DoubleValue':
                    $form->add('fittingStepDoubleValue',
                        'ihear_fittingbundle_fittingstepdoublevaluetype');
                    if ($form->has('fittingStepSingleValue'))
                        $form->remove('fittingStepSingleValue');
                    if ($form->has('fittingStepOption'))
                        $form->remove('fittingStepOption');
                    break;
                case 'Option':
                    $form->add('fittingStepOption',
                        'ihear_fittingbundle_fittingstepoptiontype');
                    if ($form->has('fittingStepSingleValue'))
                        $form->remove('fittingStepSingleValue');
                    if ($form->has('fittingStepDoubleValue'))
                        $form->remove('fittingStepDoubleValue');
                    break;
            }
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function(FormEvent $event) use ($formModifier) {
                $form = $event->getForm();
                // this is the FittingStep
                $data = $event->getData();
                // this is the Entity that contains the value(s)
                // i.e. FittingStepSingleValue
                $fittingStepType = $data->getFittingStepType();
                switch ($fittingStepType) {
                    case 'SingleValue':
                        $formModifier($form, $fittingStepType);
                        break;
                    case 'DoubleValue':
                        $formModifier($form, $fittingStepType);
                        break;
                    case 'Option':
                        $formModifier($form, $fittingStepType);
                        break;
                }
            }
        );
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Ihear\FittingBundle\Entity\FittingStep'
        ));
    }

    public function getName()
    {
        return 'ihear_fittingbundle_fittingsteptype';
    }
}

我的控制器用于编辑操作:

/** 
 * Displays a form to edit an existing FittingStep entity.
 *
 * @Route("/{id}/edit", name="admin_fittingstep_edit")
 * @Method("GET")
 * @Template()
 */
public function editAction($id)
{   
    $em = $this->getDoctrine()->getManager();

    $entity = $em->getRepository('IhearFittingBundle:FittingStep')->find($id);

    if (!$entity) {
        throw $this->createNotFoundException(
            'Unable to find FittingStep entity.');
    }   

    $editForm = $this->createForm(new FittingStepType(), $entity);
    $deleteForm = $this->createDeleteForm($id);

    return array(
        'entity'      => $entity,
        'edit_form'   => $editForm->createView(),
        'delete_form' => $deleteForm->createView(),
    );  
}

当我尝试加载表单时,我得到一个例外:

表单的视图数据应该是标量,数组或\ ArrayAccess的实例,但是类Ihear \ FittingBundle \ Entity \ FittingStep的实例 . 您可以通过将“data_class”选项设置为“Ihear \ FittingBundle \ Entity \ FittingStep”或添加视图转换器来将此类错误设置为“Ihear \ FittingBundle \ Entity \ FittingStep”转换为标量,数组或\的实例ArrayAccess接口 .

我究竟做错了什么?似乎实体之间的对象映射与表单上的映射之间存在某种脱节 . 作为旁注,我在创建表单中成功使用了 $formModifier 闭包,因此在使用嵌入表单创建新实体时它可以正常工作 .

2 回答

  • 1

    您必须将fittinStep从hidden更新为Collection

    ->add('fittingStep', 'hidden')
    

    收集文档:http://symfony.com/doc/current/reference/forms/types/collection.html

    ->add('fittingStep', 'collection', array('type'=>new FittingStepType(), 'label'=>false))
    
  • 1

    我解决了这个问题 . 实体之间的关系由嵌入式实体引用,因此我已将父实体的隐藏字段添加到嵌入式表单中 . 这个小小的流氓并没有给创建表单带来任何麻烦,但是当我嵌入表单来编辑现有实体时会导致上面的错误 . 谢谢@albert指出我的那行代码!

    class FittingStepSingleValueType extends AbstractType
    {
        private $securityContext;
    
        public function __construct(SecurityContext $securityContext)
        {   
            $this->securityContext = $securityContext;
        }   
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {   
            $builder
                ->add('max1')
                ->add('description1')
                // this line was the culprit
                //->add('fittingStep', 'hidden')
            ;   
        }   
    
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'Ihear\FittingBundle\Entity\FittingStepSingleValue'
            ));
        }
    
        public function getName()
        {
            return 'ihear_fittingbundle_fittingstepsinglevaluetype';
        }
    }
    

相关问题