TYPO3  7.6
ProgressHelper.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
12 namespace Symfony\Component\Console\Helper;
13 
16 
26 class ProgressHelper extends Helper
27 {
28  const FORMAT_QUIET = ' %percent%%';
29  const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%';
30  const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%';
31  const FORMAT_QUIET_NOMAX = ' %current%';
32  const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]';
33  const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%';
34 
35  // options
36  private $barWidth = 28;
37  private $barChar = '=';
38  private $emptyBarChar = '-';
39  private $progressChar = '>';
40  private $format = null;
41  private $redrawFreq = 1;
42 
45 
49  private $output;
50 
56  private $current;
57 
63  private $max;
64 
70  private $startTime;
71 
77  private $defaultFormatVars = array(
78  'current',
79  'max',
80  'bar',
81  'percent',
82  'elapsed',
83  );
84 
90  private $formatVars;
91 
97  private $widths = array(
98  'current' => 4,
99  'max' => 4,
100  'percent' => 3,
101  'elapsed' => 6,
102  );
103 
109  private $timeFormats = array(
110  array(0, '???'),
111  array(2, '1 sec'),
112  array(59, 'secs', 1),
113  array(60, '1 min'),
114  array(3600, 'mins', 60),
115  array(5400, '1 hr'),
116  array(86400, 'hrs', 3600),
117  array(129600, '1 day'),
118  array(604800, 'days', 86400),
119  );
120 
121  public function __construct($triggerDeprecationError = true)
122  {
123  if ($triggerDeprecationError) {
124  @trigger_error('The '.__CLASS__.' class is deprecated since version 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\ProgressBar class instead.', E_USER_DEPRECATED);
125  }
126  }
127 
133  public function setBarWidth($size)
134  {
135  $this->barWidth = (int) $size;
136  }
137 
143  public function setBarCharacter($char)
144  {
145  $this->barChar = $char;
146  }
147 
153  public function setEmptyBarCharacter($char)
154  {
155  $this->emptyBarChar = $char;
156  }
157 
163  public function setProgressCharacter($char)
164  {
165  $this->progressChar = $char;
166  }
167 
173  public function setFormat($format)
174  {
175  $this->format = $format;
176  }
177 
183  public function setRedrawFrequency($freq)
184  {
185  $this->redrawFreq = (int) $freq;
186  }
187 
194  public function start(OutputInterface $output, $max = null)
195  {
196  $this->startTime = time();
197  $this->current = 0;
198  $this->max = (int) $max;
199 
200  // Disabling output when it does not support ANSI codes as it would result in a broken display anyway.
201  $this->output = $output->isDecorated() ? $output : new NullOutput();
202  $this->lastMessagesLength = 0;
203  $this->barCharOriginal = '';
204 
205  if (null === $this->format) {
206  switch ($output->getVerbosity()) {
208  $this->format = self::FORMAT_QUIET_NOMAX;
209  if ($this->max > 0) {
210  $this->format = self::FORMAT_QUIET;
211  }
212  break;
216  $this->format = self::FORMAT_VERBOSE_NOMAX;
217  if ($this->max > 0) {
218  $this->format = self::FORMAT_VERBOSE;
219  }
220  break;
221  default:
222  $this->format = self::FORMAT_NORMAL_NOMAX;
223  if ($this->max > 0) {
224  $this->format = self::FORMAT_NORMAL;
225  }
226  break;
227  }
228  }
229 
230  $this->initialize();
231  }
232 
241  public function advance($step = 1, $redraw = false)
242  {
243  $this->setCurrent($this->current + $step, $redraw);
244  }
245 
254  public function setCurrent($current, $redraw = false)
255  {
256  if (null === $this->startTime) {
257  throw new \LogicException('You must start the progress bar before calling setCurrent().');
258  }
259 
260  $current = (int) $current;
261 
262  if ($current < $this->current) {
263  throw new \LogicException('You can\'t regress the progress bar');
264  }
265 
266  if (0 === $this->current) {
267  $redraw = true;
268  }
269 
270  $prevPeriod = (int) ($this->current / $this->redrawFreq);
271 
272  $this->current = $current;
273 
274  $currPeriod = (int) ($this->current / $this->redrawFreq);
275  if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) {
276  $this->display();
277  }
278  }
279 
287  public function display($finish = false)
288  {
289  if (null === $this->startTime) {
290  throw new \LogicException('You must start the progress bar before calling display().');
291  }
292 
293  $message = $this->format;
294  foreach ($this->generate($finish) as $name => $value) {
295  $message = str_replace("%{$name}%", $value, $message);
296  }
297  $this->overwrite($this->output, $message);
298  }
299 
307  public function clear()
308  {
309  $this->overwrite($this->output, '');
310  }
311 
315  public function finish()
316  {
317  if (null === $this->startTime) {
318  throw new \LogicException('You must start the progress bar before calling finish().');
319  }
320 
321  if (null !== $this->startTime) {
322  if (!$this->max) {
323  $this->barChar = $this->barCharOriginal;
324  $this->display(true);
325  }
326  $this->startTime = null;
327  $this->output->writeln('');
328  $this->output = null;
329  }
330  }
331 
335  private function initialize()
336  {
337  $this->formatVars = array();
338  foreach ($this->defaultFormatVars as $var) {
339  if (false !== strpos($this->format, "%{$var}%")) {
340  $this->formatVars[$var] = true;
341  }
342  }
343 
344  if ($this->max > 0) {
345  $this->widths['max'] = $this->strlen($this->max);
346  $this->widths['current'] = $this->widths['max'];
347  } else {
348  $this->barCharOriginal = $this->barChar;
349  $this->barChar = $this->emptyBarChar;
350  }
351  }
352 
360  private function generate($finish = false)
361  {
362  $vars = array();
363  $percent = 0;
364  if ($this->max > 0) {
365  $percent = (float) $this->current / $this->max;
366  }
367 
368  if (isset($this->formatVars['bar'])) {
369  $completeBars = 0;
370 
371  if ($this->max > 0) {
372  $completeBars = floor($percent * $this->barWidth);
373  } else {
374  if (!$finish) {
375  $completeBars = floor($this->current % $this->barWidth);
376  } else {
377  $completeBars = $this->barWidth;
378  }
379  }
380 
381  $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar);
382  $bar = str_repeat($this->barChar, $completeBars);
383  if ($completeBars < $this->barWidth) {
384  $bar .= $this->progressChar;
385  $bar .= str_repeat($this->emptyBarChar, $emptyBars);
386  }
387 
388  $vars['bar'] = $bar;
389  }
390 
391  if (isset($this->formatVars['elapsed'])) {
392  $elapsed = time() - $this->startTime;
393  $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT);
394  }
395 
396  if (isset($this->formatVars['current'])) {
397  $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT);
398  }
399 
400  if (isset($this->formatVars['max'])) {
401  $vars['max'] = $this->max;
402  }
403 
404  if (isset($this->formatVars['percent'])) {
405  $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT);
406  }
407 
408  return $vars;
409  }
410 
418  private function humaneTime($secs)
419  {
420  $text = '';
421  foreach ($this->timeFormats as $format) {
422  if ($secs < $format[0]) {
423  if (count($format) == 2) {
424  $text = $format[1];
425  break;
426  } else {
427  $text = ceil($secs / $format[2]).' '.$format[1];
428  break;
429  }
430  }
431  }
432 
433  return $text;
434  }
435 
442  private function overwrite(OutputInterface $output, $message)
443  {
444  $length = $this->strlen($message);
445 
446  // append whitespace to match the last line's length
447  if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) {
448  $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
449  }
450 
451  // carriage return
452  $output->write("\x0D");
453  $output->write($message);
454 
455  $this->lastMessagesLength = $this->strlen($message);
456  }
457 
461  public function getName()
462  {
463  return 'progress';
464  }
465 }