composer package updates
[openemr.git] / vendor / zendframework / zend-progressbar / src / Adapter / Console.php
blob09987dc33e1c9cd8839546911e5039ca56b7f64b
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\ProgressBar\Adapter;
12 use Zend\Stdlib\ErrorHandler;
13 use Zend\Stdlib\StringUtils;
15 /**
16 * Zend\ProgressBar\Adapter\Console offers a text-based progressbar for console
17 * applications
19 class Console extends AbstractAdapter
21 /**
22 * Percentage value of the progress
24 const ELEMENT_PERCENT = 'ELEMENT_PERCENT';
26 /**
27 * Visual value of the progress
29 const ELEMENT_BAR = 'ELEMENT_BAR';
31 /**
32 * ETA of the progress
34 const ELEMENT_ETA = 'ELEMENT_ETA';
36 /**
37 * Text part of the progress
39 const ELEMENT_TEXT = 'ELEMENT_TEXT';
41 /**
42 * Finish action: End of Line
44 const FINISH_ACTION_EOL = 'FINISH_ACTION_EOL';
46 /**
47 * Finish action: Clear Line
49 const FINISH_ACTION_CLEAR_LINE = 'FINISH_ACTION_CLEAR_LINE';
51 /**
52 * Finish action: None
54 const FINISH_ACTION_NONE = 'FINISH_ACTION_NONE';
56 /**
57 * Width of the progressbar
59 * @var int
61 protected $width = null;
63 /**
64 * Elements to display
66 * @var array
68 protected $elements = [
69 self::ELEMENT_PERCENT,
70 self::ELEMENT_BAR,
71 self::ELEMENT_ETA,
74 /**
75 * Which action to do at finish call
77 * @var string
79 protected $finishAction = self::FINISH_ACTION_EOL;
81 /**
82 * Width of the bar element
84 * @var int
86 protected $barWidth;
88 /**
89 * Left character(s) within the bar
91 * @var string
93 protected $barLeftChar = '#';
95 /**
96 * Indicator character(s) within the bar
98 * @var string
100 protected $barIndicatorChar = '';
103 * Right character(s) within the bar
105 * @var string
107 protected $barRightChar = '-';
110 * Output-stream, when STDOUT is not defined (e.g. in CGI) or set manually
112 * @var resource
114 protected $outputStream = null;
117 * Width of the text element
119 * @var string
121 protected $textWidth = 20;
124 * Whether the output started yet or not
126 * @var bool
128 protected $outputStarted = false;
131 * Charset of text element
133 * @var string
135 protected $charset = 'utf-8';
138 * Defined by Zend\ProgressBar adapter
140 * @param array|\Traversable $options
142 public function __construct($options = null)
144 // Call parent constructor with options
145 parent::__construct($options);
147 // Check if a width was set, else use auto width
148 if ($this->width === null) {
149 $this->setWidth();
154 * Close local stdout, when open
156 public function __destruct()
158 if ($this->outputStream !== null) {
159 fclose($this->outputStream);
164 * Set a different output-stream
166 * @param string $resource
167 * @throws Exception\RuntimeException
168 * @return \Zend\ProgressBar\Adapter\Console
170 public function setOutputStream($resource)
172 ErrorHandler::start();
173 $stream = fopen($resource, 'w');
174 $error = ErrorHandler::stop();
176 if ($stream === false) {
177 throw new Exception\RuntimeException('Unable to open stream', 0, $error);
180 if ($this->outputStream !== null) {
181 fclose($this->outputStream);
184 $this->outputStream = $stream;
188 * Get the current output stream
190 * @return resource
192 public function getOutputStream()
194 if ($this->outputStream === null) {
195 if (! defined('STDOUT')) {
196 $this->outputStream = fopen('php://stdout', 'w');
197 } else {
198 return STDOUT;
202 return $this->outputStream;
206 * Set the width of the progressbar
208 * @param int $width
209 * @return \Zend\ProgressBar\Adapter\Console
211 public function setWidth($width = null)
213 if ($width === null || ! is_int($width)) {
214 if (substr(PHP_OS, 0, 3) === 'WIN') {
215 // We have to default to 79 on windows, because the windows
216 // terminal always has a fixed width of 80 characters and the
217 // cursor is counted to the line, else windows would line break
218 // after every update.
219 $this->width = 79;
220 } else {
221 // Set the default width of 80
222 $this->width = 80;
224 // Try to determine the width through stty
225 ErrorHandler::start();
226 if (preg_match('#\d+ (\d+)#', shell_exec('stty size'), $match) === 1) {
227 $this->width = (int) $match[1];
228 } elseif (preg_match('#columns = (\d+);#', shell_exec('stty'), $match) === 1) {
229 $this->width = (int) $match[1];
231 ErrorHandler::stop();
233 } else {
234 $this->width = (int) $width;
237 $this->_calculateBarWidth();
239 return $this;
243 * Set the elements to display with the progressbar
245 * @param array $elements
246 * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When an invalid element is found
247 * in the array
248 * @return \Zend\ProgressBar\Adapter\Console
250 public function setElements(array $elements)
252 $allowedElements = [self::ELEMENT_PERCENT,
253 self::ELEMENT_BAR,
254 self::ELEMENT_ETA,
255 self::ELEMENT_TEXT];
257 if (count(array_diff($elements, $allowedElements)) > 0) {
258 throw new Exception\InvalidArgumentException('Invalid element found in $elements array');
261 $this->elements = $elements;
263 $this->_calculateBarWidth();
265 return $this;
269 * Set the left-hand character for the bar
271 * @param string $char
272 * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When character is empty
273 * @return \Zend\ProgressBar\Adapter\Console
275 public function setBarLeftChar($char)
277 if (empty($char)) {
278 throw new Exception\InvalidArgumentException('Character may not be empty');
281 $this->barLeftChar = (string) $char;
283 return $this;
287 * Set the right-hand character for the bar
289 * @param string $char
290 * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When character is empty
291 * @return \Zend\ProgressBar\Adapter\Console
293 public function setBarRightChar($char)
295 if (empty($char)) {
296 throw new Exception\InvalidArgumentException('Character may not be empty');
299 $this->barRightChar = (string) $char;
301 return $this;
305 * Set the indicator character for the bar
307 * @param string $char
308 * @return \Zend\ProgressBar\Adapter\Console
310 public function setBarIndicatorChar($char)
312 $this->barIndicatorChar = (string) $char;
314 return $this;
318 * Set the width of the text element
320 * @param int $width
321 * @return \Zend\ProgressBar\Adapter\Console
323 public function setTextWidth($width)
325 $this->textWidth = (int) $width;
327 $this->_calculateBarWidth();
329 return $this;
333 * Set the charset of the text element
335 * @param string $charset
337 public function setCharset($charset)
339 $this->charset = $charset;
343 * Set the finish action
345 * @param string $action
346 * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When an invalid action is specified
347 * @return \Zend\ProgressBar\Adapter\Console
349 public function setFinishAction($action)
351 $allowedActions = [self::FINISH_ACTION_CLEAR_LINE,
352 self::FINISH_ACTION_EOL,
353 self::FINISH_ACTION_NONE];
355 if (! in_array($action, $allowedActions)) {
356 throw new Exception\InvalidArgumentException('Invalid finish action specified');
359 $this->finishAction = $action;
361 return $this;
365 * Defined by Zend\ProgressBar\Adapter\AbstractAdapter
367 * @param float $current Current progress value
368 * @param float $max Max progress value
369 * @param float $percent Current percent value
370 * @param int $timeTaken Taken time in seconds
371 * @param int $timeRemaining Remaining time in seconds
372 * @param string $text Status text
373 * @return void
375 public function notify($current, $max, $percent, $timeTaken, $timeRemaining, $text)
377 // See if we must clear the line
378 if ($this->outputStarted) {
379 $data = str_repeat("\x08", $this->width);
380 } else {
381 $data = '';
382 $this->outputStarted = true;
385 // Build all elements
386 $renderedElements = [];
388 foreach ($this->elements as $element) {
389 switch ($element) {
390 case self::ELEMENT_BAR:
391 $visualWidth = $this->barWidth - 2;
392 $bar = '[';
394 $indicatorWidth = strlen($this->barIndicatorChar);
396 $doneWidth = min($visualWidth - $indicatorWidth, round($visualWidth * $percent));
397 if ($doneWidth > 0) {
398 $bar .= substr(
399 str_repeat($this->barLeftChar, ceil($doneWidth / strlen($this->barLeftChar))),
401 $doneWidth
405 $bar .= $this->barIndicatorChar;
407 $leftWidth = $visualWidth - $doneWidth - $indicatorWidth;
408 if ($leftWidth > 0) {
409 $bar .= substr(
410 str_repeat($this->barRightChar, ceil($leftWidth / strlen($this->barRightChar))),
412 $leftWidth
416 $bar .= ']';
418 $renderedElements[] = $bar;
419 break;
421 case self::ELEMENT_PERCENT:
422 $renderedElements[] = str_pad(round($percent * 100), 3, ' ', STR_PAD_LEFT) . '%';
423 break;
425 case self::ELEMENT_ETA:
426 // In the first 5 seconds we don't get accurate results,
427 // this skipping technique is found in many progressbar
428 // implementations.
429 if ($timeTaken < 5) {
430 $renderedElements[] = str_repeat(' ', 12);
431 break;
434 if ($timeRemaining === null || $timeRemaining > 86400) {
435 $etaFormatted = '??:??:??';
436 } else {
437 $hours = floor($timeRemaining / 3600);
438 $minutes = floor(($timeRemaining % 3600) / 60);
439 $seconds = ($timeRemaining % 3600 % 60);
441 $etaFormatted = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
444 $renderedElements[] = 'ETA ' . $etaFormatted;
445 break;
447 case self::ELEMENT_TEXT:
448 $wrapper = StringUtils::getWrapper($this->charset);
449 $renderedElements[] = $wrapper->strPad(
450 $wrapper->substr($text, 0, $this->textWidth),
451 $this->textWidth,
452 ' ',
453 STR_PAD_RIGHT
455 break;
459 $data .= implode(' ', $renderedElements);
461 // Output line data
462 $this->_outputData($data);
466 * Defined by Zend\ProgressBar\Adapter\AbstractAdapter
468 * @return void
470 public function finish()
472 switch ($this->finishAction) {
473 case self::FINISH_ACTION_EOL:
474 $this->_outputData(PHP_EOL);
475 break;
477 case self::FINISH_ACTION_CLEAR_LINE:
478 if ($this->outputStarted) {
479 $data = str_repeat("\x08", $this->width)
480 . str_repeat(' ', $this->width)
481 . str_repeat("\x08", $this->width);
483 $this->_outputData($data);
485 break;
487 case self::FINISH_ACTION_NONE:
488 break;
493 * Calculate the bar width when other elements changed
495 * @return void
497 // @codingStandardsIgnoreStart
498 protected function _calculateBarWidth()
500 // @codingStandardsIgnoreEnd
501 if (in_array(self::ELEMENT_BAR, $this->elements)) {
502 $barWidth = $this->width;
504 if (in_array(self::ELEMENT_PERCENT, $this->elements)) {
505 $barWidth -= 4;
508 if (in_array(self::ELEMENT_ETA, $this->elements)) {
509 $barWidth -= 12;
512 if (in_array(self::ELEMENT_TEXT, $this->elements)) {
513 $barWidth -= $this->textWidth;
516 $this->barWidth = $barWidth - (count($this->elements) - 1);
521 * Outputs given data to STDOUT.
523 * This split-off is required for unit-testing.
525 * @param string $data
526 * @return void
528 // @codingStandardsIgnoreStart
529 protected function _outputData($data)
531 // @codingStandardsIgnoreEnd
532 fwrite($this->getOutputStream(), $data);