@@ -44,61 +44,96 @@ class ProgressBar
44
44
private $ step ;
45
45
private $ max ;
46
46
private $ startTime ;
47
+ private $ stepWidth ;
48
+ private $ percent ;
47
49
private $ lastMessagesLength ;
48
50
private $ barCharOriginal ;
49
51
52
+ static private $ formatters ;
53
+
50
54
/**
51
- * List of formatting variables
55
+ * Constructor.
52
56
*
53
- * @var array
57
+ * @param OutputInterface $output An OutputInterface instance
58
+ * @param integer $max Maximum steps (0 if unknown)
54
59
*/
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
+ }
62
71
63
72
/**
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.
65
76
*
66
- * @var array
77
+ * @param string $name The placeholder name (including the delimiter char like %)
78
+ * @param callable $callable A PHP callable
67
79
*/
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
+ }
69
88
70
89
/**
71
- * Various time formats
90
+ * Gets the progress bar start time.
72
91
*
73
- * @var array
92
+ * @return int The progress bar start time
74
93
*/
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
+ }
86
98
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
+ }
89
108
90
109
/**
91
- * Constructor .
110
+ * Gets the progress bar step .
92
111
*
93
- * @param OutputInterface $output An OutputInterface instance
94
- * @param integer $max Maximum steps (0 if unknown)
112
+ * @return int The progress bar step
95
113
*/
96
- public function __construct ( OutputInterface $ output , $ max = 0 )
114
+ public function getStep ( )
97
115
{
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 ;
102
137
}
103
138
104
139
/**
@@ -111,6 +146,16 @@ public function setBarWidth($size)
111
146
$ this ->barWidth = (int ) $ size ;
112
147
}
113
148
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
+
114
159
/**
115
160
* Sets the bar character.
116
161
*
@@ -121,6 +166,16 @@ public function setBarCharacter($char)
121
166
$ this ->barChar = $ char ;
122
167
}
123
168
169
+ /**
170
+ * Gets the bar character.
171
+ *
172
+ * @return string A character
173
+ */
174
+ public function getBarCharacter ()
175
+ {
176
+ return $ this ->barChar ;
177
+ }
178
+
124
179
/**
125
180
* Sets the empty bar character.
126
181
*
@@ -131,6 +186,16 @@ public function setEmptyBarCharacter($char)
131
186
$ this ->emptyBarChar = $ char ;
132
187
}
133
188
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
+
134
199
/**
135
200
* Sets the progress bar character.
136
201
*
@@ -141,6 +206,16 @@ public function setProgressCharacter($char)
141
206
$ this ->progressChar = $ char ;
142
207
}
143
208
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
+
144
219
/**
145
220
* Sets the progress bar format.
146
221
*
@@ -176,13 +251,6 @@ public function start()
176
251
$ this ->format = $ this ->determineBestFormat ();
177
252
}
178
253
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
-
186
254
if (!$ this ->max ) {
187
255
$ this ->barCharOriginal = $ this ->barChar ;
188
256
$ this ->barChar = $ this ->emptyBarChar ;
@@ -267,11 +335,11 @@ public function display()
267
335
throw new \LogicException ('You must start the progress bar before calling display(). ' );
268
336
}
269
337
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 ) );
275
343
}
276
344
277
345
/**
@@ -286,72 +354,6 @@ public function clear()
286
354
$ this ->overwrite ('' );
287
355
}
288
356
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
-
355
357
/**
356
358
* Overwrites a previous message to the output.
357
359
*
@@ -400,4 +402,32 @@ private function determineBestFormat()
400
402
401
403
return $ format ;
402
404
}
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
+ }
403
433
}
0 commit comments