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 ( d7609d...cf51ac )
by Cees-Jan
02:08
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 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
                $this->storeCache($request, $response);
195 2
                $deferred->resolve($response);
196
            }, function ($error) use ($deferred) {
197
                $deferred->reject($error);
198 4
            });
199
200 4
            return $deferred->promise();
201 5
        });
202
    }
203
204
    /**
205
     * @param string $path
206
     * @return RequestInterface
207
     */
208 5
    protected function createRequest(string $path): RequestInterface
209
    {
210 5
        $url = $this->getBaseURL() . $path;
211 5
        $headers = $this->getHeaders();
212 5
        return new Request('GET', $url, $headers);
213
    }
214
215
    /**
216
     * @return array
217
     */
218 5
    public function getHeaders(): array
219
    {
220
        $headers = [
221 5
            'User-Agent' => $this->options['user_agent'],
222
        ];
223 5
        $headers += $this->options['headers'];
224 5
        return $headers;
225
    }
226
227
    /**
228
     * @param string $json
229
     * @return PromiseInterface
230
     */
231
    public function jsonDecode(string $json): PromiseInterface
232
    {
233 3
        return futureFunctionPromise($this->loop, $json, function ($json) {
234 3
            return json_decode($json, true);
235 3
        });
236
    }
237
238
    /**
239
     * @return Hydrator
240
     */
241 1
    public function getHydrator(): Hydrator
242
    {
243 1
        return $this->hydrator;
244
    }
245
246
    /**
247
     * @return LoopInterface
248
     */
249 3
    public function getLoop(): LoopInterface
250
    {
251 3
        return $this->loop;
252
    }
253
254
    /**
255
     * @return string
256
     */
257 8
    public function getBaseURL(): string
258
    {
259 8
        return $this->options['schema'] . '://' . $this->options['host'] . $this->options['path'];
260
    }
261
}
262