Doctrine ManyToMany 自引用双向 - Parent 未更新

Doctrine ManyToMany self referencing bidirectionnal - Parent not updated

我正在尝试创建一个公司服务的多对多关系。 每个服务有 N parents 个服务和 N children 个服务。

我在这里查看了原则文档:Many-To-Many, Self-referencing 并按如下方式实现了它:

这是我的服务实体:

<?
namespace AppBundle\Entity;

class Service
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", mappedBy="enfants", cascade={"persist"})
     */
    private $parents;

    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", inversedBy="parents")
     * @ORM\JoinTable(name="app_services_hierarchy",
     *      joinColumns={@ORM\JoinColumn(name="parent_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="enfant_id", referencedColumnName="id")}
     *      )
     */
    private $enfants;

    public function __construct()
    {
        $this->enfants  = new ArrayCollection();
        $this->parents  = new ArrayCollection();
    }

    public function getId(){
        return $this->id;
    }

    //--------------------------------------------------Enfants
    public function getEnfants(){
        return $this->enfants;
    }

    public function setEnfants($enfant){
        $this->enfants = $enfant;
    }

    public function addEnfant(Service $s){
        $this->enfants[] = $s;
        return $this;
    }

    public function removeEnfant(Service $s){
        $this->enfants->removeElement($s);
    }

    //--------------------------------------------------Parents
    public function getParents(){
        return $this->parents;
    }

    public function setParents($parents){
        $this->parents = $parents;
    }

    public function addParent(Service $s){
        $this->parents[] = $s;
        return $this;
    }

    public function removeParent(Service $s){
        $this->parents->removeElement($s);
    }

}

这是我的编辑功能(Controller.php) :

public function editAction(Request $request, $id)
{
    $service  = $this->getDoctrine()->getRepository(Service::class)->find($id);
    $form     = $this->createForm(ServiceType::class, $service);
    $form     ->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        $entityManager = $this->getDoctrine()->getManager();
        $entityManager ->persist($service);

        dump($service);

        $entityManager ->flush();
    }

    return $this->render('AppBundle:Service:edit.html.twig', array(
        'form'      => $form->createView(),
    ));
}

生成的表单如下所示:

问题:

我的问题是 children 已更新,但 parents 未更新。当我在我的控制器中 dump() 时,我可以在 $service 变量中看到 parents 但在我的数据库 table (app_services_hierarchie) 中唯一更新的是children.

代码中 $parents$enfants 之间的区别在于,如果您的 $enfants 映射,但不是 $parents 映射的情况。

Doctrine 不会存储 $parents 除非你通过 cascade={"persist"} 告诉它这样做。

/**
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", mappedBy="enfants", cascade={"persist"})
 */

这与@GregoireDucharme 链接的 post 中给出的答案基本相同。

编辑: 经过一番研究,显然这个问题不能用级联来解决。根据 Doctrine documentation:

Doctrine will only check the owning side of an association for changes.

所以您要做的就是告诉您的 $parents 也更新 $children 属性。

public function addParent(Service $s){
    $this->parents[] = $s;
    $s->addEnfant($this);
    return $this;
}

public function removeParent(Service $s){
    $this->parents->removeElement($s);
    $s->removeEnfant($this);
}

在您的表单中,确保指定以下内容:

->add('parents', 'collection', array(
    'by_reference' => false,
    //...
))

(我没有对上面的任何代码进行拼写检查,因此请谨慎行事。)

如果'by_reference'设置为trueaddParentremoveParent将不会被调用。

感谢 Anny Filina 的 blog post

它还声明您可以从 $parents 属性 中删除 cascade 选项,但您可能应该将 cascade={"persist","remove"} 添加到 $enfants 属性.