Doctrine2 ArrayCollection

3.9k views Asked by At

Ok, I have a User entity as follows

<?php
class User 
{
    /**
     * @var integer
     * @Id
     * @Column(type="integer")
     * @GeneratedValue
     */
    protected $id;
    /**
     * @var \Application\Entity\Url[]
     * @OneToMany(targetEntity="Url", mappedBy="user", cascade={"persist", "remove"})
     */
    protected $urls;
    public function __construct()
    {
        $this->urls = new \Doctrine\Common\Collections\ArrayCollection();
    }
    public function addUrl($url)
    {
       // This is where I have a problem
    }
}

Now, what I want to do is check if the User has already the $url in the $urls ArrayCollection before persisting the $url.

Now some of the examples I found says we should do something like

if (!$this->getUrls()->contains($url)) {
    // add url
}

but this doesn't work as this compares the element values. As the $url doesn't have id value yet, this will always fail and $url will be dublicated.

So I'd really appreciate if someone could explain how I can add an element to the ArrayCollection without persisting it and avoiding the duplication?

Edit

I have managed to achive this via

$p = function ($key, $element) use ($url) 
{ 
    if ($element->getUrlHash() == $url->getUrlHash()) { 
        return true; 
    } else { 
        return false; 
    } 
};

But doesn't this still load all urls and then performs the check? I don't think this is efficient as there might be thousands of urls per user.

2

There are 2 answers

2
beberlei On BEST ANSWER

This is not yet possible in a "domain driven" way, ie. just using objects. You should execute a query to check for the existance:

SELECT count(u.id) FROM User u WHERE ?1 IN u.urls AND u.id = ?2

With Doctrine 2.1 this will be possible using a combination of two new features:

  1. Extra Lazy Collections
  2. @IndexBy for collections, so you would define @OneToMany(targetEntity="Url", indexBy="location")
  3. ExtraLazy Collection Support for index by using ->contains().

Points 1 and 2 are already implemented in Doctrine 2 master, but 3 is still missing.

2
Cobby On

You should try using the exists method on the collection and manually compare values.