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 ?
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.
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With