From c742a6722765735611bf62ec57e9a5204d2aa192 Mon Sep 17 00:00:00 2001 From: Greg Anderson Date: Tue, 26 Apr 2016 08:04:23 -0700 Subject: [PATCH 1/4] Add SectionsFormatter to implement --sections data format. --- src/FormatterManager.php | 1 + src/Formatters/SectionsFormatter.php | 66 ++++++++++++ src/Transformations/TableTransformation.php | 4 +- tests/testFormatters.php | 113 +++++++++++--------- 4 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 src/Formatters/SectionsFormatter.php diff --git a/src/FormatterManager.php b/src/FormatterManager.php index 0e85c53..37ad69a 100644 --- a/src/FormatterManager.php +++ b/src/FormatterManager.php @@ -25,6 +25,7 @@ public function __construct() 'list' => '\Consolidation\OutputFormatters\Formatters\ListFormatter', 'csv' => '\Consolidation\OutputFormatters\Formatters\CsvFormatter', 'table' => '\Consolidation\OutputFormatters\Formatters\TableFormatter', + 'sections' => '\Consolidation\OutputFormatters\Formatters\SectionsFormatter', ]; // Make the empty format an alias for the 'string' formatter. diff --git a/src/Formatters/SectionsFormatter.php b/src/Formatters/SectionsFormatter.php new file mode 100644 index 0000000..b9e7af9 --- /dev/null +++ b/src/Formatters/SectionsFormatter.php @@ -0,0 +1,66 @@ + $this->tableStyle, + 'include-field-labels' => true, + ]; + + $table = new Table($output); + $table->setStyle('compact'); + foreach ($tableTransformer as $rowid => $row) { + $output->writeln(''); + $output->writeln($rowid); // TODO: convert to a label + $sectionData = new AssociativeList($row); + $sectionTableTransformer = $sectionData->restructure([], $options); + $table->setRows($sectionTableTransformer->getTableData(true)); + $table->render(); + } + } +} diff --git a/src/Transformations/TableTransformation.php b/src/Transformations/TableTransformation.php index aed8fbb..24c07bc 100644 --- a/src/Transformations/TableTransformation.php +++ b/src/Transformations/TableTransformation.php @@ -37,8 +37,8 @@ public function isList() protected static function transformRows($data, $fieldLabels) { $rows = []; - foreach ($data as $row) { - $rows[] = static::transformRow($row, $fieldLabels); + foreach ($data as $rowid => $row) { + $rows[$rowid] = static::transformRow($row, $fieldLabels); } return $rows; } diff --git a/tests/testFormatters.php b/tests/testFormatters.php index ec13b1a..4447e4b 100644 --- a/tests/testFormatters.php +++ b/tests/testFormatters.php @@ -423,14 +423,13 @@ function testTableWithMissingCell() | x | | z | +-----+-----+-------+ EOT; + $this->assertFormattedOutputMatches($expected, 'table', $data); $expectedCsv = <<assertFormattedOutputMatches($expected, 'table', $data); $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data); } @@ -476,6 +475,7 @@ function testSimpleTable() | x | y | z | +-----+-----+-------+ EOT; + $this->assertFormattedOutputMatches($expected, 'table', $data); $expectedBorderless = <<assertFormattedOutputMatches($expectedBorderless, 'table', $data, ['table-style' => 'borderless']); $expectedJson = <<assertFormattedOutputMatches($expectedJson, 'json', $data); $expectedCsv = <<assertFormattedOutputMatches($expectedCsv, 'csv', $data); $expectedList = <<assertFormattedOutputMatches($expected, 'table', $data); - $this->assertFormattedOutputMatches($expectedBorderless, 'table', $data, ['table-style' => 'borderless']); - $this->assertFormattedOutputMatches($expectedJson, 'json', $data); - $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data); $this->assertFormattedOutputMatches($expectedList, 'list', $data); } @@ -550,6 +548,7 @@ function testTableWithAlternatives() | x | y | apples|oranges | +-----+---------------------------+----------------+ EOT; + $this->assertFormattedOutputMatches($expected, 'table', $data); $expectedBorderless = <<assertFormattedOutputMatches($expectedBorderless, 'table', $data, ['table-style' => 'borderless']); $expectedJson = <<assertFormattedOutputMatches($expectedJson, 'json', $data); $expectedCsv = <<assertFormattedOutputMatches($expectedCsv, 'csv', $data); $expectedList = <<assertFormattedOutputMatches($expected, 'table', $data); - $this->assertFormattedOutputMatches($expectedBorderless, 'table', $data, ['table-style' => 'borderless']); - $this->assertFormattedOutputMatches($expectedJson, 'json', $data); - $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data); $this->assertFormattedOutputMatches($expectedList, 'list', $data); } function testSimpleTableWithFieldLabels() { $data = $this->simpleTableExampleData(); + $configurationData = [ + 'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'], + ]; + $configurationDataAnnotationFormat = [ + 'field-labels' => "one: Uno\ntwo: Dos\nthree: Tres", + ]; $expected = <<assertFormattedOutputMatches($expected, 'table', $data, $configurationData); + $expectedAnnotationFormatConfigData = <<assertFormattedOutputMatches($expectedAnnotationFormatConfigData, 'table', $data, $configurationDataAnnotationFormat); $expectedWithNoFields = <<assertFormattedOutputMatches($expectedWithNoFields, 'table', $data, $configurationData, ['include-field-labels' => false]); $expectedWithReorderedFields = <<assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]); + $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]); + $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => 'San,Ichi']); + + $expectedSections = <<assertFormattedOutputMatches($expectedSections, 'sections', $data, $configurationData); $expectedJson = << ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'], - ]; - $configurationDataAnnotationFormat = [ - 'field-labels' => "one: Uno\ntwo: Dos\nthree: Tres", - ]; - $this->assertFormattedOutputMatches($expected, 'table', $data, $configurationData); - $this->assertFormattedOutputMatches($expectedAnnotationFormatConfigData, 'table', $data, $configurationDataAnnotationFormat); - $this->assertFormattedOutputMatches($expectedWithNoFields, 'table', $data, $configurationData, ['include-field-labels' => false]); - $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]); - $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]); - $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => 'San,Ichi']); $this->assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]); } @@ -697,23 +708,22 @@ function testSimpleList() | Three | carrot | +-------+--------+ EOT; + $this->assertFormattedOutputMatches($expected, 'table', $data); $expectedList = <<< EOT apple banana carrot EOT; + $this->assertFormattedOutputMatches($expectedList, 'list', $data); $expectedCsv = <<< EOT One,Two,Three apple,banana,carrot EOT; + $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data); $expectedCsvNoHeaders = 'apple,banana,carrot'; - - $this->assertFormattedOutputMatches($expected, 'table', $data); - $this->assertFormattedOutputMatches($expectedList, 'list', $data); - $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data); $this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, [], ['include-field-labels' => false]); } @@ -740,6 +750,7 @@ function testAssociativeListWithCsvCells() | Four | peaches,pumpkin pie | +-------+---------------------+ EOT; + $this->assertFormattedOutputMatches($expected, 'table', $data); $expectedList = <<< EOT apple @@ -747,17 +758,15 @@ function testAssociativeListWithCsvCells() carrot peaches,pumpkin pie EOT; + $this->assertFormattedOutputMatches($expectedList, 'list', $data); $expectedCsv = <<< EOT One,Two,Three,Four apple,"banana,plantain",carrot,"peaches,pumpkin pie" EOT; + $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data); $expectedCsvNoHeaders = 'apple,"banana,plantain",carrot,"peaches,pumpkin pie"'; - - $this->assertFormattedOutputMatches($expected, 'table', $data); - $this->assertFormattedOutputMatches($expectedList, 'list', $data); - $this->assertFormattedOutputMatches($expectedCsv, 'csv', $data); $this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, [], ['include-field-labels' => false]); } @@ -765,6 +774,9 @@ function testAssociativeListWithCsvCells() function testSimpleListWithFieldLabels() { $data = $this->simpleListExampleData(); + $configurationData = [ + 'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'], + ]; $expected = <<assertFormattedOutputMatches($expected, 'table', $data, $configurationData); $expectedWithReorderedFields = <<assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]); + $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]); $expectedJson = << ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'], - ]; - $this->assertFormattedOutputMatches($expected, 'table', $data, $configurationData); - $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['three', 'one']]); - $this->assertFormattedOutputMatches($expectedWithReorderedFields, 'table', $data, $configurationData, ['fields' => ['San', 'Ichi']]); $this->assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]); } From dd31b3fd7bc0d5bd8f01436580045a67dd5d9425 Mon Sep 17 00:00:00 2001 From: Greg Anderson Date: Tue, 26 Apr 2016 09:55:33 -0700 Subject: [PATCH 2/4] Remove dead code. --- src/Formatters/SectionsFormatter.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Formatters/SectionsFormatter.php b/src/Formatters/SectionsFormatter.php index b9e7af9..315fef9 100644 --- a/src/Formatters/SectionsFormatter.php +++ b/src/Formatters/SectionsFormatter.php @@ -47,11 +47,6 @@ public function validate($structuredData) */ public function write(OutputInterface $output, $tableTransformer, $options = []) { - $options += [ - 'table-style' => $this->tableStyle, - 'include-field-labels' => true, - ]; - $table = new Table($output); $table->setStyle('compact'); foreach ($tableTransformer as $rowid => $row) { From 76bdedf18b702dd60fe841dc871d42f8d3d618d8 Mon Sep 17 00:00:00 2001 From: Greg Anderson Date: Tue, 26 Apr 2016 10:10:31 -0700 Subject: [PATCH 3/4] Add data format test to sections formatter. --- tests/testFormatters.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/testFormatters.php b/tests/testFormatters.php index 4447e4b..222d024 100644 --- a/tests/testFormatters.php +++ b/tests/testFormatters.php @@ -459,8 +459,19 @@ protected function simpleTableExampleData() */ function testIncompatibleDataForTableFormatter() { - $data = $this->simpleTableExampleData(); - $this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'table', $data->getArrayCopy()); + $data = $this->simpleTableExampleData()->getArrayCopy(); + $this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'table', $data); + } + + /** + * @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException + * @expectedExceptionCode 1 + * @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\SectionsFormatter must be an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields. Instead, an array was provided. + */ + function testIncompatibleDataForSectionsFormatter() + { + $data = $this->simpleTableExampleData()->getArrayCopy(); + $this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'sections', $data); } function testSimpleTable() From e2894030a77172adf857941fa11c467dbb3e8d85 Mon Sep 17 00:00:00 2001 From: Greg Anderson Date: Tue, 26 Apr 2016 10:37:13 -0700 Subject: [PATCH 4/4] Add row-labels mappings to sections data output format. --- src/Formatters/SectionsFormatter.php | 3 ++- src/StructuredData/RowsOfFields.php | 4 +++- src/Transformations/TableTransformation.php | 17 ++++++++++++++++- tests/testFormatters.php | 5 +++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Formatters/SectionsFormatter.php b/src/Formatters/SectionsFormatter.php index 315fef9..2b34b49 100644 --- a/src/Formatters/SectionsFormatter.php +++ b/src/Formatters/SectionsFormatter.php @@ -50,8 +50,9 @@ public function write(OutputInterface $output, $tableTransformer, $options = []) $table = new Table($output); $table->setStyle('compact'); foreach ($tableTransformer as $rowid => $row) { + $rowLabel = $tableTransformer->getRowLabel($rowid); $output->writeln(''); - $output->writeln($rowid); // TODO: convert to a label + $output->writeln($rowLabel); // TODO: convert to a label $sectionData = new AssociativeList($row); $sectionTableTransformer = $sectionData->restructure([], $options); $table->setRows($sectionTableTransformer->getTableData(true)); diff --git a/src/StructuredData/RowsOfFields.php b/src/StructuredData/RowsOfFields.php index 1ea3239..a42ce90 100644 --- a/src/StructuredData/RowsOfFields.php +++ b/src/StructuredData/RowsOfFields.php @@ -41,7 +41,7 @@ protected function createTableTransformation($data, $configurationData, $options $reorderer = new ReorderFields(); $fieldLabels = $reorderer->reorder($options['fields'], $options['field-labels'], $data); - $tableTransformer = new TableTransformation($data, $fieldLabels); + $tableTransformer = new TableTransformation($data, $fieldLabels, $options['row-labels']); return $tableTransformer; } @@ -51,6 +51,7 @@ protected function interpretOptions($configurationData, $options) $configurationData += $this->defaultOptions(); $configurationData['field-labels'] = PropertyParser::parse($configurationData['field-labels']); + $configurationData['row-labels'] = PropertyParser::parse($configurationData['row-labels']); $configurationData['default-fields'] = PropertyParser::parse($configurationData['default-fields']); return $options + $configurationData; @@ -61,6 +62,7 @@ protected function defaultOptions() return [ 'fields' => [], 'field-labels' => [], + 'row-labels' => [], 'default-fields' => [], ]; } diff --git a/src/Transformations/TableTransformation.php b/src/Transformations/TableTransformation.php index 24c07bc..6f0fc74 100644 --- a/src/Transformations/TableTransformation.php +++ b/src/Transformations/TableTransformation.php @@ -6,14 +6,16 @@ class TableTransformation extends \ArrayObject implements TableDataInterface { protected $headers; + protected $rowLabels; protected $layout; const TABLE_LAYOUT = 'table'; const LIST_LAYOUT = 'list'; - public function __construct($data, $fieldLabels) + public function __construct($data, $fieldLabels, $rowLabels = []) { $this->headers = $fieldLabels; + $this->rowLabels = $rowLabels; $rows = static::transformRows($data, $fieldLabels); $this->layout = self::TABLE_LAYOUT; parent::__construct($rows); @@ -65,6 +67,19 @@ public function getHeader($key) return $key; } + public function getRowLabels() + { + return $this->rowLabels; + } + + public function getRowLabel($rowid) + { + if (array_key_exists($rowid, $this->rowLabels)) { + return $this->rowLabels[$rowid]; + } + return $rowid; + } + public function getData() { return $this->getArrayCopy(); diff --git a/tests/testFormatters.php b/tests/testFormatters.php index 222d024..9fb4655 100644 --- a/tests/testFormatters.php +++ b/tests/testFormatters.php @@ -613,6 +613,7 @@ function testSimpleTableWithFieldLabels() $data = $this->simpleTableExampleData(); $configurationData = [ 'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'], + 'row-labels' => ['id-123' => 'Walrus', 'id-456' => 'Carpenter'], ]; $configurationDataAnnotationFormat = [ 'field-labels' => "one: Uno\ntwo: Dos\nthree: Tres", @@ -660,12 +661,12 @@ function testSimpleTableWithFieldLabels() $expectedSections = <<