Completed
Push — master ( f109b4...9b270d )
by David
01:41
created

HttpApi   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 202
Duplicated Lines 17.82 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 55.56%

Importance

Changes 0
Metric Value
wmc 31
lcom 2
cbo 6
dl 36
loc 202
ccs 40
cts 72
cp 0.5556
rs 9.92
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A httpPost() 0 4 1
A hydrateResponse() 0 12 3
A __construct() 0 13 4
B handleErrors() 0 26 10
A httpGet() 0 16 3
A httpPostRaw() 12 12 2
A httpPut() 12 12 2
A httpDelete() 12 12 2
A createRequestBody() 0 17 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 131
    public function __construct($httpClient, RequestBuilder $requestBuilder, Hydrator $hydrator)
48
    {
49
        if (!is_a($httpClient, ClientInterface::class) &&
50
            !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 131
        $this->httpClient = $httpClient;
55 131
        $this->requestBuilder = $requestBuilder;
56 131
        if (!$hydrator instanceof NoopHydrator) {
57 131
            $this->hydrator = $hydrator;
58
        }
59 131
    }
60
61
    /**
62
     * @return mixed|ResponseInterface
63
     *
64
     * @throws \Exception
65
     */
66 104
    protected function hydrateResponse(ResponseInterface $response, string $class)
67
    {
68 104
        if (null === $this->hydrator) {
69
            return $response;
70
        }
71
72 104
        if (!in_array($response->getStatusCode(), [200, 201, 202], true)) {
73
            $this->handleErrors($response);
74
        }
75
76 104
        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 409:
99
                throw HttpClientException::conflict($response);
100
            case 413:
101
                throw HttpClientException::payloadTooLarge($response);
102
            case 429:
103
                throw HttpClientException::tooManyRequests($response);
104
            case 500 <= $statusCode:
105
                throw HttpServerException::serverError($statusCode);
106
            default:
107
                throw new UnknownErrorException();
108
        }
109
    }
110
111
    /**
112
     * Send a GET request with query parameters.
113
     *
114
     * @param string $path           Request path
115
     * @param array  $parameters     GET parameters
116
     * @param array  $requestHeaders Request Headers
117
     */
118 27
    protected function httpGet(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
119
    {
120 27
        if (count($parameters) > 0) {
121 10
            $path .= '?'.urldecode(http_build_query($parameters));
122
        }
123
124
        try {
125 27
            $response = $this->httpClient->sendRequest(
126 27
                $this->requestBuilder->create('GET', $path, $requestHeaders)
127
            );
128
        } catch (Psr18\NetworkExceptionInterface $e) {
129
            throw HttpServerException::networkError($e);
130
        }
131
132 27
        return $response;
133
    }
134
135
    /**
136
     * Send a POST request with parameters.
137
     *
138
     * @param string $path           Request path
139
     * @param array  $parameters     POST parameters
140
     * @param array  $requestHeaders Request headers
141
     */
142 17
    protected function httpPost(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
143
    {
144 17
        return $this->httpPostRaw($path, $this->createRequestBody($parameters), $requestHeaders);
145
    }
146
147
    /**
148
     * Send a POST request with raw data.
149
     *
150
     * @param string       $path           Request path
151
     * @param array|string $body           Request body
152
     * @param array        $requestHeaders Request headers
153
     */
154 20 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...
155
    {
156
        try {
157 20
            $response = $this->httpClient->sendRequest(
158 20
                $this->requestBuilder->create('POST', $path, $requestHeaders, $body)
159
            );
160
        } catch (Psr18\NetworkExceptionInterface $e) {
161
            throw HttpServerException::networkError($e);
162
        }
163
164 20
        return $response;
165
    }
166
167
    /**
168
     * Send a PUT request.
169
     *
170
     * @param string $path           Request path
171
     * @param array  $parameters     PUT parameters
172
     * @param array  $requestHeaders Request headers
173
     */
174 13 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...
175
    {
176
        try {
177 13
            $response = $this->httpClient->sendRequest(
178 13
                $this->requestBuilder->create('PUT', $path, $requestHeaders, $this->createRequestBody($parameters))
179
            );
180
        } catch (Psr18\NetworkExceptionInterface $e) {
181
            throw HttpServerException::networkError($e);
182
        }
183
184 13
        return $response;
185
    }
186
187
    /**
188
     * Send a DELETE request.
189
     *
190
     * @param string $path           Request path
191
     * @param array  $parameters     DELETE parameters
192
     * @param array  $requestHeaders Request headers
193
     */
194 17 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...
195
    {
196
        try {
197 17
            $response = $this->httpClient->sendRequest(
198 17
                $this->requestBuilder->create('DELETE', $path, $requestHeaders, $this->createRequestBody($parameters))
199
            );
200
        } catch (Psr18\NetworkExceptionInterface $e) {
201
            throw HttpServerException::networkError($e);
202
        }
203
204 17
        return $response;
205
    }
206
207
    /**
208
     * Prepare a set of key-value-pairs to be encoded as multipart/form-data.
209
     *
210
     * @param array $parameters Request parameters
211
     */
212 47
    private function createRequestBody(array $parameters): array
213
    {
214 47
        $resources = [];
215 47
        foreach ($parameters as $key => $values) {
216 28
            if (!is_array($values)) {
217 27
                $values = [$values];
218
            }
219 28
            foreach ($values as $value) {
220 28
                $resources[] = [
221 28
                    'name' => $key,
222 28
                    'content' => $value,
223
                ];
224
            }
225
        }
226
227 47
        return $resources;
228
    }
229
}
230