Whoops   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 9
dl 0
loc 146
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A catchErrors() 0 6 1
A handlerContainer() 0 6 1
A __construct() 0 7 2
B process() 0 46 6
A getWhoopsInstance() 0 9 2
B updateResponseContentType() 0 26 6
1
<?php
2
declare(strict_types = 1);
3
4
namespace Middlewares;
5
6
use Middlewares\Utils\Factory;
7
use Psr\Container\ContainerInterface;
8
use Psr\Http\Message\ResponseFactoryInterface;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use Psr\Http\Server\MiddlewareInterface;
12
use Psr\Http\Server\RequestHandlerInterface;
13
use Whoops\Handler\JsonResponseHandler;
14
use Whoops\Handler\PlainTextHandler;
15
use Whoops\Handler\PrettyPageHandler;
16
use Whoops\Handler\XmlResponseHandler;
17
use Whoops\Run;
18
19
class Whoops implements MiddlewareInterface
20
{
21
    /**
22
     * @var Run|null
23
     */
24
    private $whoops;
25
26
    /**
27
     * @var bool Whether catch errors or not
28
     */
29
    private $catchErrors = true;
30
31
    /**
32
     * @var ContainerInterface|null
33
     */
34
    protected $handlerContainer;
35
36
    /**
37
     * @var ResponseFactoryInterface
38
     */
39
    private $responseFactory;
40
41
    /**
42
     * Set the whoops instance.
43
     */
44
    public function __construct(
45
        Run $whoops = null,
46
        ResponseFactoryInterface $responseFactory = null
47
    ) {
48
        $this->whoops = $whoops;
49
        $this->responseFactory = $responseFactory ?: Factory::getResponseFactory();
50
    }
51
52
    /**
53
     * Whether catch errors or not.
54
     */
55
    public function catchErrors(bool $catchErrors = true): self
56
    {
57
        $this->catchErrors = $catchErrors;
58
59
        return $this;
60
    }
61
62
    /**
63
     * Set the PSR-11 container to create the error handler using the Accept header
64
     */
65
    public function handlerContainer(ContainerInterface $handlerContainer): self
66
    {
67
        $this->handlerContainer = $handlerContainer;
68
69
        return $this;
70
    }
71
72
    /**
73
     * Process a server request and return a response.
74
     */
75
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
76
    {
77
        ob_start();
78
        $level = ob_get_level();
79
80
        $method = Run::EXCEPTION_HANDLER;
81
        $whoops = $this->whoops ?: $this->getWhoopsInstance($request);
82
83
        $whoops->allowQuit(false);
84
        $whoops->writeToOutput(false);
85
        $whoops->sendHttpCode(false);
86
87
        //Catch errors means register whoops globally
88
        if ($this->catchErrors) {
89
            $whoops->register();
90
91
            $shutdown = function () use ($whoops) {
92
                $whoops->allowQuit(true);
93
                $whoops->writeToOutput(true);
94
                $whoops->sendHttpCode(true);
95
96
                $method = Run::SHUTDOWN_HANDLER;
97
                $whoops->$method();
98
            };
99
100
            register_shutdown_function($shutdown);
101
        }
102
103
        try {
104
            $response = $handler->handle($request);
105
        } catch (\Throwable $exception) {
106
            $response = $this->responseFactory->createResponse(500);
107
            $response->getBody()->write($whoops->$method($exception));
108
            $response = self::updateResponseContentType($response, $whoops);
109
        } finally {
110
            while (ob_get_level() >= $level) {
111
                ob_end_clean();
112
            }
113
        }
114
115
        if ($this->catchErrors) {
116
            $whoops->unregister();
117
        }
118
119
        return $response;
120
    }
121
122
    /**
123
     * Returns the whoops instance or create one.
124
     */
125
    protected function getWhoopsInstance(ServerRequestInterface $request): Run
126
    {
127
        $whoops = new Run();
128
        $container = $this->handlerContainer ?: new WhoopsHandlerContainer();
129
        $handler = $container->get($request->getHeaderLine('Accept'));
130
        $whoops->appendHandler($handler);
0 ignored issues
show
Documentation introduced by Oscar Otero
$handler is of type *, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
131
132
        return $whoops;
133
    }
134
135
    /**
136
     * Returns the content-type for the whoops instance
137
     */
138
    private static function updateResponseContentType(ResponseInterface $response, Run $whoops): ResponseInterface
139
    {
140
        if (1 !== count($whoops->getHandlers())) {
141
            return $response;
142
        }
143
144
        $handler = current($whoops->getHandlers());
145
146
        if ($handler instanceof PrettyPageHandler) {
147
            return $response->withHeader('Content-Type', 'text/html');
148
        }
149
150
        if ($handler instanceof JsonResponseHandler) {
151
            return $response->withHeader('Content-Type', 'application/json');
152
        }
153
154
        if ($handler instanceof XmlResponseHandler) {
155
            return $response->withHeader('Content-Type', 'text/xml');
156
        }
157
158
        if ($handler instanceof PlainTextHandler) {
159
            return $response->withHeader('Content-Type', 'text/plain');
160
        }
161
162
        return $response;
163
    }
164
}
165