TYPO3  7.6
SymfonyStyle.php
Go to the documentation of this file.
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\Style;
13 
26 
33 {
34  const MAX_LINE_LENGTH = 120;
35 
36  private $input;
37  private $questionHelper;
38  private $progressBar;
39  private $lineLength;
40  private $bufferedOutput;
41 
47  {
48  $this->input = $input;
49  $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
50  // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
51  $this->lineLength = min($this->getTerminalWidth() - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
52 
53  parent::__construct($output);
54  }
55 
65  public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false)
66  {
67  $this->autoPrependBlock();
68  $messages = is_array($messages) ? array_values($messages) : array($messages);
69  $lines = array();
70 
71  // add type
72  if (null !== $type) {
73  $messages[0] = sprintf('[%s] %s', $type, $messages[0]);
74  }
75 
76  // wrap and add newlines for each element
77  foreach ($messages as $key => $message) {
78  $message = OutputFormatter::escape($message);
79  $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix), PHP_EOL, true)));
80 
81  if (count($messages) > 1 && $key < count($messages) - 1) {
82  $lines[] = '';
83  }
84  }
85 
86  if ($padding && $this->isDecorated()) {
87  array_unshift($lines, '');
88  $lines[] = '';
89  }
90 
91  foreach ($lines as &$line) {
92  $line = sprintf('%s%s', $prefix, $line);
93  $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));
94 
95  if ($style) {
96  $line = sprintf('<%s>%s</>', $style, $line);
97  }
98  }
99 
100  $this->writeln($lines);
101  $this->newLine();
102  }
103 
107  public function title($message)
108  {
109  $this->autoPrependBlock();
110  $this->writeln(array(
111  sprintf('<comment>%s</>', $message),
112  sprintf('<comment>%s</>', str_repeat('=', strlen($message))),
113  ));
114  $this->newLine();
115  }
116 
120  public function section($message)
121  {
122  $this->autoPrependBlock();
123  $this->writeln(array(
124  sprintf('<comment>%s</>', $message),
125  sprintf('<comment>%s</>', str_repeat('-', strlen($message))),
126  ));
127  $this->newLine();
128  }
129 
133  public function listing(array $elements)
134  {
135  $this->autoPrependText();
136  $elements = array_map(function ($element) {
137  return sprintf(' * %s', $element);
138  }, $elements);
139 
140  $this->writeln($elements);
141  $this->newLine();
142  }
143 
147  public function text($message)
148  {
149  $this->autoPrependText();
150 
151  if (!is_array($message)) {
152  $this->writeln(sprintf(' // %s', $message));
153 
154  return;
155  }
156 
157  foreach ($message as $element) {
158  $this->text($element);
159  }
160  }
161 
165  public function success($message)
166  {
167  $this->block($message, 'OK', 'fg=white;bg=green', ' ', true);
168  }
169 
173  public function error($message)
174  {
175  $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
176  }
177 
181  public function warning($message)
182  {
183  $this->block($message, 'WARNING', 'fg=white;bg=red', ' ', true);
184  }
185 
189  public function note($message)
190  {
191  $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
192  }
193 
197  public function caution($message)
198  {
199  $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
200  }
201 
205  public function table(array $headers, array $rows)
206  {
207  $headers = array_map(function ($value) { return sprintf('<info>%s</>', $value); }, $headers);
208 
209  $table = new Table($this);
210  $table->setHeaders($headers);
211  $table->setRows($rows);
212  $table->setStyle('symfony-style-guide');
213 
214  $table->render();
215  $this->newLine();
216  }
217 
221  public function ask($question, $default = null, $validator = null)
222  {
223  $question = new Question($question, $default);
224  $question->setValidator($validator);
225 
226  return $this->askQuestion($question);
227  }
228 
232  public function askHidden($question, $validator = null)
233  {
234  $question = new Question($question);
235 
236  $question->setHidden(true);
237  $question->setValidator($validator);
238 
239  return $this->askQuestion($question);
240  }
241 
245  public function confirm($question, $default = true)
246  {
247  return $this->askQuestion(new ConfirmationQuestion($question, $default));
248  }
249 
253  public function choice($question, array $choices, $default = null)
254  {
255  if (null !== $default) {
256  $values = array_flip($choices);
257  $default = $values[$default];
258  }
259 
260  return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
261  }
262 
266  public function progressStart($max = 0)
267  {
268  $this->progressBar = $this->createProgressBar($max);
269  $this->progressBar->start();
270  }
271 
275  public function progressAdvance($step = 1)
276  {
277  $this->getProgressBar()->advance($step);
278  }
279 
283  public function progressFinish()
284  {
285  $this->getProgressBar()->finish();
286  $this->newLine(2);
287  $this->progressBar = null;
288  }
289 
293  public function createProgressBar($max = 0)
294  {
295  $progressBar = parent::createProgressBar($max);
296 
297  if ('\\' === DIRECTORY_SEPARATOR) {
298  $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591
299  $progressBar->setProgressCharacter('');
300  $progressBar->setBarCharacter('▓'); // dark shade character \u2593
301  }
302 
303  return $progressBar;
304  }
305 
311  public function askQuestion(Question $question)
312  {
313  if ($this->input->isInteractive()) {
314  $this->autoPrependBlock();
315  }
316 
317  if (!$this->questionHelper) {
318  $this->questionHelper = new SymfonyQuestionHelper();
319  }
320 
321  $answer = $this->questionHelper->ask($this->input, $this, $question);
322 
323  if ($this->input->isInteractive()) {
324  $this->newLine();
325  $this->bufferedOutput->write("\n");
326  }
327 
328  return $answer;
329  }
330 
334  public function writeln($messages, $type = self::OUTPUT_NORMAL)
335  {
336  parent::writeln($messages, $type);
337  $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type);
338  }
339 
343  public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
344  {
345  parent::write($messages, $newline, $type);
346  $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type);
347  }
348 
352  public function newLine($count = 1)
353  {
354  parent::newLine($count);
355  $this->bufferedOutput->write(str_repeat("\n", $count));
356  }
357 
361  private function getProgressBar()
362  {
363  if (!$this->progressBar) {
364  throw new \RuntimeException('The ProgressBar is not started.');
365  }
366 
367  return $this->progressBar;
368  }
369 
370  private function getTerminalWidth()
371  {
372  $application = new Application();
373  $dimensions = $application->getTerminalDimensions();
374 
375  return $dimensions[0] ?: self::MAX_LINE_LENGTH;
376  }
377 
378  private function autoPrependBlock()
379  {
380  $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
381 
382  if (!isset($chars[0])) {
383  return $this->newLine(); //empty history, so we should start with a new line.
384  }
385  //Prepend new line for each non LF chars (This means no blank line was output before)
386  $this->newLine(2 - substr_count($chars, "\n"));
387  }
388 
389  private function autoPrependText()
390  {
391  $fetched = $this->bufferedOutput->fetch();
392  //Prepend new line if last char isn't EOL:
393  if ("\n" !== substr($fetched, -1)) {
394  $this->newLine();
395  }
396  }
397 
398  private function reduceBuffer($messages)
399  {
400  // We need to know if the two last chars are PHP_EOL
401  // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer
402  return array_map(function ($value) {
403  return substr($value, -4);
404  }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages));
405  }
406 }