Files
Mangarr/src/Domain/Manga/Infrastructure/Provider/MangadexProvider.php
ext.jeremy.guillot@maxicoffee.domains ae0eac3197 feat: SearchManga endpoint + tests
2025-02-10 21:33:34 +01:00

126 lines
3.9 KiB
PHP

<?php
namespace App\Domain\Manga\Infrastructure\Provider;
use App\Domain\Manga\Domain\Contract\Client\MangadexClientInterface;
use App\Domain\Manga\Domain\Contract\Provider\MangaProviderInterface;
use App\Domain\Manga\Domain\Model\Manga;
use App\Domain\Manga\Domain\Model\MangaCollection;
use App\Domain\Manga\Domain\Model\ValueObject\ExternalId;
use App\Domain\Manga\Domain\Model\ValueObject\MangaId;
use App\Domain\Manga\Domain\Model\ValueObject\MangaSlug;
use App\Domain\Manga\Domain\Model\ValueObject\MangaTitle;
use Ramsey\Uuid\Uuid;
use Symfony\Component\String\Slugger\SluggerInterface;
readonly class MangadexProvider implements MangaProviderInterface
{
public function __construct(
private MangadexClientInterface $client,
private SluggerInterface $slugger
) {}
public function search(string $title): MangaCollection
{
$results = $this->client->searchManga($title);
if (empty($results['data'])) {
return new MangaCollection([]);
}
$mangas = $this->createMangasFromResults($results['data']);
$this->enrichWithRatings($mangas);
usort($mangas, fn ($a, $b) => ($b->getRating() ?? 0) <=> ($a->getRating() ?? 0));
return new MangaCollection($mangas);
}
/**
* @param array<mixed> $results
* @return Manga[]
*/
private function createMangasFromResults(array $results): array
{
$mangas = [];
foreach ($results as $result) {
$manga = $this->createMangaFromResult($result);
if ($manga !== null) {
$mangas[] = $manga;
}
}
return $mangas;
}
private function createMangaFromResult(array $result): ?Manga
{
try {
$attributes = $result['attributes'];
$title = $attributes['title']['en'] ?? null;
if (!$title) {
return null;
}
$genres = array_map(
fn ($tag) => $tag['attributes']['name']['en'],
$attributes['tags']
);
$author = '';
$imageUrl = null;
foreach ($result['relationships'] as $relationship) {
if ($relationship['type'] === 'author') {
$author = $relationship['attributes']['name'];
}
if ($relationship['type'] === 'cover_art') {
$imageUrl = sprintf(
'https://mangadex.org/covers/%s/%s',
$result['id'],
$relationship['attributes']['fileName']
);
}
}
return new Manga(
new MangaId((string) Uuid::uuid4()),
new MangaTitle($title),
new MangaSlug($this->slugger->slug($title)->lower()),
$attributes['description']['fr'] ?? $attributes['description']['en'] ?? '',
$author,
$attributes['year'] ?? 0,
$genres,
$attributes['status'],
new ExternalId($result['id']),
$imageUrl,
null
);
} catch (\Exception $e) {
return null;
}
}
/**
* @param Manga[] $mangas
*/
private function enrichWithRatings(array $mangas): void
{
$externalIds = array_map(
fn (Manga $manga) => $manga->getExternalId()->getValue(),
$mangas
);
$ratings = $this->client->getMangaRatings($externalIds);
if (isset($ratings['statistics'])) {
foreach ($mangas as $manga) {
$externalId = $manga->getExternalId()->getValue();
if (isset($ratings['statistics'][$externalId]['rating']['average'])) {
$manga->setRating($ratings['statistics'][$externalId]['rating']['average']);
}
}
}
}
}