Tmdb   B
last analyzed

Complexity

Total Complexity 51

Size/Duplication

Total Lines 362
Duplicated Lines 0 %

Test Coverage

Coverage 99.19%

Importance

Changes 12
Bugs 0 Features 0
Metric Value
eloc 110
c 12
b 0
f 0
dl 0
loc 362
ccs 123
cts 124
cp 0.9919
rs 7.92
wmc 51

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A getRequest() 0 5 1
A postRequest() 0 5 1
A deleteRequest() 0 5 1
A sendRequest() 0 10 2
A decodeRequest() 0 17 4
A getLogger() 0 3 1
A __get() 0 7 2
A getConfiguration() 0 11 3
A buildHTTPUrl() 0 15 1
A checkOptionQuery() 0 4 2
A checkOptionSortBy() 0 11 4
A checkOptionSessionId() 0 4 2
A checkOptionIncludeAdult() 0 4 2
A checkOptionPage() 0 4 2
B checkOptionExternalSource() 0 16 10
A checkOptionLanguage() 0 9 4
A checkOptionYear() 0 4 2
A checkOptionDate() 0 5 2
A checkOptionDateRange() 0 11 4

How to fix   Complexity   

Complex Class

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.

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 declare(strict_types=1);
2
3
/**
4
 * This file is part of the Tmdb package.
5
 *
6
 * (c) Vincent Faliès <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @author Vincent Faliès <[email protected]>
12
 * @copyright Copyright (c) 2017
13
 */
14
15
namespace VfacTmdb;
16
17
use VfacTmdb\Interfaces\TmdbInterface;
18
use VfacTmdb\Interfaces\HttpRequestInterface;
19
use Psr\Log\LoggerInterface;
20
use VfacTmdb\Exceptions\TmdbException;
21
use VfacTmdb\Exceptions\IncorrectParamException;
22
use VfacTmdb\Exceptions\ServerErrorException;
23
24
/**
25
 * Tmdb wrapper core class
26
 * @package Tmdb
27
 * @author Vincent Faliès <[email protected]>
28
 * @copyright Copyright (c) 2017
29
 */
30
class Tmdb implements TmdbInterface
31
{
32
33
    /**
34
     * API Key
35
     * @var string
36
     */
37
    private $api_key = null;
38
39
    /**
40
     * API configuration
41
     * @var \stdClass
42
     */
43
    protected $configuration = null;
44
45
    /**
46
     * API Genres
47
     * @var \stdClass
48
     */
49
    protected $genres = null;
50
51
    /**
52
     * Base URL of the API
53
     * @var string
54
     */
55
    public $base_api_url = 'https://api.themoviedb.org/';
56
57
    /**
58
     * Logger
59
     * @var LoggerInterface
60
     */
61
    protected $logger = null;
62
63
    /**
64
     * API Version
65
     * @var int
66
     */
67
    protected $version = 3;
68
69
    /**
70
     * Http request object
71
     * @var HttpRequestInterface
72
     */
73
    protected $http_request = null;
74
    /**
75
     * Request object
76
     * @var \stdClass
77
     */
78
    protected $request;
79
    /**
80
     * Last request url
81
     * @var string
82
     */
83
    protected $url = null;
84
85
    /**
86
     * Constructor
87
     * @param string $api_key TMDB API Key
88
     * @param int $version Version of API (Not yet used)
89
     * @param LoggerInterface $logger Logger used in the class
90
     * @param HttpRequestInterface $http_request
91
     */
92 1386
    public function __construct(string $api_key, int $version, LoggerInterface $logger, HttpRequestInterface $http_request)
93
    {
94 1386
        $this->api_key      = $api_key;
95 1386
        $this->logger       = $logger;
96 1386
        $this->version      = $version;
97 1386
        $this->http_request = $http_request;
98 1386
        $this->request      = new \stdClass;
99 1386
    }
100
101
    /**
102
     * Send request to TMDB API with GET method
103
     * @param string $action API action to request
104
     * @param array $options Array of options of the request (optional)
105
     * @return \stdClass|null
106
     */
107 1206
    public function getRequest(string $action, array $options = array()) : ?\stdClass
108
    {
109 1206
        $this->logger->debug('Start sending HTTP request with GET method', array('action' => $action, 'options' => $options));
110 1206
        $this->url = $this->buildHTTPUrl($action, $options);
111 1206
        return $this->sendRequest('GET', $this->url);
112
    }
113
114
    /**
115
     * Send request to TMDB API with POST method
116
     * @param string $action API action to request
117
     * @param array $options Array of options of the request (optional)
118
     * @param array $form_params form_params for request options
119
     * @return \stdClass|null
120
     */
121 45
    public function postRequest(string $action, array $options = array(), array $form_params = array()) : ?\stdClass
122
    {
123 45
        $this->logger->debug('Start sending HTTP request with POST method', array('action' => $action, 'options' => $options, 'form_params' => $form_params));
124 45
        $this->url = $this->buildHTTPUrl($action, $options);
125 45
        return $this->sendRequest('POST', $this->url, $form_params);
126
    }
127
128
    /**
129
     * Send request to TMDB API with DELETE method
130
     * @param  string $action  API action to request
131
     * @param  array  $options Array of options of the request (optional)
132
     * @return \stdClass|null
133
     */
134 15
    public function deleteRequest(string $action, array $options = array()) : ?\stdClass
135
    {
136 15
        $this->logger->debug('Start sending HTTP request with DELETE method', array('action' => $action, 'options' => $options));
137 15
        $this->url = $this->buildHTTPUrl($action, $options);
138 15
        return $this->sendRequest('DELETE', $this->url);
139
    }
140
141
    /**
142
     * Send request to TMDB API with GET method
143
     * @param string $method HTTP method (GET, POST)
144
     * @param string $url API url to request
145
     * @param array $form_params form params request options
146
     * @return \stdClass|null
147
     */
148 18
    protected function sendRequest(string $method, string $url, array $form_params = array()) : ?\stdClass
149
    {
150
        try {
151 18
            $method_name = strtolower($method) . 'Response';
152 18
            $res = $this->http_request->$method_name($url, [], $form_params);
153 18
            $response = $this->decodeRequest($res, $method, $url, $form_params);
154 9
            return $response;
155 9
        } catch (TmdbException $e) {
156 9
            $this->logger->error('sendRequest failed : ' . $e->getMessage(), array('method' => $method, 'url' => $url, 'form_params' => $form_params));
157 9
            throw $e;
158
        }
159
    }
160
161
    /**
162
     * Decode request response
163
     * @param  mixed $res
164
     * @param  string $method
165
     * @param  string $url
166
     * @param  array $form_params
167
     * @return \stdClass
168
     */
169 18
    private function decodeRequest($res, $method, $url, $form_params) : \stdClass
170
    {
171 18
        $content = $res->getBody();
172
173 18
        if (is_object($content)) {
174
            $content = $content->getContents();
175
        }
176 18
        if (empty($content)) {
177 6
            $this->logger->error('Request Body empty', array('method' => $method, 'url' => $url, 'form_params' => $form_params));
178 6
            throw new ServerErrorException();
179
        }
180 12
        $response = json_decode($content);
181 12
        if (empty($response)) {
182 3
            $this->logger->error('Request Body can not be decode', array('method' => $method, 'url' => $url, 'form_params' => $form_params));
183 3
            throw new ServerErrorException();
184
        }
185 9
        return $response;
186
    }
187
188
    /**
189
     * Build URL for HTTP Call
190
     * @param string $action API action to request
191
     * @param array $options Array of options of the request (optional)
192
     * @return string
193
     */
194 1212
    private function buildHTTPUrl(string $action, array $options) : string
195
    {
196
        // Url construction
197 1212
        $url = $this->base_api_url . $this->version . '/' . $action;
198
199
        // Parameters
200 1212
        $params            = [];
201 1212
        $params['api_key'] = $this->api_key;
202
203 1212
        $params = array_merge($params, $options);
204
205
        // URL with paramters construction
206 1212
        $url = $url . '?' . http_build_query($params);
207
208 1212
        return $url;
209
    }
210
211
    /**
212
     * Get API Configuration
213
     * @return \stdClass
214
     * @throws TmdbException
215
     */
216 180
    public function getConfiguration() : \stdClass
217
    {
218
        try {
219 180
            $this->logger->debug('Start getting configuration');
220 180
            if (is_null($this->configuration)) {
221 180
                $this->logger->debug('No configuration found, sending HTTP request to get it');
222 180
                $this->configuration = $this->getRequest('configuration');
223
            }
224 177
            return $this->configuration;
225 3
        } catch (TmdbException $ex) {
226 3
            throw $ex;
227
        }
228
    }
229
230
    /**
231
     * Get logger
232
     * @return LoggerInterface
233
     */
234 1266
    public function getLogger() : LoggerInterface
235
    {
236 1266
        return $this->logger;
237
    }
238
239
    /**
240
     * Magical property getter
241
     * @param  string $name Name of the property
242
     * @return string       Value of the property
243
     */
244 270
    public function __get(string $name) : string
245
    {
246 180
        switch ($name) {
247 270
            case 'url':
248 267
                return $this->$name;
249
            default:
250 3
                throw new IncorrectParamException;
251
        }
252
    }
253
254
    /**
255
     * @inheritDoc
256
     */
257 87
    public function checkOptionYear(array $options, array &$return) : void
258
    {
259 87
        if (isset($options['year'])) {
260 3
            $return['year'] = (int) $options['year'];
261
        }
262 87
    }
263
264
    /**
265
     * @inheritDoc
266
     */
267 1011
    public function checkOptionLanguage(array $options, array &$return) : void
268
    {
269 1011
        if (isset($options['language'])) {
270 126
            $check = preg_match("#([a-z]{2})-([A-Z]{2})#", $options['language']);
271 126
            if ($check === 0 || $check === false) {
272 3
                $this->logger->error('Incorrect language param option', array('language' => $options['language']));
273 3
                throw new IncorrectParamException;
274
            }
275 123
            $return['language'] = $options['language'];
276
        }
277 1008
    }
278
279
    /**
280
     * @inheritDoc
281
     */
282 87
    public function checkOptionIncludeAdult(array $options, array &$return) : void
283
    {
284 87
        if (isset($options['include_adult'])) {
285 3
            $return['include_adult'] = filter_var($options['include_adult'], FILTER_VALIDATE_BOOLEAN);
286
        }
287 87
    }
288
289
    /**
290
     * @inheritDoc
291
     */
292 147
    public function checkOptionPage(array $options, array &$return) : void
293
    {
294 147
        if (isset($options['page'])) {
295 3
            $return['page'] = (int) $options['page'];
296
        }
297 147
    }
298
299
    /**
300
     * @inheritDoc
301
     */
302 27
    public function checkOptionSortBy(array $options, array &$return) : void
303
    {
304 27
        if (isset($options['sort_by'])) {
305 6
            switch ($options['sort_by']) {
306 6
                case 'asc':
307 3
                case 'desc':
308 3
                    break;
309
                default:
310 3
                    throw new IncorrectParamException;
311
            }
312 3
            $return['sort_by'] = 'created_at.' . $options['sort_by'];
313
        }
314 24
    }
315
316
    /**
317
     * @inheritDoc
318
     */
319 84
    public function checkOptionQuery(array $options, array &$return) : void
320
    {
321 84
        if (isset($options['query'])) {
322 84
            $return['query'] = trim($options['query']);
323
        }
324 84
    }
325
326
    /**
327
     * @inheritDoc
328
     */
329 21
    public function checkOptionSessionId(array $options, array &$return) : void
330
    {
331 21
        if (isset($options['session_id'])) {
332 21
            $return['session_id'] = trim($options['session_id']);
333
        }
334 21
    }
335
336
    /**
337
     * @inheritDoc
338
     */
339 60
    public function checkOptionExternalSource(array $options, array &$return) : void
340
    {
341 60
        if (isset($options['external_source'])) {
342 60
            switch ($options['external_source']) {
343 60
                case 'imdb_id':
344 21
                case 'freebase_mid':
345 21
                case 'freebase_id':
346 21
                case 'tvdb_id':
347 18
                case 'tvrage_id':
348 15
                case 'facebook_id':
349 12
                case 'twitter_id':
350 9
                case 'instagram_id':
351 57
                    $return['external_source'] = trim($options['external_source']);
352 57
                    break;
353
                default:
354 3
                    throw new IncorrectParamException;
355
            }
356
        }
357 57
    }
358
359
    /*
360
     * Check date option
361
     * @param  string $option
362
     * @param  string $format
363
     * @return bool
364
     * @author Steve Richter <[email protected]>
365
     */
366 42
    public function checkOptionDate(string $option, string $format = 'Y-m-d') : bool
367
    {
368 42
        $date = \DateTime::createFromFormat($format, $option);
369
370 42
        return $date && $date->format($format) === $option;
371
    }
372
373
    /**
374
     * Check date range options
375
     * @param  array $options
376
     * @param  array &$return Return array to save valid options
377
     * @return void
378
     * @throws IncorrectParamException
379
     * @author Steve Richter <[email protected]>
380
     */
381 123
    public function checkOptionDateRange(array $options, array &$return) : void
382
    {
383 123
        foreach (['start_date', 'end_date'] as $optionName) {
384 123
            if (isset($options[$optionName])) {
385 42
                if ($this->checkOptionDate($options[$optionName])) {
386 15
                    $return[$optionName] = $options[$optionName];
387 15
                    continue;
388
                }
389
390 30
                $this->logger->error('Incorrect date param option', array($optionName => $options[$optionName]));
391 84
                throw new IncorrectParamException;
392
            }
393
        }
394 93
    }
395
}
396