Files
slim-blog/src/Media/Application/MediaApplicationService.php
2026-03-16 16:02:01 +01:00

125 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Media\Application;
use App\Media\Domain\MediaStorageInterface;
use App\Media\Media;
use App\Media\MediaRepositoryInterface;
use App\Media\MediaServiceInterface;
use App\Post\PostRepositoryInterface;
use App\Shared\Pagination\PaginatedResult;
use PDOException;
use Psr\Http\Message\UploadedFileInterface;
/**
* Service applicatif du domaine Media.
*
* Coordonne le stockage physique des fichiers, la persistance des métadonnées
* et le contrôle d'usage des médias avant suppression.
*/
class MediaApplicationService implements MediaServiceInterface
{
public function __construct(
private readonly MediaRepositoryInterface $mediaRepository,
private readonly PostRepositoryInterface $postRepository,
private readonly MediaStorageInterface $mediaStorage,
private readonly string $uploadUrl,
private readonly int $maxSize,
) {
}
/** @return Media[] */
public function findAll(): array
{
return $this->mediaRepository->findAll();
}
/** @return PaginatedResult<Media> */
public function findPaginated(int $page, int $perPage): PaginatedResult
{
$page = max(1, $page);
$total = $this->mediaRepository->countAll();
$offset = ($page - 1) * $perPage;
return new PaginatedResult(
$this->mediaRepository->findPage($perPage, $offset),
$total,
$page,
$perPage,
);
}
/** @return Media[] */
public function findByUserId(int $userId): array
{
return $this->mediaRepository->findByUserId($userId);
}
/** @return PaginatedResult<Media> */
public function findByUserIdPaginated(int $userId, int $page, int $perPage): PaginatedResult
{
$page = max(1, $page);
$total = $this->mediaRepository->countByUserId($userId);
$offset = ($page - 1) * $perPage;
return new PaginatedResult(
$this->mediaRepository->findByUserPage($userId, $perPage, $offset),
$total,
$page,
$perPage,
);
}
public function findById(int $id): ?Media
{
return $this->mediaRepository->findById($id);
}
public function store(UploadedFileInterface $uploadedFile, int $userId): string
{
$preparedUpload = $this->mediaStorage->prepareUpload($uploadedFile, $this->maxSize);
$hash = $preparedUpload->getHash();
$existing = $this->mediaRepository->findByHashForUser($hash, $userId);
if ($existing !== null) {
$this->mediaStorage->cleanupPreparedUpload($preparedUpload);
return $existing->getUrl();
}
$filename = $this->mediaStorage->storePreparedUpload($uploadedFile, $preparedUpload);
$url = rtrim($this->uploadUrl, '/') . '/' . $filename;
$media = new Media(0, $filename, $url, $hash, $userId);
try {
$this->mediaRepository->create($media);
} catch (PDOException $e) {
$this->mediaStorage->deleteStoredFile($filename);
$duplicate = $this->mediaRepository->findByHashForUser($hash, $userId);
if ($duplicate !== null) {
return $duplicate->getUrl();
}
throw $e;
}
return $url;
}
/** @return array{count:int, posts:array<int, \App\Post\Post>} */
public function getUsageSummary(Media $media, int $sampleLimit = 5): array
{
return [
'count' => $this->postRepository->countByEmbeddedMediaUrl($media->getUrl()),
'posts' => $this->postRepository->findByEmbeddedMediaUrl($media->getUrl(), $sampleLimit),
];
}
public function delete(Media $media): void
{
$this->mediaStorage->deleteStoredFile($media->getFilename());
$this->mediaRepository->delete($media->getId());
}
}