Completed
Push — master ( bd5ff6...90c2c7 )
by Bernhard
07:04
created

Grid   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 83.33%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 19
c 2
b 1
f 0
lcom 1
cbo 7
dl 0
loc 219
ccs 55
cts 66
cp 0.8333
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 2
A addCell() 0 6 1
A setCells() 0 8 1
A getMinNbColumns() 0 4 1
A setMinNbColumns() 0 7 1
A getMaxNbColumns() 0 4 1
A setMaxNbColumns() 0 7 1
A render() 0 14 2
A addCells() 0 8 2
B getCellWrapper() 0 26 4
B renderRows() 0 32 3
1
<?php
2
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webmozart\Console\UI\Component;
13
14
use Webmozart\Console\Api\Formatter\Formatter;
15
use Webmozart\Console\Api\IO\IO;
16
use Webmozart\Console\UI\Component;
17
use Webmozart\Console\UI\Style\GridStyle;
18
use Webmozart\Console\Util\StringUtil;
19
20
/**
21
 * A grid of cells that are dynamically organized in the console window.
22
 *
23
 * You can add data cells with {@link addCell()}. Optionally, you can set the
24
 * minimum and maximum allowed number of columns with {@link setMinNbColumns()}
25
 * and {@link setMaxNbColumns()}.
26
 *
27
 * If you want to style the grid, pass a {@link GridStyle} to the constructor.
28
 *
29
 * @since  1.0
30
 *
31
 * @author Bernhard Schussek <[email protected]>
32
 */
33
class Grid implements Component
34
{
35
    /**
36
     * @var GridStyle
37
     */
38
    private $style;
39
40
    /**
41
     * @var string[]
42
     */
43
    private $cells = array();
44
45
    /**
46
     * @var int
47
     */
48
    private $minNbColumns = 4;
49
50
    /**
51
     * @var int
52
     */
53
    private $maxNbColumns = PHP_INT_MAX;
54
55
    /**
56
     * Creates a new grid.
57
     *
58
     * @param GridStyle $style The rendering style. By default, the grid is
0 ignored issues
show
Documentation introduced by
Should the type for parameter $style not be null|GridStyle?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
59
     *                         rendered with the style
60
     *                         {@link GridStyle::borderless()}.
61
     */
62 11
    public function __construct(GridStyle $style = null)
63
    {
64 11
        $this->style = $style ?: GridStyle::borderless();
65 11
    }
66
67
    /**
68
     * Adds a data cell to the grid.
69
     *
70
     * @param string $cell The data cell.
71
     *
72
     * @return static The current instance.
73
     */
74
    public function addCell($cell)
75
    {
76
        $this->cells[] = $cell;
77
78
        return $this;
79
    }
80
81
    /**
82
     * Adds data cells to the grid.
83
     *
84
     * @param string[] $cells The data cells.
85
     *
86
     * @return static The current instance.
87
     */
88 10
    public function addCells(array $cells)
89
    {
90 10
        foreach ($cells as $cell) {
91 10
            $this->cells[] = $cell;
92
        }
93
94 10
        return $this;
95
    }
96
97
    /**
98
     * Sets the data cells in the grid.
99
     *
100
     * @param string[] $cells The data cells to set.
101
     *
102
     * @return static The current instance.
103
     */
104
    public function setCells(array $cells)
105
    {
106
        $this->cells = array();
107
108
        $this->addCells($cells);
109
110
        return $this;
111
    }
112
113
    /**
114
     * Returns the minimum number of columns in the grid.
115
     *
116
     * The default minimum is 4.
117
     *
118
     * @return int The minimum number of columns.
119
     */
120
    public function getMinNbColumns()
121
    {
122
        return $this->minNbColumns;
123
    }
124
125
    /**
126
     * Sets the minimum number of columns in the grid.
127
     *
128
     * The default minimum is 4.
129
     *
130
     * @param int $minNbColumns The minimum number of columns.
131
     *
132
     * @return static The current instance.
133
     */
134 1
    public function setMinNbColumns($minNbColumns)
135
    {
136 1
        $this->minNbColumns = $minNbColumns;
137 1
        $this->maxNbColumns = max($this->maxNbColumns, $minNbColumns);
138
139 1
        return $this;
140
    }
141
142
    /**
143
     * Returns the maximum number of columns in the grid.
144
     *
145
     * The default maximum is unlimited.
146
     *
147
     * @return int The maximum number of columns.
148
     */
149
    public function getMaxNbColumns()
150
    {
151
        return $this->maxNbColumns;
152
    }
153
154
    /**
155
     * Sets the maximum number of columns in the grid.
156
     *
157
     * The default maximum is unlimited.
158
     *
159
     * @param int $maxNbColumns The maximum number of columns.
160
     *
161
     * @return static The current instance.
162
     */
163 1
    public function setMaxNbColumns($maxNbColumns)
164
    {
165 1
        $this->minNbColumns = min($this->minNbColumns, $maxNbColumns);
166 1
        $this->maxNbColumns = $maxNbColumns;
167
168 1
        return $this;
169
    }
170
171
    /**
172
     * Renders the grid.
173
     *
174
     * @param IO  $io          The I/O.
175
     * @param int $indentation The number of spaces to indent.
176
     */
177 11
    public function render(IO $io, $indentation = 0)
178
    {
179
        // Is the grid empty?
180 11
        if (!$this->cells) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cells of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
181 1
            return;
182
        }
183
184 10
        $screenWidth = $io->getTerminalDimensions()->getWidth();
185 10
        $excessColumnWidth = StringUtil::getLength(sprintf($this->style->getCellFormat(), ''), $io);
186
187 10
        $wrapper = $this->getCellWrapper($io, $screenWidth, $excessColumnWidth, $indentation);
188
189 10
        $this->renderRows($io, $wrapper->getWrappedRows(), $wrapper->getColumnLengths(), $excessColumnWidth, $indentation);
190 10
    }
