Completed
Push — master ( d8ae00...12ed8a )
by Tobias
02:18
created

HttpApi   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 198
Duplicated Lines 18.18 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 58.81%

Importance

Changes 0
Metric Value
wmc 29
lcom 2
cbo 6
dl 36
loc 198
ccs 40
cts 68
cp 0.5881
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
B handleErrors() 0 22 8
A httpGet() 0 16 3
A httpPost() 0 4 1
A httpPostRaw() 12 12 2
A httpPut() 12 12 2
A httpDelete() 12 12 2
A createRequestBody() 0 17 4
A hydrateResponse() 0 12 3
A __construct() 0 13 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 120
    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 120
        $this->httpClient = $httpClient;
55 120
        $this->requestBuilder = $requestBuilder;
56 120
        if (!$hydrator instanceof NoopHydrator) {
57 120
            $this->hydrator = $hydrator;
58
        }
59 120
    }
60
61
    /**
62
     * @return mixed|ResponseInterface
63
     *
64
     * @throws \Exception
65
     */
66 94
    protected function hydrateResponse(ResponseInterface $response, string $class)
67
    {
68 94
        if (null === $this->hydrator) {
69
            return $response;
70
        }
71
72 94
        if (!in_array($response->getStatusCode(), [200, 201, 202], true)) {
73
            $this->handleErrors($response);
74
        }
75
76 94
        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 21
    protected function httpGet(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
115
    {
116 21
        if (count($parameters) > 0) {
117 6
            $path .= '?'.http_build_query($parameters);
118
        }
119
120
        try {
121 21
            $response = $this->httpClient->sendRequest(
122 21
                $this->requestBuilder->create('GET', $path, $requestHeaders)
123
            );
124
        } catch (Psr18\NetworkExceptionInterface $e) {
125
            throw HttpServerException::networkError($e);
126
        }
127
128 21
        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 17
    protected function httpPost(string $path, array $parameters = [], array $requestHeaders = []): ResponseInterface
139
    {
140 17
        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 18 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 18
            $response = $this->httpClient->sendRequest(
154 18
                $this->requestBuilder->create('POST', $path, $requestHeaders, $body)
155
            );
156
        } catch (Psr18\NetworkExceptionInterface $e) {
157
            throw HttpServerException::networkError($e);
158
        }
159
160 18
        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 15 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 15
            $response = $this->httpClient->sendRequest(
194 15
                $this->requestBuilder->create('DELETE', $path, $requestHeaders, $this->createRequestBody($parameters))
195
            );
196
        } catch (Psr18\NetworkExceptionInterface $e) {
197
            throw HttpServerException::networkError($e);
198
        }
199
200 15
        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 44
    private function createRequestBody(array $parameters): array
209
    {
210 44
        $resources = [];
211 44
        foreach ($parameters as $key => $values) {
212 28
            if (!is_array($values)) {
213 27
                $values = [$values];
214
            }
215 28
            foreach ($values as $value) {
216 28
                $resources[] = [
217 28
                    'name' => $key,
218 28
                    'content' => $value,
219
                ];
220
            }
221
        }
222
223 44
        return $resources;
224
    }
225
}
226