Yaffs site version 1.1
[yaffs-website] / vendor / consolidation / output-formatters / src / Transformations / Wrap / ColumnWidths.php
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 ColumnWidths
10 {
11     protected $widths;
12
13     public function __construct($widths = [])
14     {
15         $this->widths = $widths;
16     }
17
18     public function paddingSpace(
19         $paddingInEachCell,
20         $extraPaddingAtEndOfLine = 0,
21         $extraPaddingAtBeginningOfLine = 0
22     ) {
23         return ($extraPaddingAtBeginningOfLine + $extraPaddingAtEndOfLine + (count($this->widths) * $paddingInEachCell));
24     }
25
26     /**
27      * Find all of the columns that are shorter than the specified threshold.
28      */
29     public function findShortColumns($thresholdWidth)
30     {
31         $thresholdWidths = array_fill_keys(array_keys($this->widths), $thresholdWidth);
32
33         return $this->findColumnsUnderThreshold($thresholdWidths);
34     }
35
36     /**
37      * Find all of the columns that are shorter than the corresponding minimum widths.
38      */
39     public function findUndersizedColumns($minimumWidths)
40     {
41         return $this->findColumnsUnderThreshold($minimumWidths->widths());
42     }
43
44     protected function findColumnsUnderThreshold(array $thresholdWidths)
45     {
46         $shortColWidths = [];
47         foreach ($this->widths as $key => $maxLength) {
48             if (isset($thresholdWidths[$key]) && ($maxLength <= $thresholdWidths[$key])) {
49                 $shortColWidths[$key] = $maxLength;
50             }
51         }
52
53         return new ColumnWidths($shortColWidths);
54     }
55
56     /**
57      * If the widths specified by this object do not fit within the
58      * provided avaiable width, then reduce them all proportionally.
59      */
60     public function adjustMinimumWidths($availableWidth, $dataCellWidths)
61     {
62         $result = $this->selectColumns($dataCellWidths->keys());
63         if ($result->isEmpty()) {
64             return $result;
65         }
66         $numberOfColumns = $dataCellWidths->count();
67
68         // How many unspecified columns are there?
69         $unspecifiedColumns = $numberOfColumns - $result->count();
70         $averageWidth = $this->averageWidth($availableWidth);
71
72         // Reserve some space for the columns that have no minimum.
73         // Make sure they collectively get at least half of the average
74         // width for each column. Or should it be a quarter?
75         $reservedSpacePerColumn = ($averageWidth / 2);
76         $reservedSpace = $reservedSpacePerColumn * $unspecifiedColumns;
77
78         // Calculate how much of the available space is remaining for use by
79         // the minimum column widths after the reserved space is accounted for.
80         $remainingAvailable = $availableWidth - $reservedSpace;
81
82         // Don't do anything if our widths fit inside the available widths.
83         if ($result->totalWidth() <= $remainingAvailable) {
84             return $result;
85         }
86
87         // Shrink the minimum widths if the table is too compressed.
88         return $result->distribute($remainingAvailable);
89     }
90
91     /**
92      * Return proportional weights
93      */
94     public function distribute($availableWidth)
95     {
96         $result = [];
97         $totalWidth = $this->totalWidth();
98         $lastColumn = $this->lastColumn();
99         $widths = $this->widths();
100
101         // Take off the last column, and calculate proportional weights
102         // for the first N-1 columns.
103         array_pop($widths);
104         foreach ($widths as $key => $width) {
105             $result[$key] = round(($width / $totalWidth) * $availableWidth);
106         }
107
108         // Give the last column the rest of the available width
109         $usedWidth = $this->sumWidth($result);
110         $result[$lastColumn] = $availableWidth - $usedWidth;
111
112         return new ColumnWidths($result);
113     }
114
115     public function lastColumn()
116     {
117         $keys = $this->keys();
118         return array_pop($keys);
119     }
120
121     /**
122      * Return the number of columns.
123      */
124     public function count()
125     {
126         return count($this->widths);
127     }
128
129     /**
130      * Calculate how much space is available on average for all columns.
131      */
132     public function averageWidth($availableWidth)
133     {
134         if ($this->isEmpty()) {
135             debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
136         }
137         return $availableWidth / $this->count();
138     }
139
140     /**
141      * Return the available keys (column identifiers) from the calculated
142      * data set.
143      */
144     public function keys()
145     {
146         return array_keys($this->widths);
147     }
148
149     /**
150      * Set the length of the specified column.
151      */
152     public function setWidth($key, $width)
153     {
154         $this->widths[$key] = $width;
155     }
156
157     /**
158      * Return the length of the specified column.
159      */
160     public function width($key)
161     {
162         return isset($this->widths[$key]) ? $this->widths[$key] : 0;
163     }
164
165     /**
166      * Return all of the lengths
167      */
168     public function widths()
169     {
170         return $this->widths;
171     }
172
173     /**
174      * Return true if there is no data in this object
175      */
176     public function isEmpty()
177     {
178         return empty($this->widths);
179     }
180
181     /**
182      * Return the sum of the lengths of the provided widths.
183      */
184     public function totalWidth()
185     {
186         return static::sumWidth($this->widths());
187     }
188
189     /**
190      * Return the sum of the lengths of the provided widths.
191      */
192     public static function sumWidth($widths)
193     {
194         return array_reduce(
195             $widths,
196             function ($carry, $item) {
197                 return $carry + $item;
198             }
199         );
200     }
201
202     /**
203      * Ensure that every item in $widths that has a corresponding entry
204      * in $minimumWidths is as least as large as the minimum value held there.
205      */
206     public function enforceMinimums($minimumWidths)
207     {
208         $result = [];
209         if ($minimumWidths instanceof ColumnWidths) {
210             $minimumWidths = $minimumWidths->widths();
211         }
212         $minimumWidths += $this->widths;
213
214         foreach ($this->widths as $key => $value) {
215             $result[$key] = max($value, $minimumWidths[$key]);
216         }
217
218         return new ColumnWidths($result);
219     }
220
221     /**
222      * Remove all of the specified columns from this data structure.
223      */
224     public function removeColumns($columnKeys)
225     {
226         $widths = $this->widths();
227
228         foreach ($columnKeys as $key) {
229             unset($widths[$key]);
230         }
231
232         return new ColumnWidths($widths);
233     }
234
235     /**
236      * Select all columns that exist in the provided list of keys.
237      */
238     public function selectColumns($columnKeys)
239     {
240         $widths = [];
241
242         foreach ($columnKeys as $key) {
243             if (isset($this->widths[$key])) {
244                 $widths[$key] = $this->width($key);
245             }
246         }
247
248         return new ColumnWidths($widths);
249     }
250
251     /**
252      * Combine this set of widths with another set, and return
253      * a new set that contains the entries from both.
254      */
255     public function combine(ColumnWidths $combineWith)
256     {
257         // Danger: array_merge renumbers numeric keys; that must not happen here.
258         $combined = $combineWith->widths();
259         foreach ($this->widths() as $key => $value) {
260             $combined[$key] = $value;
261         }
262         return new ColumnWidths($combined);
263     }
264 }