PageRenderTime 28ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/symfony/console/Symfony/Component/Console/Helper/Table.php

https://gitlab.com/xolotsoft/pumasruiz
PHP | 410 lines | 221 code | 65 blank | 124 comment | 26 complexity | 6632a79c72735d43508dee333501e77d MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Console\Helper;
  11. use Symfony\Component\Console\Output\OutputInterface;
  12. /**
  13. * Provides helpers to display a table.
  14. *
  15. * @author Fabien Potencier <fabien@symfony.com>
  16. * @author Саша Стаменковић <umpirsky@gmail.com>
  17. */
  18. class Table
  19. {
  20. /**
  21. * Table headers.
  22. *
  23. * @var array
  24. */
  25. private $headers = array();
  26. /**
  27. * Table rows.
  28. *
  29. * @var array
  30. */
  31. private $rows = array();
  32. /**
  33. * Column widths cache.
  34. *
  35. * @var array
  36. */
  37. private $columnWidths = array();
  38. /**
  39. * Number of columns cache.
  40. *
  41. * @var array
  42. */
  43. private $numberOfColumns;
  44. /**
  45. * @var OutputInterface
  46. */
  47. private $output;
  48. /**
  49. * @var TableStyle
  50. */
  51. private $style;
  52. private static $styles;
  53. public function __construct(OutputInterface $output)
  54. {
  55. $this->output = $output;
  56. if (!self::$styles) {
  57. self::$styles = self::initStyles();
  58. }
  59. $this->setStyle('default');
  60. }
  61. /**
  62. * Sets a style definition.
  63. *
  64. * @param string $name The style name
  65. * @param TableStyle $style A TableStyle instance
  66. */
  67. public static function setStyleDefinition($name, TableStyle $style)
  68. {
  69. if (!self::$styles) {
  70. self::$styles = self::initStyles();
  71. }
  72. self::$styles[$name] = $style;
  73. }
  74. /**
  75. * Gets a style definition by name.
  76. *
  77. * @param string $name The style name
  78. *
  79. * @return TableStyle A TableStyle instance
  80. */
  81. public static function getStyleDefinition($name)
  82. {
  83. if (!self::$styles) {
  84. self::$styles = self::initStyles();
  85. }
  86. if (!self::$styles[$name]) {
  87. throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
  88. }
  89. return self::$styles[$name];
  90. }
  91. /**
  92. * Sets table style.
  93. *
  94. * @param TableStyle|string $name The style name or a TableStyle instance
  95. *
  96. * @return Table
  97. */
  98. public function setStyle($name)
  99. {
  100. if ($name instanceof TableStyle) {
  101. $this->style = $name;
  102. } elseif (isset(self::$styles[$name])) {
  103. $this->style = self::$styles[$name];
  104. } else {
  105. throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
  106. }
  107. return $this;
  108. }
  109. /**
  110. * Gets the current table style.
  111. *
  112. * @return TableStyle
  113. */
  114. public function getStyle()
  115. {
  116. return $this->style;
  117. }
  118. public function setHeaders(array $headers)
  119. {
  120. $this->headers = array_values($headers);
  121. return $this;
  122. }
  123. public function setRows(array $rows)
  124. {
  125. $this->rows = array();
  126. return $this->addRows($rows);
  127. }
  128. public function addRows(array $rows)
  129. {
  130. foreach ($rows as $row) {
  131. $this->addRow($row);
  132. }
  133. return $this;
  134. }
  135. public function addRow($row)
  136. {
  137. if ($row instanceof TableSeparator) {
  138. $this->rows[] = $row;
  139. return;
  140. }
  141. if (!is_array($row)) {
  142. throw new \InvalidArgumentException('A row must be an array or a TableSeparator instance.');
  143. }
  144. $this->rows[] = array_values($row);
  145. end($this->rows);
  146. $rowKey = key($this->rows);
  147. reset($this->rows);
  148. foreach ($row as $key => $cellValue) {
  149. if (!strstr($cellValue, "\n")) {
  150. continue;
  151. }
  152. $lines = explode("\n", $cellValue);
  153. $this->rows[$rowKey][$key] = $lines[0];
  154. unset($lines[0]);
  155. foreach ($lines as $lineKey => $line) {
  156. $nextRowKey = $rowKey + $lineKey + 1;
  157. if (isset($this->rows[$nextRowKey])) {
  158. $this->rows[$nextRowKey][$key] = $line;
  159. } else {
  160. $this->rows[$nextRowKey] = array($key => $line);
  161. }
  162. }
  163. }
  164. return $this;
  165. }
  166. public function setRow($column, array $row)
  167. {
  168. $this->rows[$column] = $row;
  169. return $this;
  170. }
  171. /**
  172. * Renders table to output.
  173. *
  174. * Example:
  175. * +---------------+-----------------------+------------------+
  176. * | ISBN | Title | Author |
  177. * +---------------+-----------------------+------------------+
  178. * | 99921-58-10-7 | Divine Comedy | Dante Alighieri |
  179. * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
  180. * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
  181. * +---------------+-----------------------+------------------+
  182. */
  183. public function render()
  184. {
  185. $this->renderRowSeparator();
  186. $this->renderRow($this->headers, $this->style->getCellHeaderFormat());
  187. if (!empty($this->headers)) {
  188. $this->renderRowSeparator();
  189. }
  190. foreach ($this->rows as $row) {
  191. if ($row instanceof TableSeparator) {
  192. $this->renderRowSeparator();
  193. } else {
  194. $this->renderRow($row, $this->style->getCellRowFormat());
  195. }
  196. }
  197. if (!empty($this->rows)) {
  198. $this->renderRowSeparator();
  199. }
  200. $this->cleanup();
  201. }
  202. /**
  203. * Renders horizontal header separator.
  204. *
  205. * Example: +-----+-----------+-------+
  206. */
  207. private function renderRowSeparator()
  208. {
  209. if (0 === $count = $this->getNumberOfColumns()) {
  210. return;
  211. }
  212. if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) {
  213. return;
  214. }
  215. $markup = $this->style->getCrossingChar();
  216. for ($column = 0; $column < $count; $column++) {
  217. $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->getColumnWidth($column)).$this->style->getCrossingChar();
  218. }
  219. $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
  220. }
  221. /**
  222. * Renders vertical column separator.
  223. */
  224. private function renderColumnSeparator()
  225. {
  226. $this->output->write(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
  227. }
  228. /**
  229. * Renders table row.
  230. *
  231. * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
  232. *
  233. * @param array $row
  234. * @param string $cellFormat
  235. */
  236. private function renderRow(array $row, $cellFormat)
  237. {
  238. if (empty($row)) {
  239. return;
  240. }
  241. $this->renderColumnSeparator();
  242. for ($column = 0, $count = $this->getNumberOfColumns(); $column < $count; $column++) {
  243. $this->renderCell($row, $column, $cellFormat);
  244. $this->renderColumnSeparator();
  245. }
  246. $this->output->writeln('');
  247. }
  248. /**
  249. * Renders table cell with padding.
  250. *
  251. * @param array $row
  252. * @param int $column
  253. * @param string $cellFormat
  254. */
  255. private function renderCell(array $row, $column, $cellFormat)
  256. {
  257. $cell = isset($row[$column]) ? $row[$column] : '';
  258. $width = $this->getColumnWidth($column);
  259. // str_pad won't work properly with multi-byte strings, we need to fix the padding
  260. if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($cell)) {
  261. $width += strlen($cell) - mb_strlen($cell, $encoding);
  262. }
  263. $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
  264. $content = sprintf($this->style->getCellRowContentFormat(), $cell);
  265. $this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType())));
  266. }
  267. /**
  268. * Gets number of columns for this table.
  269. *
  270. * @return int
  271. */
  272. private function getNumberOfColumns()
  273. {
  274. if (null !== $this->numberOfColumns) {
  275. return $this->numberOfColumns;
  276. }
  277. $columns = array(count($this->headers));
  278. foreach ($this->rows as $row) {
  279. $columns[] = count($row);
  280. }
  281. return $this->numberOfColumns = max($columns);
  282. }
  283. /**
  284. * Gets column width.
  285. *
  286. * @param int $column
  287. *
  288. * @return int
  289. */
  290. private function getColumnWidth($column)
  291. {
  292. if (isset($this->columnWidths[$column])) {
  293. return $this->columnWidths[$column];
  294. }
  295. $lengths = array($this->getCellWidth($this->headers, $column));
  296. foreach ($this->rows as $row) {
  297. if ($row instanceof TableSeparator) {
  298. continue;
  299. }
  300. $lengths[] = $this->getCellWidth($row, $column);
  301. }
  302. return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
  303. }
  304. /**
  305. * Gets cell width.
  306. *
  307. * @param array $row
  308. * @param int $column
  309. *
  310. * @return int
  311. */
  312. private function getCellWidth(array $row, $column)
  313. {
  314. return isset($row[$column]) ? Helper::strlenWithoutDecoration($this->output->getFormatter(), $row[$column]) : 0;
  315. }
  316. /**
  317. * Called after rendering to cleanup cache data.
  318. */
  319. private function cleanup()
  320. {
  321. $this->columnWidths = array();
  322. $this->numberOfColumns = null;
  323. }
  324. private static function initStyles()
  325. {
  326. $borderless = new TableStyle();
  327. $borderless
  328. ->setHorizontalBorderChar('=')
  329. ->setVerticalBorderChar(' ')
  330. ->setCrossingChar(' ')
  331. ;
  332. $compact = new TableStyle();
  333. $compact
  334. ->setHorizontalBorderChar('')
  335. ->setVerticalBorderChar(' ')
  336. ->setCrossingChar('')
  337. ->setCellRowContentFormat('%s')
  338. ;
  339. return array(
  340. 'default' => new TableStyle(),
  341. 'borderless' => $borderless,
  342. 'compact' => $compact,
  343. );
  344. }
  345. }