|
@@ -3,160 +3,75 @@
|
|
|
namespace App\Service;
|
|
namespace App\Service;
|
|
|
|
|
|
|
|
use App\Entity\Film;
|
|
use App\Entity\Film;
|
|
|
-use App\Entity\Genre;
|
|
|
|
|
-use App\Entity\MediaVideo;
|
|
|
|
|
-use App\Entity\Realisateur;
|
|
|
|
|
-use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
|
|
|
-use stdClass;
|
|
|
|
|
-
|
|
|
|
|
-class TmdbApiService
|
|
|
|
|
|
|
+use App\Service\Tmdb\FilmFactory;
|
|
|
|
|
+use App\Service\Tmdb\TmdbApiException;
|
|
|
|
|
+use App\Service\Tmdb\TmdbClient;
|
|
|
|
|
+use App\Service\Tmdb\TmdbMovie;
|
|
|
|
|
+use App\Service\Tmdb\TmdbSearchResult;
|
|
|
|
|
+use Psr\Log\LoggerInterface;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Orchestration TMDb pour l'application : recherche et mapping vers l'entité Film.
|
|
|
|
|
+ */
|
|
|
|
|
+final class TmdbApiService
|
|
|
{
|
|
{
|
|
|
- protected string $content = "";
|
|
|
|
|
- protected int $nbResults = 0;
|
|
|
|
|
- protected int $nbPages = 0;
|
|
|
|
|
- protected array $films = [];
|
|
|
|
|
-
|
|
|
|
|
public function __construct(
|
|
public function __construct(
|
|
|
- protected HttpClientInterface $tmdbClient,
|
|
|
|
|
- protected UniciteCollections $uc,
|
|
|
|
|
|
|
+ protected TmdbClient $client,
|
|
|
|
|
+ protected FilmFactory $filmFactory,
|
|
|
|
|
+ protected LoggerInterface $logger,
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
|
- public function query(string $titre, int $page = 1): bool
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Recherche par titre. Les fiches détaillées sont récupérées en parallèle
|
|
|
|
|
+ * afin d'obtenir genres, réalisateurs et bande-annonce.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @throws TmdbApiException si la recherche elle-même échoue
|
|
|
|
|
+ */
|
|
|
|
|
+ public function search(string $titre, int $page = 1): TmdbSearchResult
|
|
|
{
|
|
{
|
|
|
- try {
|
|
|
|
|
- $response = $this->tmdbClient->request("GET", "search/movie", [
|
|
|
|
|
- "query" => [
|
|
|
|
|
- "query" => $titre,
|
|
|
|
|
- "page" => $page,
|
|
|
|
|
- ],
|
|
|
|
|
- ]);
|
|
|
|
|
|
|
+ $result = $this->client->search($titre, $page);
|
|
|
|
|
|
|
|
- $this->content = $response->getContent();
|
|
|
|
|
- $this->jsonDecode();
|
|
|
|
|
- } catch (\Exception $e) {
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ $ids = [];
|
|
|
|
|
+ foreach ($result->movies as $movie) {
|
|
|
|
|
+ $ids[$movie->tmdbId] = $movie->tmdbId;
|
|
|
}
|
|
}
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ $details = $this->client->getMovies($ids);
|
|
|
|
|
|
|
|
- public function getDetailMovie(string $id): ?string
|
|
|
|
|
- {
|
|
|
|
|
- $detail = null;
|
|
|
|
|
- try {
|
|
|
|
|
- $response = $this->tmdbClient->request("GET", "movie/" . $id, [
|
|
|
|
|
- "query" => [
|
|
|
|
|
- "append_to_response" => "credits,videos",
|
|
|
|
|
- ],
|
|
|
|
|
- ]);
|
|
|
|
|
- $detail = $response->getContent();
|
|
|
|
|
- } catch (\Exception $e) {
|
|
|
|
|
- return null;
|
|
|
|
|
|
|
+ $movies = [];
|
|
|
|
|
+ foreach ($result->movies as $movie) {
|
|
|
|
|
+ $movies[$movie->tmdbId] = $details[$movie->tmdbId] ?? $movie;
|
|
|
}
|
|
}
|
|
|
- return $detail;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public function getFilms(): array
|
|
|
|
|
- {
|
|
|
|
|
- return $this->films;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public function countResults(): int
|
|
|
|
|
- {
|
|
|
|
|
- return $this->nbResults;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public function countPages(): int
|
|
|
|
|
- {
|
|
|
|
|
- return $this->nbPages;
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- protected function jsonDecode(): void
|
|
|
|
|
- {
|
|
|
|
|
- $json = json_decode($this->content);
|
|
|
|
|
-
|
|
|
|
|
- $this->nbResults = $json->total_results;
|
|
|
|
|
- $this->nbPages = $json->total_pages;
|
|
|
|
|
- $entrees = $json->results;
|
|
|
|
|
-
|
|
|
|
|
- foreach ($entrees as $entree) {
|
|
|
|
|
- $film = $this->hydrateFilm($entree->id);
|
|
|
|
|
-
|
|
|
|
|
- $this->films[$entree->id]["data"] = $film;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return $result->withMovies($movies);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Construit une entité Film depuis la fiche TMDb correspondante.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @throws TmdbApiException si la fiche est introuvable ou illisible
|
|
|
|
|
+ */
|
|
|
public function hydrateFilm(int $filmTmdbId): Film
|
|
public function hydrateFilm(int $filmTmdbId): Film
|
|
|
{
|
|
{
|
|
|
- $filmTmdb = json_decode($this->getDetailMovie($filmTmdbId));
|
|
|
|
|
- $film = new Film();
|
|
|
|
|
- $film->setTitre($filmTmdb->title)->setInformation($filmTmdb->overview);
|
|
|
|
|
-
|
|
|
|
|
- if (preg_match("/^\d{4}-\d{2}-\d{2}$/", $filmTmdb->release_date)) {
|
|
|
|
|
- $dateSortie = $filmTmdb->release_date;
|
|
|
|
|
- $annee = substr($dateSortie, 0, 4) . "-01-01";
|
|
|
|
|
- $film
|
|
|
|
|
- ->setDateSortie(new \DateTimeImmutable($dateSortie))
|
|
|
|
|
- ->setAnnee(new \DateTimeImmutable($annee));
|
|
|
|
|
- } elseif (preg_match("/^\d{4}/", $filmTmdb->release_date)) {
|
|
|
|
|
- $annee = substr($filmTmdb->release_date, 0, 4) . "-01-01";
|
|
|
|
|
- $film->setAnnee(new \DateTimeImmutable($annee));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- foreach ($filmTmdb->genres as $genre) {
|
|
|
|
|
- $film->addGenre(new Genre()->setName($genre->name));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- foreach ($this->getRealisateurs($filmTmdb) as $realisateur) {
|
|
|
|
|
- $film->addRealisateur($realisateur);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $videoTmdb = $this->getOneVideo($filmTmdb);
|
|
|
|
|
- if (!empty($videoTmdb)) {
|
|
|
|
|
- $video = new MediaVideo();
|
|
|
|
|
- $video->setFromTmdb($videoTmdb["type"], $videoTmdb["identif"]);
|
|
|
|
|
- $film->addMediaVideo($video);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $film = $this->uc->assureUniciteCollections($film);
|
|
|
|
|
- return $film;
|
|
|
|
|
|
|
+ return $this->filmFactory->createFilm($this->client->getMovie($filmTmdbId));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * @return array<int, Realisateur>
|
|
|
|
|
|
|
+ * Construit une entité Film à partir du film TMDb fourni (issu d'une recherche).
|
|
|
*/
|
|
*/
|
|
|
- public function getRealisateurs(stdClass $detailMovie): array
|
|
|
|
|
|
|
+ public function createFilm(TmdbMovie $movie): Film
|
|
|
{
|
|
{
|
|
|
- $directors = [];
|
|
|
|
|
- foreach ($detailMovie->credits->crew as $crew) {
|
|
|
|
|
- if ($crew->job === "Director") {
|
|
|
|
|
- $realisateur = new Realisateur();
|
|
|
|
|
- $realisateur->setNomComplet($crew->name);
|
|
|
|
|
- $directors[] = $realisateur;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return $directors;
|
|
|
|
|
|
|
+ return $this->filmFactory->createFilm($movie);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * @return array<string, string>
|
|
|
|
|
|
|
+ * Variante non levante : renvoie null et logge l'erreur au lieu de lever.
|
|
|
*/
|
|
*/
|
|
|
- public function getOneVideo(stdClass $detailMovie): array
|
|
|
|
|
|
|
+ public function findFilm(int $filmTmdbId): ?Film
|
|
|
{
|
|
{
|
|
|
- foreach ($detailMovie->videos->results as $video) {
|
|
|
|
|
- if (
|
|
|
|
|
- ($video->site === "YouTube" ||
|
|
|
|
|
- $video->site === "Vimeo" ||
|
|
|
|
|
- $video->site === "DailyMotion") &&
|
|
|
|
|
- $video->type === "Trailer" &&
|
|
|
|
|
- $video->iso_639_1 === "fr" &&
|
|
|
|
|
- $video->iso_3166_1 === "FR"
|
|
|
|
|
- ) {
|
|
|
|
|
- return [
|
|
|
|
|
- "type" => strtolower($video->site),
|
|
|
|
|
- "identif" => $video->key,
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ return $this->hydrateFilm($filmTmdbId);
|
|
|
|
|
+ } catch (TmdbApiException $e) {
|
|
|
|
|
+ return null;
|
|
|
}
|
|
}
|
|
|
- return [];
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|