Skip to content

Commit 88f8411

Browse files
committed
Implement MarkdownTable
1 parent 6d20ccc commit 88f8411

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
<?php
2+
3+
namespace PHPSemVerChecker\Console\Helper;
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 $this
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 \Symfony\Component\Console\Helper\TableSeparator|array $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+
* @return $this
98+
*/
99+
public function setRow($index, array $row)
100+
{
101+
$this->rows[$index] = $row;
102+
return $this;
103+
}
104+
105+
/**
106+
* Renders table to output.
107+
*/
108+
public function render()
109+
{
110+
$this->prepare();
111+
$this->output->writeln('');
112+
$this->renderRow($this->headers);
113+
$this->renderRowSeparator();
114+
foreach ($this->rows as $row) {
115+
$this->renderRow($row);
116+
}
117+
}
118+
119+
/**
120+
* Renders a single row.
121+
*
122+
* @param \Symfony\Component\Console\Helper\TableSeparator|array $row
123+
*/
124+
private function renderRow($row)
125+
{
126+
if ($row instanceof TableSeparator) {
127+
$this->renderRowSeparator();
128+
return;
129+
}
130+
$this->output->write('| ');
131+
$cells = [];
132+
foreach ($row as $index => $content) {
133+
$cell = $content;
134+
$padding = $this->columnWidths[$index] - Helper::strlenWithoutDecoration($this->output->getFormatter(), $content);
135+
$cell .= str_repeat(' ', $padding);
136+
$cells[] = $cell;
137+
}
138+
$this->output->writeln(implode(' | ', $cells) . ' |');
139+
}
140+
141+
/**
142+
* Renders the row separator. In this case it should only be used as a header separator.
143+
*/
144+
private function renderRowSeparator()
145+
{
146+
$this->output->write('|');
147+
foreach ($this->columnWidths as $columnWidth) {
148+
$this->output->write(str_repeat('-', $columnWidth + 1));
149+
$this->output->write('-|');
150+
}
151+
$this->output->writeln('');
152+
}
153+
154+
/**
155+
* Prepare for rendering.
156+
*/
157+
private function prepare()
158+
{
159+
$this->columnWidths = [];
160+
$this->prepareColumnWidths($this->headers);
161+
foreach ($this->rows as $row) {
162+
$this->prepareColumnWidths($row);
163+
}
164+
}
165+
166+
/**
167+
* Extracts maximum column widths from a row.
168+
*
169+
* @param \Symfony\Component\Console\Helper\TableSeparator|array $row
170+
*/
171+
private function prepareColumnWidths($row)
172+
{
173+
if ($row instanceof TableSeparator) {
174+
return;
175+
}
176+
foreach ($row as $index => $content) {
177+
$currentMaximum = 0;
178+
if (isset($this->columnWidths[$index])) {
179+
$currentMaximum = $this->columnWidths[$index];
180+
}
181+
$width = Helper::strlenWithoutDecoration($this->output->getFormatter(), $content);
182+
$this->columnWidths[$index] = max($currentMaximum, $width);
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)