Passed
Push — master ( 821e6b...4c7f2a )
by Steven
08:13
created

src/Http.php (4 issues)

1
<?php
2
3
namespace Stevenmaguire\Services\Trello;
4
5
use GuzzleHttp\Client as HttpClient;
6
use GuzzleHttp\ClientInterface as HttpClientInterface;
7
use GuzzleHttp\Exception\RequestException;
8
use GuzzleHttp\Psr7;
9
use GuzzleHttp\Psr7\Request;
10
use Psr\Http\Message\RequestInterface;
11
12
class Http
13
{
14
    public const HTTP_DELETE = 'DELETE';
15
    public const HTTP_GET = 'GET';
16
    public const HTTP_POST = 'POST';
17
    public 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 HttpClientInterface
30
     */
31
    protected $httpClient;
32
33
    /**
34 702
     * Creates a new http broker.
35
     */
36 702
    public function __construct()
37 702
    {
38
        $this->httpClient = new HttpClient();
39
    }
40
41
    /**
42
     * Adds authentication credentials to given request.
43
     *
44
     * @param  RequestInterface  $request
45
     *
46 682
     * @return RequestInterface
47
     */
48 682
    protected function authenticateRequest(RequestInterface $request)
49 682
    {
50
        $uri = $request->getUri();
51 682
        parse_str($uri->getQuery(), $query);
52 682
53
        $query['key'] = Configuration::get('key');
54 682
        $query['token'] = Configuration::get('token');
55
56 682
        $uri = $uri->withQuery(http_build_query($query));
57
58
        return $request->withUri($uri);
59
    }
60
61
    /**
62
     * Creates a request.
63
     *
64
     * @param  string $verb
65
     * @param  string $path
66
     * @param  array  $parameters
67
     *
68 684
     * @return Request
69
     */
70 684
    protected function createRequest($verb, $path, $parameters = [])
71 2
    {
72 2
        if (isset($parameters['file'])) {
73 2
            $this->queueResourceAs(
74 1
                'file',
75 2
                Psr7\stream_for($parameters['file'])
0 ignored issues
show
The function stream_for was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
                /** @scrutinizer ignore-call */ 
76
                Psr7\stream_for($parameters['file'])
Loading history...
76 1
            );
77
            unset($parameters['file']);
78 684
        }
79 684
80 684
        $request = new Request(
81 684
            $verb,
82 342
            $this->getUrlFromPath($path),
83
            $this->getHeaders()
84 684
        );
85 684
86 684
        return $request->withUri(
87 342
            $request->getUri()->withQuery(
88 342
                http_build_query($parameters)
89
            )
90
        );
91
    }
92
93
    /**
94
     * Retrieves http response for a request with the delete method.
95
     *
96
     * @param  string $path
97
     * @param  array  $parameters
98
     *
99 62
     * @return object
100
     */
101 62
    public function delete($path, $parameters = [])
102
    {
103 62
        $request = $this->getRequest(static::HTTP_DELETE, $path, $parameters);
104
105
        return $this->sendRequest($request);
106
    }
107
108
    /**
109
     * Retrieves http response for a request with the get method.
110
     *
111
     * @param  string $path
112
     * @param  array  $parameters
113
     *
114 312
     * @return object
115
     */
116 312
    public function get($path, $parameters = [])
117
    {
118 312
        $request = $this->getRequest(static::HTTP_GET, $path, $parameters);
119
120
        return $this->sendRequest($request);
121
    }
122
123
    /**
124
     * Creates and returns a request.
125
     *
126
     * @param  string $method
127
     * @param  string $path
128
     * @param  array  $parameters
129
     *
130 684
     * @return RequestInterface
131
     */
132 684
    public function getRequest($method, $path, $parameters = [], $authenticated = true)
133
    {
134 684
        $request = $this->createRequest($method, $path, $parameters);
135 682
136 341
        if ($authenticated) {
137
            $request = $this->authenticateRequest($request);
138 684
        }
139
140
        return $request;
141
    }
142
143
    /**
144
     * Retrieves default headers.
145
     *
146 684
     * @return array
147
     */
148 684
    protected function getHeaders()
149
    {
150
        return [];
151
    }
152
153
    /**
154
     * Prepares an array of important exception parts based on composition of a
155
     * given exception.
156
     *
157
     * @param  RequestException  $requestException
158
     *
159 8
     * @return array
160
     */
161 8
    private function getRequestExceptionParts(RequestException $requestException)
162 8
    {
163 8
        $response = $requestException->getResponse();
164 8
        $parts = [];
165 8
        $parts['reason'] = $response ? $response->getReasonPhrase() : $requestException->getMessage();
166
        $parts['code'] = $response ? $response->getStatusCode() : $requestException->getCode();
167 8
        $parts['body'] = $response ? $response->getBody() : null;
168
169
        return $parts;
170
    }
171
172
    /**
173
     * Creates an array of request options based on the current status of the
174
     * http client.
175
     *
176 680
     * @return array
177
     */
178
    protected function getRequestOptions()
179 680
    {
180 340
        $options = [
181
            'proxy' => Configuration::get('proxy'),
182 680
        ];
183 2
184 1
        if (! empty(array_filter($this->multipartResources))) {
185
            $options['multipart'] = $this->multipartResources;
186 680
        }
187
188
        return $options;
189
    }
190
191
    /**
192
     * Creates fully qualified domain from given path.
193
     *
194
     * @param  string  $path
195
     *
196 684
     * @return string
197
     */
198 684
    protected function getUrlFromPath($path = '/')
199
    {
200
        return Configuration::get('domain').'/'.Configuration::get('version').'/'.ltrim($path, '/');
201
    }
202
203
    /**
204
     * Retrieves http response for a request with the post method.
205
     *
206
     * @param  string $path
207
     * @param  array  $parameters
208
     *
209 86
     * @return object
210
     */
211 86
    public function post($path, $parameters)
212
    {
213 86
        $request = $this->getRequest(static::HTTP_POST, $path, $parameters);
214
215
        return $this->sendRequest($request);
216
    }
217
218
    /**
219
     * Retrieves http response for a request with the put method.
220
     *
221
     * @param  string $path
222
     * @param  array  $parameters
223
     *
224 218
     * @return object
225
     */
226 218
    public function put($path, $parameters)
227
    {
228 218
        $request = $this->getRequest(static::HTTP_PUT, $path, $parameters);
229
230
        return $this->sendRequest($request);
231
    }
232
233
    /**
234
     * Retrieves http response for a request with the put method,
235
     * ensuring parameters are passed as body.
236
     *
237
     * @param  string $path
238
     * @param  array  $parameters
239
     *
240 2
     * @return object
241
     */
242 2
    public function putAsBody($path, $parameters)
243 2
    {
244 2
        $request = $this->getRequest(static::HTTP_PUT, $path)
245
            ->withBody(Psr7\stream_for(json_encode($parameters)))
0 ignored issues
show
The function stream_for was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

245
            ->withBody(/** @scrutinizer ignore-call */ Psr7\stream_for(json_encode($parameters)))
Loading history...
246 2
            ->withHeader('content-type', 'application/json');
247
248
        return $this->sendRequest($request);
249
    }
250
251
    /**
252
     * Adds a given resource to multipart stream collection, to be processed by next request.
253
     *
254
     * @param  string                                           $name
255
     * @param  resource|string|Psr\Http\Message\StreamInterface $resource
0 ignored issues
show
The type Stevenmaguire\Services\T...Message\StreamInterface was not found. Did you mean Psr\Http\Message\StreamInterface? If so, make sure to prefix the type with \.
Loading history...
256
     *
257 2
     * @return void
258
     */
259 2
    protected function queueResourceAs($name, $resource)
260 2
    {
261 2
        array_push($this->multipartResources, [
262 1
            'name' => $name,
263 2
            'contents' => $resource,
264
        ]);
265
    }
266
267
    /**
268
     * Retrieves http response for a given request.
269
     *
270
     * @param  RequestInterface $request
271
     *
272
     * @return object
273 680
     * @throws Exceptions\Exception
274
     */
275
    protected function sendRequest(RequestInterface $request)
276 680
    {
277 680
        try {
278 680
            $response = $this->httpClient->send(
279 340
                $request,
280
                $this->getRequestOptions()
281 672
            );
282
283 672
            $this->multipartResources = [];
284 8
285 8
            return json_decode($response->getBody());
286
        } catch (RequestException $e) {
287
            $this->throwRequestException($e);
288
        }
289
    } // @codeCoverageIgnore
290
291
    /**
292
     * Updates the http client.
293
     *
294
     * @param HttpClientInterface  $httpClient
295
     *
296 680
     * @return Http
297
     */
298 680
    public function setClient(HttpClientInterface $httpClient)
299
    {
300 680
        $this->httpClient = $httpClient;
301
302
        return $this;
303
    }
304
305
    /**
306
     * Creates local exception from guzzle request exception, which includes
307
     * response body.
308
     *
309
     * @param  RequestException  $requestException
310
     *
311
     * @return void
312 8
     * @throws Exceptions\Exception
313
     */
314 8
    protected function throwRequestException(RequestException $requestException)
315
    {
316 8
        $exceptionParts = $this->getRequestExceptionParts($requestException);
317 8
318 8
        $exception = new Exceptions\Exception(
319 4
            $exceptionParts['reason'],
320 4
            $exceptionParts['code'],
321
            $requestException
322 8
        );
323 8
324
        $body = $exceptionParts['body'];
325 8
        $json = json_decode($body);
0 ignored issues
show
It seems like $body can also be of type null; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

325
        $json = json_decode(/** @scrutinizer ignore-type */ $body);
Loading history...
326 5
327
        if (json_last_error() == JSON_ERROR_NONE) {
328
            throw $exception->setResponseBody($json);
329 3
        }
330
331
        throw $exception->setResponseBody($body);
332 2
    }
333
}
334