|
1
|
|
|
<?php |
|
2
|
|
|
namespace Consolidation\OutputFormatters\Transformations\Wrap; |
|
3
|
|
|
|
|
4
|
|
|
use Symfony\Component\Console\Helper\TableStyle; |
|
5
|
|
|
|
|
6
|
|
|
/** |
|
7
|
|
|
* Calculate the width of data in table cells in preparation for word wrapping. |
|
8
|
|
|
*/ |
|
9
|
|
|
class DataCellWidths |
|
10
|
|
|
{ |
|
11
|
|
|
protected $widths; |
|
12
|
|
|
|
|
13
|
|
|
public function __construct($widths = []) |
|
14
|
|
|
{ |
|
15
|
|
|
$this->widths = $widths; |
|
16
|
|
|
} |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* Calculate the longest cell data from any row of each of the cells. |
|
20
|
|
|
*/ |
|
21
|
|
View Code Duplication |
public function calculateLongestCell($rows) |
|
|
|
|
|
|
22
|
|
|
{ |
|
23
|
|
|
$this->widths = []; |
|
24
|
|
|
|
|
25
|
|
|
// Examine each row and find the longest line length and longest |
|
26
|
|
|
// word in each column. |
|
27
|
|
|
foreach ($rows as $rowkey => $row) { |
|
28
|
|
|
foreach ($row as $colkey => $cell) { |
|
29
|
|
|
$lineLength = strlen($cell); |
|
30
|
|
|
if ((!isset($this->widths[$colkey]) || ($this->widths[$colkey] < $lineLength))) { |
|
31
|
|
|
$this->widths[$colkey] = $lineLength; |
|
32
|
|
|
} |
|
33
|
|
|
} |
|
34
|
|
|
} |
|
35
|
|
|
} |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* Calculate the longest word and longest line in the provided data. |
|
39
|
|
|
*/ |
|
40
|
|
View Code Duplication |
public function calculateLongestWord($rows) |
|
|
|
|
|
|
41
|
|
|
{ |
|
42
|
|
|
$this->widths = []; |
|
43
|
|
|
|
|
44
|
|
|
// Examine each row and find the longest line length and longest |
|
45
|
|
|
// word in each column. |
|
46
|
|
|
foreach ($rows as $rowkey => $row) { |
|
47
|
|
|
foreach ($row as $colkey => $cell) { |
|
48
|
|
|
$longestWordLength = static::longestWordLength($cell); |
|
49
|
|
|
if ((!isset($this->widths[$colkey]) || ($this->widths[$colkey] < $longestWordLength))) { |
|
50
|
|
|
$this->widths[$colkey] = $longestWordLength; |
|
51
|
|
|
} |
|
52
|
|
|
} |
|
53
|
|
|
} |
|
54
|
|
|
} |
|
55
|
|
|
|
|
56
|
|
|
public function paddingSpace( |
|
57
|
|
|
$paddingInEachCell, |
|
58
|
|
|
$extraPaddingAtEndOfLine = 0, |
|
59
|
|
|
$extraPaddingAtBeginningOfLine = 0 |
|
60
|
|
|
) { |
|
61
|
|
|
|
|
62
|
|
|
return ($extraPaddingAtBeginningOfLine + $extraPaddingAtEndOfLine + (count($this->widths) * $paddingInEachCell)); |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
/** |
|
66
|
|
|
* Find all columns that are shorter than the specified threshold width. |
|
67
|
|
|
* These are removed from this object, and returned as the result of |
|
68
|
|
|
* this method. |
|
69
|
|
|
*/ |
|
70
|
|
|
public function removeShortColumns($thresholdWidth) |
|
71
|
|
|
{ |
|
72
|
|
|
$shortColWidths = $this->findShortColumns($thresholdWidth); |
|
73
|
|
|
$this->removeColumns($shortColWidths->keys()); |
|
74
|
|
|
return $shortColWidths; |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
/** |
|
78
|
|
|
* Find all of the columns that are shorter than the specified threshold. |
|
79
|
|
|
*/ |
|
80
|
|
|
public function findShortColumns($thresholdWidth) |
|
81
|
|
|
{ |
|
82
|
|
|
$shortColWidths = []; |
|
83
|
|
|
|
|
84
|
|
|
foreach ($this->widths as $key => $maxLength) { |
|
85
|
|
|
if ($maxLength <= $thresholdWidth) { |
|
86
|
|
|
$shortColWidths[$key] = $maxLength; |
|
87
|
|
|
} |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
return new DataCellWidths($shortColWidths); |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* Remove all of the specified columns from this data structure. |
|
95
|
|
|
*/ |
|
96
|
|
|
public function removeColumns($columnKeys) |
|
97
|
|
|
{ |
|
98
|
|
|
foreach ($columnKeys as $key) { |
|
99
|
|
|
unset($this->widths[$key]); |
|
100
|
|
|
} |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
/** |
|
104
|
|
|
* Need to think about the name of this function a bit. |
|
105
|
|
|
* Maybe second parameter is just a column count. |
|
106
|
|
|
*/ |
|
107
|
|
|
public function adjustMinimumWidths($availableWidth, DataCellWidths $dataCellWidths) |
|
|
|
|
|
|
108
|
|
|
{ |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* Return proportional weights |
|
113
|
|
|
*/ |
|
114
|
|
|
public function distribute($availableWidth) |
|
115
|
|
|
{ |
|
116
|
|
|
$result = []; |
|
117
|
|
|
$totalWidth = $this->totalWidth(); |
|
118
|
|
|
$lastColumn = $this->lastColumn(); |
|
119
|
|
|
$widths = $this->widths(); |
|
120
|
|
|
|
|
121
|
|
|
// Take off the last column, and calculate proportional weights |
|
122
|
|
|
// for the first N-1 columns. |
|
123
|
|
|
array_pop($widths); |
|
124
|
|
|
foreach ($widths as $key => $width) { |
|
125
|
|
|
$result[$key] = round(($width / $totalWidth) * $availableWidth); |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
// Give the last column the rest of the available width |
|
129
|
|
|
$usedWidth = $this->sumWidth($result); |
|
130
|
|
|
$result[$lastColumn] = $availableWidth - $usedWidth; |
|
131
|
|
|
|
|
132
|
|
|
return new DataCellWidths($result); |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
public function lastColumn() |
|
136
|
|
|
{ |
|
137
|
|
|
$keys = $this->keys(); |
|
138
|
|
|
return array_pop($keys); |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
/** |
|
142
|
|
|
* Return the available keys (column identifiers) from the calculated |
|
143
|
|
|
* data set. |
|
144
|
|
|
*/ |
|
145
|
|
|
public function keys() |
|
146
|
|
|
{ |
|
147
|
|
|
return array_keys($this->widths); |
|
148
|
|
|
} |
|
149
|
|
|
|
|
150
|
|
|
/** |
|
151
|
|
|
* Set the length of the specified column. |
|
152
|
|
|
*/ |
|
153
|
|
|
public function setWidth($key, $width) |
|
154
|
|
|
{ |
|
155
|
|
|
$this->widths[$key] = $width; |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
|
|
/** |
|
159
|
|
|
* Return the length of the specified column. |
|
160
|
|
|
*/ |
|
161
|
|
|
public function width($key) |
|
162
|
|
|
{ |
|
163
|
|
|
return isset($this->widths[$key]) ? $this->widths[$key] : 0; |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
/** |
|
167
|
|
|
* Return all of the lengths |
|
168
|
|
|
*/ |
|
169
|
|
|
public function widths() |
|
170
|
|
|
{ |
|
171
|
|
|
return $this->widths; |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
/** |
|
175
|
|
|
* Return true if there is no data in this object |
|
176
|
|
|
*/ |
|
177
|
|
|
public function isEmpty() |
|
178
|
|
|
{ |
|
179
|
|
|
return empty($this->widths); |
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
/** |
|
183
|
|
|
* Return the sum of the lengths of the provided widths. |
|
184
|
|
|
*/ |
|
185
|
|
|
public function totalWidth() |
|
186
|
|
|
{ |
|
187
|
|
|
return static::sumWidth($this->widths()); |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
/** |
|
191
|
|
|
* Return the sum of the lengths of the provided widths. |
|
192
|
|
|
*/ |
|
193
|
|
|
public static function sumWidth($widths) |
|
194
|
|
|
{ |
|
195
|
|
|
return array_reduce( |
|
196
|
|
|
$widths, |
|
197
|
|
|
function ($carry, $item) { |
|
198
|
|
|
return $carry + $item; |
|
199
|
|
|
} |
|
200
|
|
|
); |
|
201
|
|
|
} |
|
202
|
|
|
|
|
203
|
|
|
/** |
|
204
|
|
|
* Ensure that every item in $widths that has a corresponding entry |
|
205
|
|
|
* in $minimumWidths is as least as large as the minimum value held there. |
|
206
|
|
|
*/ |
|
207
|
|
|
public function enforceMinimums($minimumWidths) |
|
208
|
|
|
{ |
|
209
|
|
|
$result = []; |
|
210
|
|
|
if ($minimumWidths instanceof DataCellWidths) { |
|
211
|
|
|
$minimumWidths = $minimumWidths->widths(); |
|
212
|
|
|
} |
|
213
|
|
|
$minimumWidths += $this->widths; |
|
214
|
|
|
|
|
215
|
|
|
foreach ($this->widths as $key => $value) { |
|
216
|
|
|
$result[$key] = min($value, $minimumWidths[$key]); |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
|
|
return new DataCellWidths($result); |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
|
|
/** |
|
223
|
|
|
* Combine this set of widths with another set, and return |
|
224
|
|
|
* a new set that contains the entries from both. |
|
225
|
|
|
*/ |
|
226
|
|
|
public function combine(DataCellWidths $combineWith) |
|
227
|
|
|
{ |
|
228
|
|
|
$combined = array_merge($combineWith->widths(), $this->widths()); |
|
229
|
|
|
|
|
230
|
|
|
return new DataCellWidths($combined); |
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
/** |
|
234
|
|
|
* Return the length of the longest word in the string. |
|
235
|
|
|
* @param string $str |
|
236
|
|
|
* @return int |
|
237
|
|
|
*/ |
|
238
|
|
|
protected static function longestWordLength($str) |
|
239
|
|
|
{ |
|
240
|
|
|
$words = preg_split('#[ /-]#', $str); |
|
241
|
|
|
$lengths = array_map(function ($s) { |
|
242
|
|
|
return strlen($s); |
|
243
|
|
|
}, $words); |
|
244
|
|
|
return max($lengths); |
|
245
|
|
|
} |
|
246
|
|
|
} |
|
247
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.