Yaffs site version 1.1
[yaffs-website] / vendor / symfony / console / Helper / ProgressIndicator.php
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\InvalidArgumentException;
15 use Symfony\Component\Console\Exception\LogicException;
16 use Symfony\Component\Console\Output\OutputInterface;
17
18 /**
19  * @author Kevin Bond <kevinbond@gmail.com>
20  */
21 class ProgressIndicator
22 {
23     private $output;
24     private $startTime;
25     private $format;
26     private $message;
27     private $indicatorValues;
28     private $indicatorCurrent;
29     private $indicatorChangeInterval;
30     private $indicatorUpdateTime;
31     private $started = false;
32
33     private static $formatters;
34     private static $formats;
35
36     /**
37      * @param OutputInterface $output
38      * @param string|null     $format                  Indicator format
39      * @param int             $indicatorChangeInterval Change interval in milliseconds
40      * @param array|null      $indicatorValues         Animated indicator characters
41      */
42     public function __construct(OutputInterface $output, $format = null, $indicatorChangeInterval = 100, $indicatorValues = null)
43     {
44         $this->output = $output;
45
46         if (null === $format) {
47             $format = $this->determineBestFormat();
48         }
49
50         if (null === $indicatorValues) {
51             $indicatorValues = array('-', '\\', '|', '/');
52         }
53
54         $indicatorValues = array_values($indicatorValues);
55
56         if (2 > count($indicatorValues)) {
57             throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
58         }
59
60         $this->format = self::getFormatDefinition($format);
61         $this->indicatorChangeInterval = $indicatorChangeInterval;
62         $this->indicatorValues = $indicatorValues;
63         $this->startTime = time();
64     }
65
66     /**
67      * Sets the current indicator message.
68      *
69      * @param string|null $message
70      */
71     public function setMessage($message)
72     {
73         $this->message = $message;
74
75         $this->display();
76     }
77
78     /**
79      * Gets the current indicator message.
80      *
81      * @return string|null
82      *
83      * @internal for PHP 5.3 compatibility
84      */
85     public function getMessage()
86     {
87         return $this->message;
88     }
89
90     /**
91      * Gets the progress bar start time.
92      *
93      * @return int The progress bar start time
94      *
95      * @internal for PHP 5.3 compatibility
96      */
97     public function getStartTime()
98     {
99         return $this->startTime;
100     }
101
102     /**
103      * Gets the current animated indicator character.
104      *
105      * @return string
106      *
107      * @internal for PHP 5.3 compatibility
108      */
109     public function getCurrentValue()
110     {
111         return $this->indicatorValues[$this->indicatorCurrent % count($this->indicatorValues)];
112     }
113
114     /**
115      * Starts the indicator output.
116      *
117      * @param $message
118      */
119     public function start($message)
120     {
121         if ($this->started) {
122             throw new LogicException('Progress indicator already started.');
123         }
124
125         $this->message = $message;
126         $this->started = true;
127         $this->startTime = time();
128         $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
129         $this->indicatorCurrent = 0;
130
131         $this->display();
132     }
133
134     /**
135      * Advances the indicator.
136      */
137     public function advance()
138     {
139         if (!$this->started) {
140             throw new LogicException('Progress indicator has not yet been started.');
141         }
142
143         if (!$this->output->isDecorated()) {
144             return;
145         }
146
147         $currentTime = $this->getCurrentTimeInMilliseconds();
148
149         if ($currentTime < $this->indicatorUpdateTime) {
150             return;
151         }
152
153         $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
154         ++$this->indicatorCurrent;
155
156         $this->display();
157     }
158
159     /**
160      * Finish the indicator with message.
161      *
162      * @param $message
163      */
164     public function finish($message)
165     {
166         if (!$this->started) {
167             throw new LogicException('Progress indicator has not yet been started.');
168         }
169
170         $this->message = $message;
171         $this->display();
172         $this->output->writeln('');
173         $this->started = false;
174     }
175
176     /**
177      * Gets the format for a given name.
178      *
179      * @param string $name The format name
180      *
181      * @return string|null A format string
182      */
183     public static function getFormatDefinition($name)
184     {
185         if (!self::$formats) {
186             self::$formats = self::initFormats();
187         }
188
189         return isset(self::$formats[$name]) ? self::$formats[$name] : null;
190     }
191
192     /**
193      * Sets a placeholder formatter for a given name.
194      *
195      * This method also allow you to override an existing placeholder.
196      *
197      * @param string   $name     The placeholder name (including the delimiter char like %)
198      * @param callable $callable A PHP callable
199      */
200     public static function setPlaceholderFormatterDefinition($name, $callable)
201     {
202         if (!self::$formatters) {
203             self::$formatters = self::initPlaceholderFormatters();
204         }
205
206         self::$formatters[$name] = $callable;
207     }
208
209     /**
210      * Gets the placeholder formatter for a given name.
211      *
212      * @param string $name The placeholder name (including the delimiter char like %)
213      *
214      * @return callable|null A PHP callable
215      */
216     public static function getPlaceholderFormatterDefinition($name)
217     {
218         if (!self::$formatters) {
219             self::$formatters = self::initPlaceholderFormatters();
220         }
221
222         return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
223     }
224
225     private function display()
226     {
227         if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
228             return;
229         }
230
231         $self = $this;
232
233         $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
234             if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
235                 return call_user_func($formatter, $self);
236             }
237
238             return $matches[0];
239         }, $this->format));
240     }
241
242     private function determineBestFormat()
243     {
244         switch ($this->output->getVerbosity()) {
245             // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
246             case OutputInterface::VERBOSITY_VERBOSE:
247                 return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
248             case OutputInterface::VERBOSITY_VERY_VERBOSE:
249             case OutputInterface::VERBOSITY_DEBUG:
250                 return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
251             default:
252                 return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
253         }
254     }
255
256     /**
257      * Overwrites a previous message to the output.
258      *
259      * @param string $message The message
260      */
261     private function overwrite($message)
262     {
263         if ($this->output->isDecorated()) {
264             $this->output->write("\x0D\x1B[2K");
265             $this->output->write($message);
266         } else {
267             $this->output->writeln($message);
268         }
269     }
270
271     private function getCurrentTimeInMilliseconds()
272     {
273         return round(microtime(true) * 1000);
274     }
275
276     private static function initPlaceholderFormatters()
277     {
278         return array(
279             'indicator' => function (ProgressIndicator $indicator) {
280                 return $indicator->getCurrentValue();
281             },
282             'message' => function (ProgressIndicator $indicator) {
283                 return $indicator->getMessage();
284             },
285             'elapsed' => function (ProgressIndicator $indicator) {
286                 return Helper::formatTime(time() - $indicator->getStartTime());
287             },
288             'memory' => function () {
289                 return Helper::formatMemory(memory_get_usage(true));
290             },
291         );
292     }
293
294     private static function initFormats()
295     {
296         return array(
297             'normal' => ' %indicator% %message%',
298             'normal_no_ansi' => ' %message%',
299
300             'verbose' => ' %indicator% %message% (%elapsed:6s%)',
301             'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
302
303             'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
304             'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
305         );
306     }
307 }