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 (#4)
by Cees-Jan
48:39 queued 38:43
created

Client::constructMiddlewares()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2
c 0
b 0
f 0
cc 4
eloc 11
nc 6
nop 1
1
<?php declare(strict_types=1);
2
3
namespace ApiClients\Foundation\Transport;
4
5
use ApiClients\Foundation\Middleware\MiddlewareRunner;
6
use ApiClients\Foundation\Middleware\MiddlewareInterface;
7
use ApiClients\Foundation\Transport\CommandBus;
8
use Clue\React\Buzz\Browser;
9
use RingCentral\Psr7\Uri;
10
use Interop\Container\ContainerInterface;
11
use InvalidArgumentException;
12
use Psr\Http\Message\RequestInterface;
13
use Psr\Http\Message\ResponseInterface;
14
use React\EventLoop\LoopInterface;
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::HEADERS => [],
26
    ];
27
28
    /**
29
     * @var LoopInterface
30
     */
31
    protected $loop;
32
33
    /**
34
     * @var ContainerInterface
35
     */
36
    protected $container;
37
38
    /**
39
     * @var Browser
40
     */
41
    protected $browser;
42
43
    /**
44
     * @var array
45
     */
46
    protected $options = [];
47
48
    /**
49
     * @var MiddlewareInterface[]
50
     */
51
    protected $middleware = [];
52
53
    /**
54
     * @param LoopInterface $loop
55
     * @param ContainerInterface $container
56
     * @param Browser $buzz
57
     * @param array $options
58
     */
59
    public function __construct(
60
        LoopInterface $loop,
61
        ContainerInterface $container,
62
        Browser $buzz,
63
        array $options = []
64
    ) {
65
        $this->loop = $loop;
66
        $this->container = $container;
67
        $this->browser = $buzz;
68
        $this->options = $options + self::DEFAULT_OPTIONS;
69
70
        if (isset($this->options[Options::MIDDLEWARE])) {
71
            $this->middleware = $this->options[Options::MIDDLEWARE];
72
        }
73
74
        $this->determineUserAgent();
75
    }
76
77
    protected function determineUserAgent()
78
    {
79
        if (!isset($this->options[Options::USER_AGENT]) && !isset($this->options[Options::USER_AGENT_STRATEGY])) {
80
            throw new InvalidArgumentException('No way to determine user agent');
81
        }
82
83
        if (!isset($this->options[Options::USER_AGENT_STRATEGY])) {
84
            return;
85
        }
86
87
        $strategy = $this->options[Options::USER_AGENT_STRATEGY];
88
89
        if (!class_exists($strategy)) {
90
            throw new InvalidArgumentException(sprintf('Strategy "%s", doesn\'t exist', $strategy));
91
        }
92
93
        if (!is_subclass_of($strategy, UserAgentStrategyInterface::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...trategyInterface::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
94
            throw new InvalidArgumentException(sprintf(
95
                'Strategy "%s", doesn\'t implement',
96
                $strategy,
97
                UserAgentStrategyInterface::class
98
            ));
99
        }
100
101
        $this->options[Options::USER_AGENT] = $this->container->get($strategy)->determineUserAgent($this->options);
102
    }
103
104
    protected function constructMiddlewares(array $options): MiddlewareRunner
105
    {
106
        $set = $this->middleware;
107
108
        if (isset($options[Options::MIDDLEWARE])) {
109
            $set = $this->combinedMiddlewares($options[Options::MIDDLEWARE]);
110
        }
111
112
        $args = [];
113
        $args[] = $options;
114
        foreach ($set as $middleware) {
115
            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...
116
                continue;
117
            }
118
119
            $args[] = $this->container->get($middleware);
120
        }
121
122
        return new MiddlewareRunner(...$args);
123
    }
124
125
    protected function combinedMiddlewares(array $extraMiddlewares): array
126
    {
127
        $set = $this->middleware;
128
129
        foreach ($extraMiddlewares as $middleware) {
130
            if (in_array($middleware, $set)) {
131
                continue;
132
            }
133
134
            $set[] = $middleware;
135
        }
136
137
        return $set;
138
    }
139
140
    /**
141
     * @param RequestInterface $request
142
     * @param array $options
143
     * @return PromiseInterface
144
     */
145
    public function request(RequestInterface $request, array $options = []): PromiseInterface
146
    {
147
        $request = $this->applyApiSettingsToRequest($request);
148
        $options = $this->applyRequestOptions($options);
149
        $executioner = $this->constructMiddlewares($options);
150
151
        return $executioner->pre($request)->then(function ($request) use ($options) {
152
            return resolve($this->browser->send(
153
                $request
154
            ));
155
        }, function (ResponseInterface $response) {
156
            return resolve($response);
157
        })->then(function (ResponseInterface $response) use ($executioner) {
158
            return $executioner->post($response);
159
        });
160
    }
161
162
    protected function applyApiSettingsToRequest(RequestInterface $request): RequestInterface
163
    {
164
        $uri = $request->getUri();
165
        if (strpos((string)$uri, '://') === false) {
166
            $uri = Uri::resolve(
167
                new Uri(
168
                    $this->options[Options::SCHEMA] .
169
                    '://' .
170
                    $this->options[Options::HOST] .
171
                    $this->options[Options::PATH]
172
                ),
173
                $request->getUri()
174
            );
175
        }
176
177
        foreach ($this->options[Options::HEADERS] as $key => $value) {
178
            $request = $request->withAddedHeader($key, $value);
179
        }
180
181
        return $request->withUri($uri)->withAddedHeader('User-Agent', $this->options[Options::USER_AGENT]);
182
    }
183
184
    public function applyRequestOptions(array $options): array
185
    {
186
        if (!isset($this->options[Options::DEFAULT_REQUEST_OPTIONS])) {
187
            return $options;
188
        }
189
190
        return array_merge_recursive(
191
            $this->options[Options::DEFAULT_REQUEST_OPTIONS],
192
            $options
193
        );
194
    }
195
}
196