Merge file:///media/external_data/workspace/web/sport-group
[sport-group.git] / library / Zend / ProgressBar / Adapter / Console.php
blob42cfacaa43f9aee4a3ee3d8a088d84dcac499d32
1 <?php
2 /**
3 * LICENSE
5 * This source file is subject to the new BSD license that is bundled
6 * with this package in the file LICENSE.txt.
7 * It is also available through the world-wide-web at this URL:
8 * http://framework.zend.com/license/new-bsd
9 * If you did not receive a copy of the license and are unable to
10 * obtain it through the world-wide-web, please send an email
11 * to license@zend.com so we can send you a copy immediately.
13 * @category Zend
14 * @package Zend_ProgressBar
15 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
16 * @license http://framework.zend.com/license/new-bsd New BSD License
17 * @version $Id: Console.php 16215 2009-06-21 19:36:07Z thomas $
20 /**
21 * @see Zend_ProgressBar_Adapter
23 require_once 'Zend/ProgressBar/Adapter.php';
25 /**
26 * @see Zend_Text_MultiByte
28 require_once 'Zend/Text/MultiByte.php';
30 /**
31 * Zend_ProgressBar_Adapter_Console offers a text-based progressbar for console
32 * applications
34 * @category Zend
35 * @package Zend_ProgressBar
36 * @uses Zend_ProgressBar_Adapter_Interface
37 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
38 * @license http://framework.zend.com/license/new-bsd New BSD License
40 class Zend_ProgressBar_Adapter_Console extends Zend_ProgressBar_Adapter
42 /**
43 * Percentage value of the progress
45 const ELEMENT_PERCENT = 'ELEMENT_PERCENT';
47 /**
48 * Visual value of the progress
50 const ELEMENT_BAR = 'ELEMENT_BAR';
52 /**
53 * ETA of the progress
55 const ELEMENT_ETA = 'ELEMENT_ETA';
57 /**
58 * Text part of the progress
60 const ELEMENT_TEXT = 'ELEMENT_TEXT';
62 /**
63 * Finish action: End of Line
65 const FINISH_ACTION_EOL = 'FINISH_ACTION_EOL';
67 /**
68 * Finish action: Clear Line
70 const FINISH_ACTION_CLEAR_LINE = 'FINISH_ACTION_CLEAR_LINE';
72 /**
73 * Finish action: None
75 const FINISH_ACTION_NONE = 'FINISH_ACTION_NONE';
77 /**
78 * Width of the progressbar
80 * @var integer
82 protected $_width = null;
84 /**
85 * Elements to display
87 * @var array
89 protected $_elements = array(self::ELEMENT_PERCENT,
90 self::ELEMENT_BAR,
91 self::ELEMENT_ETA);
93 /**
94 * Which action to do at finish call
96 * @var string
98 protected $_finishAction = self::FINISH_ACTION_EOL;
101 * Width of the bar element
103 * @var integer
105 protected $_barWidth;
108 * Left character(s) within the bar
110 * @var string
112 protected $_barLeftChar = '#';
115 * Indicator character(s) within the bar
117 * @var string
119 protected $_barIndicatorChar = '';
122 * Right character(s) within the bar
124 * @var string
126 protected $_barRightChar = '-';
129 * Output-stream, when STDOUT is not defined (e.g. in CGI) or set manually
131 * @var resource
133 protected $_outputStream = null;
136 * Width of the text element
138 * @var string
140 protected $_textWidth = 20;
143 * Wether the output started yet or not
145 * @var boolean
147 protected $_outputStarted = false;
150 * Charset of text element
152 * @var string
154 protected $_charset = 'utf-8';
157 * Defined by Zend_ProgressBar_Adapter
159 * @param null|array|Zend_Config $options
161 public function __construct($options = null)
163 // Call parent constructor with options
164 parent::__construct($options);
166 // Check if a width was set, else use auto width
167 if ($this->_width === null) {
168 $this->setWidth();
173 * Close local stdout, when open
175 public function __destruct()
177 if ($this->_outputStream !== null) {
178 fclose($this->_outputStream);
183 * Set a different output-stream
185 * @param string $resource
186 * @return Zend_ProgressBar_Adapter_Console
188 public function setOutputStream($resource)
190 $stream = @fopen($resource, 'w');
192 if ($stream === false) {
193 require_once 'Zend/ProgressBar/Adapter/Exception.php';
194 throw new Zend_ProgressBar_Adapter_Exception('Unable to open stream');
197 if ($this->_outputStream !== null) {
198 fclose($this->_outputStream);
201 $this->_outputStream = $stream;
205 * Get the current output stream
207 * @return resource
209 public function getOutputStream()
211 if ($this->_outputStream === null) {
212 if (!defined('STDOUT')) {
213 $this->_outputStream = fopen('php://stdout', 'w');
214 } else {
215 return STDOUT;
219 return $this->_outputStream;
223 * Set the width of the progressbar
225 * @param integer $width
226 * @return Zend_ProgressBar_Adapter_Console
228 public function setWidth($width = null)
230 if ($width === null || !is_integer($width)) {
231 if (substr(PHP_OS, 0, 3) === 'WIN') {
232 // We have to default to 79 on windows, because the windows
233 // terminal always has a fixed width of 80 characters and the
234 // cursor is counted to the line, else windows would line break
235 // after every update.
236 $this->_width = 79;
237 } else {
238 // Set the default width of 80
239 $this->_width = 80;
241 // Try to determine the width through stty
242 if (preg_match('#\d+ (\d+)#', @shell_exec('stty size'), $match) === 1) {
243 $this->_width = (int) $match[1];
244 } else if (preg_match('#columns = (\d+);#', @shell_exec('stty'), $match) === 1) {
245 $this->_width = (int) $match[1];
248 } else {
249 $this->_width = (int) $width;
252 $this->_calculateBarWidth();
254 return $this;
258 * Set the elements to display with the progressbar
260 * @param array $elements
261 * @throws Zend_ProgressBar_Adapter_Exception When an invalid element is foudn in the array
262 * @return Zend_ProgressBar_Adapter_Console
264 public function setElements(array $elements)
266 $allowedElements = array(self::ELEMENT_PERCENT,
267 self::ELEMENT_BAR,
268 self::ELEMENT_ETA,
269 self::ELEMENT_TEXT);
271 if (count(array_diff($elements, $allowedElements)) > 0) {
272 require_once 'Zend/ProgressBar/Adapter/Exception.php';
273 throw new Zend_ProgressBar_Adapter_Exception('Invalid element found in $elements array');
276 $this->_elements = $elements;
278 $this->_calculateBarWidth();
280 return $this;
284 * Set the left-hand character for the bar
286 * @param string $char
287 * @throws Zend_ProgressBar_Adapter_Exception When character is empty
288 * @return Zend_ProgressBar_Adapter_Console
290 public function setBarLeftChar($char)
292 if (empty($char)) {
293 require_once 'Zend/ProgressBar/Adapter/Exception.php';
294 throw new Zend_ProgressBar_Adapter_Exception('Character may not be empty');
297 $this->_barLeftChar = (string) $char;
299 return $this;
303 * Set the right-hand character for the bar
305 * @param string $char
306 * @throws Zend_ProgressBar_Adapter_Exception When character is empty
307 * @return Zend_ProgressBar_Adapter_Console
309 public function setBarRightChar($char)
311 if (empty($char)) {
312 require_once 'Zend/ProgressBar/Adapter/Exception.php';
313 throw new Zend_ProgressBar_Adapter_Exception('Character may not be empty');
316 $this->_barRightChar = (string) $char;
318 return $this;
322 * Set the indicator character for the bar
324 * @param string $char
325 * @return Zend_ProgressBar_Adapter_Console
327 public function setBarIndicatorChar($char)
329 $this->_barIndicatorChar = (string) $char;
331 return $this;
335 * Set the width of the text element
337 * @param integer $width
338 * @return Zend_ProgressBar_Adapter_Console
340 public function setTextWidth($width)
342 $this->_textWidth = (int) $width;
344 $this->_calculateBarWidth();
346 return $this;
350 * Set the charset of the text element
352 * @param string $charset
354 public function setCharset($charset)
356 $this->_charset = $charset;
360 * Set the finish action
362 * @param string $action
363 * @throws Zend_ProgressBar_Adapter_Exception When an invalid action is specified
364 * @return Zend_ProgressBar_Adapter_Console
366 public function setFinishAction($action)
368 $allowedActions = array(self::FINISH_ACTION_CLEAR_LINE,
369 self::FINISH_ACTION_EOL,
370 self::FINISH_ACTION_NONE);
372 if (!in_array($action, $allowedActions)) {
373 require_once 'Zend/ProgressBar/Adapter/Exception.php';
374 throw new Zend_ProgressBar_Adapter_Exception('Invalid finish action specified');
377 $this->_finishAction = $action;
379 return $this;
383 * Defined by Zend_ProgressBar_Adapter_Interface
385 * @param float $current Current progress value
386 * @param float $max Max progress value
387 * @param float $percent Current percent value
388 * @param integer $timeTaken Taken time in seconds
389 * @param integer $timeRemaining Remaining time in seconds
390 * @param string $text Status text
391 * @return void
393 public function notify($current, $max, $percent, $timeTaken, $timeRemaining, $text)
395 // See if we must clear the line
396 if ($this->_outputStarted) {
397 $data = str_repeat("\x08", $this->_width);
398 } else {
399 $data = '';
400 $this->_outputStarted = true;
403 // Build all elements
404 $renderedElements = array();
406 foreach ($this->_elements as $element) {
407 switch ($element) {
408 case self::ELEMENT_BAR:
409 $visualWidth = $this->_barWidth - 2;
410 $bar = '[';
412 $indicatorWidth = strlen($this->_barIndicatorChar);
414 $doneWidth = min($visualWidth - $indicatorWidth, round($visualWidth * $percent));
415 if ($doneWidth > 0) {
416 $bar .= substr(str_repeat($this->_barLeftChar, ceil($doneWidth / strlen($this->_barLeftChar))), 0, $doneWidth);
419 $bar .= $this->_barIndicatorChar;
421 $leftWidth = $visualWidth - $doneWidth - $indicatorWidth;
422 if ($leftWidth > 0) {
423 $bar .= substr(str_repeat($this->_barRightChar, ceil($leftWidth / strlen($this->_barRightChar))), 0, $leftWidth);
426 $bar .= ']';
428 $renderedElements[] = $bar;
429 break;
431 case self::ELEMENT_PERCENT:
432 $renderedElements[] = str_pad(round($percent * 100), 3, ' ', STR_PAD_LEFT) . '%';
433 break;
435 case self::ELEMENT_ETA:
436 // In the first 5 seconds we don't get accurate results,
437 // this skipping technique is found in many progressbar
438 // implementations.
439 if ($timeTaken < 5) {
440 $renderedElements[] = str_repeat(' ', 12);
441 break;
444 if ($timeRemaining === null || $timeRemaining > 86400) {
445 $etaFormatted = '??:??:??';
446 } else {
447 $hours = floor($timeRemaining / 3600);
448 $minutes = floor(($timeRemaining % 3600) / 60);
449 $seconds = ($timeRemaining % 3600 % 60);
451 $etaFormatted = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
454 $renderedElements[] = 'ETA ' . $etaFormatted;
455 break;
457 case self::ELEMENT_TEXT:
458 $renderedElements[] = Zend_Text_MultiByte::strPad(substr($text, 0, $this->_textWidth), $this->_textWidth, ' ', STR_PAD_RIGHT, $this->_charset);
459 break;
463 $data .= implode(' ', $renderedElements);
465 // Output line data
466 $this->_outputData($data);
470 * Defined by Zend_ProgressBar_Adapter_Interface
472 * @return void
474 public function finish()
476 switch ($this->_finishAction) {
477 case self::FINISH_ACTION_EOL:
478 $this->_outputData(PHP_EOL);
479 break;
481 case self::FINISH_ACTION_CLEAR_LINE:
482 if ($this->_outputStarted) {
483 $data = str_repeat("\x08", $this->_width)
484 . str_repeat(' ', $this->_width)
485 . str_repeat("\x08", $this->_width);
487 $this->_outputData($data);
489 break;
491 case self::FINISH_ACTION_NONE:
492 break;
497 * Calculate the bar width when other elements changed
499 * @return void
501 protected function _calculateBarWidth()
503 if (in_array(self::ELEMENT_BAR, $this->_elements)) {
504 $barWidth = $this->_width;
506 if (in_array(self::ELEMENT_PERCENT, $this->_elements)) {
507 $barWidth -= 4;
510 if (in_array(self::ELEMENT_ETA, $this->_elements)) {
511 $barWidth -= 12;
514 if (in_array(self::ELEMENT_TEXT, $this->_elements)) {
515 $barWidth -= $this->_textWidth;
518 $this->_barWidth = $barWidth - (count($this->_elements) - 1);
523 * Outputs given data to STDOUT.
525 * This split-off is required for unit-testing.
527 * @param string $data
528 * @return void
530 protected function _outputData($data)
532 fwrite($this->getOutputStream(), $data);