Passed
Push — console ( 5778b8...1e780d )
by Arnaud
09:42 queued 06:33
created

ConsoleLogger::padPrefix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * This file is part of the Cecil/Cecil package.
4
 *
5
 * Copyright (c) Arnaud Ligny <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Cecil\Logger;
12
13
use Psr\Log\InvalidArgumentException;
14
use Psr\Log\LogLevel;
15
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
16
use Symfony\Component\Console\Helper\ProgressBar;
17
use Symfony\Component\Console\Output\OutputInterface;
18
19
class ConsoleLogger extends PrintLogger
20
{
21
    const ERROR = 'error';
22
    const WARNING = 'comment';
23
    const NOTICE = 'info';
24
    const INFO = 'text';
25
26
    protected $output;
27
    protected $verbosityLevelMap = [
28
        LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
29
        LogLevel::ALERT     => OutputInterface::VERBOSITY_NORMAL,
30
        LogLevel::CRITICAL  => OutputInterface::VERBOSITY_NORMAL,
31
        LogLevel::ERROR     => OutputInterface::VERBOSITY_NORMAL,
32
        LogLevel::WARNING   => OutputInterface::VERBOSITY_NORMAL,
33
        LogLevel::NOTICE    => OutputInterface::VERBOSITY_VERBOSE,
34
        LogLevel::INFO      => OutputInterface::VERBOSITY_VERY_VERBOSE,
35
        LogLevel::DEBUG     => OutputInterface::VERBOSITY_DEBUG,
36
    ];
37
    protected $formatLevelMap = [
38
        LogLevel::EMERGENCY => self::ERROR,
39
        LogLevel::ALERT     => self::ERROR,
40
        LogLevel::CRITICAL  => self::ERROR,
41
        LogLevel::ERROR     => self::ERROR,
42
        LogLevel::WARNING   => self::INFO,
43
        LogLevel::NOTICE    => self::NOTICE,
44
        LogLevel::INFO      => self::INFO,
45
        LogLevel::DEBUG     => self::INFO,
46
    ];
47
48
    /** @var ProgressBar */
49
    protected $progressBar = null;
50
    /** @var int */
51
    private $progressBarMax;
52
53
    public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])
54
    {
55
        $this->output = $output;
56
        $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
57
        $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     *
63
     * @return void
64
     */
65
    public function log($level, $message, array $context = [])
66
    {
67
        $output = $this->output;
68
        $outputStyle = new OutputFormatterStyle('white');
69
        $output->getFormatter()->setStyle('text', $outputStyle);
70
71
        // updates the levels mapping if output supports the Progress Bar
72
        if ($output->isDecorated()) {
73
            array_replace_recursive($this->verbosityLevelMap, [
74
                LogLevel::NOTICE    => OutputInterface::VERBOSITY_NORMAL,
75
                LogLevel::INFO      => OutputInterface::VERBOSITY_VERBOSE,
76
            ]);
77
        }
78
79
        if (!isset($this->verbosityLevelMap[$level])) {
80
            throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
81
        }
82
83
        // steps Progress Bar
84
        if ($output->isDecorated()) {
85
            if ($output->getVerbosity() == OutputInterface::VERBOSITY_NORMAL && array_key_exists('step', $context)) {
86
                $this->printProgressBar($context['step'][0], $context['step'][1]);
87
88
                return;
89
            }
90
        }
91
92
        // default pattern: <level>message</level>
93
        $pattern = '<%1$s>%2$s%3$s</%1$s>';
94
        $prefix = '';
95
96
        // steps prefix
97
        if (array_key_exists('step', $context)) {
98
            $prefix = sprintf('%s. ', $this->padPrefix($context['step'][0], $context['step'][1]));
99
        }
100
101
        // sub steps progress
102
        if (array_key_exists('progress', $context)) {
103
            // the verbose Progress Bar
104
            if ($output->isDecorated()) {
105
                if ($output->getVerbosity() == OutputInterface::VERBOSITY_VERBOSE) {
106
                    $this->printProgressBar($context['progress'][0], $context['progress'][1]);
107
108
                    return;
109
                }
110
            }
111
            // prefix
112
            $prefix = sprintf(
113
                '[%s/%s] ',
114
                $this->padPrefix($context['progress'][0], $context['progress'][1]),
115
                $context['progress'][1]
116
            );
117
        }
118
119
        $output->writeln(
120
            sprintf($pattern, $this->formatLevelMap[$level], $prefix, $this->interpolate($message, $context)),
121
            $this->verbosityLevelMap[$level]
122
        );
123
    }
124
125
    /**
126
     * Prints the Progress Bar.
127
     *
128
     * @param int $itemsCount
129
     * @param int $itemsMax
130
     *
131
     * @return void
132
     */
133
    protected function printProgressBar(int $itemsCount, int $itemsMax): void
134
    {
135
        $this->createProgressBar($itemsMax);
136
        $this->progressBar->clear();
137
        $this->progressBar->setProgress($itemsCount);
138
        $this->progressBar->display();
139
        if ($itemsCount == $itemsMax) {
140
            $this->progressBar->finish();
141
            $this->output->writeln('');
142
        }
143
    }
144
145
    /**
146
     * Creates the Progress bar.
147
     *
148
     * @param int $max
149
     *
150
     * @return void
151
     */
152
    private function createProgressBar(int $max): void
153
    {
154
        if ($this->progressBar === null || $max != $this->progressBarMax) {
155
            $this->progressBarMax = $max;
156
            $this->progressBar = new ProgressBar($this->output, $max);
157
            $this->progressBar->setOverwrite(true);
158
            $this->progressBar->setFormat('%percent:3s%% [%bar%] %current%/%max%');
159
            $this->progressBar->setBarCharacter('#');
160
            $this->progressBar->setEmptyBarCharacter(' ');
161
            $this->progressBar->setProgressCharacter('#');
162
            $this->progressBar->setRedrawFrequency(1);
163
            $this->progressBar->start();
164
        }
165
    }
166
167
    /**
168
     * Prefix padding.
169
     *
170
     * @param string $prefix
171
     * @param string $max
172
     *
173
     * @return string
174
     */
175
    private function padPrefix(string $prefix, string $max): string
176
    {
177
        return str_pad($prefix, strlen($max), ' ', STR_PAD_LEFT);
178
    }
179
}
180