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
19:15 queued 09:29
created

Client::combinedMiddlewares()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
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\Request as Psr7Request;
10
use RingCentral\Psr7\Uri;
11
use Interop\Container\ContainerInterface;
12
use Psr\Http\Message\RequestInterface;
13
use Psr\Http\Message\ResponseInterface;
14
use React\EventLoop\LoopInterface;
15
use React\Promise\CancellablePromiseInterface;
16
use React\Promise\PromiseInterface;
17
use function React\Promise\reject;
18
use function React\Promise\resolve;
19
use function WyriHaximus\React\futureFunctionPromise;
20
21
class Client
22
{
23
    const DEFAULT_OPTIONS = [
24
        Options::SCHEMA => 'https',
25
        Options::PATH => '/',
26
        Options::USER_AGENT => 'WyriHaximus/php-api-client',
27
        Options::HEADERS => [],
28
    ];
29
30
    /**
31
     * @var LoopInterface
32
     */
33
    protected $loop;
34
35
    /**
36
     * @var ContainerInterface
37
     */
38
    protected $container;
39
40
    /**
41
     * @var GuzzleClient
42
     */
43
    protected $handler;
44
45
    /**
46
     * @var array
47
     */
48
    protected $options = [];
49
50
    /**
51
     * @var MiddlewareInterface[]
52
     */
53
    protected $middleware = [];
54
55
    /**
56
     * @param LoopInterface $loop
57
     * @param ContainerInterface $container
58
     * @param Browser $buzz
59
     * @param array $options
60
     */
61
    public function __construct(
62
        LoopInterface $loop,
63
        ContainerInterface $container,
64
        Browser $buzz,
65
        array $options = []
66
    ) {
67
        $this->loop = $loop;
68
        $this->container = $container;
69
        $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...
70
        $this->options = $options + self::DEFAULT_OPTIONS;
71
72
        if (isset($this->options[Options::MIDDLEWARE])) {
73
            $this->middleware = $this->options[Options::MIDDLEWARE];
74
        }
75
    }
76
77
    protected function constructMiddlewares(array $options): MiddlewareRunner
78
    {
79
        $set = $this->middleware;
80
81
        if (isset($options[Options::MIDDLEWARE])) {
82
            $set = $this->combinedMiddlewares($options[Options::MIDDLEWARE]);
83
        }
84
85
        $args = [];
86
        $args[] = $options;
87
        foreach ($set as $middleware) {
88
            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...
89
                continue;
90
            }
91
92
            $middlewares[] = $this->container->get($middleware);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$middlewares was never initialized. Although not strictly required by PHP, it is generally a good practice to add $middlewares = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
93
        }
94
95
        return new MiddlewareRunner(...$args);
96
    }
97
98
    protected function combinedMiddlewares(array $extraMiddlewares): array
99
    {
100
        $set = $this->middleware;
101
102
        foreach ($extraMiddlewares as $middleware) {
103
            if (in_array($middleware, $set)) {
104
                continue;
105
            }
106
107
            $set[] = $middleware;
108
        }
109
110
        return $set;
111
    }
112
113
    /**
114
     * @param RequestInterface $request
115
     * @param array $options
116
     * @return PromiseInterface
117
     */
118
    public function request(RequestInterface $request, array $options = []): PromiseInterface
119
    {
120
        $request = $this->applyApiSettingsToRequest($request);
121
        $options = $this->applyRequestOptions($options);
122
        $executioner = $this->constructMiddlewares($options);
123
124
        return $executioner->pre($request)->then(function ($request) use ($options) {
125
            return resolve($this->handler->send(
126
                $request
127
            ));
128
        }, function (ResponseInterface $response) {
129
            return resolve($response);
130
        })->then(function (ResponseInterface $response) use ($executioner) {
131
            return $executioner->post($response);
132
        });
133
    }
134
135
    protected function applyApiSettingsToRequest(RequestInterface $request): RequestInterface
136
    {
137
        $uri = $request->getUri();
138
        if (strpos((string)$uri, '://') === false) {
139
            $uri = Uri::resolve(
140
                new Uri(
141
                    $this->options[Options::SCHEMA] .
142
                    '://' .
143
                    $this->options[Options::HOST] .
144
                    $this->options[Options::PATH]
145
                ),
146
                $request->getUri()
147
            );
148
        }
149
150
        return new Psr7Request(
151
            $request->getMethod(),
152
            $uri,
153
            $this->options[Options::HEADERS] + $request->getHeaders(),
154
            $request->getBody(),
155
            $request->getProtocolVersion()
156
        );
157
    }
158
159
    public function applyRequestOptions(array $options): array
160
    {
161
        if (!isset($this->options[Options::DEFAULT_REQUEST_OPTIONS])) {
162
            return $options;
163
        }
164
165
        return array_merge_recursive(
166
            $this->options[Options::DEFAULT_REQUEST_OPTIONS],
167
            $options
168
        );
169
    }
170
}
171