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
06:40
created

Client::applyRequestOptions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
1
<?php declare(strict_types=1);
2
3
namespace ApiClients\Foundation\Transport;
4
5
use ApiClients\Foundation\Middleware\MiddlewareInterface;
6
use ApiClients\Foundation\Transport\CommandBus;
7
use Clue\React\Buzz\Browser;
8
use GuzzleHttp\Psr7\Request as Psr7Request;
9
use GuzzleHttp\Psr7\Uri;
10
use Interop\Container\ContainerInterface;
11
use Psr\Http\Message\RequestInterface;
12
use Psr\Http\Message\ResponseInterface;
13
use React\EventLoop\LoopInterface;
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 Browser $buzz
58
     * @param array $options
59
     */
60
    public function __construct(
61
        LoopInterface $loop,
62
        ContainerInterface $container,
63
        Browser $buzz,
64
        array $options = []
65
    ) {
66
        $this->loop = $loop;
67
        $this->container = $container;
68
        $this->handler = $buzz;
0 ignored issues
show
Documentation Bug introduced by
It seems like $buzz of type object<Clue\React\Buzz\Browser> is incompatible with the declared type object<ApiClients\Founda...Transport\GuzzleClient> of property $handler.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
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\M...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
        $options = $this->applyRequestOptions($options);
139
        $middlewares = $this->constructMiddlewares($options);
140
141
        return $this->preRequest($middlewares, $request, $options)->then(function ($request) use ($options) {
142
            return resolve($this->handler->send(
143
                $request
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 applyApiSettingsToRequest(RequestInterface $request): RequestInterface
153
    {
154
        $uri = $request->getUri();
155
        if (substr((string)$uri, 0, 4) !== 'http') {
156
            $uri = Uri::resolve(
157
                new Uri(
158
                    $this->options[Options::SCHEMA] .
159
                    '://' .
160
                    $this->options[Options::HOST] .
161
                    $this->options[Options::PATH]
162
                ),
163
                $request->getUri()
164
            );
165
        }
166
167
        return new Psr7Request(
168
            $request->getMethod(),
169
            $uri,
170
            $this->getHeaders() + $request->getHeaders(),
171
            $request->getBody(),
172
            $request->getProtocolVersion()
173
        );
174
    }
175
176
    public function applyRequestOptions(array $options): array
177
    {
178
        if (!isset($this->options[Options::DEFAULT_REQUEST_OPTIONS])) {
179
            return $options;
180
        }
181
182
        return array_merge_recursive(
183
            $this->options[Options::DEFAULT_REQUEST_OPTIONS],
184
            $options
185
        );
186
    }
187
188
    /**
189
     * @return array
190
     */
191
    public function getHeaders(): array
192
    {
193
        $headers = [
194
            'User-Agent' => $this->options[Options::USER_AGENT],
195
        ];
196
        $headers += $this->options[Options::HEADERS];
197
        return $headers;
198
    }
199
200
    /**
201
     * @return string
202
     */
203
    public function getBaseURL(): string
204
    {
205
        return $this->options[Options::SCHEMA] . '://' . $this->options[Options::HOST] . $this->options[Options::PATH];
206
    }
207
}
208