Skip to content

Commit

Permalink
feature #17761 [Console] Add non-auto column width functionality (ake…
Browse files Browse the repository at this point in the history
…eman)

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](symfony/symfony-docs#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
  • Loading branch information
fabpot committed Mar 1, 2016
2 parents 200f109 + 2d1e5ce commit dad9b25
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CHANGELOG
-----

* added truncate method to FormatterHelper
* added setColumnWidth(s) method to Table

2.8.3
-----
Expand Down
59 changes: 50 additions & 9 deletions Helper/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Table
*
* @var array
*/
private $columnWidths = array();
private $effectiveColumnWidths = array();

/**
* Number of columns cache.
Expand All @@ -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)
Expand Down Expand Up @@ -186,6 +193,38 @@ public function getColumnStyle($columnIndex)
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);
Expand Down Expand Up @@ -296,7 +335,7 @@ private function renderRowSeparator()

$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));
Expand Down Expand Up @@ -342,11 +381,11 @@ private function renderRow(array $row, $cellFormat)
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];
}
}

Expand Down Expand Up @@ -572,7 +611,7 @@ private function calculateColumnsWidth($rows)
$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;
}
}

Expand All @@ -596,26 +635,28 @@ private function getColumnSeparatorWidth()
*/
private function getCellWidth(array $row, $column)
{
$cellWidth = 0;

if (isset($row[$column])) {
$cell = $row[$column];
$cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
// 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);
}

/**
* Called after rendering to cleanup cache data.
*/
private function cleanup()
{
$this->columnWidths = array();
$this->effectiveColumnWidths = array();
$this->numberOfColumns = null;
}

Expand Down
63 changes: 63 additions & 0 deletions Tests/Helper/TableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,69 @@ public function testColumnStyle()
| 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));
Expand Down

0 comments on commit dad9b25

Please sign in to comment.