1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11: * @link http://cakephp.org CakePHP(tm) Project
12: * @since 2.8
13: * @license http://www.opensource.org/licenses/mit-license.php MIT License
14: */
15: App::uses("BaseShellHelper", "Console/Helper");
16:
17: /**
18: * Create a progress bar using a supplied callback.
19: */
20: class ProgressShellHelper extends BaseShellHelper {
21:
22: /**
23: * The current progress.
24: *
25: * @var int
26: */
27: protected $_progress = 0;
28:
29: /**
30: * The total number of 'items' to progress through.
31: *
32: * @var int
33: */
34: protected $_total = 0;
35:
36: /**
37: * The width of the bar.
38: *
39: * @var int
40: */
41: protected $_width = 0;
42:
43: /**
44: * Output a progress bar.
45: *
46: * Takes a number of options to customize the behavior:
47: *
48: * - `total` The total number of items in the progress bar. Defaults
49: * to 100.
50: * - `width` The width of the progress bar. Defaults to 80.
51: * - `callback` The callback that will be called in a loop to advance the progress bar.
52: *
53: * @param array $args The arguments/options to use when outputing the progress bar.
54: * @return void
55: * @throws RuntimeException
56: */
57: public function output($args) {
58: $args += array('callback' => null);
59: if (isset($args[0])) {
60: $args['callback'] = $args[0];
61: }
62: if (!$args['callback'] || !is_callable($args['callback'])) {
63: throw new RuntimeException('Callback option must be a callable.');
64: }
65: $this->init($args);
66: $callback = $args['callback'];
67: while ($this->_progress < $this->_total) {
68: $callback($this);
69: $this->draw();
70: }
71: $this->_consoleOutput->write('');
72: }
73:
74: /**
75: * Initialize the progress bar for use.
76: *
77: * - `total` The total number of items in the progress bar. Defaults
78: * to 100.
79: * - `width` The width of the progress bar. Defaults to 80.
80: *
81: * @param array $args The initialization data.
82: * @return void
83: */
84: public function init(array $args = array()) {
85: $args += array('total' => 100, 'width' => 80);
86: $this->_progress = 0;
87: $this->_width = $args['width'];
88: $this->_total = $args['total'];
89: }
90:
91: /**
92: * Increment the progress bar.
93: *
94: * @param int $num The amount of progress to advance by.
95: * @return void
96: */
97: public function increment($num = 1) {
98: $this->_progress = min(max(0, $this->_progress + $num), $this->_total);
99: }
100:
101: /**
102: * Render the progress bar based on the current state.
103: *
104: * @return void
105: */
106: public function draw() {
107: $numberLen = strlen(' 100%');
108: $complete = round($this->_progress / $this->_total, 2);
109: $barLen = ($this->_width - $numberLen) * ($this->_progress / $this->_total);
110: $bar = '';
111: if ($barLen > 1) {
112: $bar = str_repeat('=', $barLen - 1) . '>';
113: }
114: $pad = ceil($this->_width - $numberLen - $barLen);
115: if ($pad > 0) {
116: $bar .= str_repeat(' ', $pad);
117: }
118: $percent = ($complete * 100) . '%';
119: $bar .= str_pad($percent, $numberLen, ' ', STR_PAD_LEFT);
120: $this->_consoleOutput->overwrite($bar, 0);
121: }
122: }