Completed
Push — master ( e2435c...858eab )
by Oscar
03:02
created

ErrorHandler::__invoke()   C

Complexity

Conditions 7
Paths 24

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 31
rs 6.7272
cc 7
eloc 20
nc 24
nop 3
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Utils;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * Middleware to handle php errors and exceptions.
11
 */
12
class ErrorHandler
13
{
14
    const KEY = 'EXCEPTION';
15
16
    use Utils\CallableTrait;
17
    use Utils\AttributeTrait;
18
19
    /**
20
     * @var callable|string The handler used
21
     */
22
    private $handler;
23
24
    /**
25
     * @var bool Whether or not catch exceptions
26
     */
27
    private $catchExceptions = false;
28
29
    /**
30
     * Returns the exception throwed.
31
     *
32
     * @param ServerRequestInterface $request
33
     *
34
     * @return \Exception|null
35
     */
36
    public static function getException(ServerRequestInterface $request)
37
    {
38
        return self::getAttribute($request, self::KEY);
39
    }
40
41
    /**
42
     * Constructor.
43
     *
44
     * @param callable|string|null $handler
45
     */
46
    public function __construct($handler = null)
47
    {
48
        $this->handler = $handler ?: self::CLASS.'::defaultHandler';
49
    }
50
51
    /**
52
     * Configure the catchExceptions.
53
     *
54
     * @param bool $catch
55
     *
56
     * @return self
57
     */
58
    public function catchExceptions($catch = true)
59
    {
60
        $this->catchExceptions = (boolean) $catch;
61
62
        return $this;
63
    }
64
65
    /**
66
     * Execute the middleware.
67
     *
68
     * @param ServerRequestInterface $request
69
     * @param ResponseInterface      $response
70
     * @param callable               $next
71
     *
72
     * @return ResponseInterface
73
     */
74
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
75
    {
76
        ob_start();
77
        $level = ob_get_level();
78
79
        try {
80
            $response = $next($request, $response);
81
        } catch (\Throwable $exception) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
82
            if (!$this->catchExceptions) {
83
                throw $exception;
84
            }
85
86
            $request = self::setAttribute($request, self::KEY, $exception);
87
            $response = $response->withStatus(500);
88
        } catch (\Exception $exception) {
89
            if (!$this->catchExceptions) {
90
                throw $exception;
91
            }
92
93
            $request = self::setAttribute($request, self::KEY, $exception);
94
            $response = $response->withStatus(500);
95
        } finally {
96
            Utils\Helpers::getOutput($level);
97
        }
98
99
        if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 600) {
100
            return $this->executeCallable($this->handler, $request, $response);
101
        }
102
103
        return $response;
104
    }
105
106
    public static function defaultHandler(ServerRequestInterface $request, ResponseInterface $response)
107
    {
108
        $statusCode = $response->getStatusCode();
109
        $exception = self::getException($request);
110
111
        if ($exception) {
112
            $message = sprintf('<p>%s</p><pre>%s (%s)</pre>', $exception->getMessage(), $exception->getFile(), $exception->getLine());
113
        } else {
114
            $message = '';
115
        }
116
117
        return <<<EOT
118
<!DOCTYPE html>
119
<html>
120
<head>
121
    <meta charset="utf-8">
122
    <title>Error {$statusCode}</title>
123
    <style>html{font-family: sans-serif;}</style>
124
    <meta name="viewport" content="width=device-width, initial-scale=1">
125
</head>
126
<body>
127
    <h1>Error {$statusCode}</h1>
128
    {$message}
129
</body>
130
</html>
131
EOT;
132
    }
133
}
134