Skip to content

Commit 5603b65

Browse files
committed
Implement MarkdownTable
1 parent 6d20ccc commit 5603b65

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
<?php
2+
3+
namespace PHPSemVerChecker\Console;
4+
5+
use Symfony\Component\Console\Helper\Helper;
6+
use Symfony\Component\Console\Helper\TableSeparator;
7+
use Symfony\Component\Console\Output\OutputInterface;
8+
9+
/**
10+
* Renders a Markdown compatible table.
11+
*/
12+
class MarkdownTable
13+
{
14+
/**
15+
* @var array
16+
*/
17+
private $headers = [];
18+
/**
19+
* @var array
20+
*/
21+
private $rows = [];
22+
/**
23+
* @var \Symfony\Component\Console\Output\OutputInterface
24+
*/
25+
private $output;
26+
/**
27+
* @var int[]
28+
*/
29+
private $columnWidths;
30+
31+
/**
32+
* @param \Symfony\Component\Console\Output\OutputInterface $output
33+
*/
34+
public function __construct(OutputInterface $output)
35+
{
36+
$this->output = $output;
37+
}
38+
39+
/**
40+
* Set the column headers.
41+
*
42+
* @param array $headers
43+
* @return $this
44+
*/
45+
public function setHeaders(array $headers)
46+
{
47+
// Ensure zero-indexed array
48+
$this->headers = array_values($headers);
49+
return $this;
50+
}
51+
52+
/**
53+
* Sets all rows, replacing any existing.
54+
*
55+
* @param array $rows
56+
* @return MarkdownTable
57+
*/
58+
public function setRows(array $rows)
59+
{
60+
$this->rows = [];
61+
return $this->addRows($rows);
62+
}
63+
64+
/**
65+
* @param array $rows
66+
* @return $this
67+
*/
68+
public function addRows(array $rows)
69+
{
70+
foreach ($rows as $row) {
71+
$this->addRow($row);
72+
}
73+
return $this;
74+
}
75+
76+
/**
77+
* @param $row
78+
* @return $this
79+
*/
80+
public function addRow($row)
81+
{
82+
if ($row instanceof TableSeparator) {
83+
$this->rows[] = $row;
84+
85+
return $this;
86+
}
87+
if (!is_array($row)) {
88+
throw new \InvalidArgumentException('A row must be an array or a TableSeparator instance.');
89+
}
90+
$this->rows[] = array_values($row);
91+
return $this;
92+
}
93+
94+
/**
95+
* @param int $index
96+
* @param array $row
97+
*/
98+
public function setRow($index, array $row)
99+
{
100+
$this->rows[$index] = $row;
101+
}
102+
103+
/**
104+
* Renders table to output.
105+
*/
106+
public function render()
107+
{
108+
$this->prepare();
109+
$this->output->writeln('');
110+
$this->renderRow($this->headers);
111+
$this->renderRowSeparator();
112+
foreach ($this->rows as $row) {
113+
$this->renderRow($row);
114+
}
115+
}
116+
117+
/**
118+
* Renders a single row.
119+
*
120+
* @param array|TableSeparator $row
121+
*/
122+
private function renderRow($row)
123+
{
124+
if ($row instanceof TableSeparator) {
125+
$this->renderRowSeparator();
126+
return;
127+
}
128+
$this->output->write('| ');
129+
$cells = [];
130+
foreach ($row as $index => $content) {
131+
$cell = $content;
132+
$padding = $this->columnWidths[$index] - Helper::strlenWithoutDecoration($this->output->getFormatter(), $content);
133+
$cell .= str_repeat(' ', $padding);
134+
$cells[] = $cell;
135+
}
136+
$this->output->writeln(implode(' | ', $cells).' |');
137+
}
138+
139+
/**
140+
* Renders the row separator. In this case it should only be used as a header separator.
141+
*/
142+
private function renderRowSeparator()
143+
{
144+
$this->output->write('|');
145+
foreach ($this->columnWidths as $columnWidth) {
146+
$this->output->write(str_repeat('-', $columnWidth + 1));
147+
$this->output->write('-|');
148+
}
149+
$this->output->writeln('');
150+
}
151+
152+
/**
153+
* Prepare for rendering
154+
*/
155+
private function prepare()
156+
{
157+
$this->columnWidths = [];
158+
$this->prepareColumnWidths($this->headers);
159+
foreach ($this->rows as $row) {
160+
$this->prepareColumnWidths($row);
161+
}
162+
}
163+
164+
/**
165+
* Extracts maximum column widths from a row.
166+
*
167+
* @param $row
168+
*/
169+
private function prepareColumnWidths($row)
170+
{
171+
if ($row instanceof TableSeparator) {
172+
return;
173+
}
174+
foreach ($row as $index => $content) {
175+
$currentMaximum = 0;
176+
if (isset($this->columnWidths[$index])) {
177+
$currentMaximum = $this->columnWidths[$index];
178+
}
179+
$width = Helper::strlenWithoutDecoration($this->output->getFormatter(), $content);
180+
$this->columnWidths[$index] = max($currentMaximum, $width);
181+
}
182+
}
183+
}

0 commit comments

Comments
 (0)