Skip to content

Commit 8f84347

Browse files
committed
feature #32742 [Console] Added support for definition list and horizontal table (lyrixx)
This PR was merged into the 4.4 branch. Discussion ---------- [Console] Added support for definition list and horizontal table | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | | License | MIT | Doc PR | I need that in a projet where I want to display some data horizontally. Usage: ```php <?php use Symfony\Component\Console\Helper\TableSeparator; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Style\SymfonyStyle; require __DIR__.'/vendor/autoload.php'; $io = new SymfonyStyle(new ArrayInput([]), new ConsoleOutput()); $io->table(['a', 'b', 'c'], [[1, 2, 3], [4, 5, 6]]); $io->table(['a', 'b', 'c'], [[1, 2, 3], [4, 5, 6]], true); $io->definitionList( ['foo' => 'bar'], new TableSeparator(), 'this is a title', new TableSeparator(), ['foo2' => 'bar2'] ); ``` ![image](https://user-images.githubusercontent.com/408368/63788677-2df43580-c8f6-11e9-9ce6-b7abcecf7f24.png) Commits ------- 66028fe [Console] Added support for definition list
2 parents d6ac452 + 66028fe commit 8f84347

File tree

8 files changed

+210
-7
lines changed

8 files changed

+210
-7
lines changed

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* added method `preventRedrawFasterThan()` and `forceRedrawSlowerThan()` on `ProgressBar`
99
* `Application` implements `ResetInterface`
1010
* marked all dispatched event classes as `@final`
11+
* added support for displaying table horizontally
1112

1213
4.3.0
1314
-----

src/Symfony/Component/Console/Helper/Table.php

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class Table
4848
* Table rows.
4949
*/
5050
private $rows = [];
51+
private $horizontal = false;
5152

5253
/**
5354
* Column widths cache.
@@ -322,6 +323,13 @@ public function setFooterTitle(?string $title): self
322323
return $this;
323324
}
324325

326+
public function setHorizontal(bool $horizontal = true): self
327+
{
328+
$this->horizontal = $horizontal;
329+
330+
return $this;
331+
}
332+
325333
/**
326334
* Renders table to output.
327335
*
@@ -337,14 +345,35 @@ public function setFooterTitle(?string $title): self
337345
*/
338346
public function render()
339347
{
340-
$rows = array_merge($this->headers, [$divider = new TableSeparator()], $this->rows);
348+
$divider = new TableSeparator();
349+
if ($this->horizontal) {
350+
$rows = [];
351+
foreach ($this->headers[0] ?? [] as $i => $header) {
352+
$rows[$i] = [$header];
353+
foreach ($this->rows as $row) {
354+
if ($row instanceof TableSeparator) {
355+
continue;
356+
}
357+
if (isset($row[$i])) {
358+
$rows[$i][] = $row[$i];
359+
} elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) {
360+
// Noop, there is a "title"
361+
} else {
362+
$rows[$i][] = null;
363+
}
364+
}
365+
}
366+
} else {
367+
$rows = array_merge($this->headers, [$divider], $this->rows);
368+
}
369+
341370
$this->calculateNumberOfColumns($rows);
342371

343372
$rows = $this->buildTableRows($rows);
344373
$this->calculateColumnsWidth($rows);
345374

346-
$isHeader = true;
347-
$isFirstRow = false;
375+
$isHeader = !$this->horizontal;
376+
$isFirstRow = $this->horizontal;
348377
foreach ($rows as $row) {
349378
if ($divider === $row) {
350379
$isHeader = false;
@@ -369,8 +398,11 @@ public function render()
369398
$this->renderRowSeparator(self::SEPARATOR_TOP, $this->headerTitle, $this->style->getHeaderTitleFormat());
370399
}
371400
}
372-
373-
$this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
401+
if ($this->horizontal) {
402+
$this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
403+
} else {
404+
$this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
405+
}
374406
}
375407
$this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());
376408

@@ -450,13 +482,17 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE)
450482
*
451483
* | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
452484
*/
453-
private function renderRow(array $row, string $cellFormat)
485+
private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null)
454486
{
455487
$rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
456488
$columns = $this->getRowColumns($row);
457489
$last = \count($columns) - 1;
458490
foreach ($columns as $i => $column) {
459-
$rowContent .= $this->renderCell($row, $column, $cellFormat);
491+
if ($firstCellFormat && 0 === $i) {
492+
$rowContent .= $this->renderCell($row, $column, $firstCellFormat);
493+
} else {
494+
$rowContent .= $this->renderCell($row, $column, $cellFormat);
495+
}
460496
$rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
461497
}
462498
$this->output->writeln($rowContent);

src/Symfony/Component/Console/Style/SymfonyStyle.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111

1212
namespace Symfony\Component\Console\Style;
1313

14+
use Symfony\Component\Console\Exception\InvalidArgumentException;
1415
use Symfony\Component\Console\Exception\RuntimeException;
1516
use Symfony\Component\Console\Formatter\OutputFormatter;
1617
use Symfony\Component\Console\Helper\Helper;
1718
use Symfony\Component\Console\Helper\ProgressBar;
1819
use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
1920
use Symfony\Component\Console\Helper\Table;
21+
use Symfony\Component\Console\Helper\TableCell;
22+
use Symfony\Component\Console\Helper\TableSeparator;
2023
use Symfony\Component\Console\Input\InputInterface;
2124
use Symfony\Component\Console\Output\BufferedOutput;
2225
use Symfony\Component\Console\Output\OutputInterface;
@@ -190,6 +193,69 @@ public function table(array $headers, array $rows)
190193
$this->newLine();
191194
}
192195

