chore: makes better use of symfony denormalizer

This commit is contained in:
2025-09-08 14:20:33 -05:00
parent c0f1473037
commit b42924048f
17 changed files with 449 additions and 237 deletions

View File

@@ -5,6 +5,7 @@ namespace App\Tmdb;
use Aimeos\Map;
use App\Base\Enum\MediaType;
use App\Base\Util\ImdbMatcher;
use App\Tmdb\Dto\TmdbEpisodeDto;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -37,6 +38,16 @@ class TmdbClient
protected TvEpisodeRepository $tvEpisodeRepository;
protected SearchRepository $searchRepository;
protected array $mediaTypeMap = [
MediaType::Movie->value => MediaType::Movie->value,
MediaType::TvShow->value => MediaType::TvShow->value,
MediaType::TvEpisode->value => MediaType::TvEpisode->value,
'movie' => 'movies',
'tv' => 'tvshows',
];
protected $repos = [];
public function __construct(
private readonly SerializerInterface $serializer,
private readonly CacheItemPoolInterface $cache,
@@ -96,6 +107,11 @@ class TmdbClient
$this->tvSeasonRepository = new TvSeasonRepository($this->client);
$this->tvEpisodeRepository = new TvEpisodeRepository($this->client);
$this->searchRepository = new SearchRepository($this->client);
$this->repos = [
MediaType::Movie->value => $this->movieRepository,
MediaType::TvShow->value => $this->tvRepository,
MediaType::TvEpisode->value => $this->tvEpisodeRepository,
];
}
public function search(string $term): TmdbResult|Map
@@ -109,17 +125,15 @@ class TmdbClient
$handler = $handlers[$data['media_type']];
return $this->$handler($term);
}
return $this->parseListOfResults(
$this->searchRepository->getApi()->searchMulti($term),
"movies"
);
$results = $this->searchRepository->getApi()->searchMulti($term);
return $this->parseListOfResults($results);
}
public function movieDetails(string $imdbId): ?TmdbResult
{
$tmdbId = $this->findByImdbId($imdbId)['id'];
return $this->parseResult(
$this->movieRepository->getApi()->getMovie($tmdbId, ['append_to_response' => 'external_ids']),
$this->movieRepository->getApi()->getMovie($tmdbId, ['append_to_response' => 'external_ids,credits']),
MediaType::Movie->value,
$imdbId
);
@@ -128,7 +142,7 @@ class TmdbClient
public function tvshowDetails(string $imdbId): ?TmdbResult
{
$tmdbId = $this->findByImdbId($imdbId)['id'];
$media = $this->tvRepository->getApi()->getTvShow($tmdbId, ['append_to_response' => 'external_ids']);
$media = $this->tvRepository->getApi()->getTvShow($tmdbId, ['append_to_response' => 'external_ids,credits']);
$media['seasons'] = Map::from($media['seasons'])->filter(function ($data) {
return $data['season_number'] !== 0 &&
strtolower($data['name']) !== 'specials';
@@ -147,7 +161,7 @@ class TmdbClient
public function tvSeasonDetails(string $tmdbId, int $season): array
{
$result = $this->tvSeasonRepository->getApi()->getSeason($tmdbId, $season);
$result = $this->tvSeasonRepository->getApi()->getSeason($tmdbId, $season, ['append_to_response' => 'external_ids,credits']);
$result['episodes'] = Map::from($result['episodes'])->map(function ($data) {
$data['still_path'] = self::POSTER_IMG_PATH . $data['still_path'];
$data['poster'] = $data['still_path'];
@@ -156,9 +170,9 @@ class TmdbClient
return $result;
}
public function tvEpisodeDetails(string $tmdbId, int $season, int $episode): ?TmdbResult
public function tvEpisodeDetails(string $tmdbId, int $season, int $episode): TmdbResult|TmdbEpisodeDto|null
{
$result = $this->tvEpisodeRepository->getApi()->getEpisode($tmdbId, $season, $episode, ['append_to_response' => 'external_ids']);
$result = $this->tvEpisodeRepository->getApi()->getEpisode($tmdbId, $season, $episode, ['append_to_response' => 'external_ids,credits']);
return $this->parseResult(
$result,
MediaType::TvEpisode->value,
@@ -168,56 +182,46 @@ class TmdbClient
public function relatedMedia(string $tmdbId, string $mediaType, int $resultCount = 6): Map
{
$repos = [
'movies' => $this->movieRepository,
'tvshows' => $this->tvRepository,
];
$results = $repos[$mediaType]->getApi()->getRecommendations($tmdbId);
$results = $this->repos[$mediaType]->getApi()->getRecommendations($tmdbId, ['append_to_response' => 'external_ids']);
return $this->parseListOfResults(
$results,
$mediaType,
$resultCount
);
}
public function popularMovies(int $resultCount = 6): Map
{
$results = $this->movieRepository->getApi()->getPopular();
$results['results'] = Map::from($results['results'])->map(function ($result) {
$result['media_type'] = MediaType::Movie->value;
return $result;
});
return $this->parseListOfResults(
$this->movieRepository->getApi()->getPopular(),
"movies",
$results,
$resultCount
);
}
public function popularTvShows(int $resultCount = 6): Map
{
$results = $this->tvRepository->getApi()->getPopular();
$results['results'] = Map::from($results['results'])->map(function ($result) {
$result['media_type'] = MediaType::TvShow->value;
return $result;
});
return $this->parseListOfResults(
$this->tvRepository->getApi()->getPopular(),
"tvshows",
$results,
$resultCount
);
}
private function getExternalIds(string $tmdbId, $mediaType): ?array
private function getExternalIds(int $tmdbId, string $mediaType): ?array
{
try {
switch (MediaType::tryFrom($mediaType)->value) {
case MediaType::Movie->value:
$externalIds = $this->movieRepository->getApi()->getExternalIds($tmdbId);
break;
case MediaType::TvShow->value:
$externalIds = $this->tvRepository->getApi()->getExternalIds($tmdbId);
break;
default:
$externalIds = null;
break;
}
} catch (\throwable $e) {
if (!array_key_exists($mediaType, $this->repos) ||
!in_array($mediaType, [MediaType::Movie->value, MediaType::TvShow->value])) {
return [];
}
return $externalIds;
return $this->repos[$mediaType]->getApi()->getExternalIds($tmdbId);
}
private function findByImdbId(string $imdbId): array
@@ -236,7 +240,7 @@ class TmdbClient
throw new \Exception("No results found for $imdbId");
}
private function parseResult(array $data, string $mediaType, string $imdbId): TmdbResult
private function parseResult(array $data, string $mediaType, string $imdbId): TmdbResult|TmdbEpisodeDto
{
if (!array_key_exists('external_ids', $data)) {
$data['external_ids'] = ['imdb_id' => $imdbId];
@@ -244,20 +248,21 @@ class TmdbClient
return $this->serializer->denormalize($data, TmdbResult::class, context: ['media_type' => $mediaType]);
}
private function parseListOfResults(array $data, string $mediaType, ?int $resultCount = null): Map
private function parseListOfResults(array $data, ?int $resultCount = null): Map
{
$results = Map::from($data['results'])->filter(
fn ($result) => array_key_exists('id', $result)
)->map(function ($result) {
$result['external_ids'] = $this->getExternalIds($result['id'], MediaType::Movie->value);
$results = Map::from($data['results'])->filter(function ($result) {
return array_key_exists('media_type', $result) &&
in_array($result['media_type'], array_keys($this->mediaTypeMap));
})->map(function ($result) {
$result['external_ids'] = $this->getExternalIds($result['id'], $this->mediaTypeMap[$result['media_type']]);
return $result;
})->filter(function ($result) {
return array_key_exists('id', $result) &&
array_key_exists('imdb_id', $result['external_ids']) &&
$result['external_ids']['imdb_id'] !== null &&
$result['external_ids']['imdb_id'] !== "";
})->map(function ($result) use ($mediaType) {
return $this->serializer->denormalize($result, TmdbResult::class, context: ['media_type' => $mediaType]);
})->map(function ($result) {
return $this->serializer->denormalize($result, TmdbResult::class, context: ['media_type' => $this->mediaTypeMap[$result['media_type']]]);
});
if (null !== $resultCount) {