Symfony2自定义表单类型密钥对

时间:2014-05-17 13:00:05

标签: php symfony symfony-forms symfony-2.3 fosrestbundle

我目前正在尝试为表单类型实现一个密钥对值,该值与FOSRestBundle一起使用,以允许发送如下请求:

{
    "user": {
        "username": "some_user",
        "custom_fields": {
            "telephone": "07777",
            "other_custom_field": "other custom value"
        }
    }
}

此后端表示如下:

  

用户

     

id,username,customFields

     

CustomUserField

     

id,field

     

CustomUserFieldValue

     

user_id,field_id,value

我目前制作了如下自定义表格:

<?php

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('username')
            ->add(
                'custom_fields',
                'user_custom_fields_type'
            )
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(
            array(
                'data_class'      => 'Acme\DemoBundle\Entity\User',
                'csrf_protection' => false,
            )
        );
    }

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

我的user_custom_fields_type

<?php

class CustomUserFieldType extends AbstractType
{
    private $em;

    /**
     * @param EntityManager $em
     */
    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $fields = $this->em->getRepository('AcmeDemoBundle:CustomUserField')->findAll();

        foreach($fields as $field) {
            $builder->add($field->getField(), 'textarea');
        }
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(
            array(
                'invalid_message' => 'The selected custom field does not exist'
            )
        );
    }

    public function getParent()
    {
        return 'collection';
    }

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

这一直给我一个额外字段的错误。我在CustomUserFieldType中添加了哪些内容。我怎样才能使这个工作?

注意:这是实际代码的简化版本,我尝试删除所有不相关的代码。

2 个答案:

答案 0 :(得分:0)

您需要使用表单侦听器向表单添加动态字段:
http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

在你的情况下,PRE_SET_DATA就足够了。像这样:

$em = $this->em;

$builder->addEventListener(FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ( $em )
{
    // get the form
    $form = $event->getForm();

    // fetch your data here
    $fields = $em->getRepository('AcmeDemoBundle:CustomUserField')->findAll();

    foreach($fields as $field)
    {
        // make sure you add the new fields to $form and not $builder from this event
        $form->add($field->getField(), 'textarea');
    }
});

答案 1 :(得分:0)

我有完全相同的问题,最后通过手动解析自定义字段来解决它。如果有其他解决方案,请分享:)

在UserType表单中:

$builder->addEventListener(FormEvents::POST_SET_DATA,
        function (FormEvent $event) use ( $oEm, $oUser )
        {
            $oForm = $event->getForm();
            $aFields = $oEm->getRepository('MyDBBundle:CustomUserField')->findAll();

            /** @var CustomUserField $oField */
            foreach($aFields as $oField)
            {
                $oForm->add(
                    'custom__'.$oField->getKey(),
                    $oField->getType(),
                    array(
                        'label'     => $oField->getField(),
                        'mapped'    => false,
                        'required'  => false
                    )
                );
                /** @var CustomUserFieldValue $oFieldValue */
                $oFieldValue = $oEm->getRepository('MyDBBundle:CustomUserFieldValue')->findOneBy(array('user' => $oUser, 'field' => $oField));
                if(null !== $oFieldValue) {
                    $oForm->get('custom__' . $oField->getKey())->setData($oFieldValue->getValue());
                }
            }
        }
    );

然后,在处理提交表单请求的控制器操作中:

// Handle custom user fields
foreach($oForm->all() as $sKey => $oFormData)
{
    if(strstr($sKey, 'custom__'))
    {
        $sFieldKey = str_replace('custom__', '', $sKey);
        $oField = $oEm->getRepository('MyDBBundle:CustomUserField')->findOneBy(array('key' => $sFieldKey));
        /** @var CustomUserFieldValue $oFieldValue */
        $oFieldValue = $oEm->getRepository('MyDBBundle:CustomUserFieldValue')->findOneBy(array('user' => $oEntity, 'field' => $oField));
        if($oFieldValue === null)
        {
            $oFieldValue = new CustomUserFieldValue();
            $oFieldValue->setUser($oEntity);
            $oFieldValue->setField($oField);
        }
        $oFieldValue->setValue($oFormData->getData());
        $oEm->persist($oFieldValue);
    }
}

(假设CustomUserField实体中既有“field”属性又有“key”; key 是您字段的唯一无空间标识符,字段是人类友好和可读的字段标签。)

这是有效的,希望它能有所帮助。但是,想知道是否有人有更好的解决方案。 :)