InktaleApiClient   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 250
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 3
dl 0
loc 250
c 0
b 0
f 0
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A setApiKey() 0 4 1
A get() 0 4 1
A delete() 0 4 1
A post() 0 4 1
A put() 0 4 1
A getLastResponseRaw() 0 4 1
A getLastResponse() 0 4 1
A request() 0 17 2
A initCurl() 0 16 1
A getUrl() 0 8 2
B execute() 0 41 5
A getCurlHeaders() 0 13 2
1
<?php
2
3
namespace Inktale\Api;
4
5
use Inktale\Api\Exceptions\InktaleApiAuthException;
6
use Inktale\Api\Exceptions\InktaleApiException;
7
use Inktale\Api\Structures\ApiErrorItem;
8
9
class InktaleApiClient
10
{
11
    const USER_AGENT = 'Inktale PHP wrapper (https://github.com/inktale/php-api-sdk)';
12
13
    /**
14
     * @var string
15
     */
16
    public $url = 'https://inktale.com/api/v1/';
17
18
    /**
19
     * Last JSON encoded response
20
     *
21
     * @var string
22
     */
23
    private $lastResponseRaw;
24
25
    /**
26
     * Last parsed response (json decoded)
27
     *
28
     * @var array
29
     */
30
    private $lastResponse;
31
32
    /**
33
     * Authorization token
34
     *
35
     * @var string
36
     */
37
    private $apiKey;
38
39
    /**
40
     * Your API key
41
     *
42
     * @param string|null $apiKey
43
     */
44
    public function __construct($apiKey = null)
45
    {
46
        $this->setApiKey($apiKey);
47
    }
48
49
    /**
50
     * Set authorization header key
51
     * @param string $apiKey
52
     */
53
    public function setApiKey($apiKey)
54
    {
55
        $this->apiKey = $apiKey;
56
    }
57
58
    /**
59
     * Perform a GET request to the API
60
     *
61
     * @param string $path Request path
62
     * @param array $params Additional GET parameters as an associative array
63
     * @return mixed
64
     */
65
    public function get($path, $params = [])
66
    {
67
        return $this->request('GET', $path, $params);
68
    }
69
70
    /**
71
     * Perform a DELETE request to the API
72
     *
73
     * @param string $path Request path
74
     * @param array $params Additional GET parameters as an associative array
75
     * @return mixed
76
     */
77
    public function delete($path, $params = [])
78
    {
79
        return $this->request('DELETE', $path, $params);
80
    }
81
82
    /**
83
     * Perform a POST request to the API
84
     *
85
     * @param string $path Request path
86
     * @param array $data Request body data as an associative array
87
     * @param array $params Additional GET parameters as an associative array
88
     * @return mixed
89
     */
90
    public function post($path, $data = [], $params = [])
91
    {
92
        return $this->request('POST', $path, $params, $data);
93
    }
94
95
    /**
96
     * Perform a PUT request to the API
97
     *
98
     * @param string $path Request path
99
     * @param array $data Request body data as an associative array
100
     * @param array $params Additional GET parameters as an associative array
101
     * @return mixed
102
     */
103
    public function put($path, $data = [], $params = [])
104
    {
105
        return $this->request('PUT', $path, $params, $data);
106
    }
107
108
    /**
109
     * Return raw response data from the last request
110
     *
111
     * @return string|null Response data
112
     */
113
    public function getLastResponseRaw()
114
    {
115
        return $this->lastResponseRaw;
116
    }
117
118
    /**
119
     * Return decoded response data from the last request
120
     *
121
     * @return array|null Response data
122
     */
123
    public function getLastResponse()
124
    {
125
        return $this->lastResponse;
126
    }
127
128
    /**
129
     * Internal request implementation
130
     * @param string $method POST, GET, etc.
131
     * @param string $path API endpoint path
132
     * @param array $query Query parameters
133
     * @param array|mixed $data Post data
134
     * @return mixed
135
     * @throws InktaleApiException
136
     */
137
    protected function request($method, $path, array $query = [], $data = null)
138
    {
139
        $curl = $this->initCurl($method, $path, $query);
140
141
        $bodyLength = 0;
142
        if ($data !== null) {
143
            $bodyEncoded = json_encode($data);
144
            $bodyLength = strlen($bodyEncoded);
145
            curl_setopt($curl, CURLOPT_POSTFIELDS, $bodyEncoded);
146
        }
147
148
        $headers = $this->getCurlHeaders($bodyLength, 'application/json');
149
150
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
151
152
        return $this->execute($curl);
153
    }
154
155
    /**
156
     * @param string $method
157
     * @param string $path
158
     * @param array $query Query parameters
159
     * @return resource cURL handler
160
     */
161
    protected function initCurl($method, $path, array $query)
162
    {
163
        $curl = curl_init($this->getUrl($path, $query));
164
165
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
166
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
167
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
168
        curl_setopt($curl, CURLOPT_MAXREDIRS, 3);
169
170
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 20);
171
        curl_setopt($curl, CURLOPT_TIMEOUT, 10);
172
173
        curl_setopt($curl, CURLOPT_USERAGENT, self::USER_AGENT);
174
175
        return $curl;
176
    }
177
178
    /**
179
     * @param string $path
180
     * @param array $query
181
     * @return string
182
     */
183
    private function getUrl($path, array $query)
184
    {
185
        $url = $this->url . ltrim($path, '/');
186
        if ($query) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $query of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
187
            $url .= '?' . http_build_query($query);
188
        }
189
        return $url;
190
    }
191
192
    /**
193
     * Execute cURL handler and return response
194
     * @param resource $curl
195
     * @return mixed
196
     * @throws InktaleApiException
197
     */
198
    private function execute($curl)
199
    {
200
        $this->lastResponseRaw = null;
201
        $this->lastResponse = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $lastResponse.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
202
203
        $responseRaw = curl_exec($curl);
204
205
        $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
206
207
        $errorNumber = curl_errno($curl);
208
        $error = curl_error($curl);
209
        curl_close($curl);
210
211
        if ($errorNumber) {
212
            throw new InktaleApiException('Inktale API CURL error: ' . $error, $errorNumber);
213
        }
214
215
        $response = json_decode($responseRaw, true);
216
217
        if ($responseCode >= 400 || !empty($response['error'])) {
218
            $errorItem = ApiErrorItem::fromArray($response['error']);
219
            $exceptionMessage = $errorItem->title . ': ' . $errorItem->details;
220
221
            if ($responseCode == 401) {
222
                $exception = new InktaleApiAuthException($exceptionMessage, $errorItem->code);
223
            } else {
224
                $exception = new InktaleApiException($exceptionMessage, $errorItem->code);
225
            }
226
227
            $exception->setRawResponse($responseRaw)
228
                ->setErrorDetails($errorItem->details)
229
                ->setErrorTitle($errorItem->title);
230
231
            throw $exception;
232
        }
233
234
        $this->lastResponse = $response;
235
        $this->lastResponseRaw = $responseRaw;
236
237
        return $response;
238
    }
239
240
    /**
241
     * @param int $contentLength
242
     * @param string $contentType
243
     * @return string[]
244
     */
245
    private function getCurlHeaders($contentLength, $contentType)
246
    {
247
        $headers = [
248
            'Content-Type: ' . $contentType,
249
            'Content-Length: ' . $contentLength,
250
        ];
251
252
        if ($this->apiKey) {
253
            $headers[] = 'Authorization:' . $this->apiKey;
254
        }
255
256
        return $headers;
257
    }
258
}