感谢您的贡献。我找到了一种实现方法!
解决方案是在客户表单中添加一个字段,并将其映射,同时在客户实体中添加一个实体字段但不进行映射。
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function(FormEvent $event) use ($company) {
$form = $event->getForm();
$data = $event->getData();
$form->add('customer_list', 'entity',
[
'class' => 'SomeBunlde\Entity\Customer',
'label' => 'Client',
'property' => 'fullName',
'expanded' => false,
'multiple' => false,
'mapped' => false,
'query_builder' => function(EntityRepository $er) use ($company)
{
return $er->getByCompanyQueryBuilder($company);
},
]
)
;
if ($data->getCustomer() === null) {
$form->add('customer', new CustomerType());
}
}
在实体表单字段中添加额外选项后,通过重载finishView方法:
public function finishView(FormView $view, FormInterface $form, array $options)
{
array_unshift($view->children['customer_list']->vars['choices'], new SfFormExt\ChoiceView('test', 'new', 'Nouveau client'));
}
然后我添加了两个事件监听器,一个是 pre_submit 用于删除映射的嵌入式客户表单及其数据:
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function(FormEvent $event) use ($em) {
$data = $event->getData();
if ($data['customer_list'] !== 'new') {
unset($data['customer']);
$event->getForm()->remove('customer');
$event->setData($data);
}
}
);
并绑定一个事件将现有客户附加到预订中:
$builder->addEventListener(
FormEvents::BIND,
function(FormEvent $event) use ($em) {
$form = $event->getForm();
$data = $event->getData();
if (!$form->has('customer')) {
$existing_customer = $form->get('customer_list')->getData();
if ($existing_customer instanceof Customer) {
$data->setCustomer($existing_customer);
}
}
}
);
我知道这可能不是最先进的代码,但它运行得非常好。
编辑:我遇到了一个问题,因为当customer_list设置为new时,它会抛出一个错误。我没有找到避免此错误的方法(如果您有任何想法,请告诉我!),因此我决定修改pre_submit,如果我们处于新客户情况下,则将customer_list值的数据设置为'',然后在控制器中检测是否存在新客户表单的表单验证错误,以便正确显示它。