- PHP 8.3 → 8.4 (Dockerfile + composer.json) - Symfony 7.0 → 8.0 (tous les composants symfony/*) - API Platform 3.x → 4.x : migration openapiContext → openapi: new Operation(...) - Doctrine DBAL 3 → 4 : suppression use_savepoints, replace prepare/executeQuery - Doctrine ORM 2.x → 3.x : ClassMetadataInfo → ClassMetadata, setParameters → setParameter - Doctrine Bundle 2.x → 3.x, Fixtures Bundle 3.x → 4.x - zenstruck/foundry 1.x → 2.x : ModelFactory → PersistentObjectFactory, getDefaults → defaults - phpmd/phpmd 2.x → 3.x-dev (seule version supportant Symfony 8) - phparkitect 0.3 → 0.8 : NotDependsOnTheseNamespaces prend un array - symfony/mercure-bundle 0.3 → 0.4, symfony/monolog-bundle 3 → 4 - Suppression de runtime/frankenphp-symfony (intégré nativement dans symfony/runtime 8) - worker.Caddyfile : suppression de APP_RUNTIME (détection automatique Symfony 8) - Routes errors.xml/wdt.xml/profiler.xml → .php (Symfony 8 supprime le XML) - Types::ARRAY → Types::JSON dans Entity/Manga.php (DBAL 4 retire array type) - Suppression de src/Schedule.php (doublon vide avec MonitoringSchedule) - Tests : hydra:Collection → Collection, hydra:member → member (API Platform 4)
123 lines
4.2 KiB
PHP
123 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Domain\Manga\Application\QueryHandler;
|
|
|
|
use App\Domain\Manga\Application\Query\GetMangaChapters;
|
|
use App\Domain\Manga\Application\Response\ChapterListResponse;
|
|
use App\Domain\Manga\Application\Response\ChapterResponse;
|
|
use App\Domain\Manga\Domain\Contract\Repository\MangaRepositoryInterface;
|
|
use App\Domain\Manga\Domain\Exception\MangaNotFoundException;
|
|
use App\Domain\Manga\Domain\Model\Chapter;
|
|
|
|
readonly class GetMangaChaptersHandler
|
|
{
|
|
public function __construct(
|
|
private MangaRepositoryInterface $mangaRepository,
|
|
) {
|
|
}
|
|
|
|
public function handle(GetMangaChapters $query): ChapterListResponse
|
|
{
|
|
$manga = $this->mangaRepository->findById($query->mangaId);
|
|
if (!$manga) {
|
|
throw new MangaNotFoundException();
|
|
}
|
|
|
|
$allChapters = $this->mangaRepository->findAllChapters(
|
|
mangaId: $query->mangaId,
|
|
sortOrder: 'asc'
|
|
);
|
|
|
|
$grouped = $this->groupChapters($allChapters);
|
|
|
|
if ('desc' === $query->sortOrder) {
|
|
usort($grouped, fn (ChapterResponse $a, ChapterResponse $b) => $b->number <=> $a->number);
|
|
}
|
|
|
|
$total = count($grouped);
|
|
$offset = ($query->page - 1) * $query->limit;
|
|
$paginatedChapters = array_slice($grouped, $offset, $query->limit);
|
|
|
|
return new ChapterListResponse(
|
|
chapters: $paginatedChapters,
|
|
total: $total,
|
|
page: $query->page,
|
|
limit: $query->limit
|
|
);
|
|
}
|
|
|
|
/** @param Chapter[] $chapters */
|
|
private function groupChapters(array $chapters): array
|
|
{
|
|
$result = [];
|
|
$currentGroup = [];
|
|
$currentPagesDir = null;
|
|
$currentVolume = null;
|
|
|
|
foreach ($chapters as $chapter) {
|
|
$pagesDir = $chapter->getPagesDirectory();
|
|
$volume = $chapter->getVolume();
|
|
|
|
if (null !== $pagesDir && null !== $volume) {
|
|
if ($pagesDir === $currentPagesDir && $volume === $currentVolume) {
|
|
$currentGroup[] = $chapter;
|
|
} else {
|
|
if (!empty($currentGroup)) {
|
|
$result[] = $this->buildVolumeGroupResponse($currentGroup);
|
|
}
|
|
$currentGroup = [$chapter];
|
|
$currentPagesDir = $pagesDir;
|
|
$currentVolume = $volume;
|
|
}
|
|
} else {
|
|
if (!empty($currentGroup)) {
|
|
$result[] = $this->buildVolumeGroupResponse($currentGroup);
|
|
$currentGroup = [];
|
|
$currentPagesDir = null;
|
|
$currentVolume = null;
|
|
}
|
|
$result[] = new ChapterResponse(
|
|
id: $chapter->getId(),
|
|
number: $chapter->getNumber(),
|
|
title: $chapter->getTitle(),
|
|
volume: $chapter->getVolume(),
|
|
isVisible: $chapter->isVisible(),
|
|
pagesDirectory: $chapter->getPagesDirectory(),
|
|
createdAt: $chapter->getCreatedAt()->format(\DateTimeInterface::RFC3339)
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!empty($currentGroup)) {
|
|
$result[] = $this->buildVolumeGroupResponse($currentGroup);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/** @param Chapter[] $group */
|
|
private function buildVolumeGroupResponse(array $group): ChapterResponse
|
|
{
|
|
$first = $group[0];
|
|
$numbers = array_map(fn (Chapter $c) => $c->getNumber(), $group);
|
|
$min = min($numbers);
|
|
$max = max($numbers);
|
|
|
|
$fmt = fn (float $n) => $n == (int) $n ? (string) (int) $n : (string) $n;
|
|
$range = count($group) > 1 ? $fmt($min).'-'.$fmt($max) : $fmt($min);
|
|
|
|
return new ChapterResponse(
|
|
id: $first->getId(),
|
|
number: $first->getNumber(),
|
|
title: $first->getTitle(),
|
|
volume: $first->getVolume(),
|
|
isVisible: $first->isVisible(),
|
|
pagesDirectory: $first->getPagesDirectory(),
|
|
createdAt: $first->getCreatedAt()->format(\DateTimeInterface::RFC3339),
|
|
isVolumeGroup: true,
|
|
volumeChaptersRange: $range,
|
|
volumeChapterCount: count($group)
|
|
);
|
|
}
|
|
}
|