Completed
Push — master ( b0d00a...787657 )
by Todd
08:33
created

LogFormatter::guessFormatOutput()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.3332

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 9
ccs 4
cts 6
cp 0.6667
rs 9.6667
cc 3
eloc 7
nc 3
nop 0
crap 3.3332
1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2015 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden\Cli;
9
10
/**
11
 * A helper class to format CLI output in a log-style format.
12
 */
13
class LogFormatter {
14
    /**
15
     * @var string The date format as passed to {@link strftime()}.
16
     */
17
    protected $dateFormat = '[%F %T]';
18
19
    /**
20
     * @var string The end of line string to use.
21
     */
22
    protected $eol = PHP_EOL;
23
24
    /**
25
     * @var bool Whether or not to format output.
26
     */
27
    protected $formatOutput;
28
29
    /**
30
     * @var bool Whether or not the console is on a new line.
31
     */
32
    protected $isNewline = true;
33
34
    /**
35
     * @var int The maximum level deep to output.
36
     */
37
    protected $maxLevel = 2;
38
39
    /**
40
     * @var array An array of currently running tasks.
41
     */
42
    protected $taskStack = [];
43
44
    /**
45
     * LogFormatter constructor.
46
     */
47 9
    public function __construct() {
48 9
        $this->formatOutput = Cli::guessFormatOutput();
49 9
    }
50
51
    /**
52
     * Output an error message.
53
     *
54
     * When formatting is turned on, error messages are displayed in red. Error messages are always output, even if they
55
     * are past the maximum display level.
56
     *
57
     * @param string $str The message to output.
58
     * @return LogFormatter Returns `$this` for fluent calls.
59
     */
60 2
    public function error($str) {
61 2
        return $this->message($this->formatString($str, ["\033[1;31m", "\033[0m"]), true);
62
    }
63
64
    /**
65
     * Output a success message.
66
     *
67
     * When formatting is turned on, success messages are displayed in green.
68
     *
69
     * @param string $str The message to output.
70
     * @return LogFormatter Returns `$this` for fluent calls.
71
     */
72
    public function success($str) {
73
        return $this->message($this->formatString($str, ["\033[1;32m", "\033[0m"]));
74
    }
75
76
    /**
77
     * Get the current depth of tasks.
78
     *
79
     * @return int Returns the current level.
80
     */
81 9
    protected function currentLevel() {
82 9
        return count($this->taskStack) + 1;
83
    }
84
85
    /**
86
     * Output a message that designates the beginning of a task.
87
     *
88
     * @param string $str The message to output.
89
     * @return $this Returns `$this` for fluent calls.
90
     */
91 7
    public function begin($str) {
92 7
        $output = $this->currentLevel() <= $this->getMaxLevel();
93 7
        $task = [$str, microtime(true), $output];
94
95 7
        if ($output) {
96 7
            if (!$this->isNewline) {
97 2
                echo $this->getEol();
98 2
                $this->isNewline = true;
99 2
            }
100
101 7
            echo $this->messageStr($str, false);
102 7
            $this->isNewline = false;
103 7
        }
104
105 7
        array_push($this->taskStack, $task);
106
107 7
        return $this;
108
    }
109
110
    /**
111
     * Output a message that designates a task being completed.
112
     *
113
     * @param string $str The message to output.
114
     * @param bool $force Whether or not to always output the message even if the task is past the max depth.
115
     * @return $this Returns `$this` for fluent calls.
116
     */
117 7
    public function end($str, $force = false) {
118
        // Find the task we are finishing.
119 7
        $task = array_pop($this->taskStack);
120 7
        if ($task !== null) {
121 7
            list($taskStr, $taskTimestamp, $taskOutput) = $task;
122 7
            $timespan = microtime(true) - $taskTimestamp;
0 ignored issues
show
Unused Code introduced by
$timespan is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
123 7
        } else {
124
            trigger_error('Called LogFormatter::end() without calling LogFormatter::begin()', E_USER_NOTICE);
125
        }
126
127 7
        $pastMaxLevel = $this->currentLevel() > $this->getMaxLevel();
128 7
        if ($pastMaxLevel) {
129 3
            if ($force && isset($taskStr) && isset($taskOutput)) {
130 1
                if (!$taskOutput) {
131
                    // Output the full task string if it hasn't already been output.
132 1
                    $str = $taskStr.' '.$str;
133 1
                }
134 1
                if (!$this->isNewline) {
135 1
                    echo $this->getEol();
136 1
                    $this->isNewline = true;
137 1
                }
138 1
            } else {
139 2
                return $this;
140
            }
141 1
        }
142
143 7
        if ($this->isNewline) {
144
            // Output the end message as a normal message.
145 5
            $this->message($str, $force);
146 5
        } else {
147
            // Output the end message on the same line.
148 3
            echo ' '.$str.$this->getEol();
149 3
            $this->isNewline = true;
150
        }
151
152 7
        return $this;
153
    }
154
155
    /**
156
     * Output a message that represents a task being completed in success.
157
     *
158
     * When formatting is turned on, success messages are output in green.
159
     *
160
     * @param string $str The message to output.
161
     * @param bool $force Whether or not to force a message past the max level to be output.
162
     * @return LogFormatter Returns `$this` for fluent calls.
163
     */
164
    public function endSuccess($str, $force = false) {
165
        return $this->end($this->formatString($str, ["\033[1;32m", "\033[0m"]), $force);
166
    }
167
168
    /**
169
     * Output a message that represents a task being completed in an error.
170
     *
171
     * When formatting is turned on, error messages are output in red. Error messages are always output even if they are
172
     * past the maximum depth.
173
     *
174
     * @param string $str The message to output.
175
     * @return LogFormatter Returns `$this` for fluent calls.
176
     */
177 1
    public function endError($str) {
178 1
        return $this->end($this->formatString($str, ["\033[1;31m", "\033[0m"]), true);
179
    }
180
181
    /**
182
     * Output a message that ends a task with an HTTP status code.
183
     *
184
     * This method is useful if you are making a call to an external API as a task. You can end the task by passing the
185
     * response code to this message.
186
     *
187
     * @param int $httpStatus The HTTP status code that represents the completion of a task.
188
     * @param bool $force Whether or not to force message output.
189
     * @return $this Returns `$this` for fluent calls.
190
     * @see LogFormatter::endSuccess(), LogFormatter::endError().
191
     */
192
    public function endHttpStatus($httpStatus, $force = false) {
193
        $statusStr = sprintf('%03d', $httpStatus);
194
195
        if ($httpStatus == 0 || $httpStatus >= 400) {
196
            $this->endError($statusStr);
197
        } elseif ($httpStatus >= 200 && $httpStatus < 300) {
198
            $this->endSuccess($statusStr, $force);
199
        } else {
200
            $this->end($statusStr, $force);
201
        }
202
203
        return $this;
204
    }
205
206
    /**
207
     * Output a message.
208
     *
209
     * @param string $str The message to output.
210
     * @param bool $force Whether or not to force output of the message even if it's past the max depth.
211
     * @return $this Returns `$this` for fluent calls.
212
     */
213 8
    public function message($str, $force = false) {
214 8
        $pastMaxLevel = $this->currentLevel() > $this->getMaxLevel();
215
216 8
        if ($pastMaxLevel) {
217 5
            if ($force) {
218
                // Trace down the task list and output everything that hasn't already been output.
219 3
                foreach ($this->taskStack as $indent => $task) {
220 3
                    list($taskStr, $taskTimestamp, $taskOutput) = $this->taskStack[$indent];
221 3
                    if (!$taskOutput) {
222 1
                        if (!$this->isNewline) {
223 1
                            echo $this->eol;
224 1
                            $this->isNewline = true;
225 1
                        }
226 1
                        echo $this->fullMessageStr($taskTimestamp, $taskStr, $indent, true);
227 1
                        $this->taskStack[$indent][2] = true;
228 1
                    } else {
229 3
                        continue;
230
                    }
231 3
                }
232 3
            } else {
233 5
                return $this;
234
            }
235 3
        }
236
237 7
        if (!$this->isNewline) {
238 2
            echo $this->eol;
239 2
            $this->isNewline = true;
240 2
        }
241 7
        echo $this->messageStr($str, true);
242 7
        return $this;
243
    }
244
245
    /**
246
     * Get whether or not output should be formatted.
247
     *
248
     * @return boolean Returns **true** if output should be formatted or **false** otherwise.
249
     */
250
    public function getFormatOutput() {
251
        return $this->formatOutput;
252
    }
253
254
    /**
255
     * Set whether or not output should be formatted.
256
     *
257
     * @param boolean $formatOutput Whether or not to format output.
258
     * @return LogFormatter Returns `$this` for fluent calls.
259
     */
260 9
    public function setFormatOutput($formatOutput) {
261 9
        $this->formatOutput = $formatOutput;
262 9
        return $this;
263
    }
264
265 9
    protected function fullMessageStr($timestamp, $str, $indent = null, $eol = true) {
266 9
        if ($indent === null) {
267 9
            $indent = $this->currentLevel() - 1;
268 9
        }
269
270 9
        if ($indent <= 0) {
271 9
            $indentStr = '';
272 9
        } elseif ($indent === 1) {
273 5
            $indentStr = '- ';
274 5
        } else {
275 2
            $indentStr = str_repeat('  ', $indent - 1).'- ';
276
        }
277
278 9
        $result = $indentStr.$str;
279
280 9
        if ($this->getDateFormat()) {
281 8
            $result = strftime($this->getDateFormat(), $timestamp).' '.$result;
282 8
        }
283
284 9
        if ($eol) {
285 7
            $result .= $this->eol;
286 7
        }
287 9
        return $result;
288
    }
289
290
    /**
291
     * Create a message string.
292
     *
293
     * @param string $str The message to output.
294
     * @param bool $eol Whether or not to add an EOL.
295
     * @return string Returns the message.
296
     */
297 9
    protected function messageStr($str, $eol = true) {
298 9
        return $this->fullMessageStr(time(), $str, null, $eol);
299
    }
300
301
    /**
302
     * Format some text for the console.
303
     *
304
     * @param string $text The text to format.
305
     * @param array $wrap The format to wrap in the form ['before', 'after'].
306
     * @return string Returns the string formatted according to {@link Cli::$format}.
307
     */
308 3
    protected function formatString($text, array $wrap) {
309 3
        if ($this->formatOutput) {
310
            return "{$wrap[0]}$text{$wrap[1]}";
311
        } else {
312 3
            return $text;
313
        }
314
    }
315
316
    /**
317
     * Get the maxLevel.
318
     *
319
     * @return int Returns the maxLevel.
320
     */
321
    public function getMaxLevel() {
322
        return $this->maxLevel;
323
    }
324 9
325 9
    /**
326
     * @param int $maxLevel
327 9
     * @return LogFormatter
328 9
     */
329
    public function setMaxLevel($maxLevel) {
330
        if ($maxLevel < 0) {
331
            throw new \InvalidArgumentException("The max level must be greater than zero.", 416);
332
        }
333
334
        $this->maxLevel = $maxLevel;
335
        return $this;
336
    }
337
338
    /**
339 9
     * Get the date format as passed to {@link strftime()}.
340 9
     *
341
     * @return string Returns the date format.
342
     * @see strftime()
343
     */
344
    public function getDateFormat() {
345
        return $this->dateFormat;
346
    }
347 9
348 9
    /**
349
     * Set the date format as passed to {@link strftime()}.
350
     *
351
     * @param string $dateFormat
352 9
     * @return LogFormatter Returns `$this` for fluent calls.
353 9
     * @see strftime()
354
     */
355
    public function setDateFormat($dateFormat) {
356
        $this->dateFormat = $dateFormat;
357
        return $this;
358
    }
359
360
    /**
361
     * Get the end of line string to use.
362 9
     *
363 9
     * @return string Returns the eol string.
364
     */
365
    public function getEol() {
366
        return $this->eol;
367
    }
368
369
    /**
370
     * Set the end of line string.
371
     *
372
     * @param string $eol The end of line string to use.
373 9
     * @return LogFormatter Returns `$this` for fluent calls.
374 9
     */
375 9
    public function setEol($eol) {
376
        $this->eol = $eol;
377
        return $this;
378
    }
379
}
380