Completed
Push — master ( a8687a...737d23 )
by Joachim
07:33
created

Client::addResponseError()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 0
cts 10
cp 0
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 8
nop 3
crap 20
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|string|int|bool
47
     */
48
    protected $response;
49
50 1
    public function __construct(string $apiKey, string $baseUrl = 'https://api.linkmobility.dk/v2')
51
    {
52 1
        Assert::that($baseUrl)->url();
53
54 1
        $this->apiKey = $apiKey;
55 1
        $this->baseUrl = $baseUrl;
56 1
    }
57
58
    /**
59
     * @param RequestInterface $request
60
     * @return ResponseInterface
61
     * @throws GuzzleException
62
     */
63
    public function request(RequestInterface $request) : ResponseInterface
64
    {
65
        $responseClass = $request->getResponseClass();
66
67
        return new $responseClass($this->rawRequest($request->getMethod(), $request->getUri(), $request->getOptions()));
68
    }
69
70
    /**
71
     * @param string $method
72
     * @param string $uri
73
     * @param array $options
74
     * @return mixed
75
     */
76 1
    public function rawRequest(string $method, string $uri, array $options = [])
77
    {
78
        try {
79
            // reset responses
80 1
            $this->response = [];
81 1
            $this->httpResponse = null;
82
83
            // get http client
84 1
            $client = $this->getHttpClient();
85
86
            // resolve options
87 1
            $resolver = new OptionsResolver();
88 1
            $this->configureOptions($resolver);
89 1
            $options = $resolver->resolve($options);
90
91
            // create url
92 1
            $url = $this->baseUrl . '/' . $uri . '?apikey=' . $this->apiKey;
93
94
            // do request
95 1
            $this->httpResponse = $client->request($method, $url, $options);
96
97
            // parse response
98 1
            $this->response = \GuzzleHttp\json_decode((string)$this->httpResponse->getBody(), true);
99
        } catch (ExceptionInterface $e) {
100
            $this->addResponseError($e, 'Symfony Options Resolver Exception');
0 ignored issues
show
Documentation introduced by
$e is of type object<Symfony\Component...ion\ExceptionInterface>, but the function expects a 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...
101
        } catch (GuzzleException $e) {
102
            $this->addResponseError($e, 'Guzzle Exception');
0 ignored issues
show
Documentation introduced by
$e is of type object<GuzzleHttp\Exception\GuzzleException>, but the function expects a 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...
103
        } catch (\InvalidArgumentException $e) {
104
            $this->addResponseError($e, 'JSON parse error');
105
        }
106
107 1
        return $this->response;
108
    }
109
110
    /**
111
     * @return ClientInterface
112
     */
113 1
    public function getHttpClient() : ClientInterface
114
    {
115 1
        if (!$this->httpClient) {
116 1
            $this->httpClient = new HttpClient();
117
        }
118 1
        return $this->httpClient;
119
    }
120
121
    /**
122
     * @param ClientInterface $httpClient
123
     * @return Client
124
     */
125 1
    public function setHttpClient(ClientInterface $httpClient) : Client
126
    {
127 1
        $this->httpClient = $httpClient;
128 1
        return $this;
129
    }
130
131
    /**
132
     * Returns the latest response or null if no request was made yet
133
     *
134
     * @return HttpResponseInterface|null
135
     */
136 1
    public function getHttpResponse() : ?HttpResponseInterface
137
    {
138 1
        return $this->httpResponse;
139
    }
140
141
    /**
142
     * @return array|bool|int|string
143
     */
144
    public function getResponse()
145
    {
146
        return $this->response;
147
    }
148
149 1
    protected function configureOptions(OptionsResolver $resolver) : void
150
    {
151 1
        $refl = new \ReflectionClass(RequestOptions::class);
152 1
        $requestOptions = array_values($refl->getConstants());
153 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...
154
155 1
        $resolver->setDefaults([
156 1
            RequestOptions::HEADERS => [
157
                'Accept' => 'application/json',
158
            ],
159 1
            RequestOptions::CONNECT_TIMEOUT => 30,
160 1
            RequestOptions::TIMEOUT => 120,
161 1
            RequestOptions::HTTP_ERRORS => true
162
        ]);
163 1
    }
164
165
    protected function addResponseError(\Exception $exception, string $title, ?string $detail = null) : void
166
    {
167
        if (!isset($this->response['errors'])) {
168
            $this->response['errors'] = [];
169
        }
170
171
        $error = [
172
            'title' => $title,
173
            'detail' => $detail ? : $exception->getMessage(),
174
            'meta' => [
175
                'exception' => get_class($exception)
176
            ]
177
        ];
178
179
        if ($this->httpResponse) {
180
            $error['status'] = $this->httpResponse->getStatusCode();
181
        }
182
183
        $this->response['errors'][] = $error;
184
    }
185
}
186