PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://gitlab.com/Marwamimo/Crowdrise_Web
PHP | 409 lines | 220 code | 65 blank | 124 comment | 26 complexity | fe70ff6bd9e0cd11f041a743ab6b2cb9 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. $keys = array_keys($this->rows);
  146. $rowKey = array_pop($keys);
  147. foreach ($row as $key => $cellValue) {
  148. if (!strstr($cellValue, "\n")) {
  149. continue;
  150. }
  151. $lines = explode("\n", $cellValue);
  152. $this->rows[$rowKey][$key] = $lines[0];
  153. unset($lines[0]);
  154. foreach ($lines as $lineKey => $line) {
  155. $nextRowKey = $rowKey + $lineKey + 1;
  156. if (isset($this->rows[$nextRowKey])) {
  157. $this->rows[$nextRowKey][$key] = $line;
  158. } else {
  159. $this->rows[$nextRowKey] = array($key => $line);
  160. }
  161. }
  162. }
  163. return $this;
  164. }
  165. public function setRow($column, array $row)
  166. {
  167. $this->rows[$column] = $row;
  168. return $this;
  169. }
  170. /**
  171. * Renders table to output.
  172. *
  173. * Example:
  174. * +---------------+-----------------------+------------------+
  175. * | ISBN | Title | Author |
  176. * +---------------+-----------------------+------------------+
  177. * | 99921-58-10-7 | Divine Comedy | Dante Alighieri |
  178. * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
  179. * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
  180. * +---------------+-----------------------+------------------+
  181. */
  182. public function render()
  183. {
  184. $this->renderRowSeparator();
  185. $this->renderRow($this->headers, $this->style->getCellHeaderFormat());
  186. if (!empty($this->headers)) {
  187. $this->renderRowSeparator();
  188. }
  189. foreach ($this->rows as $row) {
  190. if ($row instanceof TableSeparator) {
  191. $this->renderRowSeparator();
  192. } else {
  193. $this->renderRow($row, $this->style->getCellRowFormat());
  194. }
  195. }
  196. if (!empty($this->rows)) {
  197. $this->renderRowSeparator();
  198. }
  199. $this->cleanup();
  200. }
  201. /**
  202. * Renders horizontal header separator.
  203. *
  204. * Example: +-----+-----------+-------+
  205. */
  206. private function renderRowSeparator()
  207. {
  208. if (0 === $count = $this->getNumberOfColumns()) {
  209. return;
  210. }
  211. if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) {
  212. return;
  213. }
  214. $markup = $this->style->getCrossingChar();
  215. for ($column = 0; $column < $count; $column++) {
  216. $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->getColumnWidth($column)).$this->style->getCrossingChar();
  217. }
  218. $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
  219. }
  220. /**
  221. * Renders vertical column separator.
  222. */
  223. private function renderColumnSeparator()
  224. {
  225. $this->output->write(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
  226. }
  227. /**
  228. * Renders table row.
  229. *
  230. * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
  231. *
  232. * @param array $row
  233. * @param string $cellFormat
  234. */
  235. private function renderRow(array $row, $cellFormat)
  236. {
  237. if (empty($row)) {
  238. return;
  239. }
  240. $this->renderColumnSeparator();
  241. for ($column = 0, $count = $this->getNumberOfColumns(); $column < $count; $column++) {
  242. $this->renderCell($row, $column, $cellFormat);
  243. $this->renderColumnSeparator();
  244. }
  245. $this->output->writeln('');
  246. }
  247. /**
  248. * Renders table cell with padding.
  249. *
  250. * @param array $row
  251. * @param int $column
  252. * @param string $cellFormat
  253. */
  254. private function renderCell(array $row, $column, $cellFormat)
  255. {
  256. $cell = isset($row[$column]) ? $row[$column] : '';
  257. $width = $this->getColumnWidth($column);
  258. // str_pad won't work properly with multi-byte strings, we need to fix the padding
  259. if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($cell)) {
  260. $width += strlen($cell) - mb_strlen($cell, $encoding);
  261. }
  262. $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
  263. $content = sprintf($this->style->getCellRowContentFormat(), $cell);
  264. $this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType())));
  265. }
  266. /**
  267. * Gets number of columns for this table.
  268. *
  269. * @return int
  270. */
  271. private function getNumberOfColumns()
  272. {
  273. if (null !== $this->numberOfColumns) {
  274. return $this->numberOfColumns;
  275. }
  276. $columns = array(count($this->headers));
  277. foreach ($this->rows as $row) {
  278. $columns[] = count($row);
  279. }
  280. return $this->numberOfColumns = max($columns);
  281. }
  282. /**
  283. * Gets column width.
  284. *
  285. * @param int $column
  286. *
  287. * @return int
  288. */
  289. private function getColumnWidth($column)
  290. {
  291. if (isset($this->columnWidths[$column])) {
  292. return $this->columnWidths[$column];
  293. }
  294. $lengths = array($this->getCellWidth($this->headers, $column));
  295. foreach ($this->rows as $row) {
  296. if ($row instanceof TableSeparator) {
  297. continue;
  298. }
  299. $lengths[] = $this->getCellWidth($row, $column);
  300. }
  301. return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
  302. }
  303. /**
  304. * Gets cell width.
  305. *
  306. * @param array $row
  307. * @param int $column
  308. *
  309. * @return int
  310. */
  311. private function getCellWidth(array $row, $column)
  312. {
  313. return isset($row[$column]) ? Helper::strlenWithoutDecoration($this->output->getFormatter(), $row[$column]) : 0;
  314. }
  315. /**
  316. * Called after rendering to cleanup cache data.
  317. */
  318. private function cleanup()
  319. {
  320. $this->columnWidths = array();
  321. $this->numberOfColumns = null;
  322. }
  323. private static function initStyles()
  324. {
  325. $borderless = new TableStyle();
  326. $borderless
  327. ->setHorizontalBorderChar('=')
  328. ->setVerticalBorderChar(' ')
  329. ->setCrossingChar(' ')
  330. ;
  331. $compact = new TableStyle();
  332. $compact
  333. ->setHorizontalBorderChar('')
  334. ->setVerticalBorderChar(' ')
  335. ->setCrossingChar('')
  336. ->setCellRowContentFormat('%s')
  337. ;
  338. return array(
  339. 'default' => new TableStyle(),
  340. 'borderless' => $borderless,
  341. 'compact' => $compact,
  342. );
  343. }
  344. }