191
192 10
    private function getCellWrapper(Formatter $formatter, $screenWidth, $excessColumnWidth, $indentation)
193
    {
194 10
        $borderStyle = $this->style->getBorderStyle();
195 10
        $wrapper = new CellWrapper();
196
197 10
        foreach ($this->cells as $cell) {
198 10
            $wrapper->addCell($cell);
199
        }
200
201 10
        $nbColumns = min($this->maxNbColumns, $wrapper->getEstimatedNbColumns($screenWidth));
202
203
        do {
204 10
            $borderWidth = StringUtil::getLength($borderStyle->getLineVLChar())
205 10
                + ($nbColumns - 1) * StringUtil::getLength($borderStyle->getLineVCChar())
206 10
                + StringUtil::getLength($borderStyle->getLineVRChar());
207
208 10
            $availableWidth = $screenWidth - $indentation - $borderWidth
209 10
                - $nbColumns * $excessColumnWidth;
210
211 10
            $wrapper->fit($availableWidth, $nbColumns, $formatter);
212
213 10
            --$nbColumns;
214 10
        } while ($wrapper->hasWordCuts() && $nbColumns >= $this->minNbColumns);
215
216 10
        return $wrapper;
217
    }
218
219 10
    private function renderRows(IO $io, array $rows, array $columnLengths, $excessColumnLength, $indentation)
220
    {
221 10
        $alignments = array_fill(0, count($columnLengths), $this->style->getCellAlignment());
222 10
        $borderStyle = $this->style->getBorderStyle();
223 10
        $borderColumnLengths = array_map(function ($length) use ($excessColumnLength) {
224 10
            return $length + $excessColumnLength;
225 10
        }, $columnLengths);
226
227 10
        BorderUtil::drawTopBorder($io, $borderStyle, $borderColumnLengths, $indentation);
228
229 10
        $last = count($rows) - 1;
230
231 10
        foreach ($rows as $i => $row) {
232 10
            BorderUtil::drawRow(
233
                $io,
234
                $borderStyle,
235
                $row,
236
                $columnLengths,
237
                $alignments,
238 10
                $this->style->getCellFormat(),
239 10
                $this->style->getCellStyle(),
240 10
                $this->style->getPaddingChar(),
241
                $indentation
242
            );
243
244 10
            if ($i < $last) {
245 10
                BorderUtil::drawMiddleBorder($io, $borderStyle, $borderColumnLengths, $indentation);
246
            }
247
        }
248
249 10
        BorderUtil::drawBottomBorder($io, $borderStyle, $borderColumnLengths, $indentation);
250 10
    }
251
}
252