Symfony EntityType choice_值,包含组合主键和事件集数据

Symfony EntityType choice_值,包含组合主键和事件集数据,symfony,symfony-forms,symfony3.x,Symfony,Symfony Forms,Symfony3.x,我的自定义表单类型基于EntityType 我的实体有一个复合主键,因此我设置了选项值,以反映选项的“值”属性中的两个键字段值,该属性按预期工作 我订阅了formTypePRE_SUBMIT事件,以便我可以解析该值并将其转换回实体实例,感谢toDoctrine\ORM\EntityManager::getReference方法 我的问题一经提出就出现了。我期望eventsetData($my_retrieved_entity)方法(在事件侦听器中)成功地将表单提交的值替换为相应的实体(满足表单验

我的自定义表单类型基于
EntityType

我的实体有一个复合主键,因此我设置了
选项值
,以反映选项
的“值”
属性中的两个键字段值,该属性按预期工作

我订阅了formType
PRE_SUBMIT
事件,以便我可以解析该值并将其转换回实体实例,感谢to
Doctrine\ORM\EntityManager::getReference
方法

我的问题一经提出就出现了。我期望event
setData($my_retrieved_entity)
方法(在事件侦听器中)成功地将表单提交的值替换为相应的实体(满足表单验证管道),但我得到的似乎是默认的symfony错误消息:

«此值无效。»

/…
公共函数配置选项(选项解析器$resolver)
{
$resolver->setRequired(['entityManager','country']);
$resolver->setAllowedTypes('country',country::class);
$resolver->setAllowedTypes('entityManager',entityManager::class);
$resolver->setDefaults([
'class'=>NetworkTypeModel::class,
'占位符'=>'选择网络类型',
'choice_value'=>函数($networkType){
//设置值属性的特定格式
//因此,它反映了两个主键的值
返回$networkType
“{$networkType->getId()}{$networkType->getCountry()->getId()}”
: ''
;
}
,'query_builder'=>函数(选项$Options){
返回函数(EntityRepository$er)使用($options){
$qb=$er->createQueryBuilder('nt')
->leftJoin('nt.country','c')
->addSelect('c');
返回$qb->where($qb->expr()->eq('nt.country',':country'))
->setParameter('country',$options['country']->getId())
->orderBy('nt.label','ASC');
};
},
]);
}
公共函数buildForm(FormBuilderInterface$builder、array$options)
{
$entityManager=$options['entityManager'];
//监听post数据以转换选项的值
//返回到networkType实例
$builder->addEventListener(
FormEvents::PRE_提交,
函数(FormEvent$event)使用($entityManager){
如果($data=$event->getData()){
//特殊值已通过POST字段发送
//它需要被解析并转换回networkType实体
//根据从内部设置的格式选择_值选项。
$ids=爆炸('m',$data);
$networkType=$entityManager->getReference(
NetworkTypeModel::类,
['id'=>$ids[0],'country'=>$ids[1]]
);
//我希望$event->setData填充表单提交值
//将其设置为选定的值
$event->setData($networkType);
//但我在该字段上收到以下常见错误消息
//«此值无效。»
}
}
);
}
公共函数getParent()
{
返回EntityType::class;
}
然而,在
$event->setData($networkType)之前执行
dump($networkType)
转储与提交的项关联的完全有效的实体实例,实际上是正确的实体实例

感觉我几乎把事情做好了,但我不知道这里出了什么问题。关于如何正确地将提交的数据转换为实体、将其注入表单并满足验证器链,您有什么想法吗

编辑 我完成了工作,但可能不是真正的symfony方式。这可能有助于你理解我的需要

我使用了一个共享变量:

  • PRE_SUBMIT
    事件侦听器内部填充预期的networkType实例,使用
    $event->getData()
    解析的字符串重新构造
  • 然后在
    POST_SUBMIT
    事件中使用此实例引用作为
    FormEvent::setData
    参数
更改/添加代码:

    $entityManager = $options['entityManager'];
    $selectedNetworkType = null;

    // Transform Option's value back to a networkType instance
    $builder->addEventListener(
        FormEvents::PRE_SUBMIT,
        function (FormEvent $event) use ($entityManager, &$selectedNetworkType) {
            // Transform the custom dropdown "value" attribute coming from POST
            // into a my networkType model instance
            if ($data = $event->getData()) {
                // PRE_SUBMIT event data holds the view data as a string
                // which needs to be parsed accordingly to what have been
                // done when encoding the entity's ids in choice_value callable
                $ids = explode('¤', $data);
                // We don't need to retrieve the entire record from DB anyway
                // so we use getReference
                $networkType = $entityManager->getReference(
                    NetworkTypeModel::class,
                    ['id' => $ids[0], 'country' => $ids[1]]
                );
                // Now store the newly created networkType instance
                // for later
                $selectedNetworkType = $networkType;
            }
        }
    )->addEventListener(
        FormEvents::POST_SUBMIT,
        function (FormEvent $event) use (&$selectedNetworkType) {
            // Use the fresh stored instance to feed the model data
            $selectedNetworkType && $event->setData($selectedNetworkType);
        }
    );
为了更好地理解Symfony表单组件,我希望有人能提出解决此用例的正确方向。

谢谢。

据我所知,您的任务是修改您的表单从表单数据重新组装的实体,然后再将其发送回客户端。实际上,您需要使用FormEvents::SUBMIT来实现这一点($event->setData($data)和$event->getData(),此处用于管理重新组装的实体),您所做的是更改原始表单数据数组(您将通过在FormEvents::PRE_SUBMIT中调用$event->getData()来获得该数组,您可以通过在其上调用var_dump()来检查这一点)在代理实体上,提交表单上的实体尝试从代理重新创建实体(同时提交的有效数据必须以arrray形式提供)。还要注意的是,您使用的是实体管理器的其他实例,而不是表单本身,所以您将从表单获得的实体将不会被管理。所以,更好的方法是在submit事件中通过$event->getData()修改实体返回,但我觉得您不会得到一个,因为复合键。 还要注意的是,您可以通过以这种方式调用submit事件来获取表单数据

$event->getForm()->get('id')->getData();

当我第一次面对这样的问题时,我并不清楚这一点,因此可能会对您有所帮助。

据我所知,您的任务是修改您的表单在返回之前正在从表单数据重新组装的实体