Passed
Push — master ( 3eb4db...99d5ff )
by Kirill
03:12
created

HtmlHandler::renderException()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 50
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 32
c 1
b 0
f 0
dl 0
loc 50
rs 9.0968
cc 5
nc 9
nop 2
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Exceptions;
13
14
use Spiral\Debug\Dumper;
15
use Spiral\Debug\Renderer\HtmlRenderer;
16
use Spiral\Debug\StateInterface;
17
use Spiral\Exceptions\Style\HtmlStyle;
18
19
/**
20
 * Render exception information into html.
21
 */
22
class HtmlHandler extends AbstractHandler
23
{
24
    /**
25
     * Visual styles.
26
     */
27
    public const DEFAULT  = 'default';
28
    public const INVERTED = 'inverted';
29
30
    /** @var HtmlRenderer */
31
    protected $renderer = null;
32
33
    /** @var Highlighter */
34
    protected $highlighter = null;
35
36
    /** @var string */
37
    protected $style = self::DEFAULT;
38
39
    /** @var Dumper */
40
    protected $dumper = null;
41
42
    /** @var StateInterface|null */
43
    protected $state;
44
45
    /**
46
     * @param string $style
47
     */
48
    public function __construct(string $style = self::DEFAULT)
49
    {
50
        $this->style = $style;
51
        $this->dumper = new Dumper();
52
53
        if ($style == self::INVERTED) {
54
            $this->renderer = new HtmlRenderer(HtmlRenderer::INVERTED);
55
            $this->highlighter = new Highlighter(new HtmlStyle(HtmlStyle::INVERTED));
56
        } else {
57
            $this->renderer = new HtmlRenderer(HtmlRenderer::DEFAULT);
58
            $this->highlighter = new Highlighter(new HtmlStyle(HtmlStyle::DEFAULT));
59
        }
60
61
        $this->dumper->setRenderer(Dumper::RETURN, $this->renderer);
62
    }
63
64
    /**
65
     * @param StateInterface $state
66
     * @return HandlerInterface
67
     */
68
    public function withState(StateInterface $state): HandlerInterface
69
    {
70
        $handler = clone $this;
71
        $handler->state = $state;
72
73
        return $handler;
74
    }
75
76
    /**
77
     * @inheritdoc
78
     */
79
    public function renderException(\Throwable $e, int $verbosity = self::VERBOSITY_BASIC): string
80
    {
81
        $options = [
82
            'message'      => $this->getMessage($e),
83
            'exception'    => $e,
84
            'valueWrapper' => new ValueWrapper($this->dumper, $this->renderer, $verbosity),
85
            'style'        => $this->render('styles/' . $this->style),
86
            'footer'       => $this->render('partials/footer'),
87
            'variables'    => '',
88
            'logs'         => '',
89
            'tags'         => '',
90
        ];
91
92
        $options['stacktrace'] = $this->render('partials/stacktrace', [
93
            'exception'    => $e,
94
            'stacktrace'   => $this->getStacktrace($e),
95
            'dumper'       => $this->dumper,
96
            'renderer'     => $this->renderer,
97
            'highlighter'  => $this->highlighter,
98
            'valueWrapper' => $options['valueWrapper'],
99
            'showSource'   => $verbosity >= self::VERBOSITY_VERBOSE
100
        ]);
101
102
        $options['chain'] = $this->render('partials/chain', [
103
            'exception'    => $e,
104
            'stacktrace'   => $this->getStacktrace($e),
105
            'valueWrapper' => $options['valueWrapper'],
106
        ]);
107
108
        if ($this->state !== null) {
109
            if ($this->state->getTags() !== []) {
110
                $options['tags'] = $this->render('partials/tags', [
111
                    'tags' => $this->state->getTags()
112
                ]);
113
            }
114
115
            if ($this->state->getLogEvents() !== []) {
116
                $options['logs'] = $this->render('partials/logs', [
117
                    'logEvents' => $this->state->getLogEvents()
118
                ]);
119
            }
120
121
            if ($this->state->getVariables() !== []) {
122
                $options['variables'] = $this->render('partials/variables', [
123
                    'variables' => $this->state->getVariables()
124
                ]);
125
            }
126
        }
127
128
        return $this->render('exception', $options);
129
    }
130
131
    /**
132
     * Render PHP template.
133
     *
134
     * @param string $view
135
     * @param array  $options
136
     * @return string
137
     */
138
    private function render(string $view, array $options = []): string
139
    {
140
        extract($options, EXTR_OVERWRITE);
141
142
        ob_start();
143
        require $this->getFilename($view);
144
145
        return ob_get_clean();
146
    }
147
148
    /**
149
     * Get view filename.
150
     *
151
     * @param string $view
152
     * @return string
153
     */
154
    private function getFilename(string $view): string
155
    {
156
        return sprintf('%s/views/%s.php', dirname(__DIR__), $view);
157
    }
158
}
159