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
Push — master ( 693765...9c0f98 )
by Cees-Jan
12s
created

LoggerMiddleware::error()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 6.0208

Importance

Changes 0
Metric Value
dl 0
loc 42
ccs 22
cts 24
cp 0.9167
rs 8.6257
c 0
b 0
f 0
cc 6
nc 10
nop 3
crap 6.0208
1
<?php declare(strict_types=1);
2
3
namespace ApiClients\Middleware\Log;
4
5
use ApiClients\Foundation\Middleware\Annotation\Last;
6
use ApiClients\Foundation\Middleware\MiddlewareInterface;
7
use Psr\Http\Message\RequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\UriInterface;
10
use Psr\Log\LoggerInterface;
11
use React\Promise\CancellablePromiseInterface;
12
use Throwable;
13
use function React\Promise\reject;
14
use function React\Promise\resolve;
15
use function WyriHaximus\getIn;
16
17
class LoggerMiddleware implements MiddlewareInterface
18
{
19
    private const REQUEST            = 'request';
20
    private const RESPONSE           = 'response';
21
    private const ERROR              = 'error';
22
23
    private const MESSAGE_URL        = '[{{transaction_id}}] Requesting: {{request.uri}}';
24
    private const MESSAGE_SUCCESSFUL = '[{{transaction_id}}] Request completed with {{response.status_code}}';
25
    private const MESSAGE_ERROR      = '[{{transaction_id}}] {{error.message}}';
26
27
    /**
28
     * @var LoggerInterface
29
     */
30
    private $logger;
31
32
    private $context = [];
33
34 6
    public function __construct(LoggerInterface $logger)
35
    {
36 6
        $this->logger = $logger;
37 6
    }
38
39
    /**
40
     * @Last()
41
     */
42 6
    public function pre(
43
        RequestInterface $request,
44
        string $transactionId,
45
        array $options = []
46
    ): CancellablePromiseInterface {
47 6
        if (!isset($options[self::class][Options::LEVEL]) && !isset($options[self::class][Options::ERROR_LEVEL])) {
48 1
            return resolve($request);
49
        }
50
51 5
        $this->context[$transactionId] = [
52 5
            'transaction_id' => $transactionId,
53 5
            self::REQUEST => [],
54
        ];
55 5
        $this->context[$transactionId][self::REQUEST]['method'] = $request->getMethod();
56 5
        $this->context[$transactionId][self::REQUEST]['uri'] = (string)$this->stripQueryItems(
57 5
            $request->getUri(),
58 5
            $options
59
        );
60 5
        $this->context[$transactionId][self::REQUEST]['protocol_version'] = (string)$request->getProtocolVersion();
61 5
        $ignoreHeaders = $options[self::class][Options::IGNORE_HEADERS] ?? [];
62 5
        $this->context[$transactionId] = $this->iterateHeaders(
63 5
            $this->context[$transactionId],
64 5
            self::REQUEST,
65 5
            $request->getHeaders(),
66 5
            $ignoreHeaders
67
        );
68
69 5
        if (!isset($options[self::class][Options::URL_LEVEL])) {
70 3
            return resolve($request);
71
        }
72
73 2
        $message = $this->renderTemplate(
74 2
            $options[self::class][Options::MESSAGE_PRE] ?? self::MESSAGE_URL,
75 2
            $this->context[$transactionId]
76
        );
77 2
        $this->logger->log($options[self::class][Options::URL_LEVEL], $message, $this->context[$transactionId]);
78
79 2
        return resolve($request);
80
    }
81
82
    /**
83
     * @Last()
84
     */
85 3
    public function post(
86
        ResponseInterface $response,
87
        string $transactionId,
88
        array $options = []
89
    ): CancellablePromiseInterface {
90 3
        if (!isset($this->context[$transactionId])) {
91 1
            return resolve($response);
92
        }
93
94 2
        $context = $this->context[$transactionId];
95 2
        if (!isset($options[self::class][Options::LEVEL]) && !isset($options[self::class][Options::ERROR_LEVEL])) {
96
            unset($this->context[$transactionId]);
97
        }
98
99 2
        if (!isset($options[self::class][Options::LEVEL])) {
100
            return resolve($response);
101
        }
102
103 2
        $context = $this->addResponseToContext($context, $response, $options);
104 2
        $message = $this->renderTemplate(
105 2
            $options[self::class][Options::MESSAGE_POST] ?? self::MESSAGE_SUCCESSFUL,
106 2
            $context
107
        );
108 2
        $this->logger->log($options[self::class][Options::LEVEL], $message, $context);
109
110 2
        return resolve($response);
111
    }
112
113
    /**
114
     * @Last()
115
     */
116 4
    public function error(
117
        Throwable $throwable,
118
        string $transactionId,
119
        array $options = []
120
    ): CancellablePromiseInterface {
121 4
        if (!isset($this->context[$transactionId])) {
122 1
            return reject($throwable);
123
        }
124
125 3
        $context = $this->context[$transactionId];
126 3
        unset($this->context[$transactionId]);
127
128 3
        if (!isset($options[self::class][Options::ERROR_LEVEL])) {
129
            return reject($throwable);
130
        }
131
132 3
        $response = null;
133 3
        if (method_exists($throwable, 'getResponse')) {
134 1
            $response = $throwable->getResponse();
135
        }
136 3
        if ($response instanceof ResponseInterface) {
137 1
            $context = $this->addResponseToContext($context, $response, $options);
138
        }
139
140 3
        $context[self::ERROR]['message']  = $throwable->getMessage();
141 3
        $context[self::ERROR]['code']  = $throwable->getCode();
142 3
        $context[self::ERROR]['file']  = $throwable->getFile();
143 3
        $context[self::ERROR]['line']  = $throwable->getLine();
144 3
        $context[self::ERROR]['trace'] = $throwable->getTraceAsString();
145
146 3
        if (method_exists($throwable, 'getContext')) {
147
            $context[self::ERROR]['context'] = $throwable->getContext();
148
        }
149
150 3
        $message = $this->renderTemplate(
151 3
            $options[self::class][Options::MESSAGE_ERROR] ?? self::MESSAGE_ERROR,
152 3
            $context
153
        );
154 3
        $this->logger->log($options[self::class][Options::ERROR_LEVEL], $message, $context);
155
156 3
        return reject($throwable);
157
    }
158
159 5
    protected function iterateHeaders(
160
        array $context,
161
        string $prefix,
162
        array $headers,
163
        array $ignoreHeaders
164
    ): array {
165 5
        foreach ($headers as $header => $value) {
166 5
            if (in_array($header, $ignoreHeaders, true)) {
167 5
                continue;
168
            }
169
170 5
            $context[$prefix]['headers'][$header] = $value;
171
        }
172
173 5
        return $context;
174
    }
175
176 3
    private function addResponseToContext(
177
        array $context,
178
        ResponseInterface $response,
179
        array $options
180
    ): array {
181 3
        $context[self::RESPONSE]['status_code']      = $response->getStatusCode();
182 3
        $context[self::RESPONSE]['status_reason']    = $response->getReasonPhrase();
183 3
        $context[self::RESPONSE]['protocol_version'] = $response->getProtocolVersion();
184 3
        $ignoreHeaders = $options[self::class][Options::IGNORE_HEADERS] ?? [];
185 3
        $context  = $this->iterateHeaders(
186 3
            $context,
187 3
            self::RESPONSE,
188 3
            $response->getHeaders(),
189 3
            $ignoreHeaders
190
        );
191
192 3
        return $context;
193
    }
194
195 5
    private function stripQueryItems(UriInterface $uri, array $options): UriInterface
196
    {
197 5
        parse_str($uri->getQuery(), $query);
198 5
        foreach ($options[self::class][Options::IGNORE_URI_QUERY_ITEMS] ?? [] as $item) {
199 2
            unset($query[$item], $query[$item . '[]']);
200
        }
201
202 5
        return $uri->withQuery(http_build_query($query));
203
    }
204
205 5
    private function renderTemplate(string $template, array $context): string
206
    {
207 5
        $keyValues = [];
208 5
        preg_match_all("|\{\{(.*)\}\}|U", $template, $out, PREG_PATTERN_ORDER);
209 5
        foreach (array_unique(array_values($out[1])) as $placeHolder) {
210 5
            $keyValues['{{' . $placeHolder . '}}'] = getIn($context, $placeHolder, '');
211
        }
212 5
        $template = str_replace(array_keys($keyValues), array_values($keyValues), $template);
213
214 5
        return $template;
215
    }
216
}
217