• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / Cli / 5840386379

pending completion
5840386379

push

github

web-flow
Predefined output formats - ELK, cron. New demo and docs. (#15)

745 of 745 new or added lines in 16 files covered. (100.0%)

899 of 1078 relevant lines covered (83.4%)

136.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.47
/src/OutputMods/AbstractOutputMode.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - Cli.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/Cli
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\Cli\OutputMods;
18

19
use JBZoo\Cli\CliApplication;
20
use JBZoo\Cli\OutLvl;
21
use JBZoo\Cli\ProgressBars\AbstractProgressBar;
22
use Monolog\Formatter\NormalizerFormatter;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Output\ConsoleOutputInterface;
25
use Symfony\Component\Console\Output\OutputInterface;
26

27
use function JBZoo\Utils\bool;
28
use function JBZoo\Utils\isStrEmpty;
29

30
abstract class AbstractOutputMode
31
{
32
    protected static self $instance;
33

34
    protected CliApplication $application;
35

36
    protected float $startTimer;
37
    protected float $prevTime;
38
    protected int   $prevMemory;
39

40
    protected string $timestampFormat = 'Y-m-d\TH:i:s.uP';
41

42
    protected InputInterface  $input;
43
    protected OutputInterface $output;
44
    protected bool            $catchMode      = false;
45
    protected array           $caughtMessages = [];
46

47
    private bool $outputHasErrors = false;
48

49
    abstract public static function getName(): string;
50

51
    abstract public static function getDescription(): string;
52

53
    abstract public function createProgressBar(): AbstractProgressBar;
54

55
    abstract protected function printMessage(
56
        string $message = '',
57
        string $verboseLevel = OutLvl::DEFAULT,
58
        array $context = [],
59
    ): void;
60

61
    public function __construct(InputInterface $input, OutputInterface $output, CliApplication $application)
62
    {
63
        $this->prevMemory = \memory_get_usage(false);
572✔
64
        $this->startTimer = \microtime(true);
572✔
65
        $this->prevTime   = $this->startTimer;
572✔
66

67
        $this->application = $application;
572✔
68

69
        $this->input  = $input;
572✔
70
        $this->output = $output;
572✔
71

72
        self::$instance = $this;
572✔
73
    }
74

75
    public function getStartTime(): float
76
    {
77
        return $this->startTimer;
420✔
78
    }
79

80
    public function getInput(): InputInterface
81
    {
82
        return $this->input;
572✔
83
    }
84

85
    public function getOutput(): OutputInterface
86
    {
87
        return $this->output;
420✔
88
    }
89

90
    public function getErrOutput(): OutputInterface
91
    {
92
        if ($this->isStdoutOnly()) {
420✔
93
            return $this->output;
28✔
94
        }
95

96
        return $this->output instanceof ConsoleOutputInterface ? $this->output->getErrorOutput() : $this->output;
392✔
97
    }
98

99
    /**
100
     * Alias to write new line in std output.
101
     * @SuppressWarnings(PHPMD.CamelCaseMethodName)
102
     */
103
    public function _(
104
        iterable|float|int|bool|string|null $messages = '',
105
        string $verboseLevel = OutLvl::DEFAULT,
106
        array $context = [],
107
    ): void {
108
        $message = $this->prepareMessages($messages, $verboseLevel);
572✔
109
        $context = $this->prepareContext($context);
572✔
110

111
        if ($message === null) {
572✔
112
            return;
388✔
113
        }
114

115
        if (
116
            $this->catchMode
572✔
117
            && !bool(\preg_match('/^Working on ".*"\./', $message)) // hack for system messages
572✔
118
        ) {
119
            $this->caughtMessages[] = $message;
24✔
120

121
            return;
24✔
122
        }
123

124
        $this->printMessage($message, $verboseLevel, $context);
572✔
125
    }
126

127
    public function isOutputHasErrors(): bool
128
    {
129
        return $this->outputHasErrors;
484✔
130
    }
131

132
    public function isStdoutOnly(): bool
133
    {
134
        return bool($this->input->getOption('stdout-only'));
404✔
135
    }
136

137
    public function isDisplayProfiling(): bool
138
    {
139
        return bool($this->input->getOption('profile'));
404✔
140
    }
141

142
    public function isDisplayTimestamp(): bool
143
    {
144
        return bool($this->input->getOption('timestamp'));
404✔
145
    }
146

147
    public function isInfoLevel(): bool
148
    {
149
        return $this->getOutput()->isVerbose();
×
150
    }
151

152
    public function isWarningLevel(): bool
153
    {
154
        return $this->getOutput()->isVeryVerbose();
×
155
    }
156

157
    public function isDebugLevel(): bool
158
    {
159
        return $this->getOutput()->isDebug();
×
160
    }
161

162
    public function isProgressBarDisabled(): bool
163
    {
164
        return bool($this->getInput()->getOption('no-progress'));
96✔
165
    }
166

167
    public function onExecBefore(): void
168
    {
169
        // empty
170
    }
171

172
    public function onExecException(\Exception $exception): void
173
    {
174
        $this->_($exception->getMessage(), OutLvl::ERROR);
×
175
    }
176

177
    public function onExecAfter(int $exitCode, ?string $outputLevel = null): void
178
    {
179
        $outputLevel ??= OutLvl::DEBUG;
×
180
        if ($this->isDisplayProfiling()) {
×
181
            $outputLevel = OutLvl::DEFAULT;
×
182
        }
183

184
        $this->_('Exit code: ' . $exitCode, $outputLevel);
×
185
    }
186

187
    public function catchModeStart(): void
188
    {
189
        \ob_start();
144✔
190
        $this->catchMode = true;
144✔
191
    }
192

193
    public function catchModeFinish(): array
194
    {
195
        $echoOutput = \ob_get_clean();
136✔
196
        if (!isStrEmpty($echoOutput)) {
136✔
197
            $this->caughtMessages[] = $echoOutput;
8✔
198
        }
199

200
        $this->catchMode = false;
136✔
201

202
        $caughtMessages = $this->caughtMessages;
136✔
203

204
        $this->caughtMessages = [];
136✔
205

206
        return $caughtMessages;
136✔
207
    }
208

209
    /**
210
     * @deprecated
211
     */
212
    public static function getInstance(): self
213
    {
214
        return self::$instance;
176✔
215
    }
216

217
    /**
218
     * @SuppressWarnings(PHPMD.Superglobals)
219
     */
220
    protected function getProfileInfo(): array
221
    {
222
        $currentTime   = \microtime(true);
172✔
223
        $currentMemory = \memory_get_usage(false);
172✔
224

225
        $startTime = $_SERVER['REQUEST_TIME_FLOAT'] ?? 0.0;
172✔
226

227
        $result = [
172✔
228
            'memory_usage_real' => \memory_get_usage(true),
172✔
229
            'memory_usage'      => $currentMemory,
86✔
230
            'memory_usage_diff' => $currentMemory - $this->prevMemory,
172✔
231
            'memory_pick_real'  => \memory_get_peak_usage(true),
172✔
232
            'memory_pick'       => \memory_get_peak_usage(false),
172✔
233
            'time_total_ms'     => \round(1000 * ($currentTime - $startTime), 3),
172✔
234
            'time_diff_ms'      => \round(1000 * ($currentTime - $this->prevTime), 3),
172✔
235
        ];
86✔
236

237
        $this->prevTime   = $currentTime;
172✔
238
        $this->prevMemory = $currentMemory;
172✔
239

240
        return $result;
172✔
241
    }
242

243
    protected function prepareMessages(iterable|float|int|bool|string|null $messages, string $verboseLevel): ?string
244
    {
245
        $verboseLevel = \strtolower(\trim($verboseLevel));
572✔
246

247
        if (\is_iterable($messages)) {
572✔
248
            foreach ($messages as $message) {
388✔
249
                $this->_($message, $verboseLevel);
388✔
250
            }
251

252
            return null;
388✔
253
        }
254

255
        if ($messages === null) {
572✔
256
            $messages = 'null';
8✔
257
        } elseif (\is_bool($messages)) {
572✔
258
            $messages = $messages ? 'true' : 'false';
8✔
259
        }
260

261
        $messages = (string)$messages;
572✔
262

263
        if (\str_contains($messages, "\n")) {
572✔
264
            $this->_(\explode("\n", $messages), $verboseLevel);
144✔
265

266
            return null;
144✔
267
        }
268

269
        return $messages;
572✔
270
    }
271

272
    protected function prepareContext(array $context): array
273
    {
274
        return (array)(new NormalizerFormatter())->normalizeValue($context);
572✔
275
    }
276

277
    protected function markOutputHasErrors(bool $hasError = true): void
278
    {
279
        $this->outputHasErrors = $hasError;
104✔
280
    }
281
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc