I have the following code:
//Delete old existing file(s)
$files = $record->getFiles();
foreach ($files as $file) {
$em->remove($file);
}
$em->flush();
$link = $record->getLink() ? $record->getLink() : new Link();
$link->setRecord($record);
$link->setUrl($metaData['location']);
$em->persist($link);
$em->flush();
I need to call the first flush() or else the $file entities are not deleted..why won't they be deleted by just using the second flush()?
For reference, here is the relationship definition of Record:
/**
* @var \AppBundle\Entity\Link
*
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Link", cascade={"persist"}, mappedBy="record")
*/
private $link;
/**
* @var \AppBundle\Entity\File
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\File", cascade={"persist"}, mappedBy="record")
*/
private $files;
Also, this code using a single flush() works fine (it's deleting a OneOnOne Entity instead of a OneToMany):
//Delete old existing link
$link = $record->getLink();
if ($link) {
$em->remove($link);
}
$file = $record->getFile() ? $record->getFile() : new File();
$file->setRecord($record);
$em->persist($file);
$em->flush();
I have found two ways of making my code work, which take two different approaches:
Record Entity
/**
* @var \AppBundle\Entity\Link
*
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Link", mappedBy="record")
*/
private $link;
/**
* @var \AppBundle\Entity\File
*
* ORM\OneToMany(targetEntity="AppBundle\Entity\File", mappedBy="record")
*/
private $files;
Controller
//Delete old existing file(s)
$files = $record->getFiles();
foreach ($files as $file) {
$fileService->deleteFile($file);
//Remove the *owning* entity of the relationship
$em->remove($file);
}
$em->flush();
$em->clear();
//We need to call clear() to remove all existing references of files
//from the $record entity. Get the record again after this.
$record = $this->getRecordRepository()->findActive($id);
$link = $record->getLink() ? $record->getLink() : new Link();
$link->setRecord($record);
$link->setUrl($metaData['location']);
$em->persist($link);
$record->setType(Record::TYPE_LINK);
$em->flush();
$record perspective, and let the cascade and orphanRemoval do the restRecord Entity
/**
* @var \AppBundle\Entity\Link
*
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Link", cascade={"persist", "remove"}, mappedBy="record", orphanRemoval=true)
*/
private $link;
/**
* @var \AppBundle\Entity\File
*
* @ORM\OneToMany(targetEntity="AppBundle\Entity\File", cascade={"persist", "remove"}, mappedBy="record", orphanRemoval=true)
*/
private $files;
Controller
//Delete old existing file(s)
$files = $record->getFiles();
foreach ($files as $file) {
$fileService->deleteFile($file);
$record->removeFile($file);
}
$link = $record->getLink() ? $record->getLink() : new Link();
$link->setRecord($record);
$link->setUrl($metaData['location']);
$em->persist($link);
$record->setType(Record::TYPE_LINK);
$em->flush();
I personally favor the second approach, which needs less PHP code is more readable.
I'll leave this answer open for any comments/tips and close it this week.
The cascade parameter has a options: 'remove', 'persist', 'refresh', 'merge', and 'detach'.
Treat them as flags so you can write:
cascade={"persist","remove"}
or even:
cascade={"all"}
Maybe this helps ...
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