Completed
Push — master ( 851558...1b6b48 )
by Oscar
09:15
created

Whoops::handlerContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace Middlewares;
5
6
use Psr\Container\ContainerInterface;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Psr\Http\Server\RequestHandlerInterface;
11
use Whoops\Handler\JsonResponseHandler;
12
use Whoops\Handler\PlainTextHandler;
13
use Whoops\Handler\PrettyPageHandler;
14
use Whoops\Handler\XmlResponseHandler;
15
use Whoops\Run;
16
use Whoops\Util\SystemFacade;
17
18
class Whoops implements MiddlewareInterface
19
{
20
    /**
21
     * @var Run|null
22
     */
23
    private $whoops;
24
25
    /**
26
     * @var SystemFacade|null
27
     */
28
    private $system;
29
30
    /**
31
     * @var bool Whether catch errors or not
32
     */
33
    private $catchErrors = true;
34
35
    /**
36
     * @var ContainerInterface|null
37
     */
38
    private $handlerContainer;
39
40
    /**
41
     * Set the whoops instance.
42
     */
43
    public function __construct(Run $whoops = null, SystemFacade $system = null)
44
    {
45
        $this->whoops = $whoops;
46
        $this->system = $system;
47
    }
48
49
    /**
50
     * Whether catch errors or not.
51
     */
52
    public function catchErrors(bool $catchErrors = true): self
53
    {
54
        $this->catchErrors = (bool) $catchErrors;
55
56
        return $this;
57
    }
58
59
    /**
60
     * Set the PSR-11 container to create the error handler using the Accept header
61
     */
62
    public function handlerContainer(ContainerInterface $handlerContainer): self
63
    {
64
        $this->handlerContainer = $handlerContainer;
65
66
        return $this;
67
    }
68
69
    /**
70
     * Process a server request and return a response.
71
     */
72
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
73
    {
74
        ob_start();
75
        $level = ob_get_level();
76
77
        $method = Run::EXCEPTION_HANDLER;
78
        $whoops = $this->whoops ?: $this->getWhoopsInstance($request);
79
80
        $whoops->allowQuit(false);
81
        $whoops->writeToOutput(false);
82
        $whoops->sendHttpCode(false);
83
84
        //Catch errors means register whoops globally
85
        if ($this->catchErrors) {
86
            $whoops->register();
87
88
            $shutdown = function () use ($whoops) {
89
                $whoops->allowQuit(true);
90
                $whoops->writeToOutput(true);
91
                $whoops->sendHttpCode(true);
92
93
                $method = Run::SHUTDOWN_HANDLER;
94
                $whoops->$method();
95
            };
96
97
            if ($this->system) {
98
                $this->system->registerShutdownFunction($shutdown);
99
            } else {
100
                register_shutdown_function($shutdown);
101
            }
102
        }
103
104
        try {
105
            $response = $handler->handle($request);
106
        } catch (\Throwable $exception) {
107
            $response = Utils\Factory::createResponse(500);
108
            $response->getBody()->write($whoops->$method($exception));
109
            $response = self::updateResponseContentType($response, $whoops);
110
        } finally {
111
            while (ob_get_level() >= $level) {
112
                ob_end_clean();
113
            }
114
        }
115
116
        if ($this->catchErrors) {
117
            $whoops->unregister();
118
        }
119
120
        return $response;
121
    }
122
123
    /**
124
     * Returns the whoops instance or create one.
125
     */
126
    private function getWhoopsInstance(ServerRequestInterface $request): Run
127
    {
128
        if (!$this->system) {
129
            $this->system = new SystemFacade();
130
        }
131
132
        $whoops = new Run($this->system);
133
        $container = $this->handlerContainer ?: new WhoopsHandlerContainer();
134
        $handler = $container->get($request->getHeaderLine('Accept'));
135
        $whoops->pushHandler($handler);
0 ignored issues
show
Documentation introduced by oscarotero
$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...
136
137
        return $whoops;
138
    }
139
140
    /**
141
     * Returns the content-type for the whoops instance
142
     */
143
    private static function updateResponseContentType(ResponseInterface $response, Run $whoops): ResponseInterface
144
    {
145
        if (1 !== count($whoops->getHandlers())) {
146
            return $response;
147
        }
148
149
        $handler = current($whoops->getHandlers());
150
151
        if ($handler instanceof PrettyPageHandler) {
152
            return $response->withHeader('Content-Type', 'text/html');
153
        }
154
155
        if ($handler instanceof JsonResponseHandler) {
156
            return $response->withHeader('Content-Type', 'application/json');
157
        }
158
159
        if ($handler instanceof XmlResponseHandler) {
160
            return $response->withHeader('Content-Type', 'text/xml');
161
        }
162
163
        if ($handler instanceof PlainTextHandler) {
164
            return $response->withHeader('Content-Type', 'text/plain');
165
        }
166
167
        return $response;
168
    }
169
}
170