在Doctrine 2中更新(从反面)双向多对多关系? [英] Updating (from the inverse side) bidirectional many-to-many relationships in Doctrine 2?
问题描述
客户
是与关键字
的关键字/客户关系的反面:
Customer
is the inverse side of "keywords/customers" relationship with Keyword
:
/**
* @ORM\ManyToMany(targetEntity="Keyword", mappedBy="customers",
* cascade={"persist", "remove"}
* )
*/
protected $keywords;
创建新客户时,应选择一个或多个关键字。实体表单字段是:
When creating a new customer, one should select one or more keywords. The entity form field is:
$form->add($this->factory->createNamed('entity', 'keywords', null, array(
'class' => 'Acme\HelloBundle\Entity\Keyword',
'property' => 'select_label',
'multiple' => true,
'expanded' => true,
)));
在我的控制器代码中,绑定请求后,检查表单是否有效,客户和所有客户/关键字协会,即连接表。
In my controller code, after binding the request and check if form is valid, I need to persist both the customer and all customer/keyword(s) associations, that is the join table.
然而客户是反面的,所以这是不行的:
However customer is the inverse side, so this is not working:
if($request->isPost()) {
$form->bindRequest($request);
if(!$form->isValid()) {
return array('form' => $form->createView());
}
// Valid form here
$em = $this->getEntityManager();
$em->persist($customer);
$em->flush();
}
事件与cascade选项,此代码失败。 $ customer-> getKeywords()
将返回 Doctrine\ORM\PersistentCollection
,它只保留选定的关键字。
Event with "cascade" option, this code fails. $customer->getKeywords()
will return Doctrine\ORM\PersistentCollection
, which holds only selected keywords.
我应该手动检查哪个关键字被删除/添加,然后从拥有方更新?
Should I manually check which keyword was removed/added and then update from the owning side?
推荐答案
好的,找到方法,即使我不完全满意。关键是此示例表单集合字段类型。基本上,我以前的表单定义是:
Ok, found the way, even if I'm not fully satisfied. The key was this example form collection field type. Basically what's happening with my previous form definition was:
$customer->getKeywords() = $postData; // $postData is somewhere in form framework
这只是一个集合的指定关键字)到客户关键字。在关键字
实例(拥有方)中没有调用任何方法。关键选项是 by_reference
(对我来说这只是一个坏名字,但无论如何...):
And that is just an assignment of a collection (of selected keywords) to customer keywords. No method were invoked on Keyword
instances (owning side). The key option is by_reference
(for me it's just a bad name, but anyways...):
$form
->add($this->factory->createNamed('entity', 'keywords', null, array(
// ...
'by_reference' => false
))
);
这样,窗体框架将调用setter,即 $ customer-> setKeywords(Collection $ keywords)
。在该方法中,您可以告诉拥有方存储您的关联:
This way the form framework is going to call the setter, that is $customer->setKeywords(Collection $keywords)
. In that method, you can "tell" the owning side to store your association:
public function setKeywords(Collection $keywords)
{
foreach($keywords as $keyword) {
$keyword->addCustomer($this); // Owning side call!
}
$this->keywords = $keywords;
return $this;
}
(始终检查所有方面的重复实例,使用包含
方法)。
(Always check for duplicate instances on the owning side, using contains
method).
此时,只会添加检查的关键字( $ keyword
参数)。需要管理未检查的关键字(控制器端)的删除:
At this point, only checked keywords will be added ($keyword
argument). There is the need to manage removal of unchecked keywords (controller side):
$originalKeywords = $customer->getKeywords()->toArray(); // When GET or POST
// When POST and form valid
$checkedKeywords = $customer->getKeywords()->toArray(); // Thanks to setKeywords
// Loop over all keywords
foreach($originalKeywords as $keyword) {
if(!in_array($keyword, $checkedKeywords)) { // Keyword has been unchecked
$keyword->removeCustomer($customer);
$manager->persist($keyword);
}
}
丑,但工作。我将删除的代码移动到客户
类,但根本不可能。如果你找到一个更好的解决方案,让我知道!
Ugly, but works. I would have the code for removal moved to the Customer
class, but it's not possible at all. If you'll find a better solution, let me know!
这篇关于在Doctrine 2中更新(从反面)双向多对多关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!