feature #17761 [Console] Add non-auto column width functionality (akeeman)

This PR was squashed before being merged into the 3.1-dev branch (closes #17761).

Discussion
----------

[Console] Add non-auto column width functionality

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        | [#6296](https://github.com/symfony/symfony-docs/pull/6296)

Be able to fix a columns width in a console table (i.e. set a columns width beforehand).
When a column's contents exceed the given column width, it will stretch.

Very useful, for instance, when one wants to display multiple tables that are separated from each other, but still want to align their columns.

Commits
-------

20c81b2 [Console] Add non-auto column width functionality
This commit is contained in:
Fabien Potencier 2016-03-01 18:31:11 +01:00
commit 7351168841
3 changed files with 114 additions and 9 deletions

View File

@ -5,6 +5,7 @@ CHANGELOG
-----
* added truncate method to FormatterHelper
* added setColumnWidth(s) method to Table
2.8.3
-----

View File

@ -43,7 +43,7 @@ class Table
*
* @var array
*/
private $columnWidths = array();
private $effectiveColumnWidths = array();
/**
* Number of columns cache.
@ -67,6 +67,13 @@ class Table
*/
private $columnStyles = array();
/**
* User set column widths.
*
* @var array
*/
private $columnWidths = array();
private static $styles;
public function __construct(OutputInterface $output)
@ -186,6 +193,38 @@ class Table
return $this->getStyle();
}
/**
* Sets the minimum width of a column.
*
* @param int $columnIndex Column index
* @param int $width Minimum column width in characters
*
* @return Table
*/
public function setColumnWidth($columnIndex, $width)
{
$this->columnWidths[intval($columnIndex)] = intval($width);
return $this;
}
/**
* Sets the minimum width of all columns.
*
* @param array $widths
*
* @return Table
*/
public function setColumnWidths(array $widths)
{
$this->columnWidths = array();
foreach ($widths as $index => $width) {
$this->setColumnWidth($index, $width);
}
return $this;
}
public function setHeaders(array $headers)
{
$headers = array_values($headers);
@ -296,7 +335,7 @@ class Table
$markup = $this->style->getCrossingChar();
for ($column = 0; $column < $count; ++$column) {
$markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->columnWidths[$column]).$this->style->getCrossingChar();
$markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->effectiveColumnWidths[$column]).$this->style->getCrossingChar();
}
$this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
@ -342,11 +381,11 @@ class Table
private function renderCell(array $row, $column, $cellFormat)
{
$cell = isset($row[$column]) ? $row[$column] : '';
$width = $this->columnWidths[$column];
$width = $this->effectiveColumnWidths[$column];
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
// add the width of the following columns(numbers of colspan).
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
$width += $this->getColumnSeparatorWidth() + $this->columnWidths[$nextColumn];
$width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
}
}
@ -572,7 +611,7 @@ class Table
$lengths[] = $this->getCellWidth($row, $column);
}
$this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
$this->effectiveColumnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
}
}
@ -596,6 +635,8 @@ class Table
*/
private function getCellWidth(array $row, $column)
{
$cellWidth = 0;
if (isset($row[$column])) {
$cell = $row[$column];
$cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
@ -603,11 +644,11 @@ class Table
// we assume that cell value will be across more than one column.
$cellWidth = $cellWidth / $cell->getColspan();
}
return $cellWidth;
}
return 0;
$columnWidth = isset($this->columnWidths[$column]) ? $this->columnWidths[$column] : 0;
return max($cellWidth, $columnWidth);
}
/**
@ -615,7 +656,7 @@ class Table
*/
private function cleanup()
{
$this->columnWidths = array();
$this->effectiveColumnWidths = array();
$this->numberOfColumns = null;
}

View File

@ -620,6 +620,69 @@ TABLE;
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 |
+---------------+----------------------+-----------------+--------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testColumnWith()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('ISBN', 'Title', 'Author', 'Price'))
->setRows(array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'),
array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'),
))
->setColumnWidth(0, 15)
->setColumnWidth(3, 10);
$style = new TableStyle();
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
$expected =
<<<TABLE
+-----------------+----------------------+-----------------+------------+
| ISBN | Title | Author | Price |
+-----------------+----------------------+-----------------+------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 |
+-----------------+----------------------+-----------------+------------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));
}
public function testColumnWiths()
{
$table = new Table($output = $this->getOutputStream());
$table
->setHeaders(array('ISBN', 'Title', 'Author', 'Price'))
->setRows(array(
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri', '9.95'),
array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens', '139.25'),
))
->setColumnWidths(array(15, 0, -1, 10));
$style = new TableStyle();
$style->setPadType(STR_PAD_LEFT);
$table->setColumnStyle(3, $style);
$table->render();
$expected =
<<<TABLE
+-----------------+----------------------+-----------------+------------+
| ISBN | Title | Author | Price |
+-----------------+----------------------+-----------------+------------+
| 99921-58-10-7 | Divine Comedy | Dante Alighieri | 9.95 |
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | 139.25 |
+-----------------+----------------------+-----------------+------------+
TABLE;
$this->assertEquals($expected, $this->getOutputContent($output));