[ Index ] |
PHP Cross Reference of phpBB-3.3.12-deutsch |
[Summary view] [Print] [Text view]
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 14 use Symfony\Component\Console\Exception\LogicException; 15 use Symfony\Component\Console\Output\ConsoleOutputInterface; 16 use Symfony\Component\Console\Output\OutputInterface; 17 use Symfony\Component\Console\Terminal; 18 19 /** 20 * The ProgressBar provides helpers to display progress output. 21 * 22 * @author Fabien Potencier <fabien@symfony.com> 23 * @author Chris Jones <leeked@gmail.com> 24 */ 25 final class ProgressBar 26 { 27 private $barWidth = 28; 28 private $barChar; 29 private $emptyBarChar = '-'; 30 private $progressChar = '>'; 31 private $format; 32 private $internalFormat; 33 private $redrawFreq = 1; 34 private $output; 35 private $step = 0; 36 private $max; 37 private $startTime; 38 private $stepWidth; 39 private $percent = 0.0; 40 private $formatLineCount; 41 private $messages = []; 42 private $overwrite = true; 43 private $terminal; 44 private $firstRun = true; 45 46 private static $formatters; 47 private static $formats; 48 49 /** 50 * @param OutputInterface $output An OutputInterface instance 51 * @param int $max Maximum steps (0 if unknown) 52 */ 53 public function __construct(OutputInterface $output, $max = 0) 54 { 55 if ($output instanceof ConsoleOutputInterface) { 56 $output = $output->getErrorOutput(); 57 } 58 59 $this->output = $output; 60 $this->setMaxSteps($max); 61 $this->terminal = new Terminal(); 62 63 if (!$this->output->isDecorated()) { 64 // disable overwrite when output does not support ANSI codes. 65 $this->overwrite = false; 66 67 // set a reasonable redraw frequency so output isn't flooded 68 $this->setRedrawFrequency($max / 10); 69 } 70 71 $this->startTime = time(); 72 } 73 74 /** 75 * Sets a placeholder formatter for a given name. 76 * 77 * This method also allow you to override an existing placeholder. 78 * 79 * @param string $name The placeholder name (including the delimiter char like %) 80 * @param callable $callable A PHP callable 81 */ 82 public static function setPlaceholderFormatterDefinition($name, callable $callable) 83 { 84 if (!self::$formatters) { 85 self::$formatters = self::initPlaceholderFormatters(); 86 } 87 88 self::$formatters[$name] = $callable; 89 } 90 91 /** 92 * Gets the placeholder formatter for a given name. 93 * 94 * @param string $name The placeholder name (including the delimiter char like %) 95 * 96 * @return callable|null A PHP callable 97 */ 98 public static function getPlaceholderFormatterDefinition($name) 99 { 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Jun 23 12:25:44 2024 | Cross-referenced by PHPXref 0.7.1 |