GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 6f9c2e...17f02d )
by Cees-Jan
02:19
created

Client   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Test Coverage

Coverage 98.88%

Importance

Changes 0
Metric Value
dl 0
loc 259
ccs 88
cts 89
cp 0.9888
rs 10
c 0
b 0
f 0
wmc 19
lcom 1
cbo 13

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 3
A request() 0 6 1
A requestRaw() 0 9 1
A checkCache() 0 20 2
A storeCache() 0 18 2
A determineCacheKey() 0 15 1
A stripExtraSlashes() 0 4 1
B requestPsr7() 0 41 2
A createRequest() 0 6 1
A getHeaders() 0 8 1
A jsonDecode() 0 6 1
A getHydrator() 0 4 1
A getLoop() 0 4 1
A getBaseURL() 0 4 1
1
<?php
2
declare(strict_types=1);
3
4
namespace ApiClients\Foundation\Transport;
5
6
use GuzzleHttp\Client as GuzzleClient;
7
use GuzzleHttp\Psr7\Request;
8
use GuzzleHttp\Psr7\Response;
9
use Psr\Http\Message\RequestInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\UriInterface;
12
use React\Cache\CacheInterface;
13
use React\EventLoop\LoopInterface;
14
use React\Promise\Deferred;
15
use React\Promise\PromiseInterface;
16
use function React\Promise\reject;
17
use React\Promise\RejectedPromise;
18
use function React\Promise\resolve;
19
use function WyriHaximus\React\futureFunctionPromise;
20
21
class Client
22
{
23
    const DEFAULT_OPTIONS = [
24
        'schema' => 'https',
25
        'path' => '/',
26
        'user_agent' => 'WyriHaximus/php-api-client',
27
        'headers' => [],
28
    ];
29
30
    /**
31
     * @var GuzzleClient
32
     */
33
    protected $handler;
34
35
    /**
36
     * @var LoopInterface
37
     */
38
    protected $loop;
39
40
    /**
41
     * @var array
42
     */
43
    protected $options = [];
44
45
    /**
46
     * @var Hydrator
47
     */
48
    protected $hydrator;
49
50
    /**
51
     * @var CacheInterface
52
     */
53
    protected $cache;
54
55
    /**
56
     * @param LoopInterface $loop
57
     * @param GuzzleClient $handler
58
     * @param array $options
59
     */
60 12
    public function __construct(LoopInterface $loop, GuzzleClient $handler, array $options = [])
61
    {
62 12
        $this->loop = $loop;
63 12
        $this->handler = $handler;
64 12
        $this->options = $options + self::DEFAULT_OPTIONS;
65 12
        if (isset($this->options['cache']) && $this->options['cache'] instanceof CacheInterface) {
66 3
            $this->cache = $this->options['cache'];
67
        }
68 12
        $this->hydrator = new Hydrator($this, $options);
69 12
    }
70
71
    /**
72
     * @param string $path
73
     * @param bool $refresh
74
     * @return PromiseInterface
75
     */
76 5
    public function request(string $path, bool $refresh = false): PromiseInterface
77
    {
78
        return $this->requestRaw($path, $refresh)->then(function ($json) {
79 3
            return $this->jsonDecode($json);
80 5
        });
81
    }
82
83
    /**
84
     * @param string $path
85
     * @param bool $refresh
86
     * @return PromiseInterface
87
     */
88 5
    public function requestRaw(string $path, bool $refresh = false): PromiseInterface
89
    {
90 5
        return $this->requestPsr7(
91 5
            $this->createRequest($path),
92
            $refresh
93
        )->then(function ($response) {
94 3
            return resolve($response->getBody()->getContents());
95 5
        });
96
    }
97
98
    /**
99
     * @param UriInterface $uri
100
     * @return PromiseInterface
101
     */
102 3
    protected function checkCache(UriInterface $uri): PromiseInterface
103
    {
104 3
        if (!($this->cache instanceof CacheInterface)) {
105 1
            return reject();
106
        }
107
108 2
        $key = $this->determineCacheKey($uri);
109
        return $this->cache->get($key)->then(function ($document) {
110 1
            $document = json_decode($document, true);
111 1
            $response = new Response(
112 1
                $document['status_code'],
113 1
                $document['headers'],
114 1
                $document['body'],
115 1
                $document['protocol_version'],
116 1
                $document['reason_phrase']
117
            );
118
119 1
            return resolve($response);
120 2
        });
121
    }
122
123
    /**
124
     * @param RequestInterface $request
125
     * @param ResponseInterface $response
126
     */
127 2
    protected function storeCache(RequestInterface $request, ResponseInterface $response)
128
    {
129 2
        if (!($this->cache instanceof CacheInterface)) {
130
            return;
131
        }
132
133
        $document = [
134 2
            'body' => $response->getBody()->getContents(),
135 2
            'headers' => $response->getHeaders(),
136 2
            'protocol_version' => $response->getProtocolVersion(),
137 2
            'reason_phrase' => $response->getReasonPhrase(),
138 2
            'status_code' => $response->getStatusCode(),
139
        ];
140
141 2
        $key = $this->determineCacheKey($request->getUri());
142
143 2
        $this->cache->set($key, json_encode($document));
144 2
    }
145
146
    /**
147
     * @param UriInterface $uri
148
     * @return string
149
     */
150 3
    protected function determineCacheKey(UriInterface $uri): string
151
    {
152 3
        return $this->stripExtraSlashes(
153
            implode(
154 3
                '/',
155
                [
156 3
                    $uri->getScheme(),
157 3
                    $uri->getHost(),
158 3
                    $uri->getPort(),
159 3
                    $uri->getPath(),
160 3
                    md5($uri->getQuery()),
161
                ]
162
            )
163
        );
164
    }
165
166
    /**
167
     * @param string $string
168
     * @return string
169
     */
170 3
    protected function stripExtraSlashes(string $string): string
171
    {
172 3
        return preg_replace('#/+#', '/', $string);
173
    }
174
175
    /**
176
     * @param RequestInterface $request
177
     * @param bool $refresh
178
     * @return PromiseInterface
179
     */
180 5
    public function requestPsr7(RequestInterface $request, bool $refresh = false): PromiseInterface
181
    {
182 5
        $promise = new RejectedPromise();
183
184 5
        if (!$refresh) {
185 3
            $promise = $this->checkCache($request->getUri());
186
        }
187
188
        return $promise->otherwise(function () use ($request) {
189 4
            $deferred = new Deferred();
190
191 4
            $this->handler->sendAsync(
192
                $request
193
            )->then(function (ResponseInterface $response) use ($deferred, $request) {
194 2
                $contents = $response->getBody()->getContents();
195 2
                $this->storeCache(
196
                    $request,
197 2
                    new Response(
198 2
                        $response->getStatusCode(),
199 2
                        $response->getHeaders(),
200
                        $contents,
201 2
                        $response->getProtocolVersion(),
202 2
                        $response->getReasonPhrase()
203
                    )
204
                );
205 2
                $deferred->resolve(
206 2
                    new Response(
207 2
                        $response->getStatusCode(),
208 2
                        $response->getHeaders(),
209
                        $contents,
210 2
                        $response->getProtocolVersion(),
211 2
                        $response->getReasonPhrase()
212
                    )
213
                );
214
            }, function ($error) use ($deferred) {
215
                $deferred->reject($error);
216 4
            });
217
218 4
            return $deferred->promise();
219 5
        });
220
    }
221
222
    /**
223
     * @param string $path
224
     * @return RequestInterface
225
     */
226 5
    protected function createRequest(string $path): RequestInterface
227
    {
228 5
        $url = $this->getBaseURL() . $path;
229 5
        $headers = $this->getHeaders();
230 5
        return new Request('GET', $url, $headers);
231
    }
232
233
    /**
234
     * @return array
235
     */
236 5
    public function getHeaders(): array
237
    {
238
        $headers = [
239 5
            'User-Agent' => $this->options['user_agent'],
240
        ];
241 5
        $headers += $this->options['headers'];
242 5
        return $headers;
243
    }
244
245
    /**
246
     * @param string $json
247
     * @return PromiseInterface
248
     */
249
    public function jsonDecode(string $json): PromiseInterface
250
    {
251 3
        return futureFunctionPromise($this->loop, $json, function ($json) {
252 3
            return json_decode($json, true);
253 3
        });
254
    }
255
256
    /**
257
     * @return Hydrator
258
     */
259 1
    public function getHydrator(): Hydrator
260
    {
261 1
        return $this->hydrator;
262
    }
263
264
    /**
265
     * @return LoopInterface
266
     */
267 3
    public function getLoop(): LoopInterface
268
    {
269 3
        return $this->loop;
270
    }
271
272
    /**
273
     * @return string
274
     */
275 8
    public function getBaseURL(): string
276
    {
277 8
        return $this->options['schema'] . '://' . $this->options['host'] . $this->options['path'];
278
    }
279
}
280