Completed
Pull Request — master (#205)
by Anton
02:45
created

ErrorWriter::renderStack()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 40
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 25
nc 10
nop 1
dl 0
loc 40
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * framework
4
 *
5
 * @author    Wolfy-J
6
 */
7
8
namespace Spiral\Console;
9
10
use Spiral\Database\Exceptions\QueryExceptionInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use Symfony\Component\Console\Terminal;
13
14
class ErrorWriter
15
{
16
    /**
17
     * @var OutputInterface
18
     */
19
    private $output;
20
21
    /**
22
     * @var Terminal
23
     */
24
    private $terminal;
25
26
    /**
27
     * @param Terminal $terminal
28
     */
29
    public function __construct(Terminal $terminal)
30
    {
31
        $this->terminal = $terminal;
32
    }
33
34
    public function renderException(OutputInterface $output, \Throwable $e)
35
    {
36
        $this->output = $output;
37
38
        try {
39
            do {
40
                $this->renderHeader($e);
41
                if ($this->output->isVerbose()) {
42
                    $output->writeln('');
43
                    $this->renderStack($e);
44
                }
45
46
                $output->writeln('');
47
            } while ($e = $e->getPrevious());
48
        } finally {
49
            $this->output = null;
50
        }
51
    }
52
53
    /**
54
     * Render exception header.
55
     *
56
     * @param \Throwable $e
57
     */
58
    private function renderHeader(\Throwable $e)
59
    {
60
        if ($e instanceof \Error) {
61
            $this->title("[" . get_class($e) . "]\n" . $e->getMessage(), "bg=magenta;fg=white");
62
        } else {
63
            $this->title("[" . get_class($e) . "]\n" . $e->getMessage(), "bg=red;fg=white");
64
        }
65
66
        if ($e instanceof QueryExceptionInterface) {
67
            $this->title($e->getQuery(), "bg=blue;fg=white");
68
        }
69
70
        $this->write(
71
            "<fg=yellow>in <fg=white>%s</fg=white> at line <fg=white>%s</fg=white></fg=yellow>",
72
            basename($e->getFile()),
73
            $e->getLine()
74
        );
75
    }
76
77
    /**
78
     * Render exception call stack.
79
     *
80
     * @param \Throwable $e
81
     */
82
    private function renderStack(\Throwable $e)
83
    {
84
        $stacktrace = $e->getTrace();
85
86
        $this->write("<fg=yellow>Exception trace:</fg=yellow>");
87
88
        // ???
89
        $header = ['file' => $e->getFile(), 'line' => $e->getLine()] + $stacktrace[0];
90
        if ($stacktrace[0] != $header) {
91
            array_unshift($stacktrace, $header);
92
        }
93
94
        foreach ($stacktrace as $trace) {
95
            if (isset($trace['type']) && isset($trace['class'])) {
96
                $line = sprintf(
97
                    " %s%s%s()",
98
                    $trace['class'],
99
                    $trace['type'],
100
                    $trace['function']
101
                );
102
            } else {
103
                $line = sprintf(
104
                    " %s()",
105
                    $trace['function']
106
                );
107
            }
108
109
            if (isset($trace['file'])) {
110
                $line .= sprintf(
111
                    " <fg=yellow>at</fg=yellow> <fg=green>%s:<fg=yellow>%d</fg=yellow></fg=green>",
112
                    $trace['file'],
113
                    $trace['line']
114
                );
115
            } else {
116
                $line .= " <fg=yellow>at</fg=yellow> <fg=green>n/a:<fg=yellow>n/a</fg=yellow></fg=green>";
117
            }
118
119
            $this->write($line);
120
        }
121
    }
122
123
    /**
124
     * Render title using outlining border.
125
     *
126
     * @param string $title Title.
127
     * @param string $f     Formatting.
128
     */
129
    private function title($title, $f)
130
    {
131
        $lines = explode("\n", str_replace("\r", "", $title));
132
        $length = 0;
133
        array_walk($lines, function ($v) use (&$length) {
134
            $length = max($length, mb_strlen($v));
135
        });
136
137
        $this->write("<$f>%s</$f>", str_repeat(" ", $length + 2));
138
        foreach ($lines as $line) {
139
            $this->write(
140
                "<$f> %s%s</$f>",
141
                $line,
142
                str_repeat(" ", $length - mb_strlen($line) + 1)
143
            );
144
145
        }
146
        $this->write("<$f>%s</$f>", str_repeat(" ", $length + 2));
147
    }
148
149
    /**
150
     * Write formatted line.
151
     *
152
     * @param string $format
153
     * @param array  ...$args
154
     */
155
    private function write($format, ... $args)
156
    {
157
        $this->output->writeln(sprintf($format, ...$args), OutputInterface::VERBOSITY_QUIET);
158
    }
159
}