2 namespace Consolidation\OutputFormatters\Formatters;
4 use Symfony\Component\Console\Output\OutputInterface;
5 use Symfony\Component\Console\Helper\Table;
6 use Symfony\Component\Console\Helper\TableStyle;
8 use Consolidation\OutputFormatters\Validate\ValidDataTypesInterface;
9 use Consolidation\OutputFormatters\Options\FormatterOptions;
10 use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
11 use Consolidation\OutputFormatters\StructuredData\TableDataInterface;
12 use Consolidation\OutputFormatters\Transformations\ReorderFields;
13 use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
14 use Consolidation\OutputFormatters\Transformations\WordWrapper;
17 * Display a table of data with the Symfony Table class.
19 * This formatter takes data of either the RowsOfFields or
20 * PropertyList data type. Tables can be rendered with the
21 * rows running either vertically (the normal orientation) or
22 * horizontally. By default, associative lists will be displayed
23 * as two columns, with the key in the first column and the
24 * value in the second column.
26 class TableFormatter implements FormatterInterface, ValidDataTypesInterface, RenderDataInterface
28 use ValidDataTypesTrait;
29 use RenderTableDataTrait;
31 protected $fieldLabels;
32 protected $defaultFields;
34 public function __construct()
38 public function validDataTypes()
42 new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\RowsOfFields'),
43 new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\PropertyList')
50 public function validate($structuredData)
52 // If the provided data was of class RowsOfFields
53 // or PropertyList, it will be converted into
54 // a TableTransformation object by the restructure call.
55 if (!$structuredData instanceof TableDataInterface) {
56 throw new IncompatibleDataException(
59 $this->validDataTypes()
62 return $structuredData;
68 public function write(OutputInterface $output, $tableTransformer, FormatterOptions $options)
72 FormatterOptions::TABLE_STYLE => 'consolidation',
73 FormatterOptions::INCLUDE_FIELD_LABELS => true,
76 $table = new Table($output);
78 static::addCustomTableStyles($table);
80 $table->setStyle($options->get(FormatterOptions::TABLE_STYLE, $defaults));
81 $isList = $tableTransformer->isList();
82 $includeHeaders = $options->get(FormatterOptions::INCLUDE_FIELD_LABELS, $defaults);
83 $listDelimiter = $options->get(FormatterOptions::LIST_DELIMITER, $defaults);
85 $headers = $tableTransformer->getHeaders();
86 $data = $tableTransformer->getTableData($includeHeaders && $isList);
89 if (!empty($headers)) {
90 array_splice($headers, 1, 0, ':');
92 $data = array_map(function ($item) {
93 array_splice($item, 1, 0, ':');
98 if ($includeHeaders && !$isList) {
99 $table->setHeaders($headers);
102 // todo: $output->getFormatter();
103 $data = $this->wrap($headers, $data, $table->getStyle(), $options);
104 $table->setRows($data);
109 * Wrap the table data
111 * @param TableStyle $tableStyle
112 * @param FormatterOptions $options
115 protected function wrap($headers, $data, TableStyle $tableStyle, FormatterOptions $options)
117 $wrapper = new WordWrapper($options->get(FormatterOptions::TERMINAL_WIDTH));
118 $wrapper->setPaddingFromStyle($tableStyle);
119 if (!empty($headers)) {
120 $headerLengths = array_map(function ($item) {
121 return strlen($item);
123 $wrapper->setMinimumWidths($headerLengths);
125 return $wrapper->wrap($data);
129 * Add our custom table style(s) to the table.
131 protected static function addCustomTableStyles($table)
133 // The 'consolidation' style is the same as the 'symfony-style-guide'
134 // style, except it maintains the colored headers used in 'default'.
135 $consolidationStyle = new TableStyle();
137 ->setHorizontalBorderChar('-')
138 ->setVerticalBorderChar(' ')
139 ->setCrossingChar(' ')
141 $table->setStyleDefinition('consolidation', $consolidationStyle);