我已经构建了一个表单,可以同时批量编辑同一类型的多个实体。表单可以正常工作,它可以保存对公开字段所做的更改。
我使用从数据库中提取的实体数组初始化表单数据。 $form->handleRequest($request)
使用相同的实体数组来标识哪个实体已更改,并使用其setter来更改其更改的属性。
不幸的是$form->handleRequest($request)
正在根据实体的数组索引识别表单数据和实体之间的对应关系。
这意味着如果数据在DB中发生更改,排序会发生变化,$form->handleRequest($request)
会尝试更新错误的实体对象,因为排序顺序不完全匹配。
我在表单中添加了id
作为隐藏字段,希望Symfony2可以使用它来初始化要更新的对象......
...但是Symfony2试图使用setId($newId)
而我没有为该属性定义一个setter。所以我添加了setter,如果$newId !== $this->id
- 它做了 - 如果你切换行,或者尝试只保存一行(通过ajax)或者你从中删除行,我就会抛出异常表格(通过JS)。
我试图在查询中使用INDEX BY来获取希望匹配器算法通过数组键匹配日期>实体的实体...也不起作用。
我显然是以错误的方式解决这个问题。我没有按照它的设计方式使用它。
Symfony2可能还有另一个批量更新内容的工作流程。也许只有在通过ID在实体上初始化表单时才应使用handleRequest。也许我不应该使用handleRequest
并构建我自己的自定义逻辑来更新更改的内容。
class AAAAController extends Controller
{
public function AAAAEditAction(Request $request, $filters)
{
$AAAAs = $AAAArepo->findBy($filters);
$form = $this->createForm(new MultiAAAAType(), array('AAAAs' => $AAAAs))
->handleRequest($request);
foreach ($AAAAs as $AAAA) {
$em->persist($AAAA);
}
$em->flush();
}
}
class MultiAAAAType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'single_aaaa',
'collection',
array(
'type' => new SingleAAAAType(),
)
);
}
}
class SingleEntityType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// adding actual fields here
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => '\...\Entity\AAAA',
)
);
}
}
我知道在进行匹配后,$form->submit
曾经是常态(使用here)和handleRequest
调用submit
。
我同意,如果我使用$em->merge
更新实体,手动进行匹配并不会那么糟糕。解决方案是几行代码(如我提到的答案)。
但现在的问题是“我做错了吗?我是否应该使用上述解决方案?handleRequest
是不是设计用来处理这种情况?”。
如果handleRequest
无法处理这种情况,则意味着它无法正确处理关联,而不会进入同一个pickle。