<?php
declare(strict_types=1);
namespace App\Infrastructure\EventListener;
use App\Application\Manager\GenericManager;
use App\Application\Service\Media\MediaService;
use App\Domain\Entity\Media;
use Doctrine\ORM\Event\PostRemoveEventArgs;
use Imagick;
use ImagickException;
use League\Flysystem\FilesystemException;
use RuntimeException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Vich\UploaderBundle\Event\Event;
class ConvertImageEventListener
{
public function __construct(
public readonly GenericManager $genericManager,
private readonly MediaService $mediaService,
private readonly string $environment,
private readonly string $appAbsoluteUrl,
) {}
/**
* @param Event $event
*
* @return void
* @throws ImagickException
* @throws FilesystemException
*/
public function onVichUploaderPreUpload(Event $event): void
{
if (!$event->getObject() instanceof Media) {
return;
}
/** @var Media $media */
$media = $event->getObject();
/** @var UploadedFile $file */
$file = $media->file;
$mime = $file->getMimeType();
// Si ce n'est pas une image ou si c'est un SVG, on utilise handleNonImageMedia
if (!str_starts_with($mime, 'image/') || $mime === 'image/svg+xml') {
$this->handleNonImageMedia($event);
return;
}
$imageName = pathinfo($file->getClientOriginalName())['filename'] . '.' . 'webp';
$filepath = "/tmp/$imageName";
$img = new Imagick($file->getRealPath());
if (!$img->valid()) {
throw new RuntimeException('Invalid image');
}
$img->autoOrient();
$img->stripImage();
$img->setImageFormat('webp');
$this->mediaService->setDefaultCompression($img);
$this->mediaService->applyDefaultFilter($img);
$img->writeImage($filepath);
$file = new UploadedFile($filepath, $imageName, 'image/webp');
$media->mimeType = 'image/webp';
$media->originalName = $imageName;
$media->file = $file;
}
public function handleNonImageMedia(Event $event): void
{
/** @var Media $media */
$media = $event->getObject();
/** @var UploadedFile $file */
$file = $media->file;
$defaultName = pathinfo($file->getClientOriginalName())['filename'] . '.' . $file->getClientOriginalExtension();
$defaultMime = $file->getMimeType();
// Si c'est un SVG, on le copie directement dans le cache/full
if ($defaultMime === 'image/svg+xml') {
$filepath = "/tmp/$defaultName";
copy($file->getRealPath(), $filepath);
$file = new UploadedFile($filepath, $defaultName, $defaultMime);
} else {
$file = new UploadedFile($file->getRealPath(), $defaultName, $defaultMime);
}
$media->mimeType = $file->getMimeType();
$media->originalName = $defaultName;
$media->file = $file;
}
public function onVichUploaderPostUpload(Event $event): void
{
try {
/** @var Media $media */
$media = $event->getObject();
if (!$media) {
return;
}
$media->contentUrl = "$this->appAbsoluteUrl/api/media/$media->uuid/download";
// Si c'est une image WebP ou un SVG, on l'enregistre dans le cache
if ($media->mimeType === 'image/webp' || $media->mimeType === 'image/svg+xml') {
if ($media->mimeType === 'image/webp') {
$this->mediaService->applyDefaultFilter($media);
unlink("/tmp/{$media->originalName}");
} else {
// Pour les SVG, on les copie directement dans le cache/full
$this->mediaService->writeToAwsFilesystem(
"cache/full/{$media->filePath}",
file_get_contents("/tmp/{$media->originalName}")
);
unlink("/tmp/{$media->originalName}");
}
}
} catch (ImagickException | FilesystemException $e) {
if ($this->environment === 'dev') {
dump($e->getMessage(), $event->getObject()->filePath);
}
}
}
public function postRemove(PostRemoveEventArgs $event): void
{
$object = $event->getObject();
if (!$object instanceof Media) {
return;
}
$this->mediaService->deleteAllFiles($object);
}
}