Symfony doctrine Many to Many Integrity constraint

2019-05-21 10:16发布

I have an entity User with a manyToMany ('Self-Referencing') relation.

/**
     * @Serializer\Expose()
     * @ORM\ManyToMany(targetEntity="User")
     * @ORM\JoinTable(name="user_referent",
     *  joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *  inverseJoinColumns={@ORM\JoinColumn(name="coach_id", referencedColumnName="id")}
     * )
     * @ORM\JoinColumn(nullable=true)
     * @Assert\Valid
     *
     */
    private $coaches;

During my test when I try to create a duplicate entry, I have the right message from sql (SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry.) But I would like to catch the duplicate before flushing. So I added a if statement in the add function.

public function addCoach(User $coach)
    {
        if ($this->coaches->contains($coach)) {
            return;
        }
        $this->coaches[] = $coach;

    }

But it seems that when using a form, the addCoach function is not called. When I dump it, no value is dumped. I tried the @Assert\Valid, the @Unique or constraint on @Table... But nothing works. Is there any way to set a constraint the many to many relation a throw an message like on any other item of an entity?

1条回答
2楼-- · 2019-05-21 10:34

The addCoach method will be called only when you call that method explicitly to add coach on user entity before persisting it. It does not get called implicitly.

You can use onPrePersist method in User entity which will be implicit way to check for duplicates every time you try to flush an entity into DB.

Update your User entity's doctrine orm file with following.

<lifecycle-callbacks>
   <lifecycle-callback type="prePersist" method="prePersist" />
</lifecycle-callbacks>

And then update User entity file with following.

    /**
     * @PrePersist
     */
    public function onPrePersist()
    {
        // remove duplicates from coaches array.

        $coachKeys[] = array();
        foreach($this->coaches as $key => $coach) {
            if(!in_array($coach->getUserId(), $coachKeys) {
                $coachKeys[] = $key;
            } else {
               $this->removeCoach($this->coach); // unset($this->coache[$key]);
            }     
        }           
    }

This will make sure it removes duplicate entry before the flush.

查看更多
登录 后发表回答