Tmdb   F
last analyzed

Complexity

Total Complexity 47

Size/Duplication

Total Lines 326
Duplicated Lines 7.36 %

Coupling/Cohesion

Components 1
Dependencies 23

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 23
dl 24
loc 326
ccs 0
cts 255
cp 0
rs 3.8405
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 22 3
C getByImdbId() 0 67 17
D getMovie() 12 63 9
D getTvShow() 12 75 9
F searchByTitle() 0 45 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Tmdb often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Tmdb, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * xMDB-API
4
 *
5
 * Copyright © 2017 pudelek.org.pl
6
 *
7
 * @license MIT License (MIT)
8
 *
9
 * For the full copyright and license information, please view source file
10
 * that is bundled with this package in the file LICENSE
11
 *
12
 * @author Marcin Pudełek <[email protected]>
13
 */
14
15
/**
16
 * Created by Marcin.
17
 * Date: 29.11.2017
18
 * Time: 21:54
19
 */
20
21
namespace mrcnpdlk\Xmdb;
22
23
24
use Carbon\Carbon;
25
use mrcnpdlk\Xmdb\Exception\NotFound;
26
use mrcnpdlk\Xmdb\Model\Tmdb\Company;
27
use mrcnpdlk\Xmdb\Model\Tmdb\Country;
28
use mrcnpdlk\Xmdb\Model\Tmdb\Genre;
29
use mrcnpdlk\Xmdb\Model\Tmdb\Language;
30
use mrcnpdlk\Xmdb\Model\Tmdb\Movie\Collection;
31
use mrcnpdlk\Xmdb\Model\Tmdb\Movie\Title as MovieTitle;
32
use mrcnpdlk\Xmdb\Model\Tmdb\Person;
33
use mrcnpdlk\Xmdb\Model\Tmdb\Title;
34
use mrcnpdlk\Xmdb\Model\Tmdb\TvShow\Network;
35
use mrcnpdlk\Xmdb\Model\Tmdb\TvShow\Season;
36
use mrcnpdlk\Xmdb\Model\Tmdb\TvShow\Title as TvShowTitle;
37
use RuntimeException;
38
use Tmdb\ApiToken;
39
use Tmdb\Exception\TmdbApiException;
40
41
class Tmdb
42
{
43
    /**
44
     * @var \mrcnpdlk\Xmdb\Client
45
     */
46
    private $oClient;
47
    /**
48
     * @var \Tmdb\Client
49
     */
50
    private $oTmdbClient;
51
    /**
52
     * @var \Psr\Log\LoggerInterface
53
     */
54
    private $oLog;
55
56
    /**
57
     * Tmdb constructor.
58
     *
59
     * @param \mrcnpdlk\Xmdb\Client $oClient
60
     *
61
     * @throws \mrcnpdlk\Xmdb\Exception
62
     */
63
    public function __construct(Client $oClient)
64
    {
65
        $this->oClient = $oClient;
66
        $this->oLog    = $oClient->getLogger();
67
        try {
68
            if (null === $this->oTmdbClient) {
69
                $options = [
70
                    'cache' => [
71
                        'enabled' => true,
72
                    ],
73
                    'log'   => [
74
                        'enabled' => true,
75
                    ],
76
                ];
77
78
                $oToken            = new ApiToken($this->oClient->getTmdbToken());
79
                $this->oTmdbClient = new \Tmdb\Client($oToken, $options);
80
            }
81
        } catch (\Exception $e) {
82
            throw new Exception(sprintf('Cannot create Tmdb Client'), 1, $e);
83
        }
84
    }
85
86
    /**
87
     * @param string|null $imdbId
88
     *
89
     * @return Title
90
     * @throws \mrcnpdlk\Xmdb\Exception\NotFound Title not found
91
     * @throws \mrcnpdlk\Xmdb\Exception
92
     */
93
    public function getByImdbId(string $imdbId = null)
94
    {
95
        try {
96
            $this->oLog->info(sprintf('Searching: %s', $imdbId));
97
            if ($imdbId === null || $imdbId === '') {
98
                throw new RuntimeException('ImdbId is require!');
99
            }
100
101
            $oTitle = new Title();
102
            $find   = $this->oTmdbClient
103
                ->getFindApi()
104
                ->findBy($imdbId, [
105
                    'external_source' => 'imdb_id',
106
                    'language'        => $this->oClient->getLang(),
107
                    'include_adult'   => true,
108
                ])
109
            ;
110
            if (!empty($find['movie_results']) && \count($find['movie_results']) === 1) {
111
                $item = $find['movie_results'][0];
112
113
                $oTitle->isAdult      = isset($item['adult']) ? (bool)$item['adult'] : false;
114
                $oTitle->title        = $item['title'];
115
                $oTitle->titleOrg     = $item['original_title'];
116
                $oTitle->titleOrgLang = $item['original_language'];
117
                $oTitle->id           = $item['id'];
118
                $oTitle->imdbId       = $imdbId;
119
                $oTitle->backdrop     = $item['backdrop_path'];
120
                $oTitle->poster       = $item['poster_path'];
121
                $oTitle->releaseDate  = $item['release_date'];
122
                $oTitle->rating       = $item['vote_average'];
123
                $oTitle->voteCount    = $item['vote_count'];
124
                $oTitle->popularity   = $item['popularity'];
125
                $oTitle->isMovie      = true;
126
                $oTitle->overview     = $item['overview'];
127
                $oTitle->releaseYear  = $oTitle->releaseDate ? Carbon::parse($oTitle->releaseDate)->format('Y') : null;
128
            } elseif (!empty($find['tv_results']) && \count($find['tv_results']) === 1) {
129
                $item = $find['tv_results'][0];
130
131
                $oTitle->isAdult      = isset($item['adult']) ? (bool)$item['adult'] : false;
132
                $oTitle->title        = $item['name'];
133
                $oTitle->titleOrg     = $item['original_name'];
134
                $oTitle->titleOrgLang = $item['original_language'];
135
                $oTitle->id           = $item['id'];
136
                $oTitle->imdbId       = $imdbId;
137
                $oTitle->backdrop     = $item['backdrop_path'];
138
                $oTitle->poster       = $item['poster_path'];
139
                $oTitle->releaseDate  = $item['first_air_date'];
140
                $oTitle->rating       = $item['vote_average'];
141
                $oTitle->voteCount    = $item['vote_count'];
142
                $oTitle->popularity   = $item['popularity'];
143
                $oTitle->isMovie      = false;
144
                $oTitle->overview     = $item['overview'];
145
                $oTitle->releaseYear  = $oTitle->releaseDate ? Carbon::parse($oTitle->releaseDate)->format('Y') : null;
146
            } elseif (!empty($find['tv_results']) && !empty($find['movie_results']) && \count($find['movie_results']) === 1  && \count($find['tv_results']) === 1
147
                ) {
148
                throw new RuntimeException('Too many items in TMDB database');
149
            } else {
150
                throw new NotFound('TMDB response empty');
151
            }
152
153
            return $oTitle;
154
        } catch (NotFound $e) {
155
            throw $e;
156
        } catch (\Exception $e) {
157
            throw new Exception($e->getMessage());
158
        }
159
    }
160
161
    /**
162
     * @param int $id
163
     *
164
     * @return \mrcnpdlk\Xmdb\Model\Tmdb\Movie\Title
165
     * @throws \mrcnpdlk\Xmdb\Exception\NotFound
166
     * @throws \mrcnpdlk\Xmdb\Exception
167
     */
168
    public function getMovie(int $id): Model\Tmdb\Movie\Title
169
    {
170
        try {
171
            $tData                = $this->oTmdbClient->getMoviesApi()->getMovie($id, [
172
                'language'      => $this->oClient->getLang(),
173
                'include_adult' => true,
174
            ])
175
            ;
176
            $oTitle               = new MovieTitle();
177
            $oTitle->id           = $id;
178
            $oTitle->title        = $tData['title'];
179
            $oTitle->titleOrg     = $tData['original_title'];
180
            $oTitle->titleOrgLang = $tData['original_language'];
181
            $oTitle->isVideo      = $tData['video'];
182
            $oTitle->isAdult      = $tData['adult'];
183
            $oTitle->imdbId       = $tData['imdb_id'];
184
            $oTitle->backdrop     = $tData['backdrop_path'];
185
            $oTitle->poster       = $tData['poster_path'];
186
            $oTitle->releaseDate  = $tData['release_date'];
187
            $oTitle->releaseYear  = null;
188
            $oTitle->rating       = $tData['vote_average'];
189
            $oTitle->voteCount    = $tData['vote_count'];
190
            $oTitle->popularity   = $tData['popularity'];
191
            $oTitle->overview     = $tData['overview'];
192
            $oTitle->homepage     = $tData['homepage'];
193
            $oTitle->budget       = $tData['budget'];
194
            $oTitle->revenue      = $tData['revenue'];
195
            $oTitle->runtime      = $tData['runtime'];
196
            $oTitle->status       = $tData['status'];
197
            $oTitle->tagline      = $tData['tagline'];
198
199 View Code Duplication
            foreach ($tData['genres'] ?? [] as $g) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
                $oTitle->genres[] = new Genre($g['id'], $g['name']);
201
            }
202 View Code Duplication
            foreach ($tData['production_companies'] ?? [] as $c) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
203
                $oTitle->productionCompanies[] = new Company($c['id'], $c['name']);
204
            }
205
            foreach ($tData['production_countries'] ?? [] as $g) {
206
                $oTitle->productionCountries[] = new Country($g['iso_3166_1'], $g['name']);
207
            }
208
            foreach ($tData['spoken_languages'] ?? [] as $g) {
209
                $oTitle->spokenLanguages[] = new Language($g['iso_639_1'], $g['name']);
210
            }
211
            if (!empty($tData['belongs_to_collection'])) {
212
                $oTitle->collection = new Collection(
213
                    $tData['belongs_to_collection']['id'],
214
                    $tData['belongs_to_collection']['name'],
215
                    $tData['belongs_to_collection']['poster_path'],
216
                    $tData['belongs_to_collection']['backdrop_path']);
217
            }
218
219
            return $oTitle;
220
        } catch (\Exception $e) {
221 View Code Duplication
            if ($e instanceof TmdbApiException) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
                if ($e->getCode() === 34) {
223
                    throw new NotFound($e->getMessage());
224
                }
225
                throw new Exception(sprintf('TMDB Response Error: %s', $e->getMessage()));
226
            }
