Completed
Pull Request — master (#9)
by ARCANEDEV
02:34
created

Requestor::setHttpClient()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php namespace Arcanedev\Stripe\Http;
2
3
use Arcanedev\Stripe\Contracts\Http\RequestorInterface;
4
use Arcanedev\Stripe\Contracts\Http\Curl\HttpClientInterface;
5
use Arcanedev\Stripe\Exceptions\ApiConnectionException;
6
use Arcanedev\Stripe\Exceptions\ApiException;
7
use Arcanedev\Stripe\Exceptions\ApiKeyNotSetException;
8
use Arcanedev\Stripe\Exceptions\AuthenticationException;
9
use Arcanedev\Stripe\Exceptions\CardException;
10
use Arcanedev\Stripe\Exceptions\InvalidRequestException;
11
use Arcanedev\Stripe\Exceptions\RateLimitException;
12
use Arcanedev\Stripe\Stripe;
13
use Arcanedev\Stripe\StripeResource;
14
use Arcanedev\Stripe\Utilities\ErrorsHandler;
15
use Arcanedev\Stripe\Http\Curl\HttpClient;
16
17
/**
18
 * Class     Requestor
19
 *
20
 * @package  Arcanedev\Stripe
21
 * @author   ARCANEDEV <[email protected]>
22
 */
23
class Requestor implements RequestorInterface
24
{
25
    /* ------------------------------------------------------------------------------------------------
26
     |  Properties
27
     | ------------------------------------------------------------------------------------------------
28
     */
29
    /**
30
     * The API key that's to be used to make requests.
31
     *
32
     * @var string
33
     */
34
    private $apiKey;
35
36
    /** @var string */
37
    private $apiBaseUrl;
38
39
    /** @var HttpClientInterface */
40
    private static $httpClient;
41
42
    /** @var array */
43
    private static $allowedMethods = [
44
        'get', 'post', 'delete'
45
    ];
46
47
    /** @var ErrorsHandler */
48
    private $errorsHandler;
49
50
    /* ------------------------------------------------------------------------------------------------
51
     |  Getters & Setters
52
     | ------------------------------------------------------------------------------------------------
53
     */
54
    /**
55
     * Create Requestor instance.
56
     *
57
     * @param  string|null  $apiKey
58
     * @param  string|null  $apiBase
59
     */
60 698
    public function __construct($apiKey = null, $apiBase = null)
61
    {
62 698
        $this->setApiKey($apiKey);
63 698
        $this->setApiBase($apiBase);
64 698
        $this->errorsHandler = new ErrorsHandler;
65 698
    }
66
67
    /* ------------------------------------------------------------------------------------------------
68
     |  Getters & Setters
69
     | ------------------------------------------------------------------------------------------------
70
     */
71
    /**
72
     * Get Stripe API Key.
73
     *
74
     * @return string
75
     */
76 673
    public function getApiKey()
77
    {
78 673
        if ( ! $this->apiKey) {
79 668
            $this->setApiKey(Stripe::getApiKey());
80 668
        }
81
82 673
        return trim($this->apiKey);
83
    }
84
85
    /**
86
     * Set API Key
87
     *
88
     * @param  string  $apiKey
89
     *
90
     * @return self
91
     */
92 698
    private function setApiKey($apiKey)
93
    {
94 698
        $this->apiKey = $apiKey;
95
96 698
        return $this;
97
    }
98
99
    /**
100
     * Set API Base URL
101
     *
102
     * @param  string|null  $apiBaseUrl
103
     *
104
     * @return self
105
     */
106 698
    private function setApiBase($apiBaseUrl)
107
    {
108 698
        if (empty($apiBaseUrl)) {
109 30
            $apiBaseUrl = Stripe::getApiBaseUrl();
110 30
        }
111
112 698
        $this->apiBaseUrl = $apiBaseUrl;
113
114 698
        return $this;
115
    }
116
117
    /**
118
     * Get the HTTP client
119
     *
120
     * @return HttpClientInterface
121
     */
122 673
    private function httpClient()
123
    {
124
        // @codeCoverageIgnoreStart
125
        if ( ! self::$httpClient) {
126
            self::$httpClient = HttpClient::instance();
127
        }
128
        // @codeCoverageIgnoreEnd
129
130 673
        return self::$httpClient;
131
    }
132
133
    /**
134
     * Set the HTTP client
135
     *
136
     * @param  HttpClientInterface  $client
137
     */
138 1270
    public static function setHttpClient(HttpClientInterface $client)
139
    {
140 1270
        self::$httpClient = $client;
141 1270
    }
142
143
    /* ------------------------------------------------------------------------------------------------
144
     |  Request Functions
145
     | ------------------------------------------------------------------------------------------------
146
     */
147
    /**
148
     * Make Requestor instance.
149
     *
150
     * @param  string|null  $apiKey
151
     * @param  string       $apiBase
152
     *
153
     * @return self
154
     */
155 668
    public static function make($apiKey = null, $apiBase = '')
156
    {
157 668
        return new self($apiKey, $apiBase);
158
    }
159
160
    /**
161
     * GET Request.
162
     *
163
     * @param  string      $url
164
     * @param  array|null  $params
165
     * @param  array|null  $headers
166
     *
167
     * @return array
168
     */
169 315
    public function get($url, $params = [], $headers = null)
170
    {
171 315
        return $this->request('get', $url, $params, $headers);
172
    }
173
174
    /**
175
     * POST Request.
176
     *
177
     * @param  string      $url
178
     * @param  array|null  $params
179
     * @param  array|null  $headers
180
     *
181
     * @return array
182
     */
183 30
    public function post($url, $params = [], $headers = null)
184
    {
185 30
        return $this->request('post', $url, $params, $headers);
186
    }
187
188
    /**
189
     * DELETE Request.
190
     *
191
     * @param  string      $url
192
     * @param  array|null  $params
193
     * @param  array|null  $headers
194
     *
195
     * @return array
196
     */
197
    public function delete($url, $params = [], $headers = null)
198
    {
199
        return $this->request('delete', $url, $params, $headers);
200
    }
201
202
    /**
203
     * Make a request.
204
     * Note: An array whose first element is the Response object and second element is the API key used to make the request.
205
     *
206
     * @param  string      $method
207
     * @param  string      $url
208
     * @param  array|null  $params
209
     * @param  array|null  $headers
210
     *
211
     * @throws ApiException
212
     *
213
     * @return array
214
     */
215 668
    public function request($method, $url, $params = null, $headers = null)
216
    {
217 668
        $this->checkApiKey();
218 668
        $this->checkMethod($method);
219
220 668
        if (is_null($params)) {
221 30
            $params = [];
222 30
        }
223
224 668
        if (is_null($headers)) {
225 340
            $headers = [];
226 340
        }
227
228 668
        list($respBody, $respCode, $apiKey) = $this->requestRaw($method, $url, $params, $headers);
229
230 668
        $json     = $this->interpretResponse($respBody, $respCode);
231 638
        $response = new Response($respBody, $respCode, $headers, $json);
232
233 638
        return [$response, $apiKey];
234
    }
235
236
    /**
237
     * Raw request
238
     *
239
     * @param  string  $method
240
     * @param  string  $url
241
     * @param  array   $params
242
     * @param  array   $headers
243
     *
244
     * @throws ApiConnectionException
245
     * @throws ApiException
246
     * @throws ApiKeyNotSetException
247
     *
248
     * @return array
249
     */
250 668
    private function requestRaw($method, $url, $params, $headers)
251
    {
252 668
        $params = self::encodeObjects($params);
253
254 668
        $this->httpClient()->setApiKey($this->getApiKey());
255
256 668
        list($respBody, $respCode) = $this->httpClient()
257 668
            ->request($method, $this->apiBaseUrl . $url, $params, $headers);
258
259 668
        return [$respBody, $respCode, $this->getApiKey()];
260
    }
261
262
    /**
263
     * Interpret Response.
264
     *
265
     * @param  string  $respBody
266
     * @param  int     $respCode
267
     *
268
     * @throws ApiException
269
     * @throws AuthenticationException
270
     * @throws CardException
271
     * @throws InvalidRequestException
272
     * @throws RateLimitException
273
     *
274
     * @return array
275
     */
276 673
    private function interpretResponse($respBody, $respCode)
277
    {
278
        try {
279 673
            $response = json_decode($respBody, true);
280
281 673
            if (json_last_error() !== JSON_ERROR_NONE) {
282 5
                throw new \Exception;
283
            }
284
        }
285 673
        catch (\Exception $e) {
286 5
            throw new ApiException(
287 5
                'Invalid response body from API: ' . $respBody . ' (HTTP response code was ' . $respCode .')',
288 5
                500,
289 5
                'api_error',
290 5
                null,
291
                $respBody
292 5
            );
293
        }
294
295 668
        $this->errorsHandler->handle($respBody, $respCode, $response);
296
297 638
        return $response;
298
    }
299
300
    /* ------------------------------------------------------------------------------------------------
301
     |  Check Functions
302
     | ------------------------------------------------------------------------------------------------
303
     */
304
    /**
305
     * Check if the API Key is set.
306
     *
307
     * @return bool
308
     */
309 673
    private function isApiKeyExists()
310
    {
311 673
        $apiKey = $this->getApiKey();
312
313 673
        return ! empty($apiKey);
314
    }
315
316
    /**
317
     * Check if API Key Exists.
318
     *
319
     * @throws ApiKeyNotSetException
320
     */
321 673
    private function checkApiKey()
322
    {
323 673
        if ( ! $this->isApiKeyExists()) {
324 5
            throw new ApiKeyNotSetException(
325
                'The Stripe API Key is required !'
326 5
            );
327
        }
328 668
    }
329
330
    /**
331
     * Check Http Method.
332
     *
333
     * @param  string  $method
334
     *
335
     * @throws ApiException
336
     */
337 673
    private function checkMethod(&$method)
338
    {
339 673
        $method = strtolower($method);
340
341 673
        if ( ! in_array($method, self::$allowedMethods)) {
342 5
            throw new ApiException(
343 5
                "Unrecognized method $method, must be [" . implode(', ', self::$allowedMethods) . '].',
344
                500
345 5
            );
346
        }
347 668
    }
348
349
    /* ------------------------------------------------------------------------------------------------
350
     |  Other Functions
351
     | ------------------------------------------------------------------------------------------------
352
     */
353
    /**
354
     * Encode Objects.
355
     *
356
     * @param  StripeResource|bool|array|string  $obj
357
     *
358
     * @throws ApiException
359
     *
360
     * @return array|string
361
     */
362 673
    private static function encodeObjects($obj)
363
    {
364 673
        if ($obj instanceof StripeResource) {
365 10
            return str_utf8($obj->id);
366
        }
367
368 673
        if (is_bool($obj)) {
369 50
            return ($obj) ? 'true' : 'false';
370
        }
371
372 673
        if (is_array($obj)) {
373 673
            return array_map(function($v) {
374 553
                return self::encodeObjects($v);
375 673
            }, $obj);
376
        }
377
378 548
        return str_utf8($obj);
379
    }
380
}
381