From 39c495f81472ebb2005236536b792705b0fd5db1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 3 Mar 2014 11:06:26 +0100 Subject: [PATCH] [Console] deprecated TableHelper in favor of Table --- UPGRADE-3.0.md | 36 ++ src/Symfony/Component/Console/CHANGELOG.md | 1 + .../Component/Console/Helper/Table.php | 391 ++++++++++++++++++ .../Component/Console/Helper/TableHelper.php | 306 ++------------ .../Component/Console/Helper/TableStyle.php | 251 +++++++++++ .../Console/Tests/Helper/TableTest.php | 325 +++++++++++++++ 6 files changed, 1034 insertions(+), 276 deletions(-) create mode 100644 src/Symfony/Component/Console/Helper/Table.php create mode 100644 src/Symfony/Component/Console/Helper/TableStyle.php create mode 100644 src/Symfony/Component/Console/Tests/Helper/TableTest.php diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index afb0600602d2..3cc8a03dd635 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -48,6 +48,42 @@ UPGRADE FROM 2.x to 3.0 } ``` + * `TableHelper` has been removed in favor of `Table`. + + Before: + + ``` + $table = $app->getHelperSet()->get('table'); + $table + ->setHeaders(array('ISBN', 'Title', 'Author')) + ->setRows(array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'), + array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'), + )) + ; + $table->render($output); + ``` + + After: + + ``` + use Symfony\Component\Console\Helper\Table; + + $table = new Table($output); + $table + ->setHeaders(array('ISBN', 'Title', 'Author')) + ->setRows(array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'), + array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'), + )) + ; + $table->render(); + ``` + ### EventDispatcher * The interface `Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface` diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 00bb1303838f..30969e8b7cd0 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 2.5.0 ----- + * deprecated TableHelper in favor of Table * deprecated ProgressHelper in favor of ProgressBar * added a way to set a default command instead of `ListCommand` * added a way to set the process name of a command diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php new file mode 100644 index 000000000000..033a833bded8 --- /dev/null +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -0,0 +1,391 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Provides helpers to display a table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + */ +class Table +{ + /** + * Table headers. + * + * @var array + */ + private $headers = array(); + + /** + * Table rows. + * + * @var array + */ + private $rows = array(); + + /** + * Column widths cache. + * + * @var array + */ + private $columnWidths = array(); + + /** + * Number of columns cache. + * + * @var array + */ + private $numberOfColumns; + + /** + * @var OutputInterface + */ + private $output; + + /** + * @var TableStyle + */ + private $style; + + private static $styles; + + public function __construct(OutputInterface $output) + { + $this->output = $output; + + if (!self::$styles) { + self::$styles = self::initStyles(); + } + + $this->setStyle('default'); + } + + /** + * Sets a style definition. + * + * @param string $name The style name + * @param TableStyle $style A TableStyle instance + */ + public static function setStyleDefinition($name, TableStyle $style) + { + if (!self::$styles) { + self::$styles = self::initStyles(); + } + + self::$styles[$name] = $style; + } + + /** + * Gets a style definition by name. + * + * @param string $name The style name + * + * @return TableStyle A TableStyle instance + */ + public static function getStyleDefinition($name) + { + if (!self::$styles) { + self::$styles = self::initStyles(); + } + + if (!self::$styles[$name]) { + throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + } + + return self::$styles[$name]; + } + + /** + * Sets table style. + * + * @param string $name The style name + * + * @return Table + */ + public function setStyle($name) + { + if (isset(self::$styles[$name])) { + $this->style = self::$styles[$name]; + + return $this; + } + + throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + } + + /** + * Gets the current table style. + * + * @return TableStyle + */ + public function getStyle() + { + return $this->style; + } + + public function setHeaders(array $headers) + { + $this->headers = array_values($headers); + + return $this; + } + + public function setRows(array $rows) + { + $this->rows = array(); + + return $this->addRows($rows); + } + + public function addRows(array $rows) + { + foreach ($rows as $row) { + $this->addRow($row); + } + + return $this; + } + + public function addRow(array $row) + { + $this->rows[] = array_values($row); + + $keys = array_keys($this->rows); + $rowKey = array_pop($keys); + + foreach ($row as $key => $cellValue) { + if (!strstr($cellValue, "\n")) { + continue; + } + + $lines = explode("\n", $cellValue); + $this->rows[$rowKey][$key] = $lines[0]; + unset($lines[0]); + + foreach ($lines as $lineKey => $line) { + $nextRowKey = $rowKey + $lineKey + 1; + + if (isset($this->rows[$nextRowKey])) { + $this->rows[$nextRowKey][$key] = $line; + } else { + $this->rows[$nextRowKey] = array($key => $line); + } + } + } + + return $this; + } + + public function setRow($column, array $row) + { + $this->rows[$column] = $row; + + return $this; + } + + /** + * Renders table to output. + * + * Example: + * +---------------+-----------------------+------------------+ + * | ISBN | Title | Author | + * +---------------+-----------------------+------------------+ + * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | + * +---------------+-----------------------+------------------+ + * + * @param OutputInterface $output + */ + public function render() + { + $this->renderRowSeparator(); + $this->renderRow($this->headers, $this->style->getCellHeaderFormat()); + if (!empty($this->headers)) { + $this->renderRowSeparator(); + } + foreach ($this->rows as $row) { + $this->renderRow($row, $this->style->getCellRowFormat()); + } + if (!empty($this->rows)) { + $this->renderRowSeparator(); + } + + $this->cleanup(); + } + + /** + * Renders horizontal header separator. + * + * Example: +-----+-----------+-------+ + */ + private function renderRowSeparator() + { + if (0 === $count = $this->getNumberOfColumns()) { + return; + } + + if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) { + return; + } + + $markup = $this->style->getCrossingChar(); + for ($column = 0; $column < $count; $column++) { + $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->getColumnWidth($column)).$this->style->getCrossingChar(); + } + + $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); + } + + /** + * Renders vertical column separator. + */ + private function renderColumnSeparator() + { + $this->output->write(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar())); + } + + /** + * Renders table row. + * + * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * + * @param array $row + * @param string $cellFormat + */ + private function renderRow(array $row, $cellFormat) + { + if (empty($row)) { + return; + } + + $this->renderColumnSeparator(); + for ($column = 0, $count = $this->getNumberOfColumns(); $column < $count; $column++) { + $this->renderCell($row, $column, $cellFormat); + $this->renderColumnSeparator(); + } + $this->output->writeln(''); + } + + /** + * Renders table cell with padding. + * + * @param array $row + * @param integer $column + * @param string $cellFormat + */ + private function renderCell(array $row, $column, $cellFormat) + { + $cell = isset($row[$column]) ? $row[$column] : ''; + $width = $this->getColumnWidth($column); + + // str_pad won't work properly with multi-byte strings, we need to fix the padding + if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($cell)) { + $width += strlen($cell) - mb_strlen($cell, $encoding); + } + + $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); + + $content = sprintf($this->style->getCellRowContentFormat(), $cell); + + $this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType()))); + } + + /** + * Gets number of columns for this table. + * + * @return integer + */ + private function getNumberOfColumns() + { + if (null !== $this->numberOfColumns) { + return $this->numberOfColumns; + } + + $columns = array(count($this->headers)); + foreach ($this->rows as $row) { + $columns[] = count($row); + } + + return $this->numberOfColumns = max($columns); + } + + /** + * Gets column width. + * + * @param integer $column + * + * @return integer + */ + private function getColumnWidth($column) + { + if (isset($this->columnWidths[$column])) { + return $this->columnWidths[$column]; + } + + $lengths = array($this->getCellWidth($this->headers, $column)); + foreach ($this->rows as $row) { + $lengths[] = $this->getCellWidth($row, $column); + } + + return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2; + } + + /** + * Gets cell width. + * + * @param array $row + * @param integer $column + * + * @return integer + */ + private function getCellWidth(array $row, $column) + { + return isset($row[$column]) ? Helper::strlenWithoutDecoration($this->output->getFormatter(), $row[$column]) : 0; + } + + /** + * Called after rendering to cleanup cache data. + */ + private function cleanup() + { + $this->columnWidths = array(); + $this->numberOfColumns = null; + } + + private static function initStyles() + { + $borderless = new TableStyle(); + $borderless + ->setHorizontalBorderChar('=') + ->setVerticalBorderChar(' ') + ->setCrossingChar(' ') + ; + + $compact = new TableStyle(); + $compact + ->setHorizontalBorderChar('') + ->setVerticalBorderChar(' ') + ->setCrossingChar('') + ->setCellRowContentFormat('%s') + ; + + return array( + 'default' => new TableStyle(), + 'borderless' => $borderless, + 'compact' => $compact, + ); + } +} diff --git a/src/Symfony/Component/Console/Helper/TableHelper.php b/src/Symfony/Component/Console/Helper/TableHelper.php index 36237c8323b5..30ec870197ca 100644 --- a/src/Symfony/Component/Console/Helper/TableHelper.php +++ b/src/Symfony/Component/Console/Helper/TableHelper.php @@ -12,12 +12,15 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Output\OutputInterface; -use InvalidArgumentException; +use Symfony\Component\Console\Output\NullOutput; /** * Provides helpers to display table output. * * @author Саша Стаменковић + * @author Fabien Potencier + * + * @deprecated Deprecated since 2.5, to be removed in 3.0; use Table instead. */ class TableHelper extends Helper { @@ -26,52 +29,13 @@ class TableHelper extends Helper const LAYOUT_COMPACT = 2; /** - * Table headers. - * - * @var array - */ - private $headers = array(); - - /** - * Table rows. - * - * @var array + * @var Table */ - private $rows = array(); - - // Rendering options - private $paddingChar; - private $horizontalBorderChar; - private $verticalBorderChar; - private $crossingChar; - private $cellHeaderFormat; - private $cellRowFormat; - private $cellRowContentFormat; - private $borderFormat; - private $padType; - - /** - * Column widths cache. - * - * @var array - */ - private $columnWidths = array(); - - /** - * Number of columns cache. - * - * @var array - */ - private $numberOfColumns; - - /** - * @var OutputInterface - */ - private $output; + private $table; public function __construct() { - $this->setLayout(self::LAYOUT_DEFAULT); + $this->table = new Table(new NullOutput()); } /** @@ -85,49 +49,19 @@ public function setLayout($layout) { switch ($layout) { case self::LAYOUT_BORDERLESS: - $this - ->setPaddingChar(' ') - ->setHorizontalBorderChar('=') - ->setVerticalBorderChar(' ') - ->setCrossingChar(' ') - ->setCellHeaderFormat('%s') - ->setCellRowFormat('%s') - ->setCellRowContentFormat(' %s ') - ->setBorderFormat('%s') - ->setPadType(STR_PAD_RIGHT) - ; + $this->table->setStyle('borderless'); break; case self::LAYOUT_COMPACT: - $this - ->setPaddingChar(' ') - ->setHorizontalBorderChar('') - ->setVerticalBorderChar(' ') - ->setCrossingChar('') - ->setCellHeaderFormat('%s') - ->setCellRowFormat('%s') - ->setCellRowContentFormat('%s') - ->setBorderFormat('%s') - ->setPadType(STR_PAD_RIGHT) - ; + $this->table->setStyle('compact'); break; case self::LAYOUT_DEFAULT: - $this - ->setPaddingChar(' ') - ->setHorizontalBorderChar('-') - ->setVerticalBorderChar('|') - ->setCrossingChar('+') - ->setCellHeaderFormat('%s') - ->setCellRowFormat('%s') - ->setCellRowContentFormat(' %s ') - ->setBorderFormat('%s') - ->setPadType(STR_PAD_RIGHT) - ; + $this->table->setStyle('default'); break; default: - throw new InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout)); + throw new \InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout)); break; }; @@ -136,60 +70,35 @@ public function setLayout($layout) public function setHeaders(array $headers) { - $this->headers = array_values($headers); + $this->table->setHeaders($headers); return $this; } public function setRows(array $rows) { - $this->rows = array(); + $this->table->setRows($rows); - return $this->addRows($rows); + return $this; } public function addRows(array $rows) { - foreach ($rows as $row) { - $this->addRow($row); - } + $this->table->addRows($rows); return $this; } public function addRow(array $row) { - $this->rows[] = array_values($row); - - $keys = array_keys($this->rows); - $rowKey = array_pop($keys); - - foreach ($row as $key => $cellValue) { - if (!strstr($cellValue, "\n")) { - continue; - } - - $lines = explode("\n", $cellValue); - $this->rows[$rowKey][$key] = $lines[0]; - unset($lines[0]); - - foreach ($lines as $lineKey => $line) { - $nextRowKey = $rowKey + $lineKey + 1; - - if (isset($this->rows[$nextRowKey])) { - $this->rows[$nextRowKey][$key] = $line; - } else { - $this->rows[$nextRowKey] = array($key => $line); - } - } - } + $this->table->addRow($row); return $this; } public function setRow($column, array $row) { - $this->rows[$column] = $row; + $this->table->setRow($column, $row); return $this; } @@ -203,11 +112,7 @@ public function setRow($column, array $row) */ public function setPaddingChar($paddingChar) { - if (!$paddingChar) { - throw new \LogicException('The padding char must not be empty'); - } - - $this->paddingChar = $paddingChar; + $this->table->getStyle()->setPaddingChar($paddingChar); return $this; } @@ -221,7 +126,7 @@ public function setPaddingChar($paddingChar) */ public function setHorizontalBorderChar($horizontalBorderChar) { - $this->horizontalBorderChar = $horizontalBorderChar; + $this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar); return $this; } @@ -235,7 +140,7 @@ public function setHorizontalBorderChar($horizontalBorderChar) */ public function setVerticalBorderChar($verticalBorderChar) { - $this->verticalBorderChar = $verticalBorderChar; + $this->table->getStyle()->setVerticalBorderChar($verticalBorderChar); return $this; } @@ -249,7 +154,7 @@ public function setVerticalBorderChar($verticalBorderChar) */ public function setCrossingChar($crossingChar) { - $this->crossingChar = $crossingChar; + $this->table->getStyle()->setCrossingChar($crossingChar); return $this; } @@ -263,7 +168,7 @@ public function setCrossingChar($crossingChar) */ public function setCellHeaderFormat($cellHeaderFormat) { - $this->cellHeaderFormat = $cellHeaderFormat; + $this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat); return $this; } @@ -277,7 +182,7 @@ public function setCellHeaderFormat($cellHeaderFormat) */ public function setCellRowFormat($cellRowFormat) { - $this->cellRowFormat = $cellRowFormat; + $this->table->getStyle()->setCellHeaderFormat($cellRowFormat); return $this; } @@ -291,7 +196,7 @@ public function setCellRowFormat($cellRowFormat) */ public function setCellRowContentFormat($cellRowContentFormat) { - $this->cellRowContentFormat = $cellRowContentFormat; + $this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat); return $this; } @@ -305,7 +210,7 @@ public function setCellRowContentFormat($cellRowContentFormat) */ public function setBorderFormat($borderFormat) { - $this->borderFormat = $borderFormat; + $this->table->getStyle()->setBorderFormat($borderFormat); return $this; } @@ -319,7 +224,7 @@ public function setBorderFormat($borderFormat) */ public function setPadType($padType) { - $this->padType = $padType; + $this->table->getStyle()->setPadType($padType); return $this; } @@ -340,162 +245,11 @@ public function setPadType($padType) */ public function render(OutputInterface $output) { - $this->output = $output; - - $this->renderRowSeparator(); - $this->renderRow($this->headers, $this->cellHeaderFormat); - if (!empty($this->headers)) { - $this->renderRowSeparator(); - } - foreach ($this->rows as $row) { - $this->renderRow($row, $this->cellRowFormat); - } - if (!empty($this->rows)) { - $this->renderRowSeparator(); - } - - $this->cleanup(); - } - - /** - * Renders horizontal header separator. - * - * Example: +-----+-----------+-------+ - */ - private function renderRowSeparator() - { - if (0 === $count = $this->getNumberOfColumns()) { - return; - } - - if (!$this->horizontalBorderChar && !$this->crossingChar) { - return; - } - - $markup = $this->crossingChar; - for ($column = 0; $column < $count; $column++) { - $markup .= str_repeat($this->horizontalBorderChar, $this->getColumnWidth($column)).$this->crossingChar; - } + $p = new \ReflectionProperty($this->table, 'output'); + $p->setAccessible(true); + $p->setValue($this->table, $output); - $this->output->writeln(sprintf($this->borderFormat, $markup)); - } - - /** - * Renders vertical column separator. - */ - private function renderColumnSeparator() - { - $this->output->write(sprintf($this->borderFormat, $this->verticalBorderChar)); - } - - /** - * Renders table row. - * - * Example: | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | - * - * @param array $row - * @param string $cellFormat - */ - private function renderRow(array $row, $cellFormat) - { - if (empty($row)) { - return; - } - - $this->renderColumnSeparator(); - for ($column = 0, $count = $this->getNumberOfColumns(); $column < $count; $column++) { - $this->renderCell($row, $column, $cellFormat); - $this->renderColumnSeparator(); - } - $this->output->writeln(''); - } - - /** - * Renders table cell with padding. - * - * @param array $row - * @param integer $column - * @param string $cellFormat - */ - private function renderCell(array $row, $column, $cellFormat) - { - $cell = isset($row[$column]) ? $row[$column] : ''; - $width = $this->getColumnWidth($column); - - // str_pad won't work properly with multi-byte strings, we need to fix the padding - if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($cell)) { - $width += strlen($cell) - mb_strlen($cell, $encoding); - } - - $width += $this->strlen($cell) - self::strlenWithoutDecoration($this->output->getFormatter(), $cell); - - $content = sprintf($this->cellRowContentFormat, $cell); - - $this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->paddingChar, $this->padType))); - } - - /** - * Gets number of columns for this table. - * - * @return int - */ - private function getNumberOfColumns() - { - if (null !== $this->numberOfColumns) { - return $this->numberOfColumns; - } - - $columns = array(0); - $columns[] = count($this->headers); - foreach ($this->rows as $row) { - $columns[] = count($row); - } - - return $this->numberOfColumns = max($columns); - } - - /** - * Gets column width. - * - * @param integer $column - * - * @return int - */ - private function getColumnWidth($column) - { - if (isset($this->columnWidths[$column])) { - return $this->columnWidths[$column]; - } - - $lengths = array(0); - $lengths[] = $this->getCellWidth($this->headers, $column); - foreach ($this->rows as $row) { - $lengths[] = $this->getCellWidth($row, $column); - } - - return $this->columnWidths[$column] = max($lengths) + strlen($this->cellRowContentFormat) - 2; - } - - /** - * Gets cell width. - * - * @param array $row - * @param integer $column - * - * @return int - */ - private function getCellWidth(array $row, $column) - { - return isset($row[$column]) ? self::strlenWithoutDecoration($this->output->getFormatter(), $row[$column]) : 0; - } - - /** - * Called after rendering to cleanup cache data. - */ - private function cleanup() - { - $this->columnWidths = array(); - $this->numberOfColumns = null; + $this->table->render(); } /** diff --git a/src/Symfony/Component/Console/Helper/TableStyle.php b/src/Symfony/Component/Console/Helper/TableStyle.php new file mode 100644 index 000000000000..179749a4cd14 --- /dev/null +++ b/src/Symfony/Component/Console/Helper/TableStyle.php @@ -0,0 +1,251 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * Defines the styles for a Table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + */ +class TableStyle +{ + private $paddingChar = ' '; + private $horizontalBorderChar = '-'; + private $verticalBorderChar = '|'; + private $crossingChar = '+'; + private $cellHeaderFormat = '%s'; + private $cellRowFormat = '%s'; + private $cellRowContentFormat = ' %s '; + private $borderFormat = '%s'; + private $padType = STR_PAD_RIGHT; + + /** + * Sets padding character, used for cell padding. + * + * @param string $paddingChar + * + * @return TableStyle + */ + public function setPaddingChar($paddingChar) + { + if (!$paddingChar) { + throw new \LogicException('The padding char must not be empty'); + } + + $this->paddingChar = $paddingChar; + + return $this; + } + + /** + * Gets padding character, used for cell padding. + * + * @return string + */ + public function getPaddingChar() + { + return $this->paddingChar; + } + + /** + * Sets horizontal border character. + * + * @param string $horizontalBorderChar + * + * @return TableStyle + */ + public function setHorizontalBorderChar($horizontalBorderChar) + { + $this->horizontalBorderChar = $horizontalBorderChar; + + return $this; + } + + /** + * Gets horizontal border character. + * + * @return string + */ + public function getHorizontalBorderChar() + { + return $this->horizontalBorderChar; + } + + /** + * Sets vertical border character. + * + * @param string $verticalBorderChar + * + * @return TableStyle + */ + public function setVerticalBorderChar($verticalBorderChar) + { + $this->verticalBorderChar = $verticalBorderChar; + + return $this; + } + + /** + * Gets vertical border character. + * + * @return string + */ + public function getVerticalBorderChar() + { + return $this->verticalBorderChar; + } + + /** + * Sets crossing character. + * + * @param string $crossingChar + * + * @return TableStyle + */ + public function setCrossingChar($crossingChar) + { + $this->crossingChar = $crossingChar; + + return $this; + } + + /** + * Gets crossing character. + * + * @return string $crossingChar + */ + public function getCrossingChar() + { + return $this->crossingChar; + } + + /** + * Sets header cell format. + * + * @param string $cellHeaderFormat + * + * @return TableStyle + */ + public function setCellHeaderFormat($cellHeaderFormat) + { + $this->cellHeaderFormat = $cellHeaderFormat; + + return $this; + } + + /** + * Gets header cell format. + * + * @return string + */ + public function getCellHeaderFormat() + { + return $this->cellHeaderFormat; + } + + /** + * Sets row cell format. + * + * @param string $cellRowFormat + * + * @return TableStyle + */ + public function setCellRowFormat($cellRowFormat) + { + $this->cellRowFormat = $cellRowFormat; + + return $this; + } + + /** + * Gets row cell format. + * + * @return string + */ + public function getCellRowFormat() + { + return $this->cellRowFormat; + } + + /** + * Sets row cell content format. + * + * @param string $cellRowContentFormat + * + * @return TableStyle + */ + public function setCellRowContentFormat($cellRowContentFormat) + { + $this->cellRowContentFormat = $cellRowContentFormat; + + return $this; + } + + /** + * Gets row cell content format. + * + * @return string + */ + public function getCellRowContentFormat() + { + return $this->cellRowContentFormat; + } + + /** + * Sets table border format. + * + * @param string $borderFormat + * + * @return TableStyle + */ + public function setBorderFormat($borderFormat) + { + $this->borderFormat = $borderFormat; + + return $this; + } + + /** + * Gets table border format. + * + * @return string + */ + public function getBorderFormat() + { + return $this->borderFormat; + } + + /** + * Sets cell padding type. + * + * @param integer $padType STR_PAD_* + * + * @return TableStyle + */ + public function setPadType($padType) + { + $this->padType = $padType; + + return $this; + } + + /** + * Gets cell padding type. + * + * @param integer + */ + public function getPadType() + { + return $this->padType; + } +} diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php new file mode 100644 index 000000000000..c73f25c357a0 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -0,0 +1,325 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\TableStyle; +use Symfony\Component\Console\Output\StreamOutput; + +class TableTest extends \PHPUnit_Framework_TestCase +{ + protected $stream; + + protected function setUp() + { + $this->stream = fopen('php://memory', 'r+'); + } + + protected function tearDown() + { + fclose($this->stream); + $this->stream = null; + } + + /** + * @dataProvider testRenderProvider + */ + public function testRender($headers, $rows, $style, $expected) + { + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders($headers) + ->setRows($rows) + ->setStyle($style) + ; + $table->render(); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + /** + * @dataProvider testRenderProvider + */ + public function testRenderAddRows($headers, $rows, $style, $expected) + { + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders($headers) + ->addRows($rows) + ->setStyle($style) + ; + $table->render(); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + /** + * @dataProvider testRenderProvider + */ + public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected) + { + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders($headers) + ->setStyle($style) + ; + foreach ($rows as $row) { + $table->addRow($row); + } + $table->render(); + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + public function testRenderProvider() + { + $books = array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + array('960-425-059-0', 'The Lord of the Rings', 'J. R. R. Tolkien'), + array('80-902734-1-6', 'And Then There Were None', 'Agatha Christie'), + ); + + return array( + array( + array('ISBN', 'Title', 'Author'), + $books, + 'default', +<< array( + array('ISBN', 'Title', 'Author'), + array( + array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + ), + 'default', +<<
array( + array('ISBN', 'Title', 'Author'), + array( + array('99921-58-10-700', 'Divine Com', 'Dante Alighieri'), + array('9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'), + ), + 'default', +<<
99921-58-10-700 | Divine Com | Dante Alighieri | +| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | ++----------------------------------+----------------------+-----------------+ + +TABLE + ), + ); + } + + public function testRenderMultiByte() + { + if (!function_exists('mb_strlen')) { + $this->markTestSkipped('The "mbstring" extension is not available'); + } + + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders(array('■■')) + ->setRows(array(array(1234))) + ->setStyle('default') + ; + $table->render(); + + $expected = +<<
assertEquals($expected, $this->getOutputContent($output)); + } + + public function testStyle() + { + $style = new TableStyle(); + $style + ->setHorizontalBorderChar('.') + ->setVerticalBorderChar('.') + ->setCrossingChar('.') + ; + + Table::setStyleDefinition('dotfull', $style); + $table = new Table($output = $this->getOutputStream()); + $table + ->setHeaders(array('Foo')) + ->setRows(array(array('Bar'))) + ->setStyle('dotfull'); + $table->render(); + + $expected = +<<
assertEquals($expected, $this->getOutputContent($output)); + } + + protected function getOutputStream() + { + return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false); + } + + protected function getOutputContent(StreamOutput $output) + { + rewind($output->getStream()); + + return str_replace(PHP_EOL, "\n", stream_get_contents($output->getStream())); + } +}