PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/monica/monica/vendor/zendframework/zendframework/library/Zend/Text/Table/Table.php

https://bitbucket.org/alexandretaz/maniac_divers
PHP | 510 lines | 260 code | 73 blank | 177 comment | 39 complexity | 8542967f3b1f8d9850479a790f9a9dca MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Text\Table;
  10. use Traversable;
  11. use Zend\Stdlib\ArrayUtils;
  12. use Zend\Text\Table\Decorator\DecoratorInterface as Decorator;
  13. /**
  14. * Zend\Text\Table\Table enables developers to create tables out of characters
  15. */
  16. class Table
  17. {
  18. /**
  19. * Auto separator settings
  20. */
  21. const AUTO_SEPARATE_NONE = 0x0;
  22. const AUTO_SEPARATE_HEADER = 0x1;
  23. const AUTO_SEPARATE_FOOTER = 0x2;
  24. const AUTO_SEPARATE_ALL = 0x4;
  25. /**
  26. * Decorator used for the table borders
  27. *
  28. * @var Decorator
  29. */
  30. protected $decorator = null;
  31. /**
  32. * List of all column widths
  33. *
  34. * @var array
  35. */
  36. protected $columnWidths = null;
  37. /**
  38. * Rows of the table
  39. *
  40. * @var array
  41. */
  42. protected $rows = array();
  43. /**
  44. * Auto separation mode
  45. *
  46. * @var integer
  47. */
  48. protected $autoSeparate = self::AUTO_SEPARATE_ALL;
  49. /**
  50. * Padding for columns
  51. *
  52. * @var integer
  53. */
  54. protected $padding = 0;
  55. /**
  56. * Default column aligns for rows created by appendRow(array $data)
  57. *
  58. * @var array
  59. */
  60. protected $defaultColumnAligns = array();
  61. /**
  62. * Plugin loader for decorators
  63. *
  64. * @var DecoratorManager
  65. */
  66. protected $decoratorManager = null;
  67. /**
  68. * Charset which is used for input by default
  69. *
  70. * @var string
  71. */
  72. protected static $inputCharset = 'utf-8';
  73. /**
  74. * Charset which is used internally
  75. *
  76. * @var string
  77. */
  78. protected static $outputCharset = 'utf-8';
  79. /**
  80. * Option keys to skip when calling setOptions()
  81. *
  82. * @var array
  83. */
  84. protected $skipOptions = array(
  85. 'options',
  86. 'config',
  87. 'defaultColumnAlign',
  88. );
  89. /**
  90. * Create a basic table object
  91. *
  92. * @param array|Traversable $options Configuration options
  93. * @throws Exception\UnexpectedValueException When no columns widths were set
  94. */
  95. public function __construct($options = null)
  96. {
  97. // Set options
  98. if ($options instanceof Traversable) {
  99. $options = ArrayUtils::iteratorToArray($options);
  100. }
  101. if (is_array($options)) {
  102. $this->setOptions($options);
  103. }
  104. // If no decorator was given, use default unicode decorator
  105. if ($this->decorator === null) {
  106. if (static::getOutputCharset() === 'utf-8') {
  107. $this->setDecorator('unicode');
  108. } else {
  109. $this->setDecorator('ascii');
  110. }
  111. }
  112. }
  113. /**
  114. * Set options from array
  115. *
  116. * @param array $options Configuration for Table
  117. * @return Table
  118. */
  119. public function setOptions(array $options)
  120. {
  121. foreach ($options as $key => $value) {
  122. if (in_array(strtolower($key), $this->skipOptions)) {
  123. continue;
  124. }
  125. $method = 'set' . ucfirst($key);
  126. if (method_exists($this, $method)) {
  127. $this->$method($value);
  128. }
  129. }
  130. return $this;
  131. }
  132. /**
  133. * Set column widths
  134. *
  135. * @param array $columnWidths Widths of all columns
  136. * @throws Exception\InvalidArgumentException When no columns were supplied
  137. * @throws Exception\InvalidArgumentException When a column has an invalid width
  138. * @return Table
  139. */
  140. public function setColumnWidths(array $columnWidths)
  141. {
  142. if (count($columnWidths) === 0) {
  143. throw new Exception\InvalidArgumentException('You must supply at least one column');
  144. }
  145. foreach ($columnWidths as $columnNum => $columnWidth) {
  146. if (is_int($columnWidth) === false or $columnWidth < 1) {
  147. throw new Exception\InvalidArgumentException('Column ' . $columnNum . ' has an invalid'
  148. . ' column width');
  149. }
  150. }
  151. $this->columnWidths = $columnWidths;
  152. return $this;
  153. }
  154. /**
  155. * Set auto separation mode
  156. *
  157. * @param integer $autoSeparate Auto separation mode
  158. * @return Table
  159. */
  160. public function setAutoSeparate($autoSeparate)
  161. {
  162. $this->autoSeparate = (int) $autoSeparate;
  163. return $this;
  164. }
  165. /**
  166. * Set decorator
  167. *
  168. * @param Decorator|string $decorator Decorator to use
  169. * @return Table
  170. */
  171. public function setDecorator($decorator)
  172. {
  173. if (!$decorator instanceof Decorator) {
  174. $decorator = $this->getDecoratorManager()->get($decorator);
  175. }
  176. $this->decorator = $decorator;
  177. return $this;
  178. }
  179. /**
  180. * Set the column padding
  181. *
  182. * @param integer $padding The padding for the columns
  183. * @return Table
  184. */
  185. public function setPadding($padding)
  186. {
  187. $this->padding = max(0, (int) $padding);
  188. return $this;
  189. }
  190. /**
  191. * Get the plugin manager for decorators
  192. *
  193. * @return DecoratorManager
  194. */
  195. public function getDecoratorManager()
  196. {
  197. if ($this->decoratorManager instanceof DecoratorManager) {
  198. return $this->decoratorManager;
  199. }
  200. $this->setDecoratorManager(new DecoratorManager());
  201. return $this->decoratorManager;
  202. }
  203. /**
  204. * Set the plugin manager instance for decorators
  205. *
  206. * @param DecoratorManager $decoratorManager
  207. * @return Table
  208. */
  209. public function setDecoratorManager(DecoratorManager $decoratorManager)
  210. {
  211. $this->decoratorManager = $decoratorManager;
  212. return $this;
  213. }
  214. /**
  215. * Set default column align for rows created by appendRow(array $data)
  216. *
  217. * @param integer $columnNum
  218. * @param string $align
  219. * @return Table
  220. */
  221. public function setDefaultColumnAlign($columnNum, $align)
  222. {
  223. $this->defaultColumnAligns[$columnNum] = $align;
  224. return $this;
  225. }
  226. /**
  227. * Set the input charset for column contents
  228. *
  229. * @param string $charset
  230. */
  231. public static function setInputCharset($charset)
  232. {
  233. static::$inputCharset = strtolower($charset);
  234. }
  235. /**
  236. * Get the input charset for column contents
  237. *
  238. * @return string
  239. */
  240. public static function getInputCharset()
  241. {
  242. return static::$inputCharset;
  243. }
  244. /**
  245. * Set the output charset for column contents
  246. *
  247. * @param string $charset
  248. */
  249. public static function setOutputCharset($charset)
  250. {
  251. static::$outputCharset = strtolower($charset);
  252. }
  253. /**
  254. * Get the output charset for column contents
  255. *
  256. * @return string
  257. */
  258. public static function getOutputCharset()
  259. {
  260. return static::$outputCharset;
  261. }
  262. /**
  263. * Append a row to the table
  264. *
  265. * @param array|Row $row The row to append to the table
  266. * @throws Exception\InvalidArgumentException When $row is neither an array nor Zend_Zext_Table_Row
  267. * @throws Exception\OverflowException When a row contains too many columns
  268. * @return Table
  269. */
  270. public function appendRow($row)
  271. {
  272. if (!is_array($row) && !($row instanceof Row)) {
  273. throw new Exception\InvalidArgumentException('$row must be an array or instance of Zend\Text\Table\Row');
  274. }
  275. if (is_array($row)) {
  276. if (count($row) > count($this->columnWidths)) {
  277. throw new Exception\OverflowException('Row contains too many columns');
  278. }
  279. $data = $row;
  280. $row = new Row();
  281. $colNum = 0;
  282. foreach ($data as $columnData) {
  283. if (isset($this->defaultColumnAligns[$colNum])) {
  284. $align = $this->defaultColumnAligns[$colNum];
  285. } else {
  286. $align = null;
  287. }
  288. $row->appendColumn(new Column($columnData, $align));
  289. $colNum++;
  290. }
  291. }
  292. $this->rows[] = $row;
  293. return $this;
  294. }
  295. /**
  296. * Render the table
  297. *
  298. * @throws Exception\UnexpectedValueException When no rows were added to the table
  299. * @return string
  300. */
  301. public function render()
  302. {
  303. // There should be at least one row
  304. if (count($this->rows) === 0) {
  305. throw new Exception\UnexpectedValueException('No rows were added to the table yet');
  306. }
  307. // Initiate the result variable
  308. $result = '';
  309. // Count total columns
  310. $totalNumColumns = count($this->columnWidths);
  311. // Check if we have a horizontal character defined
  312. $hasHorizontal = $this->decorator->getHorizontal() !== '';
  313. // Now render all rows, starting from the first one
  314. $numRows = count($this->rows);
  315. foreach ($this->rows as $rowNum => $row) {
  316. // Get all column widths
  317. if (isset($columnWidths) === true) {
  318. $lastColumnWidths = $columnWidths;
  319. }
  320. $renderedRow = $row->render($this->columnWidths, $this->decorator, $this->padding);
  321. $columnWidths = $row->getColumnWidths();
  322. $numColumns = count($columnWidths);
  323. // Check what we have to draw
  324. if ($rowNum === 0 && $hasHorizontal) {
  325. // If this is the first row, draw the table top
  326. $result .= $this->decorator->getTopLeft();
  327. foreach ($columnWidths as $columnNum => $columnWidth) {
  328. $result .= str_repeat($this->decorator->getHorizontal(),
  329. $columnWidth);
  330. if (($columnNum + 1) === $numColumns) {
  331. $result .= $this->decorator->getTopRight();
  332. } else {
  333. $result .= $this->decorator->getHorizontalDown();
  334. }
  335. }
  336. $result .= "\n";
  337. } else {
  338. // Else check if we have to draw the row separator
  339. if (!$hasHorizontal) {
  340. $drawSeparator = false; // there is no horizontal character;
  341. } elseif ($this->autoSeparate & self::AUTO_SEPARATE_ALL) {
  342. $drawSeparator = true;
  343. } elseif ($rowNum === 1 && $this->autoSeparate & self::AUTO_SEPARATE_HEADER) {
  344. $drawSeparator = true;
  345. } elseif ($rowNum === ($numRows - 1) && $this->autoSeparate & self::AUTO_SEPARATE_FOOTER) {
  346. $drawSeparator = true;
  347. } else {
  348. $drawSeparator = false;
  349. }
  350. if ($drawSeparator) {
  351. $result .= $this->decorator->getVerticalRight();
  352. $currentUpperColumn = 0;
  353. $currentLowerColumn = 0;
  354. $currentUpperWidth = 0;
  355. $currentLowerWidth = 0;
  356. // Add horizontal lines
  357. // Loop through all column widths
  358. foreach ($this->columnWidths as $columnNum => $columnWidth) {
  359. // Add the horizontal line
  360. $result .= str_repeat($this->decorator->getHorizontal(),
  361. $columnWidth);
  362. // If this is the last line, break out
  363. if (($columnNum + 1) === $totalNumColumns) {
  364. break;
  365. }
  366. // Else check, which connector style has to be used
  367. $connector = 0x0;
  368. $currentUpperWidth += $columnWidth;
  369. $currentLowerWidth += $columnWidth;
  370. if ($lastColumnWidths[$currentUpperColumn] === $currentUpperWidth) {
  371. $connector |= 0x1;
  372. $currentUpperColumn += 1;
  373. $currentUpperWidth = 0;
  374. } else {
  375. $currentUpperWidth += 1;
  376. }
  377. if ($columnWidths[$currentLowerColumn] === $currentLowerWidth) {
  378. $connector |= 0x2;
  379. $currentLowerColumn += 1;
  380. $currentLowerWidth = 0;
  381. } else {
  382. $currentLowerWidth += 1;
  383. }
  384. switch ($connector) {
  385. case 0x0:
  386. $result .= $this->decorator->getHorizontal();
  387. break;
  388. case 0x1:
  389. $result .= $this->decorator->getHorizontalUp();
  390. break;
  391. case 0x2:
  392. $result .= $this->decorator->getHorizontalDown();
  393. break;
  394. case 0x3:
  395. $result .= $this->decorator->getCross();
  396. break;
  397. default:
  398. // This can never happen, but the CS tells I have to have it ...
  399. break;
  400. }
  401. }
  402. $result .= $this->decorator->getVerticalLeft() . "\n";
  403. }
  404. }
  405. // Add the rendered row to the result
  406. $result .= $renderedRow;
  407. // If this is the last row, draw the table bottom
  408. if (($rowNum + 1) === $numRows && $hasHorizontal) {
  409. $result .= $this->decorator->getBottomLeft();
  410. foreach ($columnWidths as $columnNum => $columnWidth) {
  411. $result .= str_repeat($this->decorator->getHorizontal(),
  412. $columnWidth);
  413. if (($columnNum + 1) === $numColumns) {
  414. $result .= $this->decorator->getBottomRight();
  415. } else {
  416. $result .= $this->decorator->getHorizontalUp();
  417. }
  418. }
  419. $result .= "\n";
  420. }
  421. }
  422. return $result;
  423. }
  424. /**
  425. * Magic method which returns the rendered table
  426. *
  427. * @return string
  428. */
  429. public function __toString()
  430. {
  431. try {
  432. return $this->render();
  433. } catch (\Exception $e) {
  434. trigger_error($e->getMessage(), E_USER_ERROR);
  435. }
  436. }
  437. }