Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ProgressBar.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 16.81 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\Console\Helper;
013   
014  use Symfony\Component\Console\Exception\LogicException;
015  use Symfony\Component\Console\Output\ConsoleOutputInterface;
016  use Symfony\Component\Console\Output\OutputInterface;
017  use Symfony\Component\Console\Terminal;
018   
019  /**
020   * The ProgressBar provides helpers to display progress output.
021   *
022   * @author Fabien Potencier <fabien@symfony.com>
023   * @author Chris Jones <leeked@gmail.com>
024   */
025  final class ProgressBar
026  {
027      private $barWidth = 28;
028      private $barChar;
029      private $emptyBarChar = '-';
030      private $progressChar = '>';
031      private $format;
032      private $internalFormat;
033      private $redrawFreq = 1;
034      private $output;
035      private $step = 0;
036      private $max;
037      private $startTime;
038      private $stepWidth;
039      private $percent = 0.0;
040      private $formatLineCount;
041      private $messages = [];
042      private $overwrite = true;
043      private $terminal;
044      private $firstRun = true;
045   
046      private static $formatters;
047      private static $formats;
048   
049      /**
050       * @param OutputInterface $output An OutputInterface instance
051       * @param int             $max    Maximum steps (0 if unknown)
052       */
053      public function __construct(OutputInterface $output, $max = 0)
054      {
055          if ($output instanceof ConsoleOutputInterface) {
056              $output = $output->getErrorOutput();
057          }
058   
059          $this->output = $output;
060          $this->setMaxSteps($max);
061          $this->terminal = new Terminal();
062   
063          if (!$this->output->isDecorated()) {
064              // disable overwrite when output does not support ANSI codes.
065              $this->overwrite = false;
066   
067              // set a reasonable redraw frequency so output isn't flooded
068              $this->setRedrawFrequency($max / 10);
069          }
070   
071          $this->startTime = time();
072      }
073   
074      /**
075       * Sets a placeholder formatter for a given name.
076       *
077       * This method also allow you to override an existing placeholder.
078       *
079       * @param string   $name     The placeholder name (including the delimiter char like %)
080       * @param callable $callable A PHP callable
081       */
082      public static function setPlaceholderFormatterDefinition($name, callable $callable)
083      {
084          if (!self::$formatters) {
085              self::$formatters = self::initPlaceholderFormatters();
086          }
087   
088          self::$formatters[$name] = $callable;
089      }
090   
091      /**
092       * Gets the placeholder formatter for a given name.
093       *
094       * @param string $name The placeholder name (including the delimiter char like %)
095       *
096       * @return callable|null A PHP callable
097       */
098      public static function getPlaceholderFormatterDefinition($name)
099      {
100          if (!self::$formatters) {
101              self::$formatters = self::initPlaceholderFormatters();
102          }
103   
104          return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
105      }
106   
107      /**
108       * Sets a format for a given name.
109       *
110       * This method also allow you to override an existing format.
111       *
112       * @param string $name   The format name
113       * @param string $format A format string
114       */
115      public static function setFormatDefinition($name, $format)
116      {
117          if (!self::$formats) {
118              self::$formats = self::initFormats();
119          }
120   
121          self::$formats[$name] = $format;
122      }
123   
124      /**
125       * Gets the format for a given name.
126       *
127       * @param string $name The format name
128       *
129       * @return string|null A format string
130       */
131      public static function getFormatDefinition($name)
132      {
133          if (!self::$formats) {
134              self::$formats = self::initFormats();
135          }
136   
137          return isset(self::$formats[$name]) ? self::$formats[$name] : null;
138      }
139   
140      /**
141       * Associates a text with a named placeholder.
142       *
143       * The text is displayed when the progress bar is rendered but only
144       * when the corresponding placeholder is part of the custom format line
145       * (by wrapping the name with %).
146       *
147       * @param string $message The text to associate with the placeholder
148       * @param string $name    The name of the placeholder
149       */
150      public function setMessage($message, $name = 'message')
151      {
152          $this->messages[$name] = $message;
153      }
154   
155      public function getMessage($name = 'message')
156      {
157          return $this->messages[$name];
158      }
159   
160      /**
161       * Gets the progress bar start time.
162       *
163       * @return int The progress bar start time
164       */
165      public function getStartTime()
166      {
167          return $this->startTime;
168      }
169   
170      /**
171       * Gets the progress bar maximal steps.
172       *
173       * @return int The progress bar max steps
174       */
175      public function getMaxSteps()
176      {
177          return $this->max;
178      }
179   
180      /**
181       * Gets the current step position.
182       *
183       * @return int The progress bar step
184       */
185      public function getProgress()
186      {
187          return $this->step;
188      }
189   
190      /**
191       * Gets the progress bar step width.
192       *
193       * @return int The progress bar step width
194       */
195      private function getStepWidth()
196      {
197          return $this->stepWidth;
198      }
199   
200      /**
201       * Gets the current progress bar percent.
202       *
203       * @return float The current progress bar percent
204       */
205      public function getProgressPercent()
206      {
207          return $this->percent;
208      }
209   
210      /**
211       * Sets the progress bar width.
212       *
213       * @param int $size The progress bar size
214       */
215      public function setBarWidth($size)
216      {
217          $this->barWidth = max(1, (int) $size);
218      }
219   
220      /**
221       * Gets the progress bar width.
222       *
223       * @return int The progress bar size
224       */
225      public function getBarWidth()
226      {
227          return $this->barWidth;
228      }
229   
230      /**
231       * Sets the bar character.
232       *
233       * @param string $char A character
234       */
235      public function setBarCharacter($char)
236      {
237          $this->barChar = $char;
238      }
239   
240      /**
241       * Gets the bar character.
242       *
243       * @return string A character
244       */
245      public function getBarCharacter()
246      {
247          if (null === $this->barChar) {
248              return $this->max ? '=' : $this->emptyBarChar;
249          }
250   
251          return $this->barChar;
252      }
253   
254      /**
255       * Sets the empty bar character.
256       *
257       * @param string $char A character
258       */
259      public function setEmptyBarCharacter($char)
260      {
261          $this->emptyBarChar = $char;
262      }
263   
264      /**
265       * Gets the empty bar character.
266       *
267       * @return string A character
268       */
269      public function getEmptyBarCharacter()
270      {
271          return $this->emptyBarChar;
272      }
273   
274      /**
275       * Sets the progress bar character.
276       *
277       * @param string $char A character
278       */
279      public function setProgressCharacter($char)
280      {
281          $this->progressChar = $char;
282      }
283   
284      /**
285       * Gets the progress bar character.
286       *
287       * @return string A character
288       */
289      public function getProgressCharacter()
290      {
291          return $this->progressChar;
292      }
293   
294      /**
295       * Sets the progress bar format.
296       *
297       * @param string $format The format
298       */
299      public function setFormat($format)
300      {
301          $this->format = null;
302          $this->internalFormat = $format;
303      }
304   
305      /**
306       * Sets the redraw frequency.
307       *
308       * @param int|float $freq The frequency in steps
309       */
310      public function setRedrawFrequency($freq)
311      {
312          $this->redrawFreq = max((int) $freq, 1);
313      }
314   
315      /**
316       * Starts the progress output.
317       *
318       * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
319       */
320      public function start($max = null)
321      {
322          $this->startTime = time();
323          $this->step = 0;
324          $this->percent = 0.0;
325   
326          if (null !== $max) {
327              $this->setMaxSteps($max);
328          }
329   
330          $this->display();
331      }
332   
333      /**
334       * Advances the progress output X steps.
335       *
336       * @param int $step Number of steps to advance
337       */
338      public function advance($step = 1)
339      {
340          $this->setProgress($this->step + $step);
341      }
342   
343      /**
344       * Sets whether to overwrite the progressbar, false for new line.
345       *
346       * @param bool $overwrite
347       */
348      public function setOverwrite($overwrite)
349      {
350          $this->overwrite = (bool) $overwrite;
351      }
352   
353      /**
354       * Sets the current progress.
355       *
356       * @param int $step The current progress
357       */
358      public function setProgress($step)
359      {
360          $step = (int) $step;
361   
362          if ($this->max && $step > $this->max) {
363              $this->max = $step;
364          } elseif ($step < 0) {
365              $step = 0;
366          }
367   
368          $prevPeriod = (int) ($this->step / $this->redrawFreq);
369          $currPeriod = (int) ($step / $this->redrawFreq);
370          $this->step = $step;
371          $this->percent = $this->max ? (float) $this->step / $this->max : 0;
372          if ($prevPeriod !== $currPeriod || $this->max === $step) {
373              $this->display();
374          }
375      }
376   
377      /**
378       * Finishes the progress output.
379       */
380      public function finish()
381      {
382          if (!$this->max) {
383              $this->max = $this->step;
384          }
385   
386          if ($this->step === $this->max && !$this->overwrite) {
387              // prevent double 100% output
388              return;
389          }
390   
391          $this->setProgress($this->max);
392      }
393   
394      /**
395       * Outputs the current progress string.
396       */
397      public function display()
398      {
399          if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
400              return;
401          }
402   
403          if (null === $this->format) {
404              $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
405          }
406   
407          $this->overwrite($this->buildLine());
408      }
409   
410      /**
411       * Removes the progress bar from the current line.
412       *
413       * This is useful if you wish to write some output
414       * while a progress bar is running.
415       * Call display() to show the progress bar again.
416       */
417      public function clear()
418      {
419          if (!$this->overwrite) {
420              return;
421          }
422   
423          if (null === $this->format) {
424              $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
425          }
426   
427          $this->overwrite('');
428      }
429   
430      /**
431       * Sets the progress bar format.
432       *
433       * @param string $format The format
434       */
435      private function setRealFormat($format)
436      {
437          // try to use the _nomax variant if available
438          if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
439              $this->format = self::getFormatDefinition($format.'_nomax');
440          } elseif (null !== self::getFormatDefinition($format)) {
441              $this->format = self::getFormatDefinition($format);
442          } else {
443              $this->format = $format;
444          }
445   
446          $this->formatLineCount = substr_count($this->format, "\n");
447      }
448   
449      /**
450       * Sets the progress bar maximal steps.
451       *
452       * @param int $max The progress bar max steps
453       */
454      private function setMaxSteps($max)
455      {
456          $this->max = max(0, (int) $max);
457          $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
458      }
459   
460      /**
461       * Overwrites a previous message to the output.
462       *
463       * @param string $message The message
464       */
465      private function overwrite($message)
466      {
467          if ($this->overwrite) {
468              if (!$this->firstRun) {
469                  // Erase previous lines
470                  if ($this->formatLineCount > 0) {
471                      $message = str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount).$message;
472                  }
473   
474                  // Move the cursor to the beginning of the line and erase the line
475                  $message = "\x0D\x1B[2K$message";
476              }
477          } elseif ($this->step > 0) {
478              $message = \PHP_EOL.$message;
479          }
480   
481          $this->firstRun = false;
482   
483          $this->output->write($message);
484      }
485   
486      private function determineBestFormat()
487      {
488          switch ($this->output->getVerbosity()) {
489              // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
490              case OutputInterface::VERBOSITY_VERBOSE:
491                  return $this->max ? 'verbose' : 'verbose_nomax';
492              case OutputInterface::VERBOSITY_VERY_VERBOSE:
493                  return $this->max ? 'very_verbose' : 'very_verbose_nomax';
494              case OutputInterface::VERBOSITY_DEBUG:
495                  return $this->max ? 'debug' : 'debug_nomax';
496              default:
497                  return $this->max ? 'normal' : 'normal_nomax';
498          }
499      }
500   
501      private static function initPlaceholderFormatters()
502      {
503          return [
504              'bar' => function (self $bar, OutputInterface $output) {
505                  $completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
506                  $display = str_repeat($bar->getBarCharacter(), $completeBars);
507                  if ($completeBars < $bar->getBarWidth()) {
508                      $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
509                      $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
510                  }
511   
512                  return $display;
513              },
514              'elapsed' => function (self $bar) {
515                  return Helper::formatTime(time() - $bar->getStartTime());
516              },
517              'remaining' => function (self $bar) {
518                  if (!$bar->getMaxSteps()) {
519                      throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
520                  }
521   
522                  if (!$bar->getProgress()) {
523                      $remaining = 0;
524                  } else {
525                      $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
526                  }
527   
528                  return Helper::formatTime($remaining);
529              },
530              'estimated' => function (self $bar) {
531                  if (!$bar->getMaxSteps()) {
532                      throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
533                  }
534   
535                  if (!$bar->getProgress()) {
536                      $estimated = 0;
537                  } else {
538                      $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
539                  }
540   
541                  return Helper::formatTime($estimated);
542              },
543              'memory' => function (self $bar) {
544                  return Helper::formatMemory(memory_get_usage(true));
545              },
546              'current' => function (self $bar) {
547                  return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT);
548              },
549              'max' => function (self $bar) {
550                  return $bar->getMaxSteps();
551              },
552              'percent' => function (self $bar) {
553                  return floor($bar->getProgressPercent() * 100);
554              },
555          ];
556      }
557   
558      private static function initFormats()
559      {
560          return [
561              'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
562              'normal_nomax' => ' %current% [%bar%]',
563   
564              'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
565              'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
566   
567              'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
568              'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
569   
570              'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
571              'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
572          ];
573      }
574   
575      /**
576       * @return string
577       */
578      private function buildLine()
579      {
580          $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
581          $callback = function ($matches) {
582              if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
583                  $text = \call_user_func($formatter, $this, $this->output);
584              } elseif (isset($this->messages[$matches[1]])) {
585                  $text = $this->messages[$matches[1]];
586              } else {
587                  return $matches[0];
588              }
589   
590              if (isset($matches[2])) {
591                  $text = sprintf('%'.$matches[2], $text);
592              }
593   
594              return $text;
595          };
596          $line = preg_replace_callback($regex, $callback, $this->format);
597   
598          // gets string length for each sub line with multiline format
599          $linesLength = array_map(function ($subLine) {
600              return Helper::strlenWithoutDecoration($this->output->getFormatter(), rtrim($subLine, "\r"));
601          }, explode("\n", $line));
602   
603          $linesWidth = max($linesLength);
604   
605          $terminalWidth = $this->terminal->getWidth();
606          if ($linesWidth <= $terminalWidth) {
607              return $line;
608          }
609   
610          $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);
611   
612          return preg_replace_callback($regex, $callback, $this->format);
613      }
614  }
615