Skip to content

Commit

Permalink
Fix #19906: Fixed multiline strings in the `\yii\console\widgets\Tabl…
Browse files Browse the repository at this point in the history
…e` widget
  • Loading branch information
rhertogh authored Jul 24, 2023
1 parent 76d6345 commit 1a0e91e
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 2 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Yii Framework 2 Change Log
- Enh #19853: Added support for default value for `\yii\helpers\Console::select()` (rhertogh)
- Bug #19868: Added whitespace sanitation for tests, due to updates in ICU 72 (schmunk42)
- Enh #19884: Added support Enums in Query Builder (sk1t0n)
- Bug #19906: Fixed multiline strings in the `\yii\console\widgets\Table` widget (rhertogh)


2.0.48.1 May 24, 2023
Expand Down
24 changes: 22 additions & 2 deletions framework/console/widgets/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,18 +252,32 @@ protected function renderRow(array $row, $spanLeft, $spanMiddle, $spanRight)
if ($index !== 0) {
$buffer .= $spanMiddle . ' ';
}

$arrayFromMultilineString = false;
if (is_string($cell)) {
$cellLines = explode(PHP_EOL, $cell);
if (count($cellLines) > 1) {
$cell = $cellLines;
$arrayFromMultilineString = true;
}
}

if (is_array($cell)) {
if (empty($renderedChunkTexts[$index])) {
$renderedChunkTexts[$index] = '';
$start = 0;
$prefix = $this->listPrefix;
$prefix = $arrayFromMultilineString ? '' : $this->listPrefix;
if (!isset($arrayPointer[$index])) {
$arrayPointer[$index] = 0;
}
} else {
$start = mb_strwidth($renderedChunkTexts[$index], Yii::$app->charset);
}
$chunk = Console::ansiColorizedSubstr($cell[$arrayPointer[$index]], $start, $cellSize - 4);
$chunk = Console::ansiColorizedSubstr(
$cell[$arrayPointer[$index]],
$start,
$cellSize - 2 - Console::ansiStrwidth($prefix)
);
$renderedChunkTexts[$index] .= Console::stripAnsiFormat($chunk);
$fullChunkText = Console::stripAnsiFormat($cell[$arrayPointer[$index]]);
if (isset($cell[$arrayPointer[$index] + 1]) && $renderedChunkTexts[$index] === $fullChunkText) {
Expand Down Expand Up @@ -339,6 +353,9 @@ protected function calculateRowsSize()
if (is_array($val)) {
return max(array_map('yii\helpers\Console::ansiStrwidth', $val)) + Console::ansiStrwidth($this->listPrefix);
}
if (is_string($val)) {
return max(array_map('yii\helpers\Console::ansiStrwidth', explode(PHP_EOL, $val)));
}
return Console::ansiStrwidth($val);
}, $column)) + 2;
$this->columnWidths[] = $columnWidth;
Expand Down Expand Up @@ -388,6 +405,9 @@ protected function calculateRowHeight($row)
if (is_array($val)) {
return array_map('yii\helpers\Console::ansiStrwidth', $val);
}
if (is_string($val)) {
return array_map('yii\helpers\Console::ansiStrwidth', explode(PHP_EOL, $val));
}
return Console::ansiStrwidth($val);
}, $row));
return max($rowsPerCell);
Expand Down
144 changes: 144 additions & 0 deletions tests/framework/console/widgets/TableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,121 @@ public function testTable($headers, $rows)
║ testcontent21 │ testcontent22 │ testcontent23 ║
╚═══════════════╧═══════════════╧═══════════════╝

EXPECTED;

$tableContent = $table
->setHeaders($headers)
->setRows($rows)
->setScreenWidth(200)
->run();
$this->assertEqualsWithoutLE($expected, $tableContent);
}

public function getMultiLineTableData()
{
return [
[
['test1', 'test2', 'test3' . PHP_EOL . 'multiline'],
[
['test' . PHP_EOL . 'content1', 'testcontent2', 'test' . PHP_EOL . 'content3'],
[
'testcontent21',
'testcontent22' . PHP_EOL
. 'loooooooooooooooooooooooooooooooooooong' . PHP_EOL
. 'content',
'testcontent23' . PHP_EOL
. 'loooooooooooooooooooooooooooooooooooong content'
],
]
],
[
['key1' => 'test1', 'key2' => 'test2', 'key3' => 'test3' . PHP_EOL . 'multiline'],
[
[
'key1' => 'test' . PHP_EOL . 'content1',
'key2' => 'testcontent2',
'key3' => 'test' . PHP_EOL . 'content3'
],
[
'key1' => 'testcontent21',
'key2' => 'testcontent22' . PHP_EOL
. 'loooooooooooooooooooooooooooooooooooong' . PHP_EOL
. 'content',
'key3' => 'testcontent23' . PHP_EOL
. 'loooooooooooooooooooooooooooooooooooong content'
],
]
]
];
}

/**
* @dataProvider getMultiLineTableData
*/
public function testMultiLineTable($headers, $rows)
{
$table = new Table();

$expected = <<<'EXPECTED'
╔═════════════╤═════════════════════════════════════╤═════════════════════════════════════════════╗
║ test1 │ test2 │ test3 ║
║ │ │ multiline ║
╟─────────────┼─────────────────────────────────────┼─────────────────────────────────────────────╢
║ test │ testcontent2 │ test ║
║ content1 │ │ content3 ║
╟─────────────┼─────────────────────────────────────┼─────────────────────────────────────────────╢
║ testcontent │ testcontent22 │ testcontent23 ║
║ 21 │ loooooooooooooooooooooooooooooooooo │ loooooooooooooooooooooooooooooooooooong con ║
║ │ oong │ tent ║
║ │ content │ ║
╚═════════════╧═════════════════════════════════════╧═════════════════════════════════════════════╝

EXPECTED;

$tableContent = $table
->setHeaders($headers)
->setRows($rows)
->setScreenWidth(100)
->run();
$this->assertEqualsWithoutLE($expected, $tableContent);
}

public function getNumericTableData()
{
return [
[
[1, 2, 3],
[
[1, 1.2, -1.3],
[-2, 2.2, 2.3],
]
],
[
['key1' => 1, 'key2' => 2, 'key3' => 3],
[
['key1' => 1, 'key2' => 1.2, 'key3' => -1.3],
['key1' => -2, 'key2' => 2.2, 'key3' => 2.3],
]
]
];
}

/**
* @dataProvider getNumericTableData
*/
public function testNumericTable($headers, $rows)
{
$table = new Table();

$expected = <<<'EXPECTED'
╔════╤═════╤══════╗
║ 1 │ 2 │ 3 ║
╟────┼─────┼──────╢
║ 1 │ 1.2 │ -1.3 ║
╟────┼─────┼──────╢
║ -2 │ 2.2 │ 2.3 ║
╚════╧═════╧══════╝

EXPECTED;

$tableContent = $table
Expand Down Expand Up @@ -141,6 +256,35 @@ public function testListPrefix()
);
}

public function testLongerListPrefix()
{
$table = new Table();

$expected = <<<'EXPECTED'
╔═════════════════════════════════╤═════════════════════════════════╤═════════════════════════════╗
║ test1 │ test2 │ test3 ║
╟─────────────────────────────────┼─────────────────────────────────┼─────────────────────────────╢
║ testcontent1 │ testcontent2 │ testcontent3 ║
╟─────────────────────────────────┼─────────────────────────────────┼─────────────────────────────╢
║ testcontent21 with looooooooooo │ testcontent22 with looooooooooo │ -- col1 with looooooooooooo ║
║ ooooooooooooong content │ ooooooooooooong content │ ooooooooooong content ║
║ │ │ -- col2 with long content ║
╚═════════════════════════════════╧═════════════════════════════════╧═════════════════════════════╝

EXPECTED;

$this->assertEqualsWithoutLE($expected, $table->setHeaders(['test1', 'test2', 'test3'])
->setRows([
['testcontent1', 'testcontent2', 'testcontent3'],
[
'testcontent21 with loooooooooooooooooooooooong content',
'testcontent22 with loooooooooooooooooooooooong content',
['col1 with loooooooooooooooooooooooong content', 'col2 with long content']
],
])->setScreenWidth(100)->setListPrefix('-- ')->run()
);
}

public function testCustomChars()
{
$table = new Table();
Expand Down

0 comments on commit 1a0e91e

Please sign in to comment.