Table.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <?php
  2. namespace easyTask;
  3. /**
  4. * Class Table
  5. * @package easyTask
  6. */
  7. class Table
  8. {
  9. const ALIGN_LEFT = 1;
  10. const ALIGN_RIGHT = 0;
  11. const ALIGN_CENTER = 2;
  12. /**
  13. * 头信息数据
  14. * @var array
  15. */
  16. protected $header = [];
  17. /**
  18. * 头部对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
  19. * @var int
  20. */
  21. protected $headerAlign = 1;
  22. /**
  23. * 表格数据(二维数组)
  24. * @var array
  25. */
  26. protected $rows = [];
  27. /**
  28. * 单元格对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
  29. * @var int
  30. */
  31. protected $cellAlign = 1;
  32. /**
  33. * 单元格宽度信息
  34. * @var array
  35. */
  36. protected $colWidth = [];
  37. /**
  38. * 表格输出样式
  39. * @var string
  40. */
  41. protected $style = 'default';
  42. /**
  43. * 表格样式定义
  44. * @var array
  45. */
  46. protected $format = [
  47. 'compact' => [],
  48. 'default' => [
  49. 'top' => ['+', '-', '+', '+'],
  50. 'cell' => ['|', ' ', '|', '|'],
  51. 'middle' => ['+', '-', '+', '+'],
  52. 'bottom' => ['+', '-', '+', '+'],
  53. 'cross-top' => ['+', '-', '-', '+'],
  54. 'cross-bottom' => ['+', '-', '-', '+'],
  55. ],
  56. 'markdown' => [
  57. 'top' => [' ', ' ', ' ', ' '],
  58. 'cell' => ['|', ' ', '|', '|'],
  59. 'middle' => ['|', '-', '|', '|'],
  60. 'bottom' => [' ', ' ', ' ', ' '],
  61. 'cross-top' => ['|', ' ', ' ', '|'],
  62. 'cross-bottom' => ['|', ' ', ' ', '|'],
  63. ],
  64. 'borderless' => [
  65. 'top' => ['=', '=', ' ', '='],
  66. 'cell' => [' ', ' ', ' ', ' '],
  67. 'middle' => ['=', '=', ' ', '='],
  68. 'bottom' => ['=', '=', ' ', '='],
  69. 'cross-top' => ['=', '=', ' ', '='],
  70. 'cross-bottom' => ['=', '=', ' ', '='],
  71. ],
  72. 'box' => [
  73. 'top' => ['┌', '─', '┬', '┐'],
  74. 'cell' => ['│', ' ', '│', '│'],
  75. 'middle' => ['├', '─', '┼', '┤'],
  76. 'bottom' => ['└', '─', '┴', '┘'],
  77. 'cross-top' => ['├', '─', '┴', '┤'],
  78. 'cross-bottom' => ['├', '─', '┬', '┤'],
  79. ],
  80. 'box-double' => [
  81. 'top' => ['╔', '═', '╤', '╗'],
  82. 'cell' => ['║', ' ', '│', '║'],
  83. 'middle' => ['╠', '─', '╪', '╣'],
  84. 'bottom' => ['╚', '═', '╧', '╝'],
  85. 'cross-top' => ['╠', '═', '╧', '╣'],
  86. 'cross-bottom' => ['╠', '═', '╤', '╣'],
  87. ],
  88. ];
  89. /**
  90. * 设置表格头信息 以及对齐方式
  91. * @param array $header 要输出的Header信息
  92. * @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
  93. * @return void
  94. */
  95. public function setHeader($header, $align = self::ALIGN_LEFT)
  96. {
  97. $this->header = $header;
  98. $this->headerAlign = $align;
  99. $this->checkColWidth($header);
  100. }
  101. /**
  102. * 设置输出表格数据 及对齐方式
  103. * @param array $rows 要输出的表格数据(二维数组)
  104. * @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
  105. * @return void
  106. */
  107. public function setRows($rows, $align = self::ALIGN_LEFT)
  108. {
  109. $this->rows = $rows;
  110. $this->cellAlign = $align;
  111. foreach ($rows as $row)
  112. {
  113. $this->checkColWidth($row);
  114. }
  115. }
  116. /**
  117. * 检查列数据的显示宽度
  118. * @param mixed $row 行数据
  119. * @return void
  120. */
  121. protected function checkColWidth($row)
  122. {
  123. if (is_array($row))
  124. {
  125. foreach ($row as $key => $cell)
  126. {
  127. if (!isset($this->colWidth[$key]) || strlen($cell) > $this->colWidth[$key])
  128. {
  129. $this->colWidth[$key] = strlen($cell);
  130. }
  131. }
  132. }
  133. }
  134. /**
  135. * 增加一行表格数据
  136. * @param mixed $row 行数据
  137. * @param bool $first 是否在开头插入
  138. * @return void
  139. */
  140. public function addRow($row, $first = false)
  141. {
  142. if ($first)
  143. {
  144. array_unshift($this->rows, $row);
  145. }
  146. else
  147. {
  148. $this->rows[] = $row;
  149. }
  150. $this->checkColWidth($row);
  151. }
  152. /**
  153. * 设置输出表格的样式
  154. * @param string $style 样式名
  155. * @return void
  156. */
  157. public function setStyle($style)
  158. {
  159. $this->style = isset($this->format[$style]) ? $style : 'default';
  160. }
  161. /**
  162. * 输出分隔行
  163. * @param string $pos 位置
  164. * @return string
  165. */
  166. protected function renderSeparator($pos)
  167. {
  168. $style = $this->getStyle($pos);
  169. $array = [];
  170. foreach ($this->colWidth as $width)
  171. {
  172. $array[] = str_repeat($style[1], $width + 2);
  173. }
  174. return $style[0] . implode($style[2], $array) . $style[3] . PHP_EOL;
  175. }
  176. /**
  177. * 输出表格头部
  178. * @return string
  179. */
  180. protected function renderHeader()
  181. {
  182. $style = $this->getStyle('cell');
  183. $content = $this->renderSeparator('top');
  184. foreach ($this->header as $key => $header)
  185. {
  186. $array[] = ' ' . str_pad($header, $this->colWidth[$key], $style[1], $this->headerAlign);
  187. }
  188. if (!empty($array))
  189. {
  190. $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
  191. if ($this->rows)
  192. {
  193. $content .= $this->renderSeparator('middle');
  194. }
  195. }
  196. return $content;
  197. }
  198. /**
  199. * 获取风格
  200. * @param string $style
  201. * @return array
  202. */
  203. protected function getStyle($style)
  204. {
  205. if ($this->format[$this->style])
  206. {
  207. $style = $this->format[$this->style][$style];
  208. }
  209. else
  210. {
  211. $style = [' ', ' ', ' ', ' '];
  212. }
  213. return $style;
  214. }
  215. /**
  216. * 输出表格
  217. * @param array $dataList 表格数据
  218. * @return string
  219. */
  220. public function render($dataList = [])
  221. {
  222. if ($dataList)
  223. {
  224. $this->setRows($dataList);
  225. }
  226. // 输出头部
  227. $content = $this->renderHeader();
  228. $style = $this->getStyle('cell');
  229. if ($this->rows)
  230. {
  231. foreach ($this->rows as $row)
  232. {
  233. if (is_string($row) && '-' === $row)
  234. {
  235. $content .= $this->renderSeparator('middle');
  236. }
  237. elseif (is_scalar($row))
  238. {
  239. $content .= $this->renderSeparator('cross-top');
  240. $array = str_pad($row, 3 * (count($this->colWidth) - 1) + array_reduce($this->colWidth, function ($a, $b) {
  241. return $a + $b;
  242. }));
  243. $content .= $style[0] . ' ' . $array . ' ' . $style[3] . PHP_EOL;
  244. $content .= $this->renderSeparator('cross-bottom');
  245. }
  246. else
  247. {
  248. $array = [];
  249. foreach ($row as $key => $val)
  250. {
  251. $array[] = ' ' . str_pad($val, $this->colWidth[$key], ' ', $this->cellAlign);
  252. }
  253. $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
  254. }
  255. }
  256. }
  257. $content .= $this->renderSeparator('bottom');
  258. return $content;
  259. }
  260. }