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
Pull Request — master (#2)
by Cees-Jan
07:36
created

Client::preRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 16
Ratio 100 %

Importance

Changes 0
Metric Value
dl 16
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 11
nc 2
nop 3
1
<?php declare(strict_types=1);
2
3
namespace ApiClients\Foundation\Transport;
4
5
use ApiClients\Foundation\Transport\CommandBus;
6
use GuzzleHttp\Client as GuzzleClient;
7
use GuzzleHttp\Psr7\Request as Psr7Request;
8
use GuzzleHttp\Psr7\Uri;
9
use Interop\Container\ContainerInterface;
10
use Psr\Http\Message\RequestInterface;
11
use Psr\Http\Message\ResponseInterface;
12
use React\EventLoop\LoopInterface;
13
use React\EventLoop\Timer\TimerInterface;
14
use React\Promise\CancellablePromiseInterface;
15
use React\Promise\PromiseInterface;
16
use function React\Promise\reject;
17
use function React\Promise\resolve;
18
use function WyriHaximus\React\futureFunctionPromise;
19
20
class Client
21
{
22
    const DEFAULT_OPTIONS = [
23
        Options::SCHEMA => 'https',
24
        Options::PATH => '/',
25
        Options::USER_AGENT => 'WyriHaximus/php-api-client',
26
        Options::HEADERS => [],
27
    ];
28
29
    /**
30
     * @var LoopInterface
31
     */
32
    protected $loop;
33
34
    /**
35
     * @var ContainerInterface
36
     */
37
    protected $container;
38
39
    /**
40
     * @var GuzzleClient
41
     */
42
    protected $handler;
43
44
    /**
45
     * @var array
46
     */
47
    protected $options = [];
48
49
    /**
50
     * @var MiddlewareInterface[]
51
     */
52
    protected $middleware = [];
53
54
    /**
55
     * @param LoopInterface $loop
56
     * @param ContainerInterface $container
57
     * @param GuzzleClient $handler
58
     * @param array $options
59
     */
60
    public function __construct(
61
        LoopInterface $loop,
62
        ContainerInterface $container,
63
        GuzzleClient $handler,
64
        array $options = []
65
    ) {
66
        $this->loop = $loop;
67
        $this->container = $container;
68
        $this->handler = $handler;
69
        $this->options = $options + self::DEFAULT_OPTIONS;
70
71
        if (isset($this->options[Options::MIDDLEWARE])
72
        ) {
73
            $this->middleware = $this->options[Options::MIDDLEWARE];
74
        }
75
    }
76 View Code Duplication
    protected function preRequest(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
77
        array $middlewares,
78
        RequestInterface $request,
79
        array $options
80
    ): CancellablePromiseInterface {
81
        $promise = resolve($request);
82
83
        foreach ($middlewares as $middleware) {
84
            $requestMiddleware = $middleware;
85
            $promise = $promise->then(function (RequestInterface $request) use ($options, $requestMiddleware) {
86
                return $requestMiddleware->pre($request, $options);
87
            });
88
        }
89
90
        return $promise;
91
    }
92
93 View Code Duplication
    protected function postRequest(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
94
        array $middlewares,
95
        ResponseInterface $response,
96
        array $options
97
    ): CancellablePromiseInterface {
98
        $promise = resolve($response);
99
100
        foreach ($middlewares as $middleware) {
101
            $responseMiddleware = $middleware;
102
            $promise = $promise->then(function (ResponseInterface $response) use ($options, $responseMiddleware) {
103
                return $responseMiddleware->post($response, $options);
104
            });
105
        }
106
107
        return $promise;
108
    }
109
110
    protected function constructMiddlewares(array $options): array
111
    {
112
        $set = $this->middleware;
113
114
        if (isset($options[Options::MIDDLEWARE])) {
115
            $set = $options[Options::MIDDLEWARE];
116
        }
117
118
        $middlewares = [];
119
        foreach ($set as $middleware) {
120
            if (!is_subclass_of($middleware, MiddlewareInterface::class)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \ApiClients\Foundation\T...dlewareInterface::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
121
                continue;
122
            }
123
124
            $middlewares[] = $this->container->get($middleware);
125
        }
126
127
        return $middlewares;
128
    }
129
130
    /**
131
     * @param RequestInterface $request
132
     * @param array $options
133
     * @return PromiseInterface
134
     */
135
    public function request(RequestInterface $request, array $options = []): PromiseInterface
136
    {
137
        $request = $this->applyApiSettingsToRequest($request);
138
        $middlewares = $this->constructMiddlewares($options);
139
140
        return $this->preRequest($middlewares, $request, $options)->then(function ($request) use ($options) {
141
            return resolve($this->handler->sendAsync(
142
                $request,
143
                $options
144
            ));
145
        }, function (ResponseInterface $response) {
146
            return resolve($response);
147
        })->then(function (ResponseInterface $response) use ($middlewares, $options) {
148
            return $this->postRequest($middlewares, $response, $options);
149
        });
150
    }
151
152
    protected function streamBody(Response $response)
153
    {
154
        $stream = $response->getResponse()->getBody();
155
        $this->loop->addPeriodicTimer(0.001, function (TimerInterface $timer) use ($stream, $response) {
156
            if ($stream->eof()) {
157
                $timer->cancel();
158
                $response->emit('end');
159
                return;
160
            }
161
162
            $size = $stream->getSize();
163
            if ($size === 0) {
164
                return;
165
            }
166
167
            $response->emit('data', [$stream->read($size)]);
168
        });
169
    }
170
171
    protected function applyApiSettingsToRequest(RequestInterface $request): RequestInterface
172
    {
173
        $uri = $request->getUri();
174
        if (substr((string)$uri, 0, 4) !== 'http') {
175
            $uri = Uri::resolve(
176
                new Uri(
177
                    $this->options[Options::SCHEMA] .
178
                    '://' .
179
                    $this->options[Options::HOST] .
180
                    $this->options[Options::PATH]
181
                ),
182
                $request->getUri()
183
            );
184
        }
185
186
        return new Psr7Request(
187
            $request->getMethod(),
188
            $uri,
189
            $this->getHeaders() + $request->getHeaders(),
190
            $request->getBody(),
191
            $request->getProtocolVersion()
192
        );
193
    }
194
195
    /**
196
     * @return array
197
     */
198
    public function getHeaders(): array
199
    {
200
        $headers = [
201
            'User-Agent' => $this->options[Options::USER_AGENT],
202
        ];
203
        $headers += $this->options[Options::HEADERS];
204
        return $headers;
205
    }
206
207
    /**
208
     * @return string
209
     */
210
    public function getBaseURL(): string
211
    {
212
        return $this->options[Options::SCHEMA] . '://' . $this->options[Options::HOST] . $this->options[Options::PATH];
213
    }
214
}
215