Entity association not deleted when removing file
bastien70 opened this issue · 3 comments
Bug Report
Q | A |
---|---|
BC Break | no |
Bundle version | 2.2.0 |
Symfony version | 6.3.8 |
PHP version | 8.1.16 |
Summary
There is a problem that has not been resolved for several years.
When we use a generic entity (for example, called "Media"), and we use it as a relationship for all our entities requiring the use of files, then even if we implement a delete cascade on the relationship, if we delete the file, the record of the generic entity is not deleted (or rather, it is recreated directly with the creation and edition dates, without file, and is again associated with the entity)
See #1172
How to reproduce
#[ORM\Entity(repositoryClass: MediaRepository::class)]
#[ORM\HasLifecycleCallbacks]
#[Vich\Uploadable]
class Media implements \Stringable
{
use PrimaryKeyTrait;
use CreatedAtTrait;
use UpdatedAtTrait;
#[ORM\Column(type: Types::INTEGER, nullable: true)]
private ?int $size = null;
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $mimeType = null;
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $originalName = null;
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $fileName = null;
#[Vich\UploadableField(
mapping: 'media',
fileNameProperty: 'fileName',
size: 'size',
mimeType: 'mimeType',
originalName: 'originalName'
)]
private ?File $file = null;
public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
$this->updatedAt = new \DateTimeImmutable();
}
public function setFile(File $file = null): self
{
$this->file = $file;
if ($file) {
$this->updatedAt = new \DateTimeImmutable();
}
return $this;
}
public function getFile(): ?File
{
return $this->file;
}
// other getters/setters...
}
And I associate it with my entities. By example, in my User entity, I've an avatar field :
#[ORM\OneToOne(cascade: ['persist', 'remove'], fetch: 'EAGER')]
private ?Media $avatar = null;
In the vich_uploader.yaml :
vich_uploader:
db_driver: orm
storage: flysystem
mappings:
media:
upload_destination: 'media.storage'
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
inject_on_load: true
delete_on_update: true
delete_on_remove: true
When clicking inside the checkbox and submitting the form to remove current avatar relation, the file is deleted, the Media entity is truncated, but it creates a new media (with just createdAt and updatedAt values) instead of just deleting by the way the "media" row in database
UPDATE :
I found a solution to make it work.
In my entities having a relationship with Media, I add the ORM\JoinColumn(onDelete: 'SET NULL')
And I set up an event when a Media entity is modified which checks that we still have a filename. If not, I delete the Media.
#[ORM\OneToOne(cascade: ['persist', 'remove'])]
#[ORM\JoinColumn(onDelete: 'SET NULL')]
private ?Media $avatar = null;
<?php
declare(strict_types=1);
namespace App\EventListener;
use App\Entity\Media;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Events;
#[AsDoctrineListener(
event: Events::postUpdate
)]
class MediaEventSubscriber
{
public function __construct(
private readonly EntityManagerInterface $manager
) {
}
public function postUpdate(LifecycleEventArgs $event): void
{
$media = $event->getObject();
if ($media instanceof Media) {
if (!$media->getFileName()) {
$this->manager->remove($media);
$this->manager->flush();
}
}
}
}
It's basically the same problem, but brought up to date, so that it appears in recent issues.
And a possible solution
You can bring it up by commenting on it.
Closing as a duplicate