227
228
            throw new Exception($e->getMessage());
229
        }
230
    }
231
232
    /**
233
     * @param int $id
234
     *
235
     * @return \mrcnpdlk\Xmdb\Model\Tmdb\TvShow\Title
236
     * @throws \mrcnpdlk\Xmdb\Exception\NotFound
237
     * @throws \mrcnpdlk\Xmdb\Exception
238
     */
239
    public function getTvShow(int $id): TvShowTitle
240
    {
241
        try {
242
            $tData = $this->oTmdbClient
243
                ->getTvApi()
244
                ->getTvshow($id, [
245
                    'language'           => $this->oClient->getLang(),
246
                    'include_adult'      => true,
247
                    'append_to_response' => 'external_ids',
248
                ])
249
            ;
250
251
            $oTitle                  = new TvShowTitle();
252
            $oTitle->id              = $id;
253
            $oTitle->title           = $tData['name'];
254
            $oTitle->titleOrg        = $tData['original_name'];
255
            $oTitle->titleOrgLang    = $tData['original_language'];
256
            $oTitle->inProduction    = $tData['in_production'];
257
            $oTitle->imdbId          = $tData['external_ids']['imdb_id'] ?? null;
258
            $oTitle->backdrop        = $tData['backdrop_path'];
259
            $oTitle->poster          = $tData['poster_path'];
260
            $oTitle->firstAirDate    = $tData['first_air_date'];
261
            $oTitle->lastAirDate     = $tData['last_air_date'];
262
            $oTitle->rating          = $tData['vote_average'];
263
            $oTitle->voteCount       = $tData['vote_count'];
264
            $oTitle->popularity      = $tData['popularity'];
265
            $oTitle->overview        = $tData['overview'];
266
            $oTitle->homepage        = $tData['homepage'];
267
            $oTitle->episodeRuntimes = $tData['episode_run_time'];
268
            $oTitle->status          = $tData['status'];
269
            $oTitle->type            = $tData['type'];
270
            $oTitle->languages       = $tData['languages'];
271
            $oTitle->episodesNumber  = $tData['number_of_episodes'];
272
            $oTitle->seasonsNumber   = $tData['number_of_seasons'];
273
            $oTitle->originCountries = $tData['origin_country'];
274
275 View Code Duplication
            foreach ($tData['genres'] ?? [] as $item) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
276
                $oTitle->genres[] = new Genre($item['id'], $item['name']);
277
            }
278
            foreach ($tData['networks'] ?? [] as $item) {
279
                $oTitle->networks[] = new Network($item['id'], $item['name']);
280
            }
281 View Code Duplication
            foreach ($tData['production_companies'] ?? [] as $item) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
282
                $oTitle->productionCompanies[] = new Company($item['id'], $item['name']);
283
            }
