1<?php
2/**
3 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5 *
6 * Licensed under The MIT License
7 * For full copyright and license information, please see the LICENSE.txt
8 * Redistributions of files must retain the above copyright notice.
9 *
10 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11 * @link          https://cakephp.org CakePHP(tm) Project
12 * @since         2.8
13 * @license       https://opensource.org/licenses/mit-license.php MIT License
14 */
15App::uses("BaseShellHelper", "Console/Helper");
16
17/**
18 * Create a visually pleasing ASCII art table
19 * from 2 dimensional array data.
20 */
21class TableShellHelper extends BaseShellHelper {
22
23/**
24 * Default config for this helper.
25 *
26 * @var array
27 */
28	protected $_defaultConfig = array(
29		'headers' => true,
30		'rowSeparator' => false,
31		'headerStyle' => 'info',
32	);
33
34/**
35 * Calculate the column widths
36 *
37 * @param array $rows The rows on which the columns width will be calculated on.
38 * @return array
39 */
40	protected function _calculateWidths($rows) {
41		$widths = array();
42		foreach ($rows as $line) {
43			for ($i = 0, $len = count($line); $i < $len; $i++) {
44				$columnLength = mb_strlen($line[$i]);
45				if ($columnLength > (isset($widths[$i]) ? $widths[$i] : 0)) {
46					$widths[$i] = $columnLength;
47				}
48			}
49		}
50		return $widths;
51	}
52
53/**
54 * Output a row separator.
55 *
56 * @param array $widths The widths of each column to output.
57 * @return void
58 */
59	protected function _rowSeparator($widths) {
60		$out = '';
61		foreach ($widths as $column) {
62			$out .= '+' . str_repeat('-', $column + 2);
63		}
64		$out .= '+';
65		$this->_consoleOutput->write($out);
66	}
67
68/**
69 * Output a row.
70 *
71 * @param array $row The row to output.
72 * @param array $widths The widths of each column to output.
73 * @param array $options Options to be passed.
74 * @return void
75 */
76	protected function _render($row, $widths, $options = array()) {
77		$out = '';
78		foreach ($row as $i => $column) {
79			$pad = $widths[$i] - mb_strlen($column);
80			if (!empty($options['style'])) {
81				$column = $this->_addStyle($column, $options['style']);
82			}
83			$out .= '| ' . $column . str_repeat(' ', $pad) . ' ';
84		}
85		$out .= '|';
86		$this->_consoleOutput->write($out);
87	}
88
89/**
90 * Output a table.
91 *
92 * @param array $rows The data to render out.
93 * @return void
94 */
95	public function output($rows) {
96		$config = $this->config();
97		$widths = $this->_calculateWidths($rows);
98		$this->_rowSeparator($widths);
99		if ($config['headers'] === true) {
100			$this->_render(array_shift($rows), $widths, array('style' => $config['headerStyle']));
101			$this->_rowSeparator($widths);
102		}
103		foreach ($rows as $line) {
104			$this->_render($line, $widths);
105			if ($config['rowSeparator'] === true) {
106				$this->_rowSeparator($widths);
107			}
108		}
109		if ($config['rowSeparator'] !== true) {
110			$this->_rowSeparator($widths);
111		}
112	}
113
114/**
115 * Add style tags
116 *
117 * @param string $text The text to be surrounded
118 * @param string $style The style to be applied
119 * @return string
120 */
121	protected function _addStyle($text, $style) {
122		return '<' . $style . '>' . $text . '</' . $style . '>';
123	}
124}