我的自定义表单类型基于EntityType
我的实体有一个复合主键,因此我设置choice_value
以反映选项"value"
属性中的两个关键字段值,该属性按预期工作。
我订阅了formType PRE_SUBMIT
事件,以便我可以解析该值并将其转换回实体实例,感谢Doctrine\ORM\EntityManager::getReference
方法。
提交时我的问题就出现了。我期望事件setData($my_retrieved_entity)
方法(在事件监听器内)成功地用相应的实体替换表单提交的值(满足表单验证管道)但我得到的似乎是默认的symfony错误消息:
«此值无效。»
// …
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(['entityManager','country']);
$resolver->setAllowedTypes('country', Country::class);
$resolver->setAllowedTypes('entityManager', EntityManager::class);
$resolver->setDefaults([
'class' => NetworkTypeModel::class,
'placeholder' => 'Choose a network type',
'choice_value' => function ($networkType) {
// Set specific format for for the value attribute
// so that it reflects both primary key fiels values
return $networkType
? "{$networkType->getId()}¤{$networkType->getCountry()->getId()}"
: ''
;
}
,'query_builder' => function (Options $options) {
return function (EntityRepository $er) use ($options) {
$qb = $er->createQueryBuilder('nt')
->leftJoin('nt.country', 'c')
->addSelect('c');
return $qb->where($qb->expr()->eq('nt.country', ':country'))
->setParameter('country', $options['country']->getId())
->orderBy('nt.label', 'ASC');
};
},
]);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$entityManager = $options['entityManager'];
// Listen to post DATA in order to transform Option's value
// back to a networkType instance
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) use ($entityManager) {
if ($data = $event->getData()) {
// Special value has been sent through POST field
// It needs to be parsed and transformed back to a networkType entity
// According to the format set from inside choice_value options.
$ids = explode('¤', $data);
$networkType = $entityManager->getReference(
NetworkTypeModel::class,
['id' => $ids[0], 'country' => $ids[1]]
);
// I expect $event->setData to populate the form submitted value
// to be the selected value
$event->setData($networkType);
// But I get the following common error message on that field
// «This value is not valid.»
}
}
);
}
public function getParent()
{
return EntityType::class;
}
然而,在dump($networkType)
之前执行$event->setData($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 Form组件。
谢谢。
答案 0 :(得分:0)
据我所知,您需要的是在将表单数据发送回客户端之前修改表单重组的实体。您实际上需要使用 FormEvents :: SUBMIT 来执行此操作($ event-> setData($ data)和$ event-> getData()此处用于管理重新组合的实体),以及你正在做的是改变原始表单数据数组(你将通过$ Event-> getData()调用FormEvents :: PRE_SUBMIT,你可以通过调用它上面的var_dump()来检查代理实体,在提交表单上)尝试从代理重新创建您的实体(而提交的有效数据必须以arrray的形式提供)。另请注意,您使用实体管理器的其他实例而不是使用表单本身,因此您将从表单获取的实体将不会被管理。因此,更好的方法是在提交事件中通过$ event-> getData()修改实体返回,但我不认为你因为复合键而得到一个。 另请注意,您可以通过以这种方式调用提交事件来获取表单数据
$event->getForm()->get('id')->getData();
当我第一次面对这样的问题时,我并不清楚这对你有帮助。