Completed
Push — master ( 5416cd...d3c65f )
by Valentyn
03:14
created

TmdbSearchService   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 288
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 55.78%

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 7
dl 0
loc 288
ccs 53
cts 95
cp 0.5578
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A findMoviesByQuery() 0 14 1
A findMovieById() 0 24 1
A findActorsByMovieId() 0 11 1
A findActorById() 0 20 1
A findActorTranslationsById() 0 13 1
A findMovieTranslationsById() 0 10 1
A findSimilarMoviesById() 0 11 1
B request() 0 41 6
A arrayAsString() 0 13 3
A getCacheKeyFromParams() 0 6 1
A getResponseFromCache() 0 8 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Movies\Service;
6
7
use App\Movies\Exception\TmdbMovieNotFoundException;
8
use App\Movies\Exception\TmdbRequestLimitException;
9
use GuzzleHttp\ClientInterface;
10
use GuzzleHttp\Exception\GuzzleException;
11
use Psr\Log\LoggerInterface;
12
use Psr\SimpleCache\CacheInterface;
13
14
// todo refactor cache usage
15
class TmdbSearchService
16
{
17
    private $apiKey;
18
    private $client;
19
    private $logger;
20
    private $cache;
21
    private const ApiUrl = 'https://api.themoviedb.org/3';
22
23 9
    public function __construct(LoggerInterface $logger, ClientInterface $client, CacheInterface $cache)
24
    {
25 9
        $this->apiKey = \getenv('MOVIE_DB_API_KEY'); // is it ok to use \getenv() here?
26 9
        $this->client = $client;
27 9
        $this->logger = $logger;
28 9
        $this->cache = $cache;
29 9
    }
30
31
    /**
32
     * @param string $query
33
     * @param string $locale
34
     * @param array  $data
35
     *
36
     * @throws TmdbMovieNotFoundException
37
     * @throws TmdbRequestLimitException
38
     * @throws \Psr\SimpleCache\InvalidArgumentException
39
     *
40
     * @return array
41
     */
42 1
    public function findMoviesByQuery(string $query, string $locale = 'en', $data = []): array
43
    {
44 1
        $data = array_merge([
45 1
            'api_key' => $this->apiKey,
46 1
            'language' => $locale,
47 1
            'query' => $query,
48 1
        ], $data);
49
50 1
        $movies = $this->request('/search/movie', 'GET', [
51 1
            'query' => $data,
52
        ]);
53
54 1
        return $movies;
55
    }
56
57
    /**
58
     * @param int    $tmdb_id
59
     * @param string $locale
60
     *
61
     * @throws TmdbMovieNotFoundException
62
     * @throws TmdbRequestLimitException
63
     * @throws \Psr\SimpleCache\InvalidArgumentException
64
     *
65
     * @return array
66
     */
67 1
    public function findMovieById(int $tmdb_id, string $locale = 'en'): array
68
    {
69 1
        $movie = $this->request("/movie/{$tmdb_id}", 'GET', [
70
            'query' => [
71 1
                'api_key' => $this->apiKey,
72 1
                'language' => $locale,
73 1
                'append_to_response' => 'similar,translations,credits',
74
            ],
75
        ]);
76
77 1
        $similarUrl = "/movie/{$tmdb_id}/similar";
78 1
        $params = ['api_key' => $this->apiKey, 'page' => 1];
79 1
        $this->cache->set($this->getCacheKeyFromParams($similarUrl, 'GET', ['query' => $params]), json_encode($movie['similar']), 1800);
80
81 1
        $translationsUrl = "/movie/{$tmdb_id}/translations";
82 1
        $params = ['api_key' => $this->apiKey];
83 1
        $this->cache->set($this->getCacheKeyFromParams($translationsUrl, 'GET', ['query' => $params]), json_encode($movie['translations']), 1800);
84
85 1
        $creditsUrl = "/movie/{$tmdb_id}/credits";
86 1
        $params = ['api_key' => $this->apiKey, 'language' => $locale];
87 1
        $this->cache->set($this->getCacheKeyFromParams($creditsUrl, 'GET', ['query' => $params]), json_encode($movie['credits']), 1800);
88
89 1
        return $movie;
90
    }
91
92
    /**
93
     * @param int    $movieId
94
     * @param string $locale
95
     *
96
     * @throws TmdbMovieNotFoundException
97
     * @throws TmdbRequestLimitException
98
     * @throws \Psr\SimpleCache\InvalidArgumentException
99
     *
100
     * @return array
101
     */
102
    public function findActorsByMovieId(int $movieId, string $locale = 'en'): array
103
    {
104
        $actors = $this->request("/movie/{$movieId}/credits", 'GET', [
105
            'query' => [
106
                'api_key' => $this->apiKey,
107
                'language' => $locale,
108
            ],
109
        ]);
110
111
        return $actors;
112
    }
113
114
    /**
115
     * @param int    $personId
116
     * @param string $locale
117
     *
118
     * @throws TmdbMovieNotFoundException
119
     * @throws TmdbRequestLimitException
120
     * @throws \Psr\SimpleCache\InvalidArgumentException
121
     *
122
     * @return array
123
     */
124
    public function findActorById(int $personId, string $locale = 'en'): array
125
    {
126
        $actor = $this->request("/person/{$personId}", 'GET', [
127
            'query' => [
128
                'api_key' => $this->apiKey,
129
                'language' => $locale,
130
                'append_to_response' => 'translations',
131
            ],
132
        ]);
133
134
        // todo uncomment after solving: https://www.themoviedb.org/talk/5b6dc17d92514140541358bd
135
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
136
        if (count($actor['translations'])) {
137
            $translationsUrl = "/person/{$personId}/translations";
138
            $params = ['api_key' => $this->apiKey, 'language' => $locale];
139
            $this->cache->set($this->getCacheKeyFromParams($translationsUrl, 'GET', ['query' => $params]), json_encode($actor['translations']), 1800);
140
        }*/
141
142
        return $actor;
143
    }
144
145
    /**
146
     * @param int    $personId
147
     * @param string $locale
148
     *
149
     * @throws TmdbMovieNotFoundException
150
     * @throws TmdbRequestLimitException
151
     * @throws \Psr\SimpleCache\InvalidArgumentException
152
     *
153
     * @return array
154
     */
155
    public function findActorTranslationsById(int $personId, string $locale = 'en'): array
156
    {
157
        $actors = $this->request("/person/{$personId}/translations", 'GET', [
158
            'query' => [
159
                'api_key' => $this->apiKey,
160
                'language' => $locale,
161
            ],
162
        ]);
163
164
        echo var_export($actors); exit;
165
166
        return $actors;
0 ignored issues
show
Unused Code introduced by
return $actors; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
167
    }
168
169
    /**
170
     * @param int $tmdb_id
171
     *
172
     * @throws TmdbMovieNotFoundException
173
     * @throws TmdbRequestLimitException
174
     * @throws \Psr\SimpleCache\InvalidArgumentException
175
     *
176
     * @return array
177
     */
178
    public function findMovieTranslationsById(int $tmdb_id): array
179
    {
180
        $movie = $this->request("/movie/{$tmdb_id}/translations", 'GET', [
181
            'query' => [
182
                'api_key' => $this->apiKey,
183
            ],
184
        ]);
185
186
        return $movie;
187
    }
188
189
    /**
190
     * @param int $tmdb_id
191
     * @param int $page
192
     *
193
     * @throws TmdbMovieNotFoundException
194
     * @throws TmdbRequestLimitException
195
     * @throws \Psr\SimpleCache\InvalidArgumentException
196
     *
197
     * @return array
198
     */
199
    public function findSimilarMoviesById(int $tmdb_id, int $page = 1): array
200
    {
201
        $movie = $this->request("/movie/{$tmdb_id}/similar", 'GET', [
202
            'query' => [
203
                'api_key' => $this->apiKey,
204
                'page' => $page,
205
            ],
206
        ]);
207
208
        return $movie;
209
    }
210
211
    /**
212
     * @param string $url
213
     * @param string $method
214
     * @param array  $params
215
     *
216
     * @throws TmdbMovieNotFoundException
217
     * @throws TmdbRequestLimitException
218
     * @throws \Psr\SimpleCache\InvalidArgumentException
219
     *
220
     * @return array
221
     */
222 2
    private function request(string $url, string $method = 'GET', array $params = []): array
223
    {
224 2
        if (null !== $cachedResponse = $this->getResponseFromCache($url, $method, $params)) {
225
            return $cachedResponse;
226
        }
227
228 2
        $url = self::ApiUrl.$url;
229
230
        try {
231 2
            $response = $this->client->request($method, $url, $params);
232 2
            $responseJson = $response->getBody()->getContents();
233 2
            $response = json_decode($responseJson, true);
234 2
            $this->cache->set($this->getCacheKeyFromParams($url, $method, $params), $responseJson, 1800);
235 2
            getenv('APP_ENV') === 'dev' && $this->logger->debug('Guzzle request:', [
236
                'url' => $url,
237
                'method' => $method,
238
                'params' => $params,
239 2
                'response' => $response,
240
            ]);
241
        } catch (GuzzleException $exception) {
242
            $this->logger->error('Guzzle request failed.', [
243
                'url' => $url,
244
                'method' => $method,
245
                'params' => $params,
246
                'exceptionMessage' => $exception->getMessage(),
247
                'exceptionCode' => $exception->getCode(),
248
            ]);
249
250
            $response = [];
251
252
            if ($exception->getCode() === 404) {
253
                throw new TmdbMovieNotFoundException();
254
            }
255
256
            if ($exception->getCode() === 429) {
257
                throw new TmdbRequestLimitException();
258
            }
259
        }
260
261 2
        return $response;
262
    }
263
264 2
    private function arrayAsString(array $array): string
265
    {
266 2
        $string = '';
267
268 2
        foreach ($array as $key => $value) {
269 2
            if (is_array($value) === true) {
270 2
                $value = $this->arrayAsString($value);
271
            }
272 2
            $string .= "$key-$value";
273
        }
274
275 2
        return $string;
276
    }
277
278 2
    private function getCacheKeyFromParams(string $url, string $method = 'GET', array $params = []): string
279
    {
280 2
        $key = md5($url.mb_strtolower($method).$this->arrayAsString($params));
281
282 2
        return $key;
283
    }
284
285
    /**
286
     * @param string $url
287
     * @param string $method
288
     * @param array  $params
289
     *
290
     * @throws \Psr\SimpleCache\InvalidArgumentException
291
     *
292
     * @return array|null
293
     */
294 2
    private function getResponseFromCache(string $url, string $method = 'GET', array $params = []): ?array
295
    {
296 2
        if (null !== $response = $this->cache->get($this->getCacheKeyFromParams($url, $method, $params))) {
297
            return json_decode($response, true);
298
        }
299
300 2
        return $response;
301
    }
302
}
303