284
            foreach ($tData['seasons'] ?? [] as $item) {
285
                $oTitle->seasons[] = new Season(
286
                    $item['id'],
287
                    $item['season_number'],
288
                    $item['episode_count'],
289
                    $item['air_date'],
290
                    $item['poster_path']
291
                );
292
            }
293
            foreach ($tData['created_by'] ?? [] as $item) {
294
                $oTitle->createdBy[] = new Person(
295
                    $item['id'],
296
                    $item['name'],
297
                    $item['gender'],
298
                    $item['profile_path']
299
                );
300
            }
301
302
            return $oTitle;
303
        } catch (\Exception $e) {
304 View Code Duplication
            if ($e instanceof TmdbApiException) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
                if ($e->getCode() === 34) {
306
                    throw new NotFound($e->getMessage());
307
                }
308
                throw new Exception(sprintf('TMDB Response Error: %s', $e->getMessage()));
309
            }
310
311
            throw new Exception($e->getMessage());
312
        }
313
    }
314
315
    /**
316
     * @param string $title
317
     *
318
     * @return array|\mrcnpdlk\Xmdb\Model\Tmdb\Title[]
319
     * @throws \mrcnpdlk\Xmdb\Exception
320
     */
321
    public function searchByTitle(string $title)
322
    {
323
        try {
324
            /**
325
             * @var Title[] $answer
326
             */
327
            $answer = [];
328
            $tList  = $this->oTmdbClient
329
                ->getSearchApi()
330
                ->searchMulti($title, [
331
                    'page'          => 1,
332
                    'language'      => $this->oClient->getLang(),
333
                    'include_adult' => true,
334
                ])
335
            ;
336
            foreach ($tList['results'] ?? [] as $item) {
337
                if (\in_array($item['media_type'], ['tv', 'movie'], true)) {
338
                    $oTitle               = new Title();
339
                    $oTitle->id           = $item['id'];
340
                    $oTitle->isMovie      = $item['media_type'] === 'movie';
341
                    $oTitle->isAdult      = $item['adult'] ?? null;
342
                    $oTitle->title        = $oTitle->isMovie ? $item['title'] : $item['name'];
343
                    $oTitle->titleOrg     = $oTitle->isMovie ? $item['original_title'] : $item['original_name'];
344
                    $oTitle->titleOrgLang = $item['original_language'];
345
                    $oTitle->backdrop     = $item['backdrop_path'];
346
                    $oTitle->poster       = $item['poster_path'];
347
                    $oTitle->releaseDate  = $oTitle->isMovie ? $item['release_date'] : $item['first_air_date'];
348
                    $oTitle->rating       = $item['vote_average'];
349
                    $oTitle->voteCount    = $item['vote_count'];
350
                    $oTitle->popularity   = $item['popularity'];
351
                    $oTitle->overview     = $item['overview'];
352
                    $oTitle->releaseYear  = $oTitle->releaseDate ? Carbon::parse($oTitle->releaseDate)->format('Y') : null;
353
354
                    $answer[] = $oTitle;
355
                }
356
            }
357
358
            return $answer;
359
        } catch (\Exception $e) {
360
            if ($e instanceof TmdbApiException) {
361
                throw new Exception(sprintf('TMDB Response Error: %s', $e->getMessage()));
362
            }
363
            throw new Exception($e->getMessage());
364
        }
365
    }
366
}
367