Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2a78a09

Browse filesBrowse files
committed
[Console] refactored the progress bar to allow placeholder to be extensible
1 parent 4e76aa3 commit 2a78a09
Copy full SHA for 2a78a09

File tree

Expand file treeCollapse file tree

3 files changed

+191
-113
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+191
-113
lines changed

‎src/Symfony/Component/Console/Helper/Helper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Helper/Helper.php
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,31 @@ public static function strlen($string)
5959

6060
return mb_strlen($string, $encoding);
6161
}
62+
63+
public static function formatTime($secs)
64+
{
65+
static $timeFormats = array(
66+
array(0, '< 1 sec'),
67+
array(2, '1 sec'),
68+
array(59, 'secs', 1),
69+
array(60, '1 min'),
70+
array(3600, 'mins', 60),
71+
array(5400, '1 hr'),
72+
array(86400, 'hrs', 3600),
73+
array(129600, '1 day'),
74+
array(604800, 'days', 86400),
75+
);
76+
77+
foreach ($timeFormats as $format) {
78+
if ($secs >= $format[0]) {
79+
continue;
80+
}
81+
82+
if (2 == count($format)) {
83+
return $format[1];
84+
}
85+
86+
return ceil($secs / $format[2]).' '.$format[1];
87+
}
88+
}
6289
}

‎src/Symfony/Component/Console/Helper/ProgressBar.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Helper/ProgressBar.php
+143-113Lines changed: 143 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -44,61 +44,96 @@ class ProgressBar
4444
private $step;
4545
private $max;
4646
private $startTime;
47+
private $stepWidth;
48+
private $percent;
4749
private $lastMessagesLength;
4850
private $barCharOriginal;
4951

52+
static private $formatters;
53+
5054
/**
51-
* List of formatting variables
55+
* Constructor.
5256
*
53-
* @var array
57+
* @param OutputInterface $output An OutputInterface instance
58+
* @param integer $max Maximum steps (0 if unknown)
5459
*/
55-
private $defaultFormatVars = array(
56-
'current',
57-
'max',
58-
'bar',
59-
'percent',
60-
'elapsed',
61-
);
60+
public function __construct(OutputInterface $output, $max = 0)
61+
{
62+
// Disabling output when it does not support ANSI codes as it would result in a broken display anyway.
63+
$this->output = $output->isDecorated() ? $output : new NullOutput();
64+
$this->max = (int) $max;
65+
$this->stepWidth = $this->max > 0 ? Helper::strlen($this->max) : 4;
66+
67+
if (!self::$formatters) {
68+
self::$formatters = self::initPlaceholderFormatters();
69+
}
70+
}
6271

6372
/**
64-
* Available formatting variables
73+
* Sets a placeholder formatter for a given name.
74+
*
75+
* This method also allow you to override an existing placeholder.
6576
*
66-
* @var array
77+
* @param string $name The placeholder name (including the delimiter char like %)
78+
* @param callable $callable A PHP callable
6779
*/
68-
private $formatVars;
80+
public static function setPlaceholderFormatter($name, $callable)
81+
{
82+
if (!self::$formatters) {
83+
self::$formatters = self::initPlaceholderFormatters();
84+
}
85+
86+
self::$formatters[$name] = $callable;
87+
}
6988

7089
/**
71-
* Various time formats
90+
* Gets the progress bar start time.
7291
*
73-
* @var array
92+
* @return int The progress bar start time
7493
*/
75-
private $timeFormats = array(
76-
array(0, '???'),
77-
array(2, '1 sec'),
78-
array(59, 'secs', 1),
79-
array(60, '1 min'),
80-
array(3600, 'mins', 60),
81-
array(5400, '1 hr'),
82-
array(86400, 'hrs', 3600),
83-
array(129600, '1 day'),
84-
array(604800, 'days', 86400),
85-
);
94+
public function getStartTime()
95+
{
96+
return $this->startTime;
97+
}
8698

87-
private $stepWidth;
88-
private $percent;
99+
/**
100+
* Gets the progress bar maximal steps.
101+
*
102+
* @return int The progress bar max steps
103+
*/
104+
public function getMaxSteps()
105+
{
106+
return $this->max;
107+
}
89108

90109
/**
91-
* Constructor.
110+
* Gets the progress bar step.
92111
*
93-
* @param OutputInterface $output An OutputInterface instance
94-
* @param integer $max Maximum steps (0 if unknown)
112+
* @return int The progress bar step
95113
*/
96-
public function __construct(OutputInterface $output, $max = 0)
114+
public function getStep()
97115
{
98-
// Disabling output when it does not support ANSI codes as it would result in a broken display anyway.
99-
$this->output = $output->isDecorated() ? $output : new NullOutput();
100-
$this->max = (int) $max;
101-
$this->stepWidth = $this->max > 0 ? Helper::strlen($this->max) : 4;
116+
return $this->step;
117+
}
118+
119+
/**
120+
* Gets the progress bar step width.
121+
*
122+
* @return int The progress bar step width
123+
*/
124+
public function getStepWidth()
125+
{
126+
return $this->stepWidth;
127+
}
128+
129+
/**
130+
* Gets the current progress bar percent.
131+
*
132+
* @return int The current progress bar percent
133+
*/
134+
public function getProgressPercent()
135+
{
136+
return $this->percent;
102137
}
103138

104139
/**
@@ -111,6 +146,16 @@ public function setBarWidth($size)
111146
$this->barWidth = (int) $size;
112147
}
113148

149+
/**
150+
* Gets the progress bar width.
151+
*
152+
* @return int The progress bar size
153+
*/
154+
public function getBarWidth()
155+
{
156+
return $this->barWidth;
157+
}
158+
114159
/**
115160
* Sets the bar character.
116161
*
@@ -121,6 +166,16 @@ public function setBarCharacter($char)
121166
$this->barChar = $char;
122167
}
123168

169+
/**
170+
* Gets the bar character.
171+
*
172+
* @return string A character
173+
*/
174+
public function getBarCharacter()
175+
{
176+
return $this->barChar;
177+
}
178+
124179
/**
125180
* Sets the empty bar character.
126181
*
@@ -131,6 +186,16 @@ public function setEmptyBarCharacter($char)
131186
$this->emptyBarChar = $char;
132187
}
133188

189+
/**
190+
* Gets the empty bar character.
191+
*
192+
* @return string A character
193+
*/
194+
public function getEmptyBarCharacter()
195+
{
196+
return $this->emptyBarChar;
197+
}
198+
134199
/**
135200
* Sets the progress bar character.
136201
*
@@ -141,6 +206,16 @@ public function setProgressCharacter($char)
141206
$this->progressChar = $char;
142207
}
143208

209+
/**
210+
* Gets the progress bar character.
211+
*
212+
* @return string A character
213+
*/
214+
public function getProgressCharacter()
215+
{
216+
return $this->progressChar;
217+
}
218+
144219
/**
145220
* Sets the progress bar format.
146221
*
@@ -176,13 +251,6 @@ public function start()
176251
$this->format = $this->determineBestFormat();
177252
}
178253

179-
$this->formatVars = array();
180-
foreach ($this->defaultFormatVars as $var) {
181-
if (false !== strpos($this->format, "%{$var}%")) {
182-
$this->formatVars[$var] = true;
183-
}
184-
}
185-
186254
if (!$this->max) {
187255
$this->barCharOriginal = $this->barChar;
188256
$this->barChar = $this->emptyBarChar;
@@ -267,11 +335,11 @@ public function display()
267335
throw new \LogicException('You must start the progress bar before calling display().');
268336
}
269337

270-
$message = $this->format;
271-
foreach ($this->generate() as $name => $value) {
272-
$message = str_replace("%{$name}%", $value, $message);
273-
}
274-
$this->overwrite($message);
338+
$regex = implode('|', array_keys(self::$formatters));
339+
$self = $this;
340+
$this->overwrite(preg_replace_callback("{($regex)}", function ($matches) use ($self) {
341+
return call_user_func(self::$formatters[$matches[1]], $self);
342+
}, $this->format));
275343
}
276344

277345
/**
@@ -286,72 +354,6 @@ public function clear()
286354
$this->overwrite('');
287355
}
288356

289-
/**
290-
* Generates the array map of format variables to values.
291-
*
292-
* @return array Array of format vars and values
293-
*/
294-
private function generate()
295-
{
296-
$vars = array();
297-
298-
if (isset($this->formatVars['bar'])) {
299-
$completeBars = floor($this->max > 0 ? $this->percent * $this->barWidth : $this->step % $this->barWidth);
300-
$emptyBars = $this->barWidth - $completeBars - Helper::strlen($this->progressChar);
301-
$bar = str_repeat($this->barChar, $completeBars);
302-
if ($completeBars < $this->barWidth) {
303-
$bar .= $this->progressChar;
304-
$bar .= str_repeat($this->emptyBarChar, $emptyBars);
305-
}
306-
307-
$vars['bar'] = $bar;
308-
}
309-
310-
if (isset($this->formatVars['elapsed'])) {
311-
$elapsed = time() - $this->startTime;
312-
$vars['elapsed'] = str_pad($this->humaneTime($elapsed), 6, ' ', STR_PAD_LEFT);
313-
}
314-
315-
if (isset($this->formatVars['current'])) {
316-
$vars['current'] = str_pad($this->step, $this->stepWidth, ' ', STR_PAD_LEFT);
317-
}
318-
319-
if (isset($this->formatVars['max'])) {
320-
$vars['max'] = $this->max;
321-
}
322-
323-
if (isset($this->formatVars['percent'])) {
324-
$vars['percent'] = str_pad(floor($this->percent * 100), 3, ' ', STR_PAD_LEFT);
325-
}
326-
327-
return $vars;
328-
}
329-
330-
/**
331-
* Converts seconds into human-readable format.
332-
*
333-
* @param integer $secs Number of seconds
334-
*
335-
* @return string Time in readable format
336-
*/
337-
private function humaneTime($secs)
338-
{
339-
$text = '';
340-
foreach ($this->timeFormats as $format) {
341-
if ($secs < $format[0]) {
342-
if (count($format) == 2) {
343-
$text = $format[1];
344-
break;
345-
} else {
346-
$text = ceil($secs / $format[2]).' '.$format[1];
347-
break;
348-
}
349-
}
350-
}
351-
352-
return $text;
353-
}
354-
355357
/**
356358
* Overwrites a previous message to the output.
357359
*
@@ -400,4 +402,32 @@ private function determineBestFormat()
400402

401403
return $format;
402404
}
405+
406+
static private function initPlaceholderFormatters()
407+
{
408+
return array(
409+
'%bar%' => function (ProgressBar $bar) {
410+
$completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getStep() % $bar->getBarWidth());
411+
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlen($bar->getProgressCharacter());
412+
$display = str_repeat($bar->getBarCharacter(), $completeBars);
413+
if ($completeBars < $bar->getBarWidth()) {
414+
$display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
415+
}
416+
417+
return $display;
418+
},
419+
'%elapsed%' => function (ProgressBar $bar) {
420+
return str_pad(Helper::formatTime(time() - $bar->getStartTime()), 6, ' ', STR_PAD_LEFT);
421+
},
422+
'%current%' => function (ProgressBar $bar) {
423+
return str_pad($bar->getStep(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
424+
},
425+
'%max%' => function (ProgressBar $bar) {
426+
return $bar->getMaxSteps();
427+
},
428+
'%percent%' => function (ProgressBar $bar) {
429+
return str_pad(floor($bar->getProgressPercent() * 100), 3, ' ', STR_PAD_LEFT);
430+
},
431+
);
432+
}
403433
}

‎src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,27 @@ public function testParallelBars()
298298
);
299299
}
300300

301+
public function testAddingPlaceholderFormatter()
302+
{
303+
ProgressBar::setPlaceholderFormatter('%remaining_steps%', function (ProgressBar $bar) {
304+
return $bar->getMaxSteps() - $bar->getStep();
305+
});
306+
$bar = new ProgressBar($output = $this->getOutputStream(), 3);
307+
$bar->setFormat(' %remaining_steps% [%bar%]');
308+
309+
$bar->start();
310+
$bar->advance();
311+
$bar->finish();
312+
313+
rewind($output->getStream());
314+
$this->assertEquals(
315+
$this->generateOutput(' 3 [>---------------------------]').
316+
$this->generateOutput(' 2 [=========>------------------]').
317+
$this->generateOutput(' 0 [============================]'),
318+
stream_get_contents($output->getStream())
319+
);
320+
}
321+
301322
protected function getOutputStream($decorated = true)
302323
{
303324
return new StreamOutput(fopen('php://memory', 'r+', false), StreamOutput::VERBOSITY_NORMAL, $decorated);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.