Client   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 69.23%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 7
dl 0
loc 170
ccs 36
cts 52
cp 0.6923
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A request() 0 5 1
B rawRequest() 0 36 4
A getHttpClient() 0 7 2
A setHttpClient() 0 5 1
A getHttpResponse() 0 4 1
A getResponse() 0 4 1
A configureOptions() 0 15 1
A setResponseError() 0 9 2
1
<?php declare(strict_types=1);
2
namespace Loevgaard\Linkmobility;
3
4
use Assert\Assert;
5
use GuzzleHttp\Client as HttpClient;
6
use GuzzleHttp\ClientInterface;
7
use GuzzleHttp\Exception\GuzzleException;
8
use GuzzleHttp\RequestOptions;
9
use Loevgaard\Linkmobility\Request\RequestInterface;
10
use Loevgaard\Linkmobility\Response\ResponseInterface;
11
use Psr\Http\Message\ResponseInterface as HttpResponseInterface;
12
use Symfony\Component\OptionsResolver\Exception\ExceptionInterface;
13
use Symfony\Component\OptionsResolver\OptionsResolver;
14
15
class Client
16
{
17
    /**
18
     * The API key used for making requests
19
     *
20
     * @var string
21
     */
22
    protected $apiKey;
23
24
    /**
25
     * The base url used for making requests
26
     *
27
     * @var string
28
     */
29
    protected $baseUrl;
30
31
    /**
32
     * The HTTP client used for making requests
33
     *
34
     * @var ClientInterface
35
     */
36
    protected $httpClient;
37
38
    /**
39
     * Contains the last response object
40
     *
41
     * @var HttpResponseInterface|null
42
     */
43
    protected $httpResponse;
44
45
    /**
46
     * @var array
47
     */
48
    protected $response;
49
50 2
    public function __construct(string $apiKey, string $baseUrl = 'https://api.linkmobility.dk/v2')
51
    {
52 2
        Assert::that($baseUrl)->url();
53
54 2
        $this->apiKey = $apiKey;
55 2
        $this->baseUrl = $baseUrl;
56 2
    }
57
58
    /**
59
     * @param RequestInterface $request
60
     * @return ResponseInterface
61
     * @throws ExceptionInterface
62
     */
63
    public function request(RequestInterface $request) : ResponseInterface
64
    {
65
        $responseClass = $request->getResponseClass();
66
        return new $responseClass($this->rawRequest($request->getMethod(), $request->getUri(), $request->getBody(), $request->getOptions()));
67
    }
68
69
    /**
70
     * @param string $method
71
     * @param string $uri
72
     * @param array $body
73
     * @param array $options
74
     * @return array
75
     * @throws ExceptionInterface
76
     */
77 1
    public function rawRequest(string $method, string $uri, array $body = [], array $options = []) : array
78
    {
79
        try {
80
            // reset responses
81 1
            $this->response = [];
82 1
            $this->httpResponse = null;
83
84
            // get http client
85 1
            $client = $this->getHttpClient();
86
87
            // resolve options
88 1
            $resolver = new OptionsResolver();
89 1
            $this->configureOptions($resolver);
90 1
            $options = $resolver->resolve($options);
91
92 1
            if (!empty($body)) {
93
                // the body will always override any other data sent
94
                $options['json'] = $body;
95
            }
96
97
            // create url
98 1
            $url = $this->baseUrl . $uri . '?apikey=' . $this->apiKey;
99
100
            // do request
101 1
            $this->httpResponse = $client->request($method, $url, $options);
102
103
            // parse response
104 1
            $this->response = \GuzzleHttp\json_decode((string)$this->httpResponse->getBody(), true);
0 ignored issues
show
Documentation Bug introduced by
It seems like \GuzzleHttp\json_decode(...ponse->getBody(), true) of type * is incompatible with the declared type array of property $response.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
105
        } catch (GuzzleException $e) {
106
            $this->setResponseError($e);
0 ignored issues
show
Documentation introduced by
$e is of type object<GuzzleHttp\Exception\GuzzleException>, but the function expects a string|object<Exception>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
107
        } catch (\InvalidArgumentException $e) {
108
            $this->setResponseError($e);
109
        }
110
111 1
        return $this->response;
112
    }
113
114
    /**
115
     * @return ClientInterface
116
     */
117 2
    public function getHttpClient() : ClientInterface
118
    {
119 2
        if (!$this->httpClient) {
120 1
            $this->httpClient = new HttpClient();
121
        }
122 2
        return $this->httpClient;
123
    }
124
125
    /**
126
     * @param ClientInterface $httpClient
127
     * @return Client
128
     */
129 2
    public function setHttpClient(ClientInterface $httpClient) : Client
130
    {
131 2
        $this->httpClient = $httpClient;
132 2
        return $this;
133
    }
134
135
    /**
136
     * Returns the latest response or null if no request was made yet
137
     *
138
     * @return HttpResponseInterface|null
139
     */
140 1
    public function getHttpResponse()
141
    {
142 1
        return $this->httpResponse;
143
    }
144
145
    /**
146
     * @return array
147
     */
148
    public function getResponse() : array
149
    {
150
        return (array)$this->response;
151
    }
152
153 1
    protected function configureOptions(OptionsResolver $resolver) : void
154
    {
155 1
        $refl = new \ReflectionClass(RequestOptions::class);
156 1
        $requestOptions = array_values($refl->getConstants());
157 1
        $resolver->setDefined($requestOptions);
0 ignored issues
show
Documentation introduced by
$requestOptions is of type array<integer,integer|double|string|boolean>, but the function expects a string|array<integer,string>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
158
159 1
        $resolver->setDefaults([
160 1
            RequestOptions::HEADERS => [
161
                'Accept' => 'application/json',
162
            ],
163 1
            RequestOptions::CONNECT_TIMEOUT => 30,
164 1
            RequestOptions::TIMEOUT => 120,
165 1
            RequestOptions::HTTP_ERRORS => false
166
        ]);
167 1
    }
168
169
    /**
170
     * Linkmobility always formats their errors like this, so we mimic this
171
     *
172
     * @param string|\Exception $error
173
     * @param int $statusCode
174
     */
175
    protected function setResponseError($error, int $statusCode = 500) : void
176
    {
177
        if ($error instanceof \Exception) {
178
            $error = $error->getMessage();
179
        }
180
181
        $this->response['message'] = (string)$error;
182
        $this->response['status'] = $statusCode;
183
    }
184
}
185