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 ( cf51ac...6f9c2e )
by Cees-Jan
02:29
created

Client::getBaseURL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 1
            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 1
            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
    protected function storeCache(RequestInterface $request, ResponseInterface $response)
128
    {
129
        if (!($this->cache instanceof CacheInterface)) {
130
            return;
131
        }
132
133
        $document = [
134
            'body' => $response->getBody()->getContents(),
135
            'headers' => $response->getHeaders(),
136
            'protocol_version' => $response->getProtocolVersion(),
137
            'reason_phrase' => $response->getReasonPhrase(),
138
            'status_code' => $response->getStatusCode(),
139
        ];
140
141
        $key = $this->determineCacheKey($request->getUri());
142
143
        $this->cache->set($key, json_encode($document));
144
    }
145
146
    /**
147
     * @param UriInterface $uri
148
     * @return string
149
     */
150 2
    protected function determineCacheKey(UriInterface $uri): string
151
    {
152 2
        return $this->stripExtraSlashes(
153
            implode(
154 2
                '/',
155
                [
156 2
                    $uri->getScheme(),
157 2
                    $uri->getHost(),
158 2
                    $uri->getPort(),
159 2
                    $uri->getPath(),
160 2
                    md5($uri->getQuery()),
161
                ]
162
            )
163
        );
164
    }
165
166
    /**
167
     * @param string $string
168
     * @return string
169
     */
170 2
    protected function stripExtraSlashes(string $string): string
171
    {
172 2
        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
                $cacheResponse = new Response(
196 2
                    $response->getStatusCode(),
197 2
                    $response->getHeaders(),
198
                    $contents,
199 2
                    $response->getProtocolVersion(),
200 2
                    $response->getReasonPhrase()
201
                );
202
                $deferredResponse = new Response(
203
                    $response->getStatusCode(),
204
                    $response->getHeaders(),
205
                    $contents,
206
                    $response->getProtocolVersion(),
207
                    $response->getReasonPhrase()
208
                );
209
                $this->storeCache($request, $cacheResponse);
210
                $deferred->resolve($deferredResponse);
211
            }, function ($error) use ($deferred) {
212
                $deferred->reject($error);
213 4
            });
214
215 4
            return $deferred->promise();
216 5
        });
217
    }
218
219
    /**
220
     * @param string $path
221
     * @return RequestInterface
222
     */
223 5
    protected function createRequest(string $path): RequestInterface
224
    {
225 5
        $url = $this->getBaseURL() . $path;
226 5
        $headers = $this->getHeaders();
227 5
        return new Request('GET', $url, $headers);
228
    }
229
230
    /**
231
     * @return array
232
     */
233 5
    public function getHeaders(): array
234
    {
235
        $headers = [
236 5
            'User-Agent' => $this->options['user_agent'],
237
        ];
238 5
        $headers += $this->options['headers'];
239 5
        return $headers;
240
    }
241
242
    /**
243
     * @param string $json
244
     * @return PromiseInterface
245
     */
246
    public function jsonDecode(string $json): PromiseInterface
247
    {
248 1
        return futureFunctionPromise($this->loop, $json, function ($json) {
249 1
            return json_decode($json, true);
250 1
        });
251
    }
252
253
    /**
254
     * @return Hydrator
255
     */
256 1
    public function getHydrator(): Hydrator
257
    {
258 1
        return $this->hydrator;
259
    }
260
261
    /**
262
     * @return LoopInterface
263
     */
264 3
    public function getLoop(): LoopInterface
265
    {
266 3
        return $this->loop;
267
    }
268
269
    /**
270
     * @return string
271
     */
272 8
    public function getBaseURL(): string
273
    {
274 8
        return $this->options['schema'] . '://' . $this->options['host'] . $this->options['path'];
275
    }
276
}
277