I have a strange problem with \Doctrine\ORM\UnitOfWork::getScheduledEntityDeletions
used inside onFlush
event
foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) {
if ($entity instanceof PollVote) {
$arr = $entity->getAnswer()->getVotes()->toArray();
dump($arr);
dump($entity);
dump(in_array($entity, $arr, true));
dump(in_array($entity, $arr));
}
}
And here is the result:
So we see that the object is pointing to a different instance than the original, therefore in_array
no longer yields expected results when used with stick comparison (AKA ===
). Furthermore, the \DateTime
object is pointing to a different instance.
The only possible explanation I found is the following (source):
Whenever you fetch an object from the database Doctrine will keep a copy of all the properties and associations inside the UnitOfWork. Because variables in the PHP language are subject to “copy-on-write” the memory usage of a PHP request that only reads objects from the database is the same as if Doctrine did not keep this variable copy. Only if you start changing variables PHP will create new variables internally that consume new memory.
However, I did not change anything (even the created
field is kept as it is). The only operations that were preformed on entity are:
\Doctrine\ORM\EntityRepository::findBy
(fetching from DB)\Doctrine\Common\Persistence\ObjectManager::remove
(scheduling for removal)$em->flush();
(triggering synchronization with DB)Which leads me to think (I might be wrong) that the Doctrine's change tracking method has nothing to do with the issue that I'm experiencing. Which leads me to following questions:
\Doctrine\Common\Collections\Collection::contains
uses in_array
with strict comparison) or which items in a collection are scheduled for deletion?The problem is that when you tell doctrine to remove entity, it is removed from identity map (here):
<?php
public function scheduleForDelete($entity)
{
$oid = spl_object_hash($entity);
// ....
$this->removeFromIdentityMap($entity);
// ...
if ( ! isset($this->entityDeletions[$oid])) {
$this->entityDeletions[$oid] = $entity;
$this->entityStates[$oid] = self::STATE_REMOVED;
}
}
And when you do $entity->getAnswer()->getVotes()
, it does the following:
Try to call $entity->getAnswer()->getVotes()
before you delete entity. If the problem disappears, then I am right. Of cause, I would not suggest this hack as a solution, just to make sure we understand what is going on under the hood.
UPD instead of $entity->getAnswer()->getVotes()
you should probably do foreach for all votes, because of lazy loading. If you just call $entity->getAnswer()->getVotes()
, Doctrine probably wouldn't do anytning, and will load them only when you start to iterate through them.
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