Description
Bug Report
Q | A |
---|---|
BC Break | no? |
Version | 2.4.8 (and 2.5) |
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:
/**
* @ORM\OneToOne(targetEntity="File", cascade={"all"})
* @ORM\JoinColumn(name="pdf_id", referencedColumnName="id")
*/
protected $pdf;
In the File entity:
/**
* @ORM\PostRemove()
*/
public function postRemove()
{
// "getAbsolutePath()" uses the "path" variable from the file object
// and prepends the local system path
$file = $this->getAbsolutePath();
if (null !== $file) {
// i did a `var_dump($file); exit;` to show the wrong filepath
// "fs()" returns a new `Symfony\Component\Filesystem\Filesystem`
$this->fs()->remove($file);
}
}
Simple deletion using the Entity Manager:
// i verified here that the associations were correct
$em->remove($invoice);
// i verified here that the associations were still correct
$em->flush();
// i never got here because of the `exit;` I had implemented above
Expected behavior
I expect if I'm cascading from a parent object, the resulting PostRemove should be called on the correct child object.