Chris@0
|
1 <?php
|
Chris@0
|
2 namespace Consolidation\OutputFormatters\Transformations;
|
Chris@0
|
3
|
Chris@0
|
4 use Consolidation\OutputFormatters\Transformations\Wrap\CalculateWidths;
|
Chris@0
|
5 use Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths;
|
Chris@0
|
6 use Symfony\Component\Console\Helper\TableStyle;
|
Chris@0
|
7
|
Chris@0
|
8 class WordWrapper
|
Chris@0
|
9 {
|
Chris@0
|
10 protected $width;
|
Chris@0
|
11 protected $minimumWidths;
|
Chris@0
|
12
|
Chris@0
|
13 // For now, hardcode these to match what the Symfony Table helper does.
|
Chris@0
|
14 // Note that these might actually need to be adjusted depending on the
|
Chris@0
|
15 // table style.
|
Chris@0
|
16 protected $extraPaddingAtBeginningOfLine = 0;
|
Chris@0
|
17 protected $extraPaddingAtEndOfLine = 0;
|
Chris@0
|
18 protected $paddingInEachCell = 3;
|
Chris@0
|
19
|
Chris@0
|
20 public function __construct($width)
|
Chris@0
|
21 {
|
Chris@0
|
22 $this->width = $width;
|
Chris@0
|
23 $this->minimumWidths = new ColumnWidths();
|
Chris@0
|
24 }
|
Chris@0
|
25
|
Chris@0
|
26 /**
|
Chris@0
|
27 * Calculate our padding widths from the specified table style.
|
Chris@0
|
28 * @param TableStyle $style
|
Chris@0
|
29 */
|
Chris@0
|
30 public function setPaddingFromStyle(TableStyle $style)
|
Chris@0
|
31 {
|
Chris@0
|
32 $verticalBorderLen = strlen(sprintf($style->getBorderFormat(), $style->getVerticalBorderChar()));
|
Chris@0
|
33 $paddingLen = strlen($style->getPaddingChar());
|
Chris@0
|
34
|
Chris@0
|
35 $this->extraPaddingAtBeginningOfLine = 0;
|
Chris@0
|
36 $this->extraPaddingAtEndOfLine = $verticalBorderLen;
|
Chris@0
|
37 $this->paddingInEachCell = $verticalBorderLen + $paddingLen + 1;
|
Chris@0
|
38 }
|
Chris@0
|
39
|
Chris@0
|
40 /**
|
Chris@0
|
41 * If columns have minimum widths, then set them here.
|
Chris@0
|
42 * @param array $minimumWidths
|
Chris@0
|
43 */
|
Chris@0
|
44 public function setMinimumWidths($minimumWidths)
|
Chris@0
|
45 {
|
Chris@0
|
46 $this->minimumWidths = new ColumnWidths($minimumWidths);
|
Chris@0
|
47 }
|
Chris@0
|
48
|
Chris@0
|
49 /**
|
Chris@0
|
50 * Set the minimum width of just one column
|
Chris@0
|
51 */
|
Chris@0
|
52 public function minimumWidth($colkey, $width)
|
Chris@0
|
53 {
|
Chris@0
|
54 $this->minimumWidths->setWidth($colkey, $width);
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 /**
|
Chris@0
|
58 * Wrap the cells in each part of the provided data table
|
Chris@0
|
59 * @param array $rows
|
Chris@0
|
60 * @return array
|
Chris@0
|
61 */
|
Chris@0
|
62 public function wrap($rows, $widths = [])
|
Chris@0
|
63 {
|
Chris@0
|
64 $auto_widths = $this->calculateWidths($rows, $widths);
|
Chris@0
|
65
|
Chris@0
|
66 // If no widths were provided, then disable wrapping
|
Chris@0
|
67 if ($auto_widths->isEmpty()) {
|
Chris@0
|
68 return $rows;
|
Chris@0
|
69 }
|
Chris@0
|
70
|
Chris@0
|
71 // Do wordwrap on all cells.
|
Chris@0
|
72 $newrows = array();
|
Chris@0
|
73 foreach ($rows as $rowkey => $row) {
|
Chris@0
|
74 foreach ($row as $colkey => $cell) {
|
Chris@0
|
75 $newrows[$rowkey][$colkey] = $this->wrapCell($cell, $auto_widths->width($colkey));
|
Chris@0
|
76 }
|
Chris@0
|
77 }
|
Chris@0
|
78
|
Chris@0
|
79 return $newrows;
|
Chris@0
|
80 }
|
Chris@0
|
81
|
Chris@0
|
82 /**
|
Chris@0
|
83 * Determine what widths we'll use for wrapping.
|
Chris@0
|
84 */
|
Chris@0
|
85 protected function calculateWidths($rows, $widths = [])
|
Chris@0
|
86 {
|
Chris@0
|
87 // Widths must be provided in some form or another, or we won't wrap.
|
Chris@0
|
88 if (empty($widths) && !$this->width) {
|
Chris@0
|
89 return new ColumnWidths();
|
Chris@0
|
90 }
|
Chris@0
|
91
|
Chris@0
|
92 // Technically, `$widths`, if provided here, should be used
|
Chris@0
|
93 // as the exact widths to wrap to. For now we'll just treat
|
Chris@0
|
94 // these as minimum widths
|
Chris@0
|
95 $minimumWidths = $this->minimumWidths->combine(new ColumnWidths($widths));
|
Chris@0
|
96
|
Chris@0
|
97 $calculator = new CalculateWidths();
|
Chris@0
|
98 $dataCellWidths = $calculator->calculateLongestCell($rows);
|
Chris@0
|
99
|
Chris@0
|
100 $availableWidth = $this->width - $dataCellWidths->paddingSpace($this->paddingInEachCell, $this->extraPaddingAtEndOfLine, $this->extraPaddingAtBeginningOfLine);
|
Chris@0
|
101
|
Chris@0
|
102 $this->minimumWidths->adjustMinimumWidths($availableWidth, $dataCellWidths);
|
Chris@0
|
103
|
Chris@0
|
104 return $calculator->calculate($availableWidth, $dataCellWidths, $minimumWidths);
|
Chris@0
|
105 }
|
Chris@0
|
106
|
Chris@0
|
107 /**
|
Chris@0
|
108 * Wrap one cell. Guard against modifying non-strings and
|
Chris@0
|
109 * then call through to wordwrap().
|
Chris@0
|
110 *
|
Chris@0
|
111 * @param mixed $cell
|
Chris@0
|
112 * @param string $cellWidth
|
Chris@0
|
113 * @return mixed
|
Chris@0
|
114 */
|
Chris@0
|
115 protected function wrapCell($cell, $cellWidth)
|
Chris@0
|
116 {
|
Chris@0
|
117 if (!is_string($cell)) {
|
Chris@0
|
118 return $cell;
|
Chris@0
|
119 }
|
Chris@0
|
120 return wordwrap($cell, $cellWidth, "\n", true);
|
Chris@0
|
121 }
|
Chris@0
|
122 }
|