Test Failed
Push — master ( 0a7302...827e28 )
by Carsten
04:14 queued 11s
created

setClientExceptionLoglevel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
namespace Germania\ClientIpLocation;
3
4
use Psr\Http\Client\ClientInterface;
5
use Psr\Http\Client\ClientExceptionInterface;
6
7
use Psr\Http\Message\RequestInterface;
8
use Psr\Http\Message\RequestFactoryInterface;
9
use Psr\Http\Message\ResponseInterface;
10
11
use Psr\Log\LoggerInterface;
12
use Psr\Log\NullLogger;
13
use Psr\Log\LogLevel;
14
use Psr\Log\LoggerAwareTrait;
15
16
class HttpClientLocationCreator
17
{
18
    use LoggerAwareTrait;
19 1
20
    /**
21
     * @var ClientInterface
22
     */
23
    protected $client;
24
25
26
    /**
27
     * @var RequestFactoryInterface
28
     */
29
    public $request_factory;
30
31
32
    /**
33
     * Geocoder API endpoint.
34
     *
35
     * @var string
36
     */
37
    public $api;
38
39
40
    /**
41
     * IP adress query parameter
42
     *
43
     * @var string
44
     */
45
    public $ip_var_name = "ip";
46
47
48
    /**
49
     * @var callable
50
     */
51
    public $response_decoder;
52
53
54
    /**
55
     * @var mixed
56
     */
57
    public $default_location;
58
59
60
    /**
61
     * @var string
62
     */
63
    protected $error_loglevel = LogLevel::ERROR;
64
65
66
    /**
67
     * @var string
68
     */
69
    protected $client_exception_loglevel = LogLevel::NOTICE;
70
71
72
    /**
73 2
     * @param string                  $api              Geocoder API endpoint
74
     * @param ClientInterface         $client           PSR-18 HTTP Client
75 2
     * @param RequestFactoryInterface $request_factory  PSR-17 Request factory
76 2
     * @param callable|null           $response_decoder Optional: PSR-7 Response decoder callable
77 2
     */
78 2
    public function __construct( string $api, ClientInterface $client, RequestFactoryInterface $request_factory, callable $response_decoder = null, LoggerInterface $logger = null)
79 2
    {
80 2
        $this->setApiEndpoint( $api )
81
             ->setClient($client)
82
             ->setRequestFactory($request_factory)
83
             ->setResponseDecoder($response_decoder)
84
             ->setLogger( $logger ?: new NullLogger);
85
    }
86
87 2
88
89 2
    /**
90
     * @param  string $client_ip Client IP address
91
     */
92 2
    public function __invoke( string $client_ip )
93 2
    {
94
        $request = $this->createRequest($client_ip);
95
96
        try {
97
            $response = $this->client->sendRequest( $request);
98
            $response_status = $response->getStatusCode();
99
100
            switch($response_status):
101
                case 200:
102
                    return $this->decodeResponse($response);
103
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
104
105
                case 404:
106
                    $msg = sprintf("Could not find location for IP address");
107
                    throw new ClientException($msg, $response_status);
108
                    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...
109
110
                default:
111
                    $msg = sprintf("Error response with error status code: '%s'", $response_status);
112
                    throw new ClientException($msg, $response_status);
113
114
            endswitch;
115 4
        }
116
        catch (ClientExceptionInterface $e) {
117 4
            $msg_location = sprintf("%s:%s", $e->getFile(), $e->getLine());
118 4
119
            $this->logger->log( $this->client_exception_loglevel, $e->getMessage(), [
120 4
                'type' => get_class($e),
121
                'code' => $e->getCode(),
122 4
                'request' => $request->getUri()->__toString(),
123
                'location' => $msg_location,
124
                'apiEndpoint' => $this->api,
125
                'clientIp' => $client_ip
126
            ]);
127
128
            return $this->default_location;
129
        }
130
        catch (\Throwable $e) {
131 4
            $msg = sprintf("Exception caught in HttpClientLocationCreator: %s", $e->getMessage());
132
            $msg_location = sprintf("%s:%s", $e->getFile(), $e->getLine());
133 4
            $this->logger->log( $this->error_loglevel, $msg, [
134 4
                'type' => get_class($e),
135 4
                'code' => $e->getCode(),
136
                'request' => $request->getUri()->__toString(),
137
                'location' => $msg_location,
138
                'apiEndpoint' => $this->api,
139
                'clientIp' => $client_ip
140
            ]);
141
142
            return $this->default_location;
143
        }
144
    }
145 2
146
147 2
148 2
    /**
149
     * @param  string $client_ip Client IP address
150
     * @return RequestInterface
151
     */
152
    public function createRequest( string $client_ip ) : RequestInterface
153
    {
154
        $client_ip_urlencoded = urlencode($client_ip);
155
        $query_parameter_field = "{{" . $this->ip_var_name . "}}";
156
157
        $api = str_replace($query_parameter_field, $client_ip_urlencoded, $this->api);
158 4
159
        return $this->request_factory->createRequest("GET", $api);
160 4
    }
161 4
162
163
164
    /**
165
     * @param  ResponseInterface $response
166
     * @return mixed
167
     */
168
    public function decodeResponse(ResponseInterface $response)
169
    {
170
        return $this->response_decoder
171 6
        ? ($this->response_decoder)($response)
172
        : json_decode($response->getBody(), "assoc");
173 6
    }
174 6
175
176
177
    /**
178
     * Sets the default location to return on error
179
     *
180
     * @param mixed $location
181
     */
182
    public function setDefaultLocation( $location ) : self
183 4
    {
184
        $this->default_location = $location;
185 4
        return $this;
186 4
    }
187
188
189
    /**
190
     * @param string $error_loglevel PSR-3 Loglevel name
191
     */
192
    public function setErrorLoglevel( string $error_loglevel ) {
193
        $this->error_loglevel = $error_loglevel;
194
        return $this;
195 4
    }
196
197 4
198 4
199
    /**
200
     * @param string $client_exception_loglevel PSR-3 Loglevel name
201
     */
202
    public function setClientExceptionLoglevel( string $client_exception_loglevel ) {
203
        $this->client_exception_loglevel = $client_exception_loglevel;
204
        return $this;
205
    }
206
207
208
    /**
209
     * Sets the API endpoint
210
     *
211
     * @param string $api
212
     */
213
    public function setApiEndpoint( string $api ) : self
214
    {
215
        $this->api = $api;
216
        return $this;
217
    }
218
219
220
221
    /**
222
     * Sets the HTTP Client to use.
223
     *
224
     * @param ClientInterface $client
225
     */
226
    public function setClient( ClientInterface $client ) : self
227
    {
228
        $this->client = $client;
229
        return $this;
230
    }
231
232
233
    /**
234
     * Sets the PSR-17 Request factory
235
     *
236
     * @param RequestFactoryInterface $request_factory
237
     */
238
    public function setRequestFactory( RequestFactoryInterface $request_factory ) : self
239
    {
240
        $this->request_factory = $request_factory;
241
        return $this;
242
    }
243
244
245
    /**
246
     * Sets the PSR-7 Response decoder callable.
247
     *
248
     * @param callable $response_decoder
249
     */
250
    public function setResponseDecoder( callable $response_decoder = null ) : self
251
    {
252
        $this->response_decoder = $response_decoder;
253
        return $this;
254
    }
255
256
}
257