mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
"preRemove" given wrong entity #6288
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @justin-nl on GitHub (Aug 19, 2019).
Originally assigned to: @justin-nl on GitHub.
Bug Report
Summary
I'm working in Symfony 2.8 (and 3.4), with an Invoice entity that has a OneToOne with a File entity (for a PDF upload). I'm cascading "all" from Invoice to File.
The File entity is implementing the PostRemove callback for deleting the physical file after the DB is updated. Sometimes, this is called on the wrong entity, resulting in the wrong file being deleted.
Current behavior
The PostRemove callback is called on the wrong File entity. This results in the wrong physical file being removed. The correct parent Invoice and child File entities are removed from the DB.
It seems related to recent/subsequent entity creation. I would create a few invoices. Delete one. Load another, and find that the file could not be found.
Oddly enough, once I implemented the "PreRemove" (simply for debugging which entity I was working with), the "PostRemove" suddenly worked as expected. Basically, an empty "PreRemove" function "magically" made things work.
My ultimate work-around was to store the filename in a class variable in the "PreRemove" callback, and use that variable to determine which file is deleted in the "PostRemove" callback.
How to reproduce
In the Invoice entity:
In the File entity:
Simple deletion using the Entity Manager:
Expected behavior
I expect if I'm cascading from a parent object, the resulting PostRemove should be called on the correct child object.
@lcobucci commented on GitHub (Aug 20, 2019):
@justin-nl unfortunately, v2.4 and v2.5 aren't maintained anymore (only security fixes are backported). Can you check if that still happens in v2.6.3?
@RobinHoutevelts commented on GitHub (Mar 23, 2021):
@lcobucci We seem to be hitting this as well in latest v2.8.2 with a cascading delete.
The title of this issue is wrong though, it happens in the "PostRemove" callback.
The File entity is a Proxy whose values aren’t hydrated ( uninitialised ). After persisting the deletion, when the entity passes Doctrine/ORM/UnitOfWork.php#L1248 it loses its identifier.
3358ccde39/lib/Doctrine/ORM/UnitOfWork.php (L1244-L1249)A few lines further the PostRemove event is invoked.
Anyone that listens for that event and tries to get a value from the File proxy will trigger a hydration. However because the identifier is gone, the loadById call thats being made in the ProxyFactory is passing an empty array as the $criteria.
3358ccde39/lib/Doctrine/ORM/Proxy/ProxyFactory.php (L147-L152)This causes a
SELECT * FROM filequery to be run in3358ccde39/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php (L725-L735)Which loads all(!) File entities. The first one is being returned..
Which causes the
$proxyto be hydrated with a random entity.Just like @justin-nl noticed we can fix this by making sure the entity is hydrated in a “PreRemove” event.
@akasake commented on GitHub (Mar 23, 2021):
I can confirm that @RobinHoutevelts solution works.
By adding a
PreRemoveSubscriberthat hydrates the entity, I can access the correct values of the removed entity in the postRemove event.Important to note is that you can still not access the previous
idin postRemove (cause the entity does not exist anymore).