Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Doctrine : Test if an object is in an ArrayCollection

I am trying to use the method ArrayCollection::contains to find if an object is already in my Collection, but when i am doing :

//My ArrayCollection
$lesRoles = $drt->getDrtApplication()->getRoles();
$leRole = $lesRoles->first();
echo "Property appNom : ".$leRole->getRleApplication()->getAppNom()."// Property appRole : ".$leRole->getRleId()." <br>";


$role = new \Casgaya\Role(2,$drt->getDrtApplication());
echo "Property appNom : ".$role->getRleApplication()->getAppNom()."// Property appRole : ".$role->getRleId()." <br>";

var_dump($lesRoles->contains($role));

The result is :
Property appNom : CORA// Property appRole : 2
Property appNom : CORA// Property appRole : 2
bool(false)

Since appNom and rleId are the only two properties that the entity Role own i was hopping it would return true.

EDIT NEW TEST CASE :

echo "Test object role :  <br>";
var_dump($lesRoles==$role);
echo"<br>";
echo "Test integer property rleID from object role :  <br>";
var_dump($role->getRleId() == $leRole->getRleId());
echo"<br>";
echo "Test Application object property RleApplication from object role : <br> ";
var_dump($role->getRleApplication() == $leRole->getRleApplication());

The result is :

Property appNom : CORA// Property appRole : 2
Property appNom : CORA// Property appRole : 2
Test object role :
bool(false)
Test integer property rleID from object role :
bool(true)
Test Application object property RleApplication from object role :
bool(true)

Notice that when i test the equality of the two properties, both of them are true. But when i test the equality of the both whole object, it's false.

So the question is no more about ArrayCollection::contains, but it's :
On what criteria two doctrine entities are compared in the case of equality ?

like image 403
Silfers IsNobody Avatar asked Feb 25 '16 10:02

Silfers IsNobody


3 Answers

I have found the solution by myself, here's for the people who have the same issue :

I am using the method ArrayCollection::exists instead of contains, so i can specify on which criteria should an equality between object be established :

In my case :

$result = $lesRoles->exists(function($key,$element) use ($role) 
{
    return ($element->getRleApplication() == $role->getRleApplication() && $role->getRleId() == $element->getRleId());
});

Note that here $key and $element are the current object tested from the collection.

like image 156
Silfers IsNobody Avatar answered Nov 14 '22 21:11

Silfers IsNobody


contains( mixed $element ) Checks whether the given element is contained in the collection. Only element values are compared, not keys. The comparison of two elements is strict, that means not only the value but also the type must match. For objects this means reference equality.

source: http://www.doctrine-project.org/api/common/2.1/class-Doctrine.Common.Collections.ArrayCollection.html

If you want to check if some role is contained in collection, you can retrieve it by Doctrine - it will return same object, because Doctrine usually doesn't fetch entities which are already fetched via another query.

like image 35
auroree Avatar answered Nov 14 '22 22:11

auroree


I had a same issue:

$Xrepository->removeX($x);
$x->getY()->removeXRelation($x);

In removeXXXRelation() I tested if the relation was existent with ArrayCollection->contains()
This contains() would fail

After 2 hours of debugging and trying around the solution was this

$x->getY()->removeXRelation($x);
$Xrepository->removeX($x);

Simply flipping the remove calls.

As you can see Doctrine is doing magic with the object.
This magic starts with the remove call.
A colleague told me about hibernate object lifecycle states, which resolve to:
Not-persisted, Persisted, and Not-Persisted Anymore
It is possible that due to lifecycle state changes your object is generated twice, making the contains() go false (contains checks the objects identity)
That's my theory (tell me if I am wrong)

like image 41
Jannis Avatar answered Nov 14 '22 22:11

Jannis