Completed
Branch add-psr-18-support (b79d4b)
by Steven
02:51
created

Http::getRequestOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace Stevenmaguire\Services\Trello;
4
5
use Exception;
6
use Psr\Http\Client\ClientExceptionInterface;
7
use Psr\Http\Client\ClientInterface;
8
use Psr\Http\Message\RequestInterface;
9
use Psr\Http\Message\RequestFactoryInterface;
10
use Psr\Http\Message\StreamFactoryInterface;
11
12
class Http
13
{
14
    const HTTP_DELETE = 'DELETE';
15
    const HTTP_GET = 'GET';
16
    const HTTP_POST = 'POST';
17
    const HTTP_PUT = 'PUT';
18
19
    /**
20
     * Multipart resources to include in next request.
21
     *
22
     * @var array
23
     */
24
    protected $multipartResources = [];
25
26
    /**
27
     * Http client
28
     *
29
     * @var ClientInterface
30
     */
31
    protected $httpClient;
32
33
    /**
34
     * Http request factory
35
     *
36
     * @var RequestFactoryInterface
37
     */
38
    protected $httpRequestFactory;
39
40
    /**
41
     * Http stream factory
42
     *
43
     * @var StreamFactoryInterface
44
     */
45
    protected $httpStreamFactory;
46
47
    /**
48
     * Creates a new http broker.
49
     */
50
    public function __construct()
51
    {
52
        //
53
    }
54
55
    /**
56
     * Adds authentication credentials to given request.
57
     *
58
     * @param  RequestInterface  $request
59
     *
60
     * @return RequestInterface
61
     */
62
    protected function authenticateRequest(RequestInterface $request)
63
    {
64
        $uri = $request->getUri();
65
        parse_str($uri->getQuery(), $query);
66
67
        $query['key'] = Configuration::get('key');
68
        $query['token'] = Configuration::get('token');
69
70
        $uri = $uri->withQuery(http_build_query($query));
71
72
        return $request->withUri($uri);
73
    }
74
75
    /**
76
     * Creates a request.
77
     *
78
     * @param  string $verb
79
     * @param  string $path
80
     * @param  array  $parameters
81
     *
82
     * @return Request
83
     */
84
    protected function createRequest($verb, $path, $parameters = [])
85
    {
86
        if (isset($parameters['file'])) {
87
            $this->queueResourceAs(
88
                'file',
89
                $this->httpStreamFactory->createStreamFromResource($parameters['file'])
90
            );
91
            unset($parameters['file']);
92
        }
93
94
        $request = $this->httpRequestFactory->createRequest(
95
            $verb,
96
            $this->getUrlFromPath($path)
97
        );
98
99
        $headers = $this->getHeaders();
100
101
        array_walk($headers, function ($value, $key) use (&$request) {
102
            $request = $request->withHeader($key, $value);
103
        });
104
105
        return $request->withUri(
106
            $request->getUri()->withQuery(
107
                http_build_query($parameters)
108
            )
109
        );
110
    }
111
112
    /**
113
     * Retrieves http response for a request with the delete method.
114
     *
115
     * @param  string $path
116
     * @param  array  $parameters
117
     *
118
     * @return object
119
     */
120
    public function delete($path, $parameters = [])
121
    {
122
        $request = $this->getRequest(static::HTTP_DELETE, $path, $parameters);
123
124
        return $this->sendRequest($request);
125
    }
126
127
    /**
128
     * Retrieves http response for a request with the get method.
129
     *
130
     * @param  string $path
131
     * @param  array  $parameters
132
     *
133
     * @return object
134
     */
135
    public function get($path, $parameters = [])
136
    {
137
        $request = $this->getRequest(static::HTTP_GET, $path, $parameters);
138
139
        return $this->sendRequest($request);
140
    }
141
142
    /**
143
     * Creates and returns a request.
144
     *
145
     * @param  string $method
146
     * @param  string $path
147
     * @param  array  $parameters
148
     *
149
     * @return RequestInterface
150
     */
151
    public function getRequest($method, $path, $parameters = [], $authenticated = true)
152
    {
153
        $request = $this->createRequest($method, $path, $parameters);
154
155
        if ($authenticated) {
156
            $request = $this->authenticateRequest($request);
157
        }
158
159
        return $request;
160
    }
161
162
    /**
163
     * Retrieves default headers.
164
     *
165
     * @return array
166
     */
167
    protected function getHeaders()
168
    {
169
        return ['accept' => 'application/json'];
170
    }
171
172
    /**
173
     * Prepares an anonymous class of important exception parts based on composition of a
174
     * given exception.
175
     *
176
     * @param  ClientExceptionInterface  $clientException
177
     *
178
     * @return class
179
     */
180
    private function getRequestExceptionParts(ClientExceptionInterface $clientException)
181
    {
182
        try {
183
            if (is_callable([$clientException, 'getResponse'])) {
184
                $response = $clientException->getResponse();
0 ignored issues
show
Bug introduced by
The method getResponse() does not seem to exist on object<Psr\Http\Client\ClientExceptionInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
185
            } else {
186
                throw new Exception('ClientException does not implement getResponse');
187
            }
188
        } catch (Exception $e) {
189
            $response = null;
190
        }
191
192
        $parts = new class {
193
194
        };
195
        $parts->reason = $response ? $response->getReasonPhrase() : $clientException->getMessage();
0 ignored issues
show
Bug introduced by
The property reason does not seem to exist in Stevenmaguire\Services\T...onymous//src/Http.php$0.

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...
196
        $parts->code = $response ? $response->getStatusCode() : $clientException->getCode();
0 ignored issues
show
Bug introduced by
The property code does not seem to exist in Stevenmaguire\Services\T...onymous//src/Http.php$0.

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...
197
        $parts->body = $response ? $response->getBody() : null;
0 ignored issues
show
Bug introduced by
The property body does not seem to exist in Stevenmaguire\Services\T...onymous//src/Http.php$0.

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...
198
199
        return $parts;
200
    }
201
202
    /**
203
     * Creates an array of request options based on the current status of the
204
     * http client.
205
     *
206
     * @return array
207
     */
208
    protected function getRequestOptions()
209
    {
210
        $options = [
211
            'proxy' => Configuration::get('proxy')
212
        ];
213
214
        if (!empty(array_filter($this->multipartResources))) {
215
            $options['multipart'] = $this->multipartResources;
216
        }
217
218
        return $options;
219
    }
220
221
    /**
222
     * Creates fully qualified domain from given path.
223
     *
224
     * @param  string  $path
225
     *
226
     * @return string
227
     */
228
    public function getUrlFromPath($path = '/')
229
    {
230
        return Configuration::get('domain').'/'.Configuration::get('version').'/'.ltrim($path, '/');
231
    }
232
233
    /**
234
     * Retrieves http response for a request with the post method.
235
     *
236
     * @param  string $path
237
     * @param  array  $parameters
238
     *
239
     * @return object
240
     */
241
    public function post($path, $parameters)
242
    {
243
        $request = $this->getRequest(static::HTTP_POST, $path, $parameters);
244
245
        return $this->sendRequest($request);
246
    }
247
248
    /**
249
     * Retrieves http response for a request with the put method.
250
     *
251
     * @param  string $path
252
     * @param  array  $parameters
253
     *
254
     * @return object
255
     */
256
    public function put($path, $parameters)
257
    {
258
        $request = $this->getRequest(static::HTTP_PUT, $path, $parameters);
259
260
        return $this->sendRequest($request);
261
    }
262
263
    /**
264
     * Retrieves http response for a request with the put method,
265
     * ensuring parameters are passed as body.
266
     *
267
     * @param  string $path
268
     * @param  array  $parameters
269
     *
270
     * @return object
271
     */
272
    public function putAsBody($path, $parameters)
273
    {
274
        $request = $this->getRequest(static::HTTP_PUT, $path)
275
            ->withBody($this->httpStreamFactory->createStream(json_encode($parameters)))
276
            ->withHeader('content-type', 'application/json');
277
278
        return $this->sendRequest($request);
279
    }
280
281
    /**
282
     * Adds a given resource to multipart stream collection, to be processed by next request.
283
     *
284
     * @param  string                                           $name
285
     * @param  resource|string|Psr\Http\Message\StreamInterface $resource
286
     *
287
     * @return void
288
     */
289
    protected function queueResourceAs($name, $resource)
290
    {
291
        array_push($this->multipartResources, [
292
            'name' => $name,
293
            'contents' => $resource,
294
        ]);
295
    }
296
297
    /**
298
     * Retrieves http response for a given request.
299
     *
300
     * @param  RequestInterface $request
301
     *
302
     * @return object
303
     * @throws Exceptions\Exception
304
     */
305
    protected function sendRequest(RequestInterface $request)
306
    {
307
        try {
308
            $response = $this->httpClient->send(
0 ignored issues
show
Bug introduced by
The method send() does not seem to exist on object<Psr\Http\Client\ClientInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
309
                $request,
310
                $this->getRequestOptions()
311
            );
312
313
            $this->multipartResources = [];
314
315
            return json_decode($response->getBody());
316
        } catch (ClientExceptionInterface $e) {
317
            $this->throwRequestException($e);
318
        }
319
    } // @codeCoverageIgnore
320
321
    /**
322
     * Updates the http client.
323
     *
324
     * @param ClientInterface  $httpClient
325
     *
326
     * @return Http
327
     */
328
    public function setClient(ClientInterface $httpClient)
329
    {
330
        $this->httpClient = $httpClient;
331
332
        return $this;
333
    }
334
335
    /**
336
     * Updates the http request factory.
337
     *
338
     * @param RequestFactoryInterface  $httpRequestFactory
339
     *
340
     * @return Http
341
     */
342
    public function setRequestFactory(RequestFactoryInterface $httpRequestFactory)
343
    {
344
        $this->httpRequestFactory = $httpRequestFactory;
345
346
        return $this;
347
    }
348
349
    /**
350
     * Updates the http stream factory.
351
     *
352
     * @param StreamFactoryInterface  $httpStreamFactory
353
     *
354
     * @return Http
355
     */
356
    public function setStreamFactory(StreamFactoryInterface $httpStreamFactory)
357
    {
358
        $this->httpStreamFactory = $httpStreamFactory;
359
360
        return $this;
361
    }
362
363
    /**
364
     * Creates local exception from guzzle request exception, which includes
365
     * response body.
366
     *
367
     * @param  ClientExceptionInterface  $clientException
368
     *
369
     * @return void
370
     * @throws Exceptions\Exception
371
     */
372
    protected function throwRequestException(ClientExceptionInterface $clientException)
373
    {
374
        $exceptionParts = $this->getRequestExceptionParts($clientException);
375
376
        $exception = new Exceptions\Exception(
377
            $exceptionParts->reason,
0 ignored issues
show
Bug introduced by
The property reason does not seem to exist in Stevenmaguire\Services\T...onymous//src/Http.php$0.

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...
378
            $exceptionParts->code,
0 ignored issues
show
Bug introduced by
The property code does not seem to exist in Stevenmaguire\Services\T...onymous//src/Http.php$0.

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...
379
            $clientException
380
        );
381
382
        $body = $exceptionParts->body;
0 ignored issues
show
Bug introduced by
The property body does not seem to exist in Stevenmaguire\Services\T...onymous//src/Http.php$0.

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...
383
        $json = json_decode($body);
384
385
        if (json_last_error() == JSON_ERROR_NONE) {
386
            throw $exception->setResponseBody($json);
387
        }
388
389
        throw $exception->setResponseBody($body);
390
    }
391
}
392