Completed
Pull Request — master (#76)
by Marcel
16:02
created

MarkdownTable::prepare()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
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
}
186