125 lines
3.8 KiB
PHP
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());
|
|
}
|
|
}
|