Completed
Push — master ( ac52e7...eff854 )
by Oscar
11s
created

src/Whoops.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
declare(strict_types = 1);
3
4
namespace Middlewares;
5
6
use Middlewares\Utils\Traits\HasResponseFactory;
7
use Psr\Container\ContainerInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
use Whoops\Handler\JsonResponseHandler;
13
use Whoops\Handler\PlainTextHandler;
14
use Whoops\Handler\PrettyPageHandler;
15
use Whoops\Handler\XmlResponseHandler;
16
use Whoops\Run;
17
use Whoops\Util\SystemFacade;
18
19
class Whoops implements MiddlewareInterface
20
{
21
    use HasResponseFactory;
22
23
    /**
24
     * @var Run|null
25
     */
26
    private $whoops;
27
28
    /**
29
     * @var SystemFacade|null
30
     */
31
    private $system;
32
33
    /**
34
     * @var bool Whether catch errors or not
35
     */
36
    private $catchErrors = true;
37
38
    /**
39
     * @var ContainerInterface|null
40
     */
41
    private $handlerContainer;
42
43
    /**
44
     * Set the whoops instance.
45
     */
46
    public function __construct(Run $whoops = null, SystemFacade $system = null)
47
    {
48
        $this->whoops = $whoops;
49
        $this->system = $system;
50
    }
51
52
    /**
53
     * Whether catch errors or not.
54
     */
55
    public function catchErrors(bool $catchErrors = true): self
56
    {
57
        $this->catchErrors = (bool) $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
            if ($this->system) {
101
                $this->system->registerShutdownFunction($shutdown);
102
            } else {
103
                register_shutdown_function($shutdown);
104
            }
105
        }
106
107
        try {
108
            $response = $handler->handle($request);
109
        } catch (\Throwable $exception) {
110
            $response = $this->createResponse(500);
111
            $response->getBody()->write($whoops->$method($exception));
112
            $response = self::updateResponseContentType($response, $whoops);
113
        } finally {
114
            while (ob_get_level() >= $level) {
115
                ob_end_clean();
116
            }
117
        }
118
119
        if ($this->catchErrors) {
120
            $whoops->unregister();
121
        }
122
123
        return $response;
124
    }
125
126
    /**
127
     * Returns the whoops instance or create one.
128
     */
129
    private function getWhoopsInstance(ServerRequestInterface $request): Run
130
    {
131
        if (!$this->system) {
132
            $this->system = new SystemFacade();
133
        }
134
135
        $whoops = new Run($this->system);
136
        $container = $this->handlerContainer ?: new WhoopsHandlerContainer();
137
        $handler = $container->get($request->getHeaderLine('Accept'));
138
        $whoops->pushHandler($handler);
0 ignored issues
show
$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...
139
140
        return $whoops;
141
    }
142
143
    /**
144
     * Returns the content-type for the whoops instance
145
     */
146
    private static function updateResponseContentType(ResponseInterface $response, Run $whoops): ResponseInterface
147
    {
148
        if (1 !== count($whoops->getHandlers())) {
149
            return $response;
150
        }
151
152
        $handler = current($whoops->getHandlers());
153
154
        if ($handler instanceof PrettyPageHandler) {
155
            return $response->withHeader('Content-Type', 'text/html');
156
        }
157
158
        if ($handler instanceof JsonResponseHandler) {
159
            return $response->withHeader('Content-Type', 'application/json');
160
        }
161
162
        if ($handler instanceof XmlResponseHandler) {
163
            return $response->withHeader('Content-Type', 'text/xml');
164
        }
165
166
        if ($handler instanceof PlainTextHandler) {
167
            return $response->withHeader('Content-Type', 'text/plain');
168
        }
169
170
        return $response;
171
    }
172
}
173