Completed
Push — master ( 7ba991...d4ab1b )
by Tobias
03:56
created

RestClient::responseHandler()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 13.125

Importance

Changes 4
Bugs 0 Features 0
Metric Value
dl 0
loc 24
ccs 9
cts 18
cp 0.5
rs 6.7272
c 4
b 0
f 0
cc 7
eloc 18
nc 8
nop 1
crap 13.125
1
<?PHP
2
3
/*
4
 * Copyright (C) 2013-2016 Mailgun
5
 *
6
 * This software may be modified and distributed under the terms
7
 * of the MIT license. See the LICENSE file for details.
8
 */
9
10
namespace Mailgun\Connection;
11
12
use Http\Client\HttpClient;
13
use Http\Discovery\HttpClientDiscovery;
14
use Http\Discovery\MessageFactoryDiscovery;
15
use Http\Message\MultipartStream\MultipartStreamBuilder;
16
use Mailgun\Connection\Exceptions\GenericHTTPError;
17
use Mailgun\Connection\Exceptions\InvalidCredentials;
18
use Mailgun\Connection\Exceptions\MissingEndpoint;
19
use Mailgun\Connection\Exceptions\MissingRequiredParameters;
20
use Mailgun\Constants\Api;
21
use Mailgun\Constants\ExceptionMessages;
22
use Psr\Http\Message\ResponseInterface;
23
24
/**
25
 * This class is a wrapper for the HTTP client.
26
 *
27
 * @deprecated Will be removed in 3.0
28
 */
29
class RestClient
30
{
31
    /**
32
     * Your API key.
33
     *
34
     * @var string
35
     */
36
    private $apiKey;
37
38
    /**
39
     * @var HttpClient
40
     */
41
    protected $httpClient;
42
43
    /**
44
     * @var string
45
     */
46
    protected $apiHost;
47
48
    /**
49
     * The version of the API to use.
50
     *
51
     * @var string
52
     */
53
    protected $apiVersion = 'v2';
54
55
    /**
56
     * If we should use SSL or not.
57
     *
58
     * @var bool
59
     *
60
     * @deprecated To be removed in 3.0
61
     */
62
    protected $sslEnabled = true;
63
64
    /**
65
     * @param string     $apiKey
66
     * @param string     $apiHost
67
     * @param HttpClient $httpClient
68
     */
69 31
    public function __construct($apiKey, $apiHost, HttpClient $httpClient = null)
70
    {
71 31
        $this->apiKey = $apiKey;
72 31
        $this->apiHost = $apiHost;
73 31
        $this->httpClient = $httpClient;
74 31
    }
75
76
    /**
77
     * @param string $method
78
     * @param string $uri
79
     * @param mixed  $body
80
     * @param array  $files
81
     * @param array  $headers
82
     *
83
     * @throws GenericHTTPError
84
     * @throws InvalidCredentials
85
     * @throws MissingEndpoint
86
     * @throws MissingRequiredParameters
87
     *
88
     * @return \stdClass
89
     */
90
    protected function send($method, $uri, $body = null, $files = [], array $headers = [])
91
    {
92
        $headers['User-Agent'] = Api::SDK_USER_AGENT.'/'.Api::SDK_VERSION;
93
        $headers['Authorization'] = 'Basic '.base64_encode(sprintf('%s:%s', Api::API_USER, $this->apiKey));
94
95
        if (!empty($files)) {
96
            $builder = new MultipartStreamBuilder();
97
            foreach ($files as $file) {
98
                $builder->addResource($file['name'], $file['contents'], $file);
99
            }
100
            $body = $builder->build();
101
            $headers['Content-Type'] = 'multipart/form-data; boundary="'.$builder->getBoundary().'"';
102
        } elseif (is_array($body)) {
103
            $body = http_build_query($body);
104
            $headers['Content-Type'] = 'application/x-www-form-urlencoded';
105
        }
106
107
        $request = MessageFactoryDiscovery::find()->createRequest($method, $this->getApiUrl($uri), $headers, $body);
108
        $response = $this->getHttpClient()->sendRequest($request);
109
110
        return $this->responseHandler($response);
111
    }
112
113
    /**
114
     * @param string $url
115
     *
116
     * @throws GenericHTTPError
117
     * @throws InvalidCredentials
118
     * @throws MissingEndpoint
119
     * @throws MissingRequiredParameters
120
     *
121
     * @return \stdClass
122
     */
123 1
    public function getAttachment($url)
124
    {
125 1
        $headers['User-Agent'] = Api::SDK_USER_AGENT.'/'.Api::SDK_VERSION;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$headers was never initialized. Although not strictly required by PHP, it is generally a good practice to add $headers = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
126 1
        $headers['Authorization'] = 'Basic '.base64_encode(sprintf('%s:%s', Api::API_USER, $this->apiKey));
127 1
        $request = MessageFactoryDiscovery::find()->createRequest('get', $url, $headers);
128 1
        $response = HttpClientDiscovery::find()->sendRequest($request);
129
130 1
        return $this->responseHandler($response);
131
    }
132
133
    /**
134
     * @param string $endpointUrl
135
     * @param array  $postData
136
     * @param array  $files
137
     *
138
     * @throws GenericHTTPError
139
     * @throws InvalidCredentials
140
     * @throws MissingEndpoint
141
     * @throws MissingRequiredParameters
142
     *
143
     * @return \stdClass
144
     */
145 5
    public function post($endpointUrl, array $postData = [], $files = [])
146
    {
147 5
        $postFiles = [];
148
149 5
        $fields = ['message', 'attachment', 'inline'];
150 5
        foreach ($fields as $fieldName) {
151 5
            if (isset($files[$fieldName])) {
152 3
                if (is_array($files[$fieldName])) {
153 3
                    foreach ($files[$fieldName] as $file) {
154 3
                        $postFiles[] = $this->prepareFile($fieldName, $file);
155 3
                    }
156 3
                } else {
157
                    $postFiles[] = $this->prepareFile($fieldName, $files[$fieldName]);
158
                }
159 3
            }
160 5
        }
161
162 5
        $postDataMultipart = [];
163 5
        foreach ($postData as $key => $value) {
164 5
            if (is_array($value)) {
165 2
                foreach ($value as $subValue) {
166 2
                    $postDataMultipart[] = [
167 2
                        'name' => $key,
168 2
                        'contents' => $subValue,
169
                    ];
170 2
                }
171 2
            } else {
172 5
                $postDataMultipart[] = [
173 5
                    'name' => $key,
174 5
                    'contents' => $value,
175
                ];
176
            }
177 5
        }
178
179 5
        return $this->send('POST', $endpointUrl, [], array_merge($postDataMultipart, $postFiles));
180
    }
181
182
    /**
183
     * @param string $endpointUrl
184
     * @param array  $queryString
185
     *
186
     * @throws GenericHTTPError
187
     * @throws InvalidCredentials
188
     * @throws MissingEndpoint
189
     * @throws MissingRequiredParameters
190
     *
191
     * @return \stdClass
192
     */
193
    public function get($endpointUrl, $queryString = [])
194
    {
195
        return $this->send('GET', $endpointUrl.'?'.http_build_query($queryString));
196
    }
197
198
    /**
199
     * @param string $endpointUrl
200
     *
201
     * @throws GenericHTTPError
202
     * @throws InvalidCredentials
203
     * @throws MissingEndpoint
204
     * @throws MissingRequiredParameters
205
     *
206
     * @return \stdClass
207
     */
208
    public function delete($endpointUrl)
209
    {
210
        return $this->send('DELETE', $endpointUrl);
211
    }
212
213
    /**
214
     * @param string $endpointUrl
215
     * @param mixed  $putData
216
     *
217
     * @throws GenericHTTPError
218
     * @throws InvalidCredentials
219
     * @throws MissingEndpoint
220
     * @throws MissingRequiredParameters
221
     *
222
     * @return \stdClass
223
     */
224
    public function put($endpointUrl, $putData)
225
    {
226
        return $this->send('PUT', $endpointUrl, $putData);
227
    }
228
229
    /**
230
     * @param ResponseInterface $responseObj
231
     *
232
     * @throws GenericHTTPError
233
     * @throws InvalidCredentials
234
     * @throws MissingEndpoint
235
     * @throws MissingRequiredParameters
236
     *
237
     * @return \stdClass
238
     */
239 1
    public function responseHandler(ResponseInterface $responseObj)
240
    {
241 1
        $httpResponseCode = (int) $responseObj->getStatusCode();
242
243
        switch ($httpResponseCode) {
244 1
        case 200:
245 1
            $data = (string) $responseObj->getBody();
246 1
            $jsonResponseData = json_decode($data, false);
247 1
            $result = new \stdClass();
248
            // return response data as json if possible, raw if not
249 1
            $result->http_response_body = $data && $jsonResponseData === null ? $data : $jsonResponseData;
250 1
            $result->http_response_code = $httpResponseCode;
251
252 1
            return $result;
253
        case 400:
254
            throw new MissingRequiredParameters(ExceptionMessages::EXCEPTION_MISSING_REQUIRED_PARAMETERS.$this->getResponseExceptionMessage($responseObj));
0 ignored issues
show
Deprecated Code introduced by
The class Mailgun\Connection\Excep...ssingRequiredParameters has been deprecated with message: Will be removed in 3.0

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
255
        case 401:
256
            throw new InvalidCredentials(ExceptionMessages::EXCEPTION_INVALID_CREDENTIALS);
0 ignored issues
show
Deprecated Code introduced by
The class Mailgun\Connection\Exceptions\InvalidCredentials has been deprecated with message: Will be removed in 3.0

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
257
        case 404:
258
            throw new MissingEndpoint(ExceptionMessages::EXCEPTION_MISSING_ENDPOINT.$this->getResponseExceptionMessage($responseObj));
0 ignored issues
show
Deprecated Code introduced by
The class Mailgun\Connection\Exceptions\MissingEndpoint has been deprecated with message: Will be removed in 3.0

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
259
        default:
260
            throw new GenericHTTPError(ExceptionMessages::EXCEPTION_GENERIC_HTTP_ERROR, $httpResponseCode, $responseObj->getBody());
0 ignored issues
show
Deprecated Code introduced by
The class Mailgun\Connection\Exceptions\GenericHTTPError has been deprecated with message: Will be removed in 3.0

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
261
        }
262
    }
263
264
    /**
265
     * @param ResponseInterface $responseObj
266
     *
267
     * @return string
268
     */
269
    protected function getResponseExceptionMessage(ResponseInterface $responseObj)
270
    {
271
        $body = (string) $responseObj->getBody();
272
        $response = json_decode($body);
273
        if (json_last_error() == JSON_ERROR_NONE && isset($response->message)) {
274
            return ' '.$response->message;
275
        }
276
277
        return '';
278
    }
279
280
    /**
281
     * Prepare a file for the postBody.
282
     *
283
     * @param string       $fieldName
284
     * @param string|array $filePath
285
     *
286
     * @return array
287
     */
288 3
    protected function prepareFile($fieldName, $filePath)
289
    {
290 3
        $filename = null;
291
292 3
        if (is_array($filePath) && isset($filePath['fileContent'])) {
293
            // File from memory
294 1
            $filename = $filePath['filename'];
295 1
            $resource = fopen('php://temp', 'r+');
296 1
            fwrite($resource, $filePath['fileContent']);
297 1
            rewind($resource);
298 1
        } else {
299
            // Backward compatibility code
300 3
            if (is_array($filePath) && isset($filePath['filePath'])) {
301 3
                $filename = $filePath['remoteName'];
302 3
                $filePath = $filePath['filePath'];
303 3
            }
304
305
            // Remove leading @ symbol
306 3
            if (strpos($filePath, '@') === 0) {
307 1
                $filePath = substr($filePath, 1);
308 1
            }
309
310 3
            $resource = fopen($filePath, 'r');
311
        }
312
313
        return [
314 3
            'name' => $fieldName,
315 3
            'contents' => $resource,
316 3
            'filename' => $filename,
317 3
        ];
318
    }
319
320
    /**
321
     * @return HttpClient
322
     */
323
    protected function getHttpClient()
324
    {
325
        if ($this->httpClient === null) {
326
            $this->httpClient = HttpClientDiscovery::find();
327
        }
328
329
        return $this->httpClient;
330
    }
331
332
    /**
333
     * @param string $uri
334
     *
335
     * @return string
336
     */
337
    private function getApiUrl($uri)
338
    {
339
        return $this->generateEndpoint($this->apiHost, $this->apiVersion, $this->sslEnabled).$uri;
0 ignored issues
show
Deprecated Code introduced by
The property Mailgun\Connection\RestClient::$sslEnabled has been deprecated with message: To be removed in 3.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
340
    }
341
342
    /**
343
     * @param string $apiEndpoint
344
     * @param string $apiVersion
345
     * @param bool   $ssl
346
     *
347
     * @return string
348
     */
349
    private function generateEndpoint($apiEndpoint, $apiVersion, $ssl)
350
    {
351
        return ($ssl ? 'https://' : 'http://').$apiEndpoint.'/'.$apiVersion.'/';
352
    }
353
354
    /**
355
     * @param string $apiVersion
356
     *
357
     * @return RestClient
358
     */
359
    public function setApiVersion($apiVersion)
360
    {
361
        $this->apiVersion = $apiVersion;
362
363
        return $this;
364
    }
365
366
    /**
367
     * @param bool $sslEnabled
368
     *
369
     * @return RestClient
370
     *
371
     * @deprecated To be removed in 3.0
372
     */
373
    public function setSslEnabled($sslEnabled)
374
    {
375
        $this->sslEnabled = $sslEnabled;
0 ignored issues
show
Deprecated Code introduced by
The property Mailgun\Connection\RestClient::$sslEnabled has been deprecated with message: To be removed in 3.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
376
377
        return $this;
378
    }
379
}
380