HttpApi   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 180
Duplicated Lines 13.33 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 9
dl 24
loc 180
ccs 0
cts 70
cp 0
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 2
A httpGet() 0 10 2
A httpPost() 0 6 1
A httpPostRaw() 0 6 1
A httpPut() 8 8 1
A httpDelete() 8 8 1
A httpPatch() 8 8 1
B handleErrors() 0 21 6

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
 * 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 FAPI\PhraseApp\Api;
11
12
use FAPI\PhraseApp\Exception\Domain as DomainExceptions;
13
use FAPI\PhraseApp\Exception\DomainException;
14
use FAPI\PhraseApp\Hydrator\Hydrator;
15
use FAPI\PhraseApp\Hydrator\NoopHydrator;
16
use FAPI\PhraseApp\RequestBuilder;
17
use Http\Client\HttpClient;
18
use Psr\Http\Client\ClientExceptionInterface;
19
use Psr\Http\Message\ResponseInterface;
20
21
/**
22
 * @author Sascha-Oliver Prolic <[email protected]>
23
 */
24
abstract class HttpApi
25
{
26
    /**
27
     * @var HttpClient
28
     */
29
    protected $httpClient;
30
31
    /**
32
     * @var Hydrator
33
     */
34
    protected $hydrator;
35
36
    /**
37
     * @var RequestBuilder
38
     */
39
    protected $requestBuilder;
40
41
    /**
42
     * @param HttpClient     $httpClient
43
     * @param RequestBuilder $requestBuilder
44
     * @param Hydrator       $hydrator
45
     */
46
    public function __construct(HttpClient $httpClient, Hydrator $hydrator, RequestBuilder $requestBuilder)
47
    {
48
        $this->httpClient = $httpClient;
49
        $this->requestBuilder = $requestBuilder;
50
        if (!$hydrator instanceof NoopHydrator) {
51
            $this->hydrator = $hydrator;
52
        }
53
    }
54
55
    /**
56
     * Send a GET request with query parameters.
57
     *
58
     * @param string $path           Request path
59
     * @param array  $params         GET parameters
60
     * @param array  $requestHeaders Request Headers
61
     *
62
     * @throws ClientExceptionInterface
63
     *
64
     * @return ResponseInterface
65
     */
66
    protected function httpGet(string $path, array $params = [], array $requestHeaders = []): ResponseInterface
67
    {
68
        if (empty($params)) {
69
            $path .= '?'.http_build_query($params);
70
        }
71
72
        return $this->httpClient->sendRequest(
73
            $this->requestBuilder->create('GET', $path, $requestHeaders)
74
        );
75
    }
76
77
    /**
78
     * Send a POST request with JSON-encoded parameters.
79
     *
80
     * @param string $path           Request path
81
     * @param array  $params         POST parameters to be JSON encoded
82
     * @param array  $requestHeaders Request headers
83
     *
84
     * @throws ClientExceptionInterface
85
     *
86
     * @return ResponseInterface
87
     */
88
    protected function httpPost(string $path, array $params = [], array $requestHeaders = []): ResponseInterface
89
    {
90
        $requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
91
92
        return $this->httpPostRaw($path, http_build_query($params), $requestHeaders);
93
    }
94
95
    /**
96
     * Send a POST request with raw data.
97
     *
98
     * @param string       $path           Request path
99
     * @param array|string $body           Request body
100
     * @param array        $requestHeaders Request headers
101
     *
102
     * @throws ClientExceptionInterface
103
     *
104
     * @return ResponseInterface
105
     */
106
    protected function httpPostRaw(string $path, $body, array $requestHeaders = []): ResponseInterface
107
    {
108
        return $this->httpClient->sendRequest(
109
            $this->requestBuilder->create('POST', $path, $requestHeaders, $body)
110
        );
111
    }
112
113
    /**
114
     * Send a PUT request with JSON-encoded parameters.
115
     *
116
     * @param string $path           Request path
117
     * @param array  $params         POST parameters to be JSON encoded
118
     * @param array  $requestHeaders Request headers
119
     *
120
     * @throws ClientExceptionInterface
121
     *
122
     * @return ResponseInterface
123
     */
124 View Code Duplication
    protected function httpPut(string $path, array $params = [], 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...
125
    {
126
        $requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
127
128
        return $this->httpClient->sendRequest(
129
            $this->requestBuilder->create('PUT', $path, $requestHeaders, http_build_query($params))
130
        );
131
    }
132
133
    /**
134
     * Send a DELETE request with JSON-encoded parameters.
135
     *
136
     * @param string $path           Request path
137
     * @param array  $params         POST parameters to be JSON encoded
138
     * @param array  $requestHeaders Request headers
139
     *
140
     * @throws ClientExceptionInterface
141
     *
142
     * @return ResponseInterface
143
     */
144 View Code Duplication
    protected function httpDelete(string $path, array $params = [], 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...
145
    {
146
        $requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
147
148
        return $this->httpClient->sendRequest(
149
            $this->requestBuilder->create('DELETE', $path, $requestHeaders, http_build_query($params))
150
        );
151
    }
152
153
    /**
154
     * Send a PATCH request with json encoded data.
155
     *
156
     * @param string       $path           Request path
157
     * @param array|string $body           Request body
158
     * @param array        $requestHeaders Request headers
159
     *
160
     * @throws ClientExceptionInterface
161
     *
162
     * @return ResponseInterface
163
     */
164 View Code Duplication
    protected function httpPatch(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...
165
    {
166
        $requestHeaders['Content-Type'] = 'application/json';
167
168
        return $this->httpClient->sendRequest(
169
            $this->requestBuilder->create('PATCH', $path, $requestHeaders, json_encode($body))
170
        );
171
    }
172
173
    /**
174
     * Handle HTTP errors.
175
     *
176
     * Call is controlled by the specific API methods.
177
     *
178
     * @param ResponseInterface $response
179
     *
180
     * @throws DomainException
181
     */
182
    protected function handleErrors(ResponseInterface $response)
183
    {
184
        switch ($response->getStatusCode()) {
185
            case 401:
186
                throw new DomainExceptions\InvalidApiKeyException('Invalid API key');
187
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
188
            case 403:
189
                throw new DomainExceptions\InsufficientPrivilegesException('Insufficient Privileges');
190
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
191
            case 404:
192
                throw new DomainExceptions\NotFoundException('Not found');
193
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
194
            case 422:
195
                throw new DomainExceptions\UnprocessableEntityException('Unprocessable entity');
196
            case 429:
197
                throw new DomainExceptions\RateLimitExceededException('Rate limit exceeded');
198
            default:
199
                throw new DomainExceptions\UnknownErrorException('Unknown error');
200
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
201
        }
202
    }
203
}
204