feat: SearchManga endpoint + tests
This commit is contained in:
parent
6667cc224b
commit
ae0eac3197
126
src/Domain/Manga/Infrastructure/Provider/MangadexProvider.php
Normal file
126
src/Domain/Manga/Infrastructure/Provider/MangadexProvider.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user