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
46:51 queued 36:53
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('Strategy "%s", doesn\'t implement', $strategy, UserAgentStrategyInterface::class));
95
        }
96
97
        $this->options[Options::USER_AGENT] = $this->container->get($strategy)->determineUserAgent($this->options);
98
    }
99
100
    protected function constructMiddlewares(array $options): MiddlewareRunner
101
    {
102
        $set = $this->middleware;
103
104
        if (isset($options[Options::MIDDLEWARE])) {
105
            $set = $this->combinedMiddlewares($options[Options::MIDDLEWARE]);
106
        }
107
108
        $args = [];
109
        $args[] = $options;
110
        foreach ($set as $middleware) {
111
            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...
112
                continue;
113
            }
114
115
            $args[] = $this->container->get($middleware);
116
        }
117
118
        return new MiddlewareRunner(...$args);
119
    }
120
121
    protected function combinedMiddlewares(array $extraMiddlewares): array
122
    {
123
        $set = $this->middleware;
124
125
        foreach ($extraMiddlewares as $middleware) {
126
            if (in_array($middleware, $set)) {
127
                continue;
128
            }
129
130
            $set[] = $middleware;
131
        }
132
133
        return $set;
134
    }
135
136
    /**
137
     * @param RequestInterface $request
138
     * @param array $options
139
     * @return PromiseInterface
140
     */
141
    public function request(RequestInterface $request, array $options = []): PromiseInterface
142
    {
143
        $request = $this->applyApiSettingsToRequest($request);
144
        $options = $this->applyRequestOptions($options);
145
        $executioner = $this->constructMiddlewares($options);
146
147
        return $executioner->pre($request)->then(function ($request) use ($options) {
148
            return resolve($this->browser->send(
149
                $request
150
            ));
151
        }, function (ResponseInterface $response) {
152
            return resolve($response);
153
        })->then(function (ResponseInterface $response) use ($executioner) {
154
            return $executioner->post($response);
155
        });
156
    }
157
158
    protected function applyApiSettingsToRequest(RequestInterface $request): RequestInterface
159
    {
160
        $uri = $request->getUri();
161
        if (strpos((string)$uri, '://') === false) {
162
            $uri = Uri::resolve(
163
                new Uri(
164
                    $this->options[Options::SCHEMA] .
165
                    '://' .
166
                    $this->options[Options::HOST] .
167
                    $this->options[Options::PATH]
168
                ),
169
                $request->getUri()
170
            );
171
        }
172
173
        foreach ($this->options[Options::HEADERS] as $key => $value) {
174
            $request = $request->withAddedHeader($key, $value);
175
        }
176
177
        return $request->withUri($uri)->withAddedHeader('User-Agent', $this->options[Options::USER_AGENT]);
178
    }
179
180
    public function applyRequestOptions(array $options): array
181
    {
182
        if (!isset($this->options[Options::DEFAULT_REQUEST_OPTIONS])) {
183
            return $options;
184
        }
185
186
        return array_merge_recursive(
187
            $this->options[Options::DEFAULT_REQUEST_OPTIONS],
188
            $options
189
        );
190
    }
191
}
192