Completed
Push — master ( 4851fa...058e40 )
by Valentyn
04:07
created

TmdbSearchService::getResponseFromCache()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 2.0625
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 13
    public function __construct(LoggerInterface $logger, ClientInterface $client, CacheInterface $cache)
24
    {
25 13
        $this->apiKey = \getenv('MOVIE_DB_API_KEY'); // is it ok to use \getenv() here?
26 13
        $this->client = $client;
27 13
        $this->logger = $logger;
28 13
        $this->cache = $cache;
29 13
    }
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
        $translationsUrl = "/movie/{$tmdb_id}/translations";
82
        $params = ['api_key' => $this->apiKey];
83
        $this->cache->set($this->getCacheKeyFromParams($translationsUrl, 'GET', ['query' => $params]), json_encode($movie['translations']), 1800);
84
85
        $creditsUrl = "/movie/{$tmdb_id}/credits";
86
        $params = ['api_key' => $this->apiKey, 'language' => $locale];
87
        $this->cache->set($this->getCacheKeyFromParams($creditsUrl, 'GET', ['query' => $params]), json_encode($movie['credits']), 1800);
88
89
        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
        return $actors;
161
    }
162
163
    /**
164
     * @param int $tmdb_id
165
     *
166
     * @throws TmdbMovieNotFoundException
167
     * @throws TmdbRequestLimitException
168
     * @throws \Psr\SimpleCache\InvalidArgumentException
169
     *
170
     * @return array
171
     */
172
    public function findMovieTranslationsById(int $tmdb_id): array
173
    {
174
        $movie = $this->request("/movie/{$tmdb_id}/translations", 'GET', [
175
            'query' => [
176
                'api_key' => $this->apiKey,
177
            ],
178
        ]);
179
180
        return $movie;
181
    }
182
183
    /**
184
     * @param int $tmdb_id
185
     * @param int $page
186
     *
187
     * @throws TmdbMovieNotFoundException
188
     * @throws TmdbRequestLimitException
189
     * @throws \Psr\SimpleCache\InvalidArgumentException
190
     *
191
     * @return array
192
     */
193
    public function findSimilarMoviesById(int $tmdb_id, int $page = 1): array
194
    {
195
        $movie = $this->request("/movie/{$tmdb_id}/similar", 'GET', [
196
            'query' => [
197
                'api_key' => $this->apiKey,
198
                'page' => $page,
199
            ],
200
        ]);
201
202
        return $movie;
203
    }
204
205
    /**
206
     * @param string $url
207
     * @param string $method
208
     * @param array  $params
209
     *
210
     * @throws TmdbMovieNotFoundException
211
     * @throws TmdbRequestLimitException
212
     * @throws \Psr\SimpleCache\InvalidArgumentException
213
     *
214
     * @return array
215
     */
216 2
    private function request(string $url, string $method = 'GET', array $params = []): array
217
    {
218 2
        if (null !== $cachedResponse = $this->getResponseFromCache($url, $method, $params)) {
219
            return $cachedResponse;
220
        }
221
222 2
        $url = self::ApiUrl.$url;
223
224
        try {
225 2
            $response = $this->client->request($method, $url, $params);
226 2
            $responseJson = $response->getBody()->getContents();
227 2
            $response = json_decode($responseJson, true);
228 2
            $this->cache->set($this->getCacheKeyFromParams($url, $method, $params), $responseJson, 1800);
229 2
            getenv('APP_ENV') === 'dev' && $this->logger->debug('Guzzle request:', [
230
                'url' => $url,
231
                'method' => $method,
232
                'params' => $params,
233 2
                'response' => $response,
234
            ]);
235
        } catch (GuzzleException $exception) {
236
            $this->logger->error('Guzzle request failed.', [
237
                'url' => $url,
238
                'method' => $method,
239
                'params' => $params,
240
                'exceptionMessage' => $exception->getMessage(),
241
                'exceptionCode' => $exception->getCode(),
242
            ]);
243
244
            $response = [];
245
246
            if ($exception->getCode() === 404) {
247
                throw new TmdbMovieNotFoundException();
248
            }
249
250
            if ($exception->getCode() === 429) {
251
                throw new TmdbRequestLimitException();
252
            }
253
        }
254
255 2
        return $response;
256
    }
257
258 2
    private function arrayAsString(array $array): string
259
    {
260 2
        $string = '';
261
262 2
        foreach ($array as $key => $value) {
263 2
            if (\is_array($value) === true) {
264 2
                $value = $this->arrayAsString($value);
265
            }
266 2
            $string .= "$key-$value";
267
        }
268
269 2
        return $string;
270
    }
271
272 2
    private function getCacheKeyFromParams(string $url, string $method = 'GET', array $params = []): string
273
    {
274 2
        $key = md5($url.mb_strtolower($method).$this->arrayAsString($params));
275
276 2
        return $key;
277
    }
278
279
    /**
280
     * @param string $url
281
     * @param string $method
282
     * @param array  $params
283
     *
284
     * @throws \Psr\SimpleCache\InvalidArgumentException
285
     *
286
     * @return array|null
287
     */
288 2
    private function getResponseFromCache(string $url, string $method = 'GET', array $params = []): ?array
289
    {
290 2
        if (null !== $response = $this->cache->get($this->getCacheKeyFromParams($url, $method, $params))) {
291
            return json_decode($response, true);
292
        }
293
294 2
        return $response;
295
    }
296
}
297