fix: uses symfony de-normalizer to map tmdb data to objects
This commit is contained in:
@@ -46,6 +46,7 @@
|
|||||||
"symfony/messenger": "7.3.*",
|
"symfony/messenger": "7.3.*",
|
||||||
"symfony/notifier": "7.3.*",
|
"symfony/notifier": "7.3.*",
|
||||||
"symfony/ntfy-notifier": "7.3.*",
|
"symfony/ntfy-notifier": "7.3.*",
|
||||||
|
"symfony/object-mapper": "7.3.*",
|
||||||
"symfony/runtime": "7.3.*",
|
"symfony/runtime": "7.3.*",
|
||||||
"symfony/scheduler": "7.3.*",
|
"symfony/scheduler": "7.3.*",
|
||||||
"symfony/security-bundle": "7.3.*",
|
"symfony/security-bundle": "7.3.*",
|
||||||
|
|||||||
75
composer.lock
generated
75
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "9ffd10f98137e8975de2c04ac2412ed5",
|
"content-hash": "e055bbbbe5836c92bb147b6dbb1d1d46",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "1tomany/rich-bundle",
|
"name": "1tomany/rich-bundle",
|
||||||
@@ -7783,6 +7783,79 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-02-13T10:27:54+00:00"
|
"time": "2025-02-13T10:27:54+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/object-mapper",
|
||||||
|
"version": "v7.3.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/object-mapper.git",
|
||||||
|
"reference": "f7f9833d9fcc8361239c1dae5495aa9e43ece0b5"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/object-mapper/zipball/f7f9833d9fcc8361239c1dae5495aa9e43ece0b5",
|
||||||
|
"reference": "f7f9833d9fcc8361239c1dae5495aa9e43ece0b5",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"psr/container": "^2.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/property-access": "<7.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/property-access": "^7.2",
|
||||||
|
"symfony/var-exporter": "^7.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\ObjectMapper\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides a way to map an object to another object",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/object-mapper/tree/v7.3.3"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-08-13T14:03:15+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/options-resolver",
|
"name": "symfony/options-resolver",
|
||||||
"version": "v7.3.0",
|
"version": "v7.3.0",
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ services:
|
|||||||
# please note that last definitions always *replace* previous ones
|
# please note that last definitions always *replace* previous ones
|
||||||
App\Download\Downloader\DownloaderInterface: "@App\\Download\\Downloader\\ProcessDownloader"
|
App\Download\Downloader\DownloaderInterface: "@App\\Download\\Downloader\\ProcessDownloader"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Session
|
# Session
|
||||||
Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
|
Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
|
||||||
arguments:
|
arguments:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Base\Framework\Controller;
|
|||||||
use App\Monitor\Action\Command\MonitorTvShowCommand;
|
use App\Monitor\Action\Command\MonitorTvShowCommand;
|
||||||
use App\Monitor\Action\Handler\MonitorTvShowHandler;
|
use App\Monitor\Action\Handler\MonitorTvShowHandler;
|
||||||
use App\Tmdb\Tmdb;
|
use App\Tmdb\Tmdb;
|
||||||
|
use App\Tmdb\TmdbClient;
|
||||||
use App\User\Framework\Entity\User;
|
use App\User\Framework\Entity\User;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@@ -16,20 +17,18 @@ use Symfony\Component\Routing\Attribute\Route;
|
|||||||
final class IndexController extends AbstractController
|
final class IndexController extends AbstractController
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly Tmdb $tmdb,
|
private readonly TmdbClient $tmdb,
|
||||||
private readonly MonitorTvShowHandler $monitorTvShowHandler,
|
private readonly MonitorTvShowHandler $monitorTvShowHandler,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
#[Route('/', name: 'app_index')]
|
#[Route('/', name: 'app_index')]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
/** @var User $user */
|
|
||||||
$user = $this->getUser();
|
|
||||||
return $this->render('index/index.html.twig', [
|
return $this->render('index/index.html.twig', [
|
||||||
'active_downloads' => $this->getUser()->getActiveDownloads(),
|
'active_downloads' => $this->getUser()->getActiveDownloads(),
|
||||||
'recent_downloads' => $this->getUser()->getDownloads(),
|
'recent_downloads' => $this->getUser()->getDownloads(),
|
||||||
'popular_movies' => $this->tmdb->popularMovies(1, 6),
|
'popular_movies' => $this->tmdb->popularMovies(),
|
||||||
'popular_tvshows' => $this->tmdb->popularTvShows(1, 6),
|
'popular_tvshows' => $this->tmdb->popularTvShows(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
src/Tmdb/HydrationListener.php
Normal file
14
src/Tmdb/HydrationListener.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tmdb;
|
||||||
|
|
||||||
|
use Tmdb\Event\HydrationEvent;
|
||||||
|
|
||||||
|
class HydrationListener extends \Tmdb\Event\Listener\HydrationListener
|
||||||
|
{
|
||||||
|
public function hydrateSubject(HydrationEvent $event)
|
||||||
|
{
|
||||||
|
dump($event);
|
||||||
|
dd('hre');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,10 +8,12 @@ use App\ValueObject\ResultFactory;
|
|||||||
use Psr\Cache\CacheItemPoolInterface;
|
use Psr\Cache\CacheItemPoolInterface;
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\ObjectMapper\ObjectMapper;
|
||||||
use Symfony\Contracts\Cache\ItemInterface;
|
use Symfony\Contracts\Cache\ItemInterface;
|
||||||
use Tmdb\Api\Find;
|
use Tmdb\Api\Find;
|
||||||
use Tmdb\Client;
|
use Tmdb\Client;
|
||||||
use Tmdb\Event\BeforeRequestEvent;
|
use Tmdb\Event\BeforeRequestEvent;
|
||||||
|
use Tmdb\Event\HydrationEvent;
|
||||||
use Tmdb\Event\Listener\Psr6CachedRequestListener;
|
use Tmdb\Event\Listener\Psr6CachedRequestListener;
|
||||||
use Tmdb\Event\Listener\Request\AcceptJsonRequestListener;
|
use Tmdb\Event\Listener\Request\AcceptJsonRequestListener;
|
||||||
use Tmdb\Event\Listener\Request\ApiTokenRequestListener;
|
use Tmdb\Event\Listener\Request\ApiTokenRequestListener;
|
||||||
@@ -62,8 +64,12 @@ class Tmdb
|
|||||||
'uri_factory' => null,
|
'uri_factory' => null,
|
||||||
],
|
],
|
||||||
'hydration' => [
|
'hydration' => [
|
||||||
'event_listener_handles_hydration' => false,
|
'event_listener_handles_hydration' => true,
|
||||||
'only_for_specified_models' => []
|
'only_for_specified_models' => [
|
||||||
|
Movie::class,
|
||||||
|
Tv::class,
|
||||||
|
Tv\Episode::class,
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -92,6 +98,9 @@ class Tmdb
|
|||||||
$userAgentListener = new UserAgentRequestListener();
|
$userAgentListener = new UserAgentRequestListener();
|
||||||
$this->eventDispatcher->addListener(BeforeRequestEvent::class, $userAgentListener);
|
$this->eventDispatcher->addListener(BeforeRequestEvent::class, $userAgentListener);
|
||||||
|
|
||||||
|
// $hydrationListener = new HydrationListener($this->eventDispatcher);
|
||||||
|
// $this->eventDispatcher->addListener(HydrationEvent::class, $hydrationListener);
|
||||||
|
|
||||||
$this->movieRepository = new MovieRepository($this->client);
|
$this->movieRepository = new MovieRepository($this->client);
|
||||||
$this->tvRepository = new TvRepository($this->client);
|
$this->tvRepository = new TvRepository($this->client);
|
||||||
}
|
}
|
||||||
@@ -247,19 +256,21 @@ class Tmdb
|
|||||||
return $series;
|
return $series;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function relatedMedia(string $tmdbId, string $mediaType, int $maxResults = 6)
|
public function relatedMedia(string $tmdbId, string $mediaType, int $maxResults = 20)
|
||||||
{
|
{
|
||||||
$repos = [
|
$repos = [
|
||||||
'movies' => $this->movieRepository,
|
'movies' => $this->movieRepository,
|
||||||
'tvshows' => $this->tvRepository,
|
'tvshows' => $this->tvRepository,
|
||||||
];
|
];
|
||||||
|
$results = $repos[$mediaType]->getRecommendations($tmdbId, ['append_to_response' => 'external_ids']);
|
||||||
|
|
||||||
$results = $repos[$mediaType]->getRecommendations($tmdbId);
|
$results = Map::from(array_values($results->toArray()))
|
||||||
return Map::from(array_values($results->toArray()))
|
->take($maxResults)
|
||||||
->slice(0, 6)
|
|
||||||
->map(function ($result) use ($mediaType) {
|
->map(function ($result) use ($mediaType) {
|
||||||
return $this->parseResult($result, $mediaType);
|
return $this->parseResult($result, $mediaType);
|
||||||
})->toArray();
|
})->toArray();
|
||||||
|
|
||||||
|
dd($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mediaDetails(string $id, string $type)
|
public function mediaDetails(string $id, string $type)
|
||||||
|
|||||||
166
src/Tmdb/TmdbClient.php
Normal file
166
src/Tmdb/TmdbClient.php
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tmdb;
|
||||||
|
|
||||||
|
use Aimeos\Map;
|
||||||
|
use App\Base\Enum\MediaType;
|
||||||
|
use Psr\Cache\CacheItemPoolInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\ObjectMapper\ObjectMapper;
|
||||||
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
use Symfony\Contracts\Cache\ItemInterface;
|
||||||
|
use Tmdb\Client;
|
||||||
|
use Tmdb\Event\BeforeRequestEvent;
|
||||||
|
use Tmdb\Event\HydrationEvent;
|
||||||
|
use Tmdb\Event\Listener\Psr6CachedRequestListener;
|
||||||
|
use Tmdb\Event\Listener\Request\AcceptJsonRequestListener;
|
||||||
|
use Tmdb\Event\Listener\Request\ApiTokenRequestListener;
|
||||||
|
use Tmdb\Event\Listener\Request\ContentTypeJsonRequestListener;
|
||||||
|
use Tmdb\Event\Listener\Request\UserAgentRequestListener;
|
||||||
|
use Tmdb\Event\RequestEvent;
|
||||||
|
use Tmdb\Model\Movie;
|
||||||
|
use Tmdb\Model\Tv;
|
||||||
|
use Tmdb\Repository\MovieRepository;
|
||||||
|
use Tmdb\Repository\TvRepository;
|
||||||
|
use Tmdb\Token\Api\ApiToken;
|
||||||
|
use Tmdb\Token\Api\BearerToken;
|
||||||
|
|
||||||
|
class TmdbClient
|
||||||
|
{
|
||||||
|
protected Client $client;
|
||||||
|
|
||||||
|
protected MovieRepository $movieRepository;
|
||||||
|
|
||||||
|
protected TvRepository $tvRepository;
|
||||||
|
|
||||||
|
protected ObjectMapper $objectMapper;
|
||||||
|
|
||||||
|
const POSTER_IMG_PATH = "https://image.tmdb.org/t/p/w500";
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly SerializerInterface $serializer,
|
||||||
|
private readonly CacheItemPoolInterface $cache,
|
||||||
|
private readonly EventDispatcherInterface $eventDispatcher,
|
||||||
|
#[Autowire(env: 'TMDB_API')] string $apiKey,
|
||||||
|
) {
|
||||||
|
$this->client = new Client(
|
||||||
|
[
|
||||||
|
/** @var ApiToken|BearerToken */
|
||||||
|
'api_token' => new BearerToken($apiKey),
|
||||||
|
'secure' => true,
|
||||||
|
'base_uri' => Client::TMDB_URI,
|
||||||
|
'event_dispatcher' => [
|
||||||
|
'adapter' => $this->eventDispatcher,
|
||||||
|
],
|
||||||
|
// We make use of PSR-17 and PSR-18 auto discovery to automatically guess these, but preferably set these explicitly.
|
||||||
|
'http' => [
|
||||||
|
'client' => null,
|
||||||
|
'request_factory' => null,
|
||||||
|
'response_factory' => null,
|
||||||
|
'stream_factory' => null,
|
||||||
|
'uri_factory' => null,
|
||||||
|
],
|
||||||
|
'hydration' => [
|
||||||
|
'event_listener_handles_hydration' => true,
|
||||||
|
'only_for_specified_models' => [
|
||||||
|
Movie::class,
|
||||||
|
Tv::class,
|
||||||
|
Tv\Episode::class,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required event listeners and events to be registered with the PSR-14 Event Dispatcher.
|
||||||
|
*/
|
||||||
|
$requestListener = new Psr6CachedRequestListener(
|
||||||
|
$this->client->getHttpClient(),
|
||||||
|
$this->eventDispatcher,
|
||||||
|
$cache,
|
||||||
|
$this->client->getHttpClient()->getPsr17StreamFactory(),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
$this->eventDispatcher->addListener(RequestEvent::class, $requestListener);
|
||||||
|
|
||||||
|
$apiTokenListener = new ApiTokenRequestListener($this->client->getToken());
|
||||||
|
$this->eventDispatcher->addListener(BeforeRequestEvent::class, $apiTokenListener);
|
||||||
|
|
||||||
|
$acceptJsonListener = new AcceptJsonRequestListener();
|
||||||
|
$this->eventDispatcher->addListener(BeforeRequestEvent::class, $acceptJsonListener);
|
||||||
|
|
||||||
|
$jsonContentTypeListener = new ContentTypeJsonRequestListener();
|
||||||
|
$this->eventDispatcher->addListener(BeforeRequestEvent::class, $jsonContentTypeListener);
|
||||||
|
|
||||||
|
$userAgentListener = new UserAgentRequestListener();
|
||||||
|
$this->eventDispatcher->addListener(BeforeRequestEvent::class, $userAgentListener);
|
||||||
|
|
||||||
|
// $hydrationListener = new HydrationListener($this->eventDispatcher);
|
||||||
|
// $this->eventDispatcher->addListener(HydrationEvent::class, $hydrationListener);
|
||||||
|
|
||||||
|
$this->movieRepository = new MovieRepository($this->client);
|
||||||
|
$this->tvRepository = new TvRepository($this->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function search() {}
|
||||||
|
|
||||||
|
public function find() {}
|
||||||
|
|
||||||
|
public function movieDetails() {}
|
||||||
|
|
||||||
|
public function tvshowDetails() {}
|
||||||
|
|
||||||
|
public function tvEpisodeDetails() {}
|
||||||
|
|
||||||
|
public function relatedMedia() {}
|
||||||
|
|
||||||
|
public function popularMovies(int $resultCount = 6): Map
|
||||||
|
{
|
||||||
|
$results = $this->movieRepository->getApi()->getPopular();
|
||||||
|
return Map::from($results['results'])->map(function ($result) {
|
||||||
|
$result['external_ids'] = $this->getExternalIds($result['id'], MediaType::Movie->value);
|
||||||
|
return $result;
|
||||||
|
})->filter(function ($result) {
|
||||||
|
return array_key_exists('imdb_id', $result['external_ids']);
|
||||||
|
})->map(function ($result) {
|
||||||
|
$result = $this->serializer->denormalize($result, TmdbResult::class, context: ['media_type' => MediaType::Movie->value]);
|
||||||
|
return $result;
|
||||||
|
})->slice(0, $resultCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function popularTvShows(int $resultCount = 6): Map
|
||||||
|
{
|
||||||
|
$results = $this->tvRepository->getApi()->getPopular();
|
||||||
|
return Map::from($results['results'])->map(function ($result) {
|
||||||
|
$result['external_ids'] = $this->getExternalIds($result['id'], MediaType::Movie->value);
|
||||||
|
return $result;
|
||||||
|
})->filter(function ($result) {
|
||||||
|
return array_key_exists('imdb_id', $result['external_ids']) && $result['external_ids']['imdb_id'] !== null && $result['external_ids']['imdb_id'] !== "";
|
||||||
|
})->map(function ($result) {
|
||||||
|
$result = $this->serializer->denormalize($result, TmdbResult::class, context: ['media_type' => MediaType::TvShow->value]);
|
||||||
|
return $result;
|
||||||
|
})->slice(0, $resultCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExternalIds(string $tmdbId, $mediaType)
|
||||||
|
{
|
||||||
|
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) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $externalIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,15 +2,22 @@
|
|||||||
|
|
||||||
namespace App\Tmdb;
|
namespace App\Tmdb;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Attribute\SerializedPath;
|
||||||
|
|
||||||
class TmdbResult
|
class TmdbResult
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
#[SerializedPath('[external_ids][imdb_id]')]
|
||||||
public ?string $imdbId = "",
|
public ?string $imdbId = "",
|
||||||
public ?string $tmdbId = "",
|
#[SerializedPath('[id]')]
|
||||||
|
public ?int $tmdbId = null,
|
||||||
|
#[SerializedPath('[title]')]
|
||||||
public ?string $title = "",
|
public ?string $title = "",
|
||||||
public ?string $poster = "",
|
#[SerializedPath('[overview]')]
|
||||||
public ?string $description = "",
|
public ?string $description = "",
|
||||||
public ?string $year = "",
|
public ?string $poster = "",
|
||||||
|
public ?\DateTimeInterface $premiereDate = null,
|
||||||
|
public ?string $year = null,
|
||||||
public ?string $mediaType = "",
|
public ?string $mediaType = "",
|
||||||
public ?array $episodes = null,
|
public ?array $episodes = null,
|
||||||
public ?string $episodeAirDate = null,
|
public ?string $episodeAirDate = null,
|
||||||
|
|||||||
108
src/Tmdb/TmdbResultDenormalizer.php
Normal file
108
src/Tmdb/TmdbResultDenormalizer.php
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Tmdb;
|
||||||
|
|
||||||
|
use App\Base\Enum\MediaType;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
use Symfony\Contracts\Cache\ItemInterface;
|
||||||
|
|
||||||
|
class TmdbResultDenormalizer implements DenormalizerInterface
|
||||||
|
{
|
||||||
|
const POSTER_IMG_PATH = "https://image.tmdb.org/t/p/w500";
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
#[Autowire(service: 'serializer.normalizer.object')]
|
||||||
|
private readonly NormalizerInterface $normalizer,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): TmdbResult|array|null
|
||||||
|
{
|
||||||
|
$parsers = [
|
||||||
|
MediaType::Movie->value => 'parseMovie',
|
||||||
|
MediaType::TvShow->value => 'parseTvShow',
|
||||||
|
'tvepisodes' => 'parseEpisode',
|
||||||
|
];
|
||||||
|
|
||||||
|
$denormalized = $this->normalizer->denormalize($data, TmdbResult::class, $format, $context);
|
||||||
|
return $this->{$parsers[$context['media_type']]}($data, $denormalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseTvShow(array $data, TmdbResult $result): TmdbResult
|
||||||
|
{
|
||||||
|
if (!in_array($data['first_air_date'], ['', null,])) {
|
||||||
|
$airDate = (new \DateTime($data['first_air_date']));
|
||||||
|
} else {
|
||||||
|
$airDate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->premiereDate = $airDate;
|
||||||
|
$result->poster = (null !== $data['poster_path']) ? self::POSTER_IMG_PATH . $data['poster_path'] : null;
|
||||||
|
$result->year = (null !== $airDate) ? $airDate->format('Y') : null;
|
||||||
|
$result->mediaType = "tvshows";
|
||||||
|
if (array_key_exists('episodes', $data)) {
|
||||||
|
$result->episodes = $data['episodes'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseMovie(array $data, TmdbResult $result): TmdbResult
|
||||||
|
{
|
||||||
|
if (!in_array($data['release_date'], ['', null,])) {
|
||||||
|
$airDate = (new \DateTime($data['release_date']));
|
||||||
|
} else {
|
||||||
|
$airDate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->premiereDate = $airDate;
|
||||||
|
$result->poster = (null !== $data['poster_path']) ? self::POSTER_IMG_PATH . $data['poster_path'] : null;
|
||||||
|
$result->year = (null !== $airDate) ? $airDate->format('Y') : null;
|
||||||
|
$result->mediaType = "movies";
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseEpisode(array $data, TmdbResult $result): TmdbResult
|
||||||
|
{
|
||||||
|
if (!in_array($data['air_date'], ['', null,])) {
|
||||||
|
$airDate = (new \DateTime($data['air_date']));
|
||||||
|
} else {
|
||||||
|
$airDate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->premiereDate = $airDate;
|
||||||
|
$result->episodeAirDate = $airDate;
|
||||||
|
$result->poster = (null !== $data['still_path']) ? self::POSTER_IMG_PATH . $data['still_path'] : null;
|
||||||
|
$result->year = (null !== $airDate) ? $airDate->format('Y') : null;
|
||||||
|
$result->mediaType = "tvshows";
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function supportsDenormalization(
|
||||||
|
mixed $data,
|
||||||
|
string $type,
|
||||||
|
?string $format = null,
|
||||||
|
array $context = []
|
||||||
|
): bool {
|
||||||
|
return $type === TmdbResult::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getSupportedTypes(?string $format): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
TmdbResult::class => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user