GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( c8c0ea...290e03 )
by Robert
16:34
created

Table::setListPrefix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @link https://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license https://www.yiiframework.com/license/
6
 */
7
8
namespace yii\console\widgets;
9
10
use Yii;
11
use yii\base\Widget;
12
use yii\helpers\ArrayHelper;
13
use yii\helpers\Console;
14
15
/**
16
 * Table class displays a table in console.
17
 *
18
 * For example,
19
 *
20
 * ```php
21
 * $table = new Table();
22
 *
23
 * echo $table
24
 *     ->setHeaders(['test1', 'test2', 'test3'])
25
 *     ->setRows([
26
 *         ['col1', 'col2', 'col3'],
27
 *         ['col1', 'col2', ['col3-0', 'col3-1', 'col3-2']],
28
 *     ])
29
 *     ->run();
30
 * ```
31
 *
32
 * or
33
 *
34
 * ```php
35
 * echo Table::widget([
36
 *     'headers' => ['test1', 'test2', 'test3'],
37
 *     'rows' => [
38
 *         ['col1', 'col2', 'col3'],
39
 *         ['col1', 'col2', ['col3-0', 'col3-1', 'col3-2']],
40
 *     ],
41
 * ]);
42
 *
43
 * @property-write string $listPrefix List prefix.
44
 * @property-write int $screenWidth Screen width.
45
 *
46
 * @author Daniel Gomez Pan <[email protected]>
47
 * @since 2.0.13
48
 */
49
class Table extends Widget
50
{
51
    const DEFAULT_CONSOLE_SCREEN_WIDTH = 120;
52
    const CONSOLE_SCROLLBAR_OFFSET = 3;
53
    const CHAR_TOP = 'top';
54
    const CHAR_TOP_MID = 'top-mid';
55
    const CHAR_TOP_LEFT = 'top-left';
56
    const CHAR_TOP_RIGHT = 'top-right';
57
    const CHAR_BOTTOM = 'bottom';
58
    const CHAR_BOTTOM_MID = 'bottom-mid';
59
    const CHAR_BOTTOM_LEFT = 'bottom-left';
60
    const CHAR_BOTTOM_RIGHT = 'bottom-right';
61
    const CHAR_LEFT = 'left';
62
    const CHAR_LEFT_MID = 'left-mid';
63
    const CHAR_MID = 'mid';
64
    const CHAR_MID_MID = 'mid-mid';
65
    const CHAR_RIGHT = 'right';
66
    const CHAR_RIGHT_MID = 'right-mid';
67
    const CHAR_MIDDLE = 'middle';
68
69
    /**
70
     * @var array table headers
71
     * @since 2.0.19
72
     */
73
    protected $headers = [];
74
    /**
75
     * @var array table rows
76
     * @since 2.0.19
77
     */
78
    protected $rows = [];
79
    /**
80
     * @var array table chars
81
     * @since 2.0.19
82
     */
83
    protected $chars = [
84
        self::CHAR_TOP => '═',
85
        self::CHAR_TOP_MID => '╤',
86
        self::CHAR_TOP_LEFT => '╔',
87
        self::CHAR_TOP_RIGHT => '╗',
88
        self::CHAR_BOTTOM => '═',
89
        self::CHAR_BOTTOM_MID => '╧',
90
        self::CHAR_BOTTOM_LEFT => '╚',
91
        self::CHAR_BOTTOM_RIGHT => '╝',
92
        self::CHAR_LEFT => '║',
93
        self::CHAR_LEFT_MID => '╟',
94
        self::CHAR_MID => '─',
95
        self::CHAR_MID_MID => '┼',
96
        self::CHAR_RIGHT => '║',
97
        self::CHAR_RIGHT_MID => '╢',
98
        self::CHAR_MIDDLE => '│',
99
    ];
100
    /**
101
     * @var array table column widths
102
     * @since 2.0.19
103
     */
104
    protected $columnWidths = [];
105
    /**
106
     * @var int screen width
107
     * @since 2.0.19
108
     */
109
    protected $screenWidth;
110
    /**
111
     * @var string list prefix
112
     * @since 2.0.19
113
     */
114
    protected $listPrefix = '• ';
115
116
117
    /**
118
     * Set table headers.
119
     *
120
     * @param array $headers table headers
121
     * @return $this
122
     */
123 27
    public function setHeaders(array $headers)
124
    {
125 27
        $this->headers = array_values($headers);
126 27
        return $this;
127
    }
128
129
    /**
130
     * Set table rows.
131
     *
132
     * @param array $rows table rows
133
     * @return $this
134
     */
135 28
    public function setRows(array $rows)
136
    {
137
        $this->rows = array_map(function($row) {
138
            return array_map(function($value) {
139 27
                return empty($value) && !is_numeric($value)
140 6
                    ? ' '
141 26
                    :  (is_array($value)
142 10
                        ? array_values($value)
143 27
                        : $value);
144 27
            }, array_values($row));
145 28
        }, $rows);
146 28
        return $this;
147
    }
148
149
    /**
150
     * Set table chars.
151
     *
152
     * @param array $chars table chars
153
     * @return $this
154
     */
155 1
    public function setChars(array $chars)
156
    {
157 1
        $this->chars = $chars;
158 1
        return $this;
159
    }
160
161
    /**
162
     * Set screen width.
163
     *
164
     * @param int $width screen width
165
     * @return $this
166
     */
167 26
    public function setScreenWidth($width)
168
    {
169 26
        $this->screenWidth = $width;
170 26
        return $this;
171
    }
172
173
    /**
174
     * Set list prefix.
175
     *
176
     * @param string $listPrefix list prefix
177
     * @return $this
178
     */
179 2
    public function setListPrefix($listPrefix)
180
    {
181 2
        $this->listPrefix = $listPrefix;
182 2
        return $this;
183
    }
184
185
    /**
186
     * @return string the rendered table
187
     */
188 28
    public function run()
189
    {
190 28
        $this->calculateRowsSize();
191 28
        $headerCount = count($this->headers);
192
193 28
        $buffer = $this->renderSeparator(
194 28
            $this->chars[self::CHAR_TOP_LEFT],
195 28
            $this->chars[self::CHAR_TOP_MID],
196 28
            $this->chars[self::CHAR_TOP],
197 28
            $this->chars[self::CHAR_TOP_RIGHT]
198
        );
199
        // Header
200 28
        if ($headerCount > 0) {
201 27
            $buffer .= $this->renderRow($this->headers,
202 27
                $this->chars[self::CHAR_LEFT],
203 27
                $this->chars[self::CHAR_MIDDLE],
204 27
                $this->chars[self::CHAR_RIGHT]
205
            );
206
        }
207
208
        // Content
209 28
        foreach ($this->rows as $i => $row) {
210 27
            if ($i > 0 || $headerCount > 0) {
211 27
                $buffer .= $this->renderSeparator(
212 27
                    $this->chars[self::CHAR_LEFT_MID],
213 27
                    $this->chars[self::CHAR_MID_MID],
214 27
                    $this->chars[self::CHAR_MID],
215 27
                    $this->chars[self::CHAR_RIGHT_MID]
216
                );
217
            }
218 27
            $buffer .= $this->renderRow($row,
219 27
                $this->chars[self::CHAR_LEFT],
220 27
                $this->chars[self::CHAR_MIDDLE],
221 27
                $this->chars[self::CHAR_RIGHT]);
222
        }
223
224 28
        $buffer .= $this->renderSeparator(
225 28
            $this->chars[self::CHAR_BOTTOM_LEFT],
226 28
            $this->chars[self::CHAR_BOTTOM_MID],
227 28
            $this->chars[self::CHAR_BOTTOM],
228 28
            $this->chars[self::CHAR_BOTTOM_RIGHT]
229
        );
230
231 28
        return $buffer;
232
    }
233
234
    /**
235
     * Renders a row of data into a string.
236
     *
237
     * @param array $row row of data
238
     * @param string $spanLeft character for left border
239
     * @param string $spanMiddle character for middle border
240
     * @param string $spanRight character for right border
241
     * @return string
242
     * @see \yii\console\widgets\Table::render()
243
     */
244 28
    protected function renderRow(array $row, $spanLeft, $spanMiddle, $spanRight)
245
    {
246 28
        $size = $this->columnWidths;
247
248 28
        $buffer = '';
249 28
        $arrayPointer = [];
250 28
        $renderedChunkTexts = [];
251 28
        for ($i = 0, ($max = $this->calculateRowHeight($row)) ?: $max = 1; $i < $max; $i++) {
252 28
            $buffer .= $spanLeft . ' ';
253 28
            foreach ($size as $index => $cellSize) {
254 28
                $cell = isset($row[$index]) ? $row[$index] : null;
255 28
                $prefix = '';
256 28
                if ($index !== 0) {
257 26
                    $buffer .= $spanMiddle . ' ';
258
                }
259
260 28
                $arrayFromMultilineString = false;
261 28
                if (is_string($cell)) {
262 26
                    $cellLines = explode(PHP_EOL, $cell);
263 26
                    if (count($cellLines) > 1) {
264 2
                        $cell = $cellLines;
265 2
                        $arrayFromMultilineString = true;
266
                    }
267
                }
268
269 28
                if (is_array($cell)) {
270 12
                    if (empty($renderedChunkTexts[$index])) {
271 12
                        $renderedChunkTexts[$index] = '';
272 12
                        $start = 0;
273 12
                        $prefix = $arrayFromMultilineString ? '' : $this->listPrefix;
0 ignored issues
show
introduced by
The property listPrefix is declared write-only in yii\console\widgets\Table.
Loading history...
274 12
                        if (!isset($arrayPointer[$index])) {
275 12
                            $arrayPointer[$index] = 0;
276
                        }
277
                    } else {
278 6
                        $start = mb_strwidth($renderedChunkTexts[$index], Yii::$app->charset);
279
                    }
280 12
                    $chunk = Console::ansiColorizedSubstr(
281 12
                        $cell[$arrayPointer[$index]],
282 12
                        $start,
283 12
                        $cellSize - 2 - Console::ansiStrwidth($prefix)
284
                    );
285 12
                    $renderedChunkTexts[$index] .= Console::stripAnsiFormat($chunk);
286 12
                    $fullChunkText = Console::stripAnsiFormat($cell[$arrayPointer[$index]]);
287 12
                    if (isset($cell[$arrayPointer[$index] + 1]) && $renderedChunkTexts[$index] === $fullChunkText) {
288 11
                        $arrayPointer[$index]++;
289 12
                        $renderedChunkTexts[$index] = '';
290
                    }
291
                } else {
292 28
                    $chunk = Console::ansiColorizedSubstr($cell, ($cellSize * $i) - ($i * 2), $cellSize - 2);
293
                }
294 28
                $chunk = $prefix . $chunk;
295 28
                $repeat = $cellSize - Console::ansiStrwidth($chunk) - 1;
296 28
                $buffer .= $chunk;
297 28
                if ($repeat >= 0) {
298 28
                    $buffer .= str_repeat(' ', $repeat);
299
                }
300
            }
301 28
            $buffer .= "$spanRight\n";
302
        }
303
304 28
        return $buffer;
305
    }
306
307
    /**
308
     * Renders separator.
309
     *
310
     * @param string $spanLeft character for left border
311
     * @param string $spanMid character for middle border
312
     * @param string $spanMidMid character for middle-middle border
313
     * @param string $spanRight character for right border
314
     * @return string the generated separator row
315
     * @see \yii\console\widgets\Table::render()
316
     */
317 28
    protected function renderSeparator($spanLeft, $spanMid, $spanMidMid, $spanRight)
318
    {
319 28
        $separator = $spanLeft;
320 28
        foreach ($this->columnWidths as $index => $rowSize) {
321 28
            if ($index !== 0) {
322 26
                $separator .= $spanMid;
323
            }
324 28
            $separator .= str_repeat($spanMidMid, $rowSize);
325
        }
326 28
        $separator .= $spanRight . "\n";
327 28
        return $separator;
328
    }
329
330
    /**
331
     * Calculate the size of rows to draw anchor of columns in console.
332
     *
333
     * @see \yii\console\widgets\Table::render()
334
     */
335 28
    protected function calculateRowsSize()
336
    {
337 28
        $this->columnWidths = $columns = [];
338 28
        $totalWidth = 0;
339 28
        $screenWidth = $this->getScreenWidth() - self::CONSOLE_SCROLLBAR_OFFSET;
340
341 28
        $headerCount = count($this->headers);
342 28
        if (empty($this->rows)) {
343 1
            $rowColCount = 0;
344
        } else {
345 27
            $rowColCount = max(array_map('count', $this->rows));
346
        }
347 28
        $count = max($headerCount, $rowColCount);
348 28
        for ($i = 0; $i < $count; $i++) {
349 28
            $columns[] = ArrayHelper::getColumn($this->rows, $i);
350 28
            if ($i < $headerCount) {
351 27
                $columns[$i][] = $this->headers[$i];
352
            }
353
        }
354
355 28
        foreach ($columns as $column) {
356
            $columnWidth = max(array_map(function ($val) {
357 28
                if (is_array($val)) {
358 10
                    return max(array_map('yii\helpers\Console::ansiStrwidth', $val)) + Console::ansiStrwidth($this->listPrefix);
0 ignored issues
show
introduced by
The property listPrefix is declared write-only in yii\console\widgets\Table.
Loading history...
359
                }
360 28
                if (is_string($val)) {
361 26
                    return max(array_map('yii\helpers\Console::ansiStrwidth', explode(PHP_EOL, $val)));
362
                }
363 4
                return Console::ansiStrwidth($val);
364 28
            }, $column)) + 2;
365 28
            $this->columnWidths[] = $columnWidth;
366 28
            $totalWidth += $columnWidth;
367
        }
368
369 28
        if ($totalWidth > $screenWidth) {
370 12
            $minWidth = 3;
371 12
            $fixWidths = [];
372 12
            $relativeWidth = $screenWidth / $totalWidth;
373 12
            foreach ($this->columnWidths as $j => $width) {
374 12
                $scaledWidth = (int) ($width * $relativeWidth);
375 12
                if ($scaledWidth < $minWidth) {
376 7
                    $fixWidths[$j] = 3;
377
                }
378
            }
379
380 12
            $totalFixWidth = array_sum($fixWidths);
381 12
            $relativeWidth = ($screenWidth - $totalFixWidth) / ($totalWidth - $totalFixWidth);
382 12
            foreach ($this->columnWidths as $j => $width) {
383 12
                if (!array_key_exists($j, $fixWidths)) {
384 10
                    $this->columnWidths[$j] = (int) ($width * $relativeWidth);
385
                }
386
            }
387
        }
388 28
    }
389
390
    /**
391
     * Calculate the height of a row.
392
     *
393
     * @param array $row
394
     * @return int maximum row per cell
395
     * @see \yii\console\widgets\Table::render()
396
     */
397 28
    protected function calculateRowHeight($row)
398
    {
399
        $rowsPerCell = array_map(function ($size, $columnWidth) {
400 28
            if (is_array($columnWidth)) {
401 26
                $rows = 0;
402 26
                foreach ($columnWidth as $width) {
403 26
                    $rows +=  $size == 2 ? 0 : ceil($width / ($size - 2));
404
                }
405 26
                return $rows;
406
            }
407 5
            return $size == 2 || $columnWidth == 0 ? 0 : ceil($columnWidth / ($size - 2));
408 28
        }, $this->columnWidths, array_map(function ($val) {
409 28
            if (is_array($val)) {
410 10
                return array_map('yii\helpers\Console::ansiStrwidth', $val);
411
            }
412 28
            if (is_string($val)) {
413 26
                return array_map('yii\helpers\Console::ansiStrwidth', explode(PHP_EOL, $val));
414
            }
415 2
            return Console::ansiStrwidth($val);
416 28
        }, $row));
417 28
        return max($rowsPerCell);
418
    }
419
420
    /**
421
     * Getting screen width.
422
     * If it is not able to determine screen width, default value `123` will be set.
423
     *
424
     * @return int screen width
425
     */
426 28
    protected function getScreenWidth()
427
    {
428 28
        if (!$this->screenWidth) {
0 ignored issues
show
introduced by
The property screenWidth is declared write-only in yii\console\widgets\Table.
Loading history...
429 2
            $size = Console::getScreenSize();
430 2
            $this->screenWidth = isset($size[0])
431 2
                ? $size[0]
432
                : self::DEFAULT_CONSOLE_SCREEN_WIDTH + self::CONSOLE_SCROLLBAR_OFFSET;
433
        }
434 28
        return $this->screenWidth;
435
    }
436
}
437