Passed
Push — master ( a18808...143631 )
by Tom
04:16
created

ExceptionHandler::showError()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 2
nc 2
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Utility;
6
7
use Exception;
8
use Ktomk\Pipelines\Cli\ArgsException;
9
use Ktomk\Pipelines\Cli\Streams;
10
use Ktomk\Pipelines\File\ParseException;
11
12
class ExceptionHandler
13
{
14
    /**
15
     * @var bool
16
     */
17
    private $showStacktraceFlag;
18
19
    /**
20
     * @var Help
21
     */
22
    private $help;
23
    /**
24
     * @var Streams
25
     */
26
    private $streams;
27
28
    /**
29
     * ExceptionHandler constructor.
30
     * @param Streams $streams
31
     * @param Help $help
32
     * @param bool $showStacktrace
33
     */
34 1
    public function __construct(Streams $streams, Help $help, $showStacktrace)
35
    {
36 1
        $this->streams = $streams;
37 1
        $this->help = $help;
38 1
        $this->showStacktraceFlag = $showStacktrace;
39 1
    }
40
41
    /**
42
     * @param Runnable $runnable
43
     * @return mixed|void
44
     */
45 3
    public function handle(Runnable $runnable)
46
    {
47
        try {
48 3
            $status = $runnable->run();
49 2
        } catch (Exception $e) {
50 2
            $status = $this->handleException($e);
51
        }
52
53 3
        return $status;
54
    }
55
56
    /**
57
     * @param Exception $e
58
     * @return int
59
     */
60 2
    private function handleException(Exception $e)
61
    {
62 2
        $status = $e->getCode();
63 2
        $message = $e->getMessage();
64
65
        // "catch" unexpected exceptions for user-friendly message
66 2
        if (!is_int($status) || $this->isUnexpectedException($e)) {
67 1
            $status = 2;
68 1
            $message = sprintf('fatal: %s', $e->getMessage());
69
        }
70
71 2
        $this->showError($status, $message);
72 2
        $this->showUsage($e);
73 2
        $this->showStacktrace($e);
74
75 2
        return $status;
76
    }
77
78
    /**
79
     * Show error message
80
     *
81
     * @param int $status
82
     * @param string $message
83
     */
84 2
    private function showError($status, $message)
85
    {
86 2
        if (0 !== $status && '' !== $message) {
87 2
            $this->error(sprintf('pipelines: %s', $message));
88
        }
89 2
    }
90
91
    /**
92
     * Some exceptions can show usage
93
     *
94
     * @param Exception $e
95
     */
96 2
    private function showUsage(Exception $e)
97
    {
98 2
        if ($e instanceof ArgsException) {
99 1
            $this->help->showUsage();
100
        }
101 2
    }
102
103
    /**
104
     * Show a stacktrace for debugging purposes (`--debug`` flag)
105
     *
106
     * @param Exception $e
107
     */
108 2
    private function showStacktrace(Exception $e)
109
    {
110 2
        if ($this->showStacktraceFlag) {
111 2
            $this->debugException($e);
112
        }
113 2
    }
114
115
    /**
116
     * Some exceptions are not unexpected
117
     *
118
     * The pipelines utility uses *some* exceptions to signal program
119
     * flow in context of the command line utility. E.g. to not call
120
     * exit() somewhere deep in the code (StatusException), lazy command
121
     * line argument handling (ArgsException) and lazy pipelines.yml
122
     * file parsing (ParseException).
123
     *
124
     * @param Exception $e
125
     *
126
     * @return bool
127
     */
128 2
    private function isUnexpectedException(Exception $e)
129
    {
130
        return (
131 2
            !($e instanceof ArgsException)
132 2
            && !($e instanceof StatusException)
133 2
            && !($e instanceof ParseException)
134
        );
135
    }
136
137 2
    private function debugException(Exception $e)
138
    {
139 2
        for (; $e; $e = $e->getPrevious()) {
140 2
            $this->error('--------');
141 2
            $this->error(sprintf('class....: %s', get_class($e)));
142 2
            $this->error(sprintf('message..: %s', $e->getMessage()));
143 2
            $this->error(sprintf('code.....: %s', $e->getCode()));
144 2
            $this->error(sprintf('file.....: %s', $e->getFile()));
145 2
            $this->error(sprintf('line.....: %s', $e->getLine()));
146 2
            $this->error('backtrace:');
147 2
            $this->error($e->getTraceAsString());
148
        }
149 2
        $this->error('--------');
150 2
    }
151
152 2
    private function error($message)
153
    {
154 2
        $this->streams->err(
155 2
            sprintf("%s\n", $message)
156
        );
157 2
    }
158
}
159