Completed
Push — master ( 6e372e...1fd018 )
by David
22:04
created

HttpApi::__construct()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 8
cts 9
cp 0.8889
rs 9.8333
c 0
b 0
f 0
cc 4
nc 3
nop 3
crap 4.0218
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Copyright (C) 2013 Mailgun
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license. See the LICENSE file for details.
10
 */
11
12
namespace Mailgun\Api;
13
14
use Http\Client\Common\PluginClient;
15
use Mailgun\Exception\HttpClientException;
16
use Mailgun\Exception\HttpServerException;
17
use Mailgun\Exception\UnknownErrorException;
18
use Mailgun\HttpClient\RequestBuilder;
19
use Mailgun\Hydrator\Hydrator;
20
use Mailgun\Hydrator\NoopHydrator;
21
use Psr\Http\Client as Psr18;
22
use Psr\Http\Client\ClientInterface;
23
use Psr\Http\Message\ResponseInterface;
24
25
/**
26
 * @author Tobias Nyholm <[email protected]>
27
 */
28
abstract class HttpApi
29
{
30
    /**
31
     * The HTTP client.
32
     *
33
     * @var ClientInterface|PluginClient
34
     */
35
    protected $httpClient;
36
37
    /**
38
     * @var Hydrator|null
39
     */
40
    protected $hydrator;
41
42
    /**
43
     * @var RequestBuilder
44
     */
45
    protected $requestBuilder;
46
47 106
    public function __construct($httpClient, RequestBuilder $requestBuilder, Hydrator $hydrator)
48
    {
49 106
        if (!is_a($httpClient, ClientInterface::class) &&
50 106
            !is_a($httpClient, PluginClient::class)) {
51
            throw new \RuntimeException('httpClient must be an instance of 
52
            Psr\Http\Client\ClientInterface or Http\Client\Common\PluginClient');
53
        }
54 106
        $this->httpClient = $httpClient;
55 106
        $this->requestBuilder = $requestBuilder;
56 106
        if (!$hydrator instanceof NoopHydrator) {
57 106
            $this->hydrator = $hydrator;
58
        }
59 106
    }
60
61
    /**
62
     * @return mixed|ResponseInterface
63
     *
64
     * @throws \Exception
65
     */
66 82
    protected function hydrateResponse(ResponseInterface $response, string $class)
67
    {
68 82
        if (null === $this->hydrator) {
69
            return $response;
70
        }
71
72 82
        if (200 !== $response->getStatusCode() && 201 !== $response->getStatusCode()) {
73
            $this->handleErrors($response);
74
        }
75
76 82
        return $this->hydrator->hydrate($response, $class);
77
    }
78
79
    /**
80
     * Throw the correct exception for this error.
81
     *
82
     * @throws \Exception
83
     */
84
    protected function handleErrors(ResponseInterface $response)
85
    {
86
        $statusCode = $response->getStatusCode();
87
        switch ($statusCode) {
88
            case 400:
89
                throw HttpClientException::badRequest($response);
90
            case 401:
91
                throw HttpClientException::unauthorized($response);
92
            case 402:
93
                throw HttpClientException::requestFailed($response);
94
            case 403:
95
                throw  HttpClientException::forbidden($response);
96
            case 404:
97
                throw HttpClientException::notFound($response);
98
            case 413:
99
                throw HttpClientException::payloadTooLarge($response);
100
            case 500 <= $statusCode:
101
                throw HttpServerException::serverError($statusCode);
102
            default:
103
                throw new UnknownErrorException();
104
        }
105
    }
106
107
    /**
108
     * Send a GET request with query parameters.
109
     *
110
     * @param string $path           Request path
111
     * @param array  $parameters     GET parameters
112
     * @param array  $requestHeaders Request Headers
113
     */
114 19
    protected function httpGet(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
115
    {
116 19
        if (count($parameters) > 0) {
117 5
            $path .= '?'.http_build_query($parameters);
118
        }
119
120
        try {
121 19
            $response = $this->httpClient->sendRequest(
122 19
                $this->requestBuilder->create('GET', $path, $requestHeaders)
123
            );
124
        } catch (Psr18\NetworkExceptionInterface $e) {
125
            throw HttpServerException::networkError($e);
126
        }
127
128 19
        return $response;
129
    }
130
131
    /**
132
     * Send a POST request with parameters.
133
     *
134
     * @param string $path           Request path
135
     * @param array  $parameters     POST parameters
136
     * @param array  $requestHeaders Request headers
137
     */
138 14
    protected function httpPost(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
139
    {
140 14
        return $this->httpPostRaw($path, $this->createRequestBody($parameters), $requestHeaders);
141
    }
142
143
    /**
144
     * Send a POST request with raw data.
145
     *
146
     * @param string       $path           Request path
147
     * @param array|string $body           Request body
148
     * @param array        $requestHeaders Request headers
149
     */
150 15 View Code Duplication
    protected function httpPostRaw(string $path, $body, array $requestHeaders = []): ResponseInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
151
    {
152
        try {
153 15
            $response = $this->httpClient->sendRequest(
154 15
                $this->requestBuilder->create('POST', $path, $requestHeaders, $body)
155
            );
156
        } catch (Psr18\NetworkExceptionInterface $e) {
157
            throw HttpServerException::networkError($e);
158
        }
159
160 15
        return $response;
161
    }
162
163
    /**
164
     * Send a PUT request.
165
     *
166
     * @param string $path           Request path
167
     * @param array  $parameters     PUT parameters
168
     * @param array  $requestHeaders Request headers
169
     */
170 12 View Code Duplication
    protected function httpPut(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
    {
172
        try {
173 12
            $response = $this->httpClient->sendRequest(
174 12
                $this->requestBuilder->create('PUT', $path, $requestHeaders, $this->createRequestBody($parameters))
175
            );
176
        } catch (Psr18\NetworkExceptionInterface $e) {
177
            throw HttpServerException::networkError($e);
178
        }
179
180 12
        return $response;
181
    }
182
183
    /**
184
     * Send a DELETE request.
185
     *
186
     * @param string $path           Request path
187
     * @param array  $parameters     DELETE parameters
188
     * @param array  $requestHeaders Request headers
189
     */
190 12 View Code Duplication
    protected function httpDelete(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
    {
192
        try {
193 12
            $response = $this->httpClient->sendRequest(
194 12
                $this->requestBuilder->create('DELETE', $path, $requestHeaders, $this->createRequestBody($parameters))
195
            );
196
        } catch (Psr18\NetworkExceptionInterface $e) {
197
            throw HttpServerException::networkError($e);
198
        }
199
200 12
        return $response;
201
    }
202
203
    /**
204
     * Prepare a set of key-value-pairs to be encoded as multipart/form-data.
205
     *
206
     * @param array $parameters Request parameters
207
     */
208 38
    private function createRequestBody(array $parameters): array
209
    {
210 38
        $resources = [];
211 38
        foreach ($parameters as $key => $values) {
212 25
            if (!is_array($values)) {
213 24
                $values = [$values];
214
            }
215 25
            foreach ($values as $value) {
216 25
                $resources[] = [
217 25
                    'name' => $key,
218 25
                    'content' => $value,
219
                ];
220
            }
221
        }
222
223 38
        return $resources;
224
    }
225
}
226