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
|
|
|
/* |
|
|
|
|
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; |
|
|
|
|
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
|
|
|
|
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.