feat: mise à jour de la gestion des chapitres en remplaçant les types d'identifiants par des flottants pour une meilleure cohérence, ajout de la documentation pour les méthodes de recherche de chapitres, et amélioration de la gestion des exceptions lors de la récupération des chapitres.

This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2025-04-05 11:43:40 +02:00
parent 5928cfd5f0
commit c0bd9c69b1
8 changed files with 36 additions and 22 deletions

View File

@@ -52,20 +52,20 @@ readonly class FetchMangaChaptersHandler
// Définir les règles de priorité des langues (fr > en > autres) // Définir les règles de priorité des langues (fr > en > autres)
$shouldReplaceChapter = false; $shouldReplaceChapter = false;
if (!isset($chaptersByNumber[$chapterNumber])) { if (!isset($chaptersByNumber[(string) $chapterNumber])) {
// Si c'est le premier chapitre avec ce numéro qu'on rencontre // Si c'est le premier chapitre avec ce numéro qu'on rencontre
$shouldReplaceChapter = true; $shouldReplaceChapter = true;
$chapterNumbers[] = $chapterNumber; $chapterNumbers[] = $chapterNumber;
} else if ($language === 'fr') { } else if ($language === 'fr') {
// Le français est toujours prioritaire // Le français est toujours prioritaire
$shouldReplaceChapter = true; $shouldReplaceChapter = true;
} else if ($language === 'en' && $chapterLanguages[$chapterNumber] !== 'fr') { } else if ($language === 'en' && $chapterLanguages[(string) $chapterNumber] !== 'fr') {
// L'anglais est prioritaire sur les autres langues, sauf le français // L'anglais est prioritaire sur les autres langues, sauf le français
$shouldReplaceChapter = true; $shouldReplaceChapter = true;
} }
if ($shouldReplaceChapter) { if ($shouldReplaceChapter) {
$chaptersByNumber[$chapterNumber] = new Chapter( $chaptersByNumber[(string) $chapterNumber] = new Chapter(
new ChapterId((string) Uuid::uuid4()), new ChapterId((string) Uuid::uuid4()),
$manga->getId()->getValue(), $manga->getId()->getValue(),
$chapterNumber, $chapterNumber,
@@ -75,7 +75,7 @@ readonly class FetchMangaChaptersHandler
false, false,
new \DateTimeImmutable() new \DateTimeImmutable()
); );
$chapterLanguages[$chapterNumber] = $language; $chapterLanguages[(string) $chapterNumber] = $language;
} }
} }
@@ -94,7 +94,7 @@ readonly class FetchMangaChaptersHandler
// Sauvegarde uniquement les nouveaux chapitres // Sauvegarde uniquement les nouveaux chapitres
foreach ($chaptersByNumber as $chapterNumber => $chapter) { foreach ($chaptersByNumber as $chapterNumber => $chapter) {
if (!isset($existingChapters[$chapterNumber])) { if (!isset($existingChapters[(float) $chapterNumber])) {
$this->mangaRepository->saveChapter($chapter); $this->mangaRepository->saveChapter($chapter);
} }
} }

View File

@@ -21,5 +21,9 @@ interface MangaRepositoryInterface
public function findBySlug(MangaSlug $slug): ?Manga; public function findBySlug(MangaSlug $slug): ?Manga;
public function search(string $query, int $page = 1, int $limit = 20): array; public function search(string $query, int $page = 1, int $limit = 20): array;
public function countSearch(string $query): int; public function countSearch(string $query): int;
/**
* @param float[] $chapterNumbers
* @return array<float, Chapter>
*/
public function findExistingChaptersByNumbers(string $mangaId, array $chapterNumbers): array; public function findExistingChaptersByNumbers(string $mangaId, array $chapterNumbers): array;
} }

View File

@@ -200,6 +200,10 @@ readonly class LegacyMangaRepository implements MangaRepositoryInterface
->getSingleScalarResult(); ->getSingleScalarResult();
} }
/**
* @param float[] $chapterNumbers
* @return array<float, Chapter>
*/
public function findExistingChaptersByNumbers(string $mangaId, array $chapterNumbers): array public function findExistingChaptersByNumbers(string $mangaId, array $chapterNumbers): array
{ {
$queryBuilder = $this->entityManager->createQueryBuilder() $queryBuilder = $this->entityManager->createQueryBuilder()
@@ -208,13 +212,13 @@ readonly class LegacyMangaRepository implements MangaRepositoryInterface
->where('c.manga = :mangaId') ->where('c.manga = :mangaId')
->andWhere('c.number IN (:chapterNumbers)') ->andWhere('c.number IN (:chapterNumbers)')
->setParameter('mangaId', $mangaId) ->setParameter('mangaId', $mangaId)
->setParameter('chapterNumbers', $chapterNumbers); ->setParameter('chapterNumbers', array_map('floatval', $chapterNumbers));
$chapters = $queryBuilder->getQuery()->getResult(); $chapters = $queryBuilder->getQuery()->getResult();
$chaptersByNumber = []; $chaptersByNumber = [];
foreach ($chapters as $chapter) { foreach ($chapters as $chapter) {
$chaptersByNumber[$chapter->getNumber()] = $this->toChapterDomain($chapter); $chaptersByNumber[(float) $chapter->getNumber()] = $this->toChapterDomain($chapter);
} }
return $chaptersByNumber; return $chaptersByNumber;

View File

@@ -11,6 +11,7 @@ use App\Domain\Scraping\Domain\Contract\Service\ImageDownloaderInterface;
use App\Domain\Scraping\Domain\Contract\Service\ScraperInterface; use App\Domain\Scraping\Domain\Contract\Service\ScraperInterface;
use App\Domain\Scraping\Domain\Event\ChapterScraped; use App\Domain\Scraping\Domain\Event\ChapterScraped;
use App\Domain\Scraping\Domain\Event\ChapterScrapingFailed; use App\Domain\Scraping\Domain\Event\ChapterScrapingFailed;
use App\Domain\Scraping\Domain\Model\Chapter;
use App\Domain\Scraping\Domain\Model\ScrapingJob; use App\Domain\Scraping\Domain\Model\ScrapingJob;
use App\Domain\Scraping\Domain\Model\Source; use App\Domain\Scraping\Domain\Model\Source;
use App\Domain\Scraping\Domain\Model\ValueObject\CbzGenerationRequest; use App\Domain\Scraping\Domain\Model\ValueObject\CbzGenerationRequest;
@@ -41,6 +42,7 @@ readonly class ScrapeChapterHandler
$job = null; $job = null;
try { try {
// 1. Récupération du chapitre // 1. Récupération du chapitre
/**@var Chapter $chapter */
$chapter = $this->chapterRepository->getById($command->chapterId); $chapter = $this->chapterRepository->getById($command->chapterId);
if (!$chapter) { if (!$chapter) {
throw new \InvalidArgumentException("Chapter not found with ID: {$command->chapterId}"); throw new \InvalidArgumentException("Chapter not found with ID: {$command->chapterId}");

View File

@@ -7,6 +7,9 @@ use App\Domain\Scraping\Domain\Model\Chapter;
interface ChapterRepositoryInterface interface ChapterRepositoryInterface
{ {
public function getById(string $id): ?Chapter; public function getById(string $id): ?Chapter;
public function getByMangaIdAndChapterNumber(string $mangaId, int $chapterNumber): Chapter; /**
* @throws ChapterNotFoundException
*/
public function getByMangaIdAndChapterNumber(string $mangaId, float $chapterNumber): Chapter;
public function save(Chapter $chapter): void; public function save(Chapter $chapter): void;
} }

View File

@@ -7,8 +7,8 @@ class Chapter
public function __construct( public function __construct(
public readonly string $id, public readonly string $id,
public readonly string $mangaId, public readonly string $mangaId,
public readonly int $chapterNumber, public readonly float $chapterNumber,
public readonly int $volumeNumber, public readonly ?int $volumeNumber,
public ?string $cbzPath = null, public ?string $cbzPath,
) {} ) {}
} }

View File

@@ -36,23 +36,23 @@ readonly class LegacyChapterRepository implements ChapterRepositoryInterface
/** /**
* @throws ChapterNotFoundException * @throws ChapterNotFoundException
*/ */
public function getByMangaIdAndChapterNumber(string $mangaId, int $chapterNumber): Chapter public function getByMangaIdAndChapterNumber(string $mangaId, float $chapterNumber): Chapter
{ {
$chapterEntity = $this->entityManager->getRepository(EntityChapter::class)->findOneBy([ $entity = $this->entityManager->getRepository(EntityChapter::class)->findOneBy([
'manga' => $mangaId, 'manga' => $mangaId,
'number' => $chapterNumber, 'number' => $chapterNumber
]); ]);
if (!$chapterEntity) { if ($entity === null) {
throw new ChapterNotFoundException(); throw new ChapterNotFoundException();
} }
return new Chapter( return new Chapter(
id: $chapterEntity->getId(), id: $entity->getId(),
mangaId: $chapterEntity->getManga()->getId(), mangaId: $entity->getManga()->getId(),
chapterNumber: $chapterEntity->getNumber(), chapterNumber: $entity->getNumber(),
volumeNumber: $chapterEntity->getVolume(), volumeNumber: $entity->getVolume(),
cbzPath: $chapterEntity->getCbzPath(), cbzPath: $entity->getCbzPath(),
); );
} }

View File

@@ -4,6 +4,7 @@ namespace App\Tests\Domain\Scraping\Adapter;
use App\Domain\Scraping\Domain\Contract\Repository\ChapterRepositoryInterface; use App\Domain\Scraping\Domain\Contract\Repository\ChapterRepositoryInterface;
use App\Domain\Scraping\Domain\Model\Chapter; use App\Domain\Scraping\Domain\Model\Chapter;
use App\Domain\Scraping\Domain\Exception\ChapterNotFoundException;
class InMemoryChapterRepository implements ChapterRepositoryInterface class InMemoryChapterRepository implements ChapterRepositoryInterface
{ {
@@ -14,7 +15,7 @@ class InMemoryChapterRepository implements ChapterRepositoryInterface
return $this->chapters[$id] ?? null; return $this->chapters[$id] ?? null;
} }
public function getByMangaIdAndChapterNumber(string $mangaId, int $chapterNumber): Chapter public function getByMangaIdAndChapterNumber(string $mangaId, float $chapterNumber): Chapter
{ {
foreach ($this->chapters as $chapter) { foreach ($this->chapters as $chapter) {
if ($chapter->mangaId === $mangaId && $chapter->chapterNumber === $chapterNumber) { if ($chapter->mangaId === $mangaId && $chapter->chapterNumber === $chapterNumber) {
@@ -22,7 +23,7 @@ class InMemoryChapterRepository implements ChapterRepositoryInterface
} }
} }
throw new \RuntimeException('Chapter not found'); throw new ChapterNotFoundException();
} }
public function save(Chapter $chapter): void public function save(Chapter $chapter): void