feat(manga): implémenter la page Découvrir avec recommandations MangaDex

- Endpoint GET /api/manga-discover via DiscoverMangaStateProvider + DiscoverMangaHandler
- Algorithme : top 5 manga de la collection → appel /manga/{id}/recommendation
  par source → agrégation avec système de votes (multi-sources = plus pertinent)
- Filtrage : tags exclus (Oneshot, Doujinshi, Self-Published), contentRating,
  et suppression des manga déjà en bibliothèque
- Page Vue DiscoverPage.vue : chargement auto au montage, bouton Actualiser,
  modal détail, ajout à la bibliothèque
- Adapteurs InMemory de test mis à jour (discover + getMangaRecommendations)
This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2026-03-15 21:43:57 +01:00
parent 65453c87e5
commit 814fe46ce5
14 changed files with 482 additions and 3 deletions

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Domain\Manga\Infrastructure\ApiPlatform\Resource;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use App\Domain\Manga\Infrastructure\ApiPlatform\Dto\MangaSearchCollection;
use App\Domain\Manga\Infrastructure\ApiPlatform\State\Provider\DiscoverMangaStateProvider;
#[ApiResource(
shortName: 'Mangadex',
operations: [
new Get(
uriTemplate: '/manga-discover',
output: MangaSearchCollection::class,
provider: DiscoverMangaStateProvider::class
)
]
)]
class MangaDiscoverResource
{
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Domain\Manga\Infrastructure\ApiPlatform\State\Provider;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Domain\Manga\Application\Query\DiscoverManga;
use App\Domain\Manga\Application\QueryHandler\DiscoverMangaHandler;
use App\Domain\Manga\Infrastructure\ApiPlatform\Dto\MangaSearchCollection;
use App\Domain\Manga\Infrastructure\ApiPlatform\Dto\MangaSearchItem;
readonly class DiscoverMangaStateProvider implements ProviderInterface
{
public function __construct(private DiscoverMangaHandler $handler)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): MangaSearchCollection
{
$response = $this->handler->handle(new DiscoverManga());
return new MangaSearchCollection(
items: array_map(
fn ($item) => new MangaSearchItem(
externalId: $item->externalId,
title: $item->title,
slug: $item->slug,
description: $item->description,
author: $item->author,
publicationYear: $item->publicationYear,
genres: $item->genres,
status: $item->status,
imageUrl: $item->imageUrl,
thumbnailUrl: $item->thumbnailUrl,
rating: $item->rating
),
$response->items
)
);
}
}