Passed
Branch account (184271)
by vincent
02:51
created

Tmdb::deleteRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
crap 1
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
     * Default language for API response
41
     * @var string
42
     */
43
    private $language = 'fr-FR';
44
45
    /**
46
     * Include adult content in search result
47
     * @var bool
48
     */
49
    private $include_adult = false;
50
51
    /**
52
     * API Page result
53
     * @var int
54
     */
55
    private $page = 1;
56
57
    /**
58
     * API configuration
59
     * @var \stdClass
60
     */
61
    protected $configuration = null;
62
63
    /**
64
     * API Genres
65
     * @var \stdClass
66
     */
67
    protected $genres = null;
68
69
    /**
70
     * Base URL of the API
71
     * @var string
72
     */
73
    public $base_api_url = 'https://api.themoviedb.org/';
74
75
    /**
76
     * Logger
77
     * @var LoggerInterface
78
     */
79
    protected $logger = null;
80
81
    /**
82
     * API Version
83
     * @var int
84
     */
85
    protected $version = 3;
86
87
    /**
88
     * Http request object
89
     * @var HttpRequestInterface
90
     */
91
    protected $http_request = null;
92
93
    /**
94
     * Last request url
95
     * @var string
96
     */
97
    protected $url = null;
98
99
    /**
100
     * Constructor
101
     * @param string $api_key TMDB API Key
102
     * @param int $version Version of API (Not yet used)
103
     * @param LoggerInterface $logger Logger used in the class
104
     * @param HttpRequestInterface $http_request
105
     */
106 359
    public function __construct(string $api_key, int $version = 3, LoggerInterface $logger, HttpRequestInterface $http_request)
107
    {
108 359
        $this->api_key      = $api_key;
109 359
        $this->logger       = $logger;
110 359
        $this->version      = $version;
111 359
        $this->http_request = $http_request;
112 359
        $this->request      = new \stdClass;
0 ignored issues
show
Bug introduced by
The property request does not seem to exist. Did you mean http_request?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
113 359
    }
114
115
    /**
116
     * Send request to TMDB API with GET method
117
     * @param string $action API action to request
118
     * @param array $options Array of options of the request (optional)
119
     * @return \stdClass|null
120
     */
121 317
    public function getRequest(string $action, array $options = array()) : ?\stdClass
122
    {
123 317
        $this->logger->debug('Start sending HTTP request with GET method', array('action' => $action, 'options' => $options));
124 317
        $this->url = $this->buildHTTPUrl($action, $options);
125 317
        return $this->sendRequest('GET', $this->url);
126
    }
127
128
    /**
129
     * Send request to TMDB API with POST method
130
     * @param string $action API action to request
131
     * @param array $options Array of options of the request (optional)
132
     * @param array $form_params form_params for request options
133
     * @return \stdClass|null
134
     */
135 15
    public function postRequest(string $action, array $options = array(), array $form_params = array()) : ?\stdClass
136
    {
137 15
        $this->logger->debug('Start sending HTTP request with POST method', array('action' => $action, 'options' => $options, 'form_params' => $form_params));
138 15
        $this->url = $this->buildHTTPUrl($action, $options);
139 15
        return $this->sendRequest('POST', $this->url, $form_params);
140
    }
141
142
    /**
143
     * Send request to TMDB API with DELETE method
144
     * @param  string $action  API action to request
145
     * @param  array  $options Array of options of the request (optional)
146
     * @return \stdClass|null
147
     */
148 5
    public function deleteRequest(string $action, array $options = array()) : ?\stdClass
149
    {
150 5
        $this->logger->debug('Start sending HTTP request with DELETE method', array('action' => $action, 'options' => $options));
151 5
        $this->url = $this->buildHTTPUrl($action, $options);
152 5
        return $this->sendRequest('DELETE', $this->url);
153
    }
154
155
    /**
156
     * Send request to TMDB API with GET method
157
     * @param string $method HTTP method (GET, POST)
158
     * @param string $url API url to request
159
     * @param array $form_params form params request options
160
     * @return \stdClass|null
161
     */
162 6
    protected function sendRequest(string $method, string $url, array $form_params = array()) : ?\stdClass
163
    {
164
        switch ($method) {
165 6
              case 'GET':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
166 4
                  $res = $this->http_request->getResponse($url);
167 4
                  break;
168 2
              case 'POST':
169 1
                  $res = $this->http_request->postResponse($url, [], $form_params);
170 1
                  break;
171 1
              case 'DELETE':
172 1
                  $res = $this->http_request->deleteResponse($url);
173 1
                  break;
174
        }
175
176 6
        if (empty($res->getBody()))
0 ignored issues
show
Bug introduced by
The variable $res does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
177
        {
178 2
            $this->logger->error('Request Body empty', array('method' => $method, 'url' => $url, 'form_params' => $form_params));
179 2
            throw new ServerErrorException();
180
        }
181 4
        $response = json_decode($res->getBody());
182 4
        if (empty($response)) {
183 1
            $this->logger->error('Request Body can not be decode', array('method' => $method, 'url' => $url, 'form_params' => $form_params));
184 1
            throw new ServerErrorException();
185
        }
186 3
        return $response;
187
    }
188
189
    /**
190
     * Build URL for HTTP Call
191
     * @param string $action API action to request
192
     * @param array $options Array of options of the request (optional)
193
     * @return string
194
     */
195 319
    private function buildHTTPUrl(string $action, array $options) : string
196
    {
197
        // Url construction
198 319
        $url = $this->base_api_url . $this->version . '/' . $action;
199
200
        // Parameters
201 319
        $params            = [];
202 319
        $params['api_key'] = $this->api_key;
203
204 319
        $params = array_merge($params, $options);
205
206
        // URL with paramters construction
207 319
        $url = $url . '?' . http_build_query($params);
208
209 319
        return $url;
210
    }
211
212
    /**
213
     * Get API Configuration
214
     * @return \stdClass
215
     * @throws TmdbException
216
     */
217 50
    public function getConfiguration() : \stdClass
218
    {
219
        try {
220 50
            $this->logger->debug('Start getting configuration');
221 50
            if (is_null($this->configuration)) {
222 50
                $this->logger->debug('No configuration found, sending HTTP request to get it');
223 50
                $this->configuration = $this->getRequest('configuration');
224
            }
225 49
            return $this->configuration;
226 1
        } catch (TmdbException $ex) {
227 1
            throw $ex;
228
        }
229
    }
230
231
    /**
232
     * Check options rules before send request
233
     * @param array $options Array of options to validate
234
     * @return array
235
     * @throws IncorrectParamException
236
     */
237 308
    public function checkOptions(array $options) : array
238
    {
239 308
        $params                  = [];
240
        // Set default options
241
        // $params['language']      = $this->language;
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% 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...
242
        // $params['include_adult'] = $this->include_adult;
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% 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...
243
        // $params['page']          = $this->page;
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% 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...
244
        // Check options
245 308
        foreach ($options as $key => $value) {
246
            switch ($key) {
247 73
                case 'year':
248 2
                    $params[$key] = $this->checkYear($value);
249 2
                    break;
250 72
                case 'language':
251 37
                    $params[$key] = $this->checkLanguage($value);
252 36
                    break;
253 64
                case 'include_adult':
254 1
                    $params[$key] = filter_var($value, FILTER_VALIDATE_BOOLEAN);
255 1
                    break;
256 64
                case 'page':
257 1
                    $params[$key] = (int) $value;
258 1
                    break;
259 63
                case 'sort_by':
260 2
                    $params[$key] = $this->checkSort($value);
261 1
                    break;
262 61
                case 'query':
263 33
                case 'session_id':
264 56
                    $params[$key] = trim($value);
265 56
                    break;
266
                default:
267 5
                    $this->logger->error('Unknown param options', array('options', $options));
268 5
                    throw new IncorrectParamException;
269
            }
270
        }
271 301
        return $params;
272
    }
273
274
    /**
275
     * Check year format
276
     * @param mixed $year year to validate
277
     * @return int year validated
278
     */
279 2
    private function checkYear($year) : int
280
    {
281 2
        $year = (int) $year;
282 2
        return $year;
283
    }
284
285
    /**
286
     * Check language
287
     * @param string $language Language string with format ISO 639-1
288
     * @return string Language string validated
289
     * @throws IncorrectParamException
290
     */
291 37
    private function checkLanguage(string $language) : string
292
    {
293 37
        $check = preg_match("#([a-z]{2})-([A-Z]{2})#", $language);
294 37
        if ($check === 0 || $check === false) {
295 1
            $this->logger->error('Incorrect language param option', array('language' => $language));
296 1
            throw new IncorrectParamException;
297
        }
298 36
        return $language;
299
    }
300
301
    /**
302
     * Check sort direction
303
     * @param  string $direction direction of sorting
304
     * @return string            Sort string validated
305
     * @throws IncorrectParamException
306
     */
307 2
    private function checkSort(string $direction) : string
308
    {
309
        switch ($direction) {
310 2
            case 'asc':
311 1
            case 'desc':
312 1
                break;
313
            default:
314 1
                throw new IncorrectParamException;
315
        }
316 1
        return 'created_at.'.$direction;
317
    }
318
319
    /**
320
     * Get logger
321
     * @return LoggerInterface
322
     */
323 329
    public function getLogger() : LoggerInterface
324
    {
325 329
        return $this->logger;
326
    }
327
328
    /**
329
     * Magical property getter
330
     * @param  string $name Name of the property
331
     * @return string       Value of the property
332
     */
333 73
    public function __get(string $name) : string
334
    {
335
        switch ($name) {
336 73
            case 'url':
337 72
                return $this->$name;
338
            default:
339 1
                throw new IncorrectParamException;
340
        }
341
    }
342
}
343