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
|
|
|
$translationsUrl = "/person/{$personId}/translations"; |
135
|
|
|
$params = ['api_key' => $this->apiKey, 'language' => $locale]; |
136
|
|
|
$this->cache->set($this->getCacheKeyFromParams($translationsUrl, 'GET', ['query' => $params]), json_encode($actor['translations']), 1800); |
137
|
|
|
|
138
|
|
|
return $actor; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* @param int $personId |
143
|
|
|
* @param string $locale |
144
|
|
|
* |
145
|
|
|
* @throws TmdbMovieNotFoundException |
146
|
|
|
* @throws TmdbRequestLimitException |
147
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
148
|
|
|
* |
149
|
|
|
* @return array |
150
|
|
|
*/ |
151
|
|
|
public function findActorTranslationsById(int $personId, string $locale = 'en'): array |
152
|
|
|
{ |
153
|
|
|
$actors = $this->request("/person/{$personId}/translations", 'GET', [ |
154
|
|
|
'query' => [ |
155
|
|
|
'api_key' => $this->apiKey, |
156
|
|
|
'language' => $locale, |
157
|
|
|
], |
158
|
|
|
]); |
159
|
|
|
|
160
|
|
|
echo var_export($actors); exit; |
161
|
|
|
|
162
|
|
|
return $actors; |
|
|
|
|
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* @param int $tmdb_id |
167
|
|
|
* |
168
|
|
|
* @throws TmdbMovieNotFoundException |
169
|
|
|
* @throws TmdbRequestLimitException |
170
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
171
|
|
|
* |
172
|
|
|
* @return array |
173
|
|
|
*/ |
174
|
|
|
public function findMovieTranslationsById(int $tmdb_id): array |
175
|
|
|
{ |
176
|
|
|
$movie = $this->request("/movie/{$tmdb_id}/translations", 'GET', [ |
177
|
|
|
'query' => [ |
178
|
|
|
'api_key' => $this->apiKey, |
179
|
|
|
], |
180
|
|
|
]); |
181
|
|
|
|
182
|
|
|
return $movie; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* @param int $tmdb_id |
187
|
|
|
* @param int $page |
188
|
|
|
* |
189
|
|
|
* @throws TmdbMovieNotFoundException |
190
|
|
|
* @throws TmdbRequestLimitException |
191
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
192
|
|
|
* |
193
|
|
|
* @return array |
194
|
|
|
*/ |
195
|
|
|
public function findSimilarMoviesById(int $tmdb_id, int $page = 1): array |
196
|
|
|
{ |
197
|
|
|
$movie = $this->request("/movie/{$tmdb_id}/similar", 'GET', [ |
198
|
|
|
'query' => [ |
199
|
|
|
'api_key' => $this->apiKey, |
200
|
|
|
'page' => $page, |
201
|
|
|
], |
202
|
|
|
]); |
203
|
|
|
|
204
|
|
|
return $movie; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* @param string $url |
209
|
|
|
* @param string $method |
210
|
|
|
* @param array $params |
211
|
|
|
* |
212
|
|
|
* @throws TmdbMovieNotFoundException |
213
|
|
|
* @throws TmdbRequestLimitException |
214
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
215
|
|
|
* |
216
|
|
|
* @return array |
217
|
|
|
*/ |
218
|
2 |
|
private function request(string $url, string $method = 'GET', array $params = []): array |
219
|
|
|
{ |
220
|
2 |
|
if (null !== $cachedResponse = $this->getResponseFromCache($url, $method, $params)) { |
221
|
|
|
return $cachedResponse; |
222
|
|
|
} |
223
|
|
|
|
224
|
2 |
|
$url = self::ApiUrl.$url; |
225
|
|
|
|
226
|
|
|
try { |
227
|
2 |
|
$response = $this->client->request($method, $url, $params); |
228
|
2 |
|
$responseJson = $response->getBody()->getContents(); |
229
|
2 |
|
$response = json_decode($responseJson, true); |
230
|
2 |
|
$this->cache->set($this->getCacheKeyFromParams($url, $method, $params), $responseJson, 1800); |
231
|
2 |
|
getenv('APP_ENV') === 'dev' && $this->logger->debug('Guzzle request:', [ |
232
|
|
|
'url' => $url, |
233
|
|
|
'method' => $method, |
234
|
|
|
'params' => $params, |
235
|
2 |
|
'response' => $response, |
236
|
|
|
]); |
237
|
|
|
} catch (GuzzleException $exception) { |
238
|
|
|
$this->logger->error('Guzzle request failed.', [ |
239
|
|
|
'url' => $url, |
240
|
|
|
'method' => $method, |
241
|
|
|
'params' => $params, |
242
|
|
|
'exceptionMessage' => $exception->getMessage(), |
243
|
|
|
'exceptionCode' => $exception->getCode(), |
244
|
|
|
]); |
245
|
|
|
|
246
|
|
|
$response = []; |
247
|
|
|
|
248
|
|
|
if ($exception->getCode() === 404) { |
249
|
|
|
throw new TmdbMovieNotFoundException(); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
if ($exception->getCode() === 429) { |
253
|
|
|
throw new TmdbRequestLimitException(); |
254
|
|
|
} |
255
|
|
|
} |
256
|
|
|
|
257
|
2 |
|
return $response; |
258
|
|
|
} |
259
|
|
|
|
260
|
2 |
|
private function arrayAsString(array $array): string |
261
|
|
|
{ |
262
|
2 |
|
$string = ''; |
263
|
|
|
|
264
|
2 |
|
foreach ($array as $key => $value) { |
265
|
2 |
|
if (is_array($value) === true) { |
266
|
2 |
|
$value = $this->arrayAsString($value); |
267
|
|
|
} |
268
|
2 |
|
$string .= "$key-$value"; |
269
|
|
|
} |
270
|
|
|
|
271
|
2 |
|
return $string; |
272
|
|
|
} |
273
|
|
|
|
274
|
2 |
|
private function getCacheKeyFromParams(string $url, string $method = 'GET', array $params = []): string |
275
|
|
|
{ |
276
|
2 |
|
$key = md5($url.mb_strtolower($method).$this->arrayAsString($params)); |
277
|
|
|
|
278
|
2 |
|
return $key; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* @param string $url |
283
|
|
|
* @param string $method |
284
|
|
|
* @param array $params |
285
|
|
|
* |
286
|
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException |
287
|
|
|
* |
288
|
|
|
* @return array|null |
289
|
|
|
*/ |
290
|
2 |
|
private function getResponseFromCache(string $url, string $method = 'GET', array $params = []): ?array |
291
|
|
|
{ |
292
|
2 |
|
if (null !== $response = $this->cache->get($this->getCacheKeyFromParams($url, $method, $params))) { |
293
|
|
|
return json_decode($response, true); |
294
|
|
|
} |
295
|
|
|
|
296
|
2 |
|
return $response; |
297
|
|
|
} |
298
|
|
|
} |
299
|
|
|
|
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
orexit
statements that have been added for debug purposes.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.