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 3339debe5d..c268f5f030 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);