From 6bf9eeb14ee6b4e511bc22ba87669d8e0d024473 Mon Sep 17 00:00:00 2001 From: Dany Maillard Date: Sun, 15 Apr 2018 19:52:15 +1000 Subject: [PATCH] Add title table --- .../Component/Console/Helper/Table.php | 42 +++++++++- .../Component/Console/Helper/TableStyle.php | 26 +++++++ .../Console/Tests/Helper/TableTest.php | 76 +++++++++++++++++++ 3 files changed, 141 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 54f61dc289..25b2dabceb 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -34,6 +34,9 @@ class Table private const BORDER_OUTSIDE = 0; private const BORDER_INSIDE = 1; + private $headerTitle; + private $footerTitle; + /** * Table headers. */ @@ -290,6 +293,20 @@ class Table return $this; } + public function setHeaderTitle(?string $title): self + { + $this->headerTitle = $title; + + return $this; + } + + public function setFooterTitle(?string $title): self + { + $this->footerTitle = $title; + + return $this; + } + /** * Renders table to output. * @@ -331,15 +348,17 @@ class Table } if ($isHeader || $isFirstRow) { - $this->renderRowSeparator($isFirstRow ? self::SEPARATOR_TOP_BOTTOM : self::SEPARATOR_TOP); if ($isFirstRow) { + $this->renderRowSeparator(self::SEPARATOR_TOP_BOTTOM); $isFirstRow = false; + } else { + $this->renderRowSeparator(self::SEPARATOR_TOP, $this->headerTitle, $this->style->getHeaderTitleFormat()); } } $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); } - $this->renderRowSeparator(self::SEPARATOR_BOTTOM); + $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat()); $this->cleanup(); $this->rendered = true; @@ -350,7 +369,7 @@ class Table * * Example: +-----+-----------+-------+ */ - private function renderRowSeparator(int $type = self::SEPARATOR_MID) + private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null) { if (0 === $count = $this->numberOfColumns) { return; @@ -378,6 +397,23 @@ class Table $markup .= $column === $count - 1 ? $rightChar : $midChar; } + if (null !== $title) { + $titleLength = Helper::strlenWithoutDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title)); + $markupLength = Helper::strlen($markup); + if ($titleLength > $limit = $markupLength - 4) { + $titleLength = $limit; + $formatLength = Helper::strlenWithoutDecoration($formatter, sprintf($titleFormat, '')); + $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); + } + + $titleStart = ($markupLength - $titleLength) / 2; + if (false === mb_detect_encoding($markup, null, true)) { + $markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength); + } else { + $markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength); + } + } + $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); } diff --git a/src/Symfony/Component/Console/Helper/TableStyle.php b/src/Symfony/Component/Console/Helper/TableStyle.php index a0d0b5b770..fc8eaecb80 100644 --- a/src/Symfony/Component/Console/Helper/TableStyle.php +++ b/src/Symfony/Component/Console/Helper/TableStyle.php @@ -40,6 +40,8 @@ class TableStyle private $crossingTopLeftBottomChar = '+'; private $crossingTopMidBottomChar = '+'; private $crossingTopRightBottomChar = '+'; + private $headerTitleFormat = ' %s '; + private $footerTitleFormat = ' %s '; private $cellHeaderFormat = '%s'; private $cellRowFormat = '%s'; private $cellRowContentFormat = ' %s '; @@ -429,4 +431,28 @@ class TableStyle { return $this->padType; } + + public function getHeaderTitleFormat(): string + { + return $this->headerTitleFormat; + } + + public function setHeaderTitleFormat(string $format): self + { + $this->headerTitleFormat = $format; + + return $this; + } + + public function getFooterTitleFormat(): string + { + return $this->footerTitleFormat; + } + + public function setFooterTitleFormat(string $format): self + { + $this->footerTitleFormat = $format; + + return $this; + } } diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 5d450e645b..ffce5cffc4 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -974,6 +974,82 @@ TABLE; Table::getStyleDefinition('absent'); } + /** + * @dataProvider renderSetTitle + */ + public function testSetTitle($headerTitle, $footerTitle, $style, $expected) + { + (new Table($output = $this->getOutputStream())) + ->setHeaderTitle($headerTitle) + ->setFooterTitle($footerTitle) + ->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'), + )) + ->setStyle($style) + ->render() + ; + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + public function renderSetTitle() + { + return array( + array( + 'Books', + 'Page 1/2', + 'default', + <<<'TABLE' ++---------------+----------- Books --------+------------------+ +| 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 | +| 80-902734-1-6 | And Then There Were None | Agatha Christie | ++---------------+--------- Page 1/2 -------+------------------+ + +TABLE + ), + array( + 'Books', + 'Page 1/2', + 'box', + <<<'TABLE' +┌───────────────┬─────────── Books ────────┬──────────────────┐ +│ 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 │ +│ 80-902734-1-6 │ And Then There Were None │ Agatha Christie │ +└───────────────┴───────── Page 1/2 ───────┴──────────────────┘ + +TABLE + ), + array( + 'Boooooooooooooooooooooooooooooooooooooooooooooooooooooooks', + 'Page 1/999999999999999999999999999999999999999999999999999', + 'default', + <<<'TABLE' ++- Booooooooooooooooooooooooooooooooooooooooooooooooooooo... -+ +| 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 | +| 80-902734-1-6 | And Then There Were None | Agatha Christie | ++- Page 1/99999999999999999999999999999999999999999999999... -+ + +TABLE + ), + ); + } + protected function getOutputStream($decorated = false) { return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, $decorated);