196+
/**
197+
* Formats a horizontal table.
198+
*/
199+
public function horizontalTable(array $headers, array $rows)
200+
{
201+
$style = clone Table::getStyleDefinition('symfony-style-guide');
202+
$style->setCellHeaderFormat('<info>%s</info>');
203+
204+
$table = new Table($this);
205+
$table->setHeaders($headers);
206+
$table->setRows($rows);
207+
$table->setStyle($style);
208+
$table->setHorizontal(true);
209+
210+
$table->render();
211+
$this->newLine();
212+
}
213+
214+
/**
215+
* Formats a list of key/value horizontally.
216+
*
217+
* Each row can be one of:
218+
* * 'A title'
219+
* * ['key' => 'value']
220+
* * new TableSeparator()
221+
*
222+
* @param string|array|TableSeparator ...$list
223+
*/
224+
public function definitionList(...$list)
225+
{
226+
$style = clone Table::getStyleDefinition('symfony-style-guide');
227+
$style->setCellHeaderFormat('<info>%s</info>');
228+
229+
$table = new Table($this);
230+
$headers = [];
231+
$row = [];
232+
foreach ($list as $value) {
233+
if ($value instanceof TableSeparator) {
234+
$headers[] = $value;
235+
$row[] = $value;
236+
continue;
237+
}
238+
if (\is_string($value)) {
239+
$headers[] = new TableCell($value, ['colspan' => 2]);
240+
$row[] = null;
241+
continue;
242+
}
243+
if (!\is_array($value)) {
244+
throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');
245+
}
246+
$headers[] = key($value);
247+
$row[] = current($value);
248+
}
249+
250+
$table->setHeaders($headers);
251+
$table->setRows([$row]);
252+
$table->setHorizontal();
253+
$table->setStyle($style);
254+
255+
$table->render();
256+
$this->newLine();
257+
}
258+
193259
/**
194260
* {@inheritdoc}
195261
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
use Symfony\Component\Console\Helper\TableSeparator;
4+
use Symfony\Component\Console\Input\InputInterface;
5+
use Symfony\Component\Console\Output\OutputInterface;
6+
use Symfony\Component\Console\Style\SymfonyStyle;
7+
8+
return function (InputInterface $input, OutputInterface $output) {
9+
$output = new SymfonyStyle($input, $output);
10+
11+
$output->definitionList(
12+
['foo' => 'bar'],
13+
new TableSeparator(),
14+
'this is a title',
15+
new TableSeparator(),
16+
['foo2' => 'bar2']
17+
);
18+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
use Symfony\Component\Console\Helper\TableCell;
4+
use Symfony\Component\Console\Input\InputInterface;
5+
use Symfony\Component\Console\Output\OutputInterface;
6+
use Symfony\Component\Console\Style\SymfonyStyle;
7+
8+
//Ensure formatting tables when using multiple headers with TableCell
9+
return function (InputInterface $input, OutputInterface $output) {
10+
$output = new SymfonyStyle($input, $output);
11+
$output->horizontalTable(['a', 'b', 'c', 'd'], [[1, 2, 3], [4, 5], [7, 8, 9]]);
12+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---------- ---------
2+
foo bar
3+
---------- ---------
4+
this is a title
5+
---------- ---------
6+
foo2 bar2
7+
---------- ---------
8+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
--- --- --- ---
2+
a 1 4 7
3+
b 2 5 8
4+
c 3 9
5+
d
6+
--- --- --- ---
7+

src/Symfony/Component/Console/Tests/Helper/TableTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,61 @@ public function testBoxedStyleWithColspan()
11251125
$this->assertSame($expected, $this->getOutputContent($output));
11261126
}
11271127

1128+
public function provideRenderHorizontalTests()
1129+
{
1130+
$headers = ['foo', 'bar', 'baz'];
1131+
$rows = [['one', 'two', 'tree'], ['1', '2', '3']];
1132+
$expected = <<<EOTXT
1133+
+-----+------+---+
1134+
| foo | one | 1 |
1135+
| bar | two | 2 |
1136+
| baz | tree | 3 |
1137+
+-----+------+---+
1138+
1139+
EOTXT;
1140+
yield [$headers, $rows, $expected];
1141+
1142+
$headers = ['foo', 'bar', 'baz'];
1143+
$rows = [['one', 'two'], ['1']];
1144+
$expected = <<<EOTXT
1145+
+-----+-----+---+
1146+
| foo | one | 1 |
1147+
| bar | two | |
1148+
| baz | | |
1149+
+-----+-----+---+
1150+
1151+
EOTXT;
1152+
yield [$headers, $rows, $expected];
1153+
1154+
$headers = ['foo', 'bar', 'baz'];
1155+
$rows = [['one', 'two', 'tree'], new TableSeparator(), ['1', '2', '3']];
1156+
$expected = <<<EOTXT
1157+
+-----+------+---+
1158+
| foo | one | 1 |
1159+
| bar | two | 2 |
1160+
| baz | tree | 3 |
1161+
+-----+------+---+
1162+
1163+
EOTXT;
1164+
yield [$headers, $rows, $expected];
1165+
}
1166+
1167+
/**
1168+
* @dataProvider provideRenderHorizontalTests
1169+
*/
1170+
public function testRenderHorizontal(array $headers, array $rows, string $expected)
1171+
{
1172+
$table = new Table($output = $this->getOutputStream());
1173+
$table
1174+
->setHeaders($headers)
1175+
->setRows($rows)
1176+
->setHorizontal()
1177+
;
1178+
$table->render();
1179+
1180+
$this->assertEquals($expected, $this->getOutputContent($output));
1181+
}
1182+
11281183
protected function getOutputStream($decorated = false)
11291184
{
11301185
return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, $decorated);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy