Julien
Julien

Reputation: 93

Symfony doctrine Many to Many Integrity constraint violation: 1062 Duplicate entry

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?

Upvotes: 2

Views: 2460

Answers (1)

Archi
Archi

Reputation: 495

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.

Upvotes: 3

Related Questions