PK 4AVjӢ phpunit.xml.distnu W+A
tests
src
FormatterInterface.php.php
OverrideRestructureInterface.php.php
RestructureInterface.php.php
ValidationInterface.php
Formatters/RenderDataInterface.php
StructuredData/ListDataInterface.php.php
StructuredData/RenderCellInterface.php.php
StructuredData/TableDataInterface.php.php
PK 4AVƻ
.editorconfignu W+A # This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[**.php]
indent_style = space
indent_size = 4
PK 4AV1 1 LICENSEnu W+A Copyright (c) 2016 Consolidation Org Developers
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
PK 4AV4so9 9 CONTRIBUTING.mdnu W+A # Contributing to Consolidation
Thank you for your interest in contributing to the Consolidation effort! Consolidation aims to provide reusable, loosely-coupled components useful for building command-line tools. Consolidation is built on top of Symfony Console, but aims to separate the tool from the implementation details of Symfony.
Here are some of the guidelines you should follow to make the most of your efforts:
## Code Style Guidelines
Consolidation adheres to the [PSR-2 Coding Style Guide](http://www.php-fig.org/psr/psr-2/) for PHP code.
## Pull Request Guidelines
Every pull request is run through:
- phpcs -n --standard=PSR2 src
- phpunit
- [Scrutinizer](https://scrutinizer-ci.com/g/consolidation-org/annotation-command/)
It is easy to run the unit tests and code sniffer locally; simply ensure that `./vendor/bin` is in your `$PATH`, cd to the root of the project directory, and run `phpcs` and `phpunit` as shown above. To automatically fix coding standard errors, run:
- phpcbf --standard=PSR2 src
After submitting a pull request, please examine the Scrutinizer report. It is not required to fix all Scrutinizer issues; you may ignore recommendations that you disagree with. The spacing patches produced by Scrutinizer do not conform to PSR2 standards, and therefore should never be applied. DocBlock patches may be applied at your discression. Things that Scrutinizer identifies as a bug nearly always needs to be addressed.
Pull requests must pass phpcs and phpunit in order to be merged; ideally, new functionality will also include new unit tests.
PK 4AV~ .travis.ymlnu W+A language: php
branches:
# Only test the master branch and SemVer tags.
only:
- master
- /^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+.*$/
php:
- 5.4
- 5.5
- 5.6
- 7.0
sudo: false
cache:
directories:
- vendor
- $HOME/.composer/cache
before_script:
- composer install
script:
- vendor/bin/phpcs --standard=PSR2 -n src
- vendor/bin/phpunit
after_success:
- travis_retry php vendor/bin/coveralls -v
PK 4AV`>R R
composer.jsonnu W+A {
"name": "consolidation/output-formatters",
"description": "Format text by applying transformations provided by plug-in formatters.",
"license": "MIT",
"authors": [
{
"name": "Greg Anderson",
"email": "greg.1.anderson@greenknowe.org"
}
],
"autoload":{
"psr-4":{
"Consolidation\\OutputFormatters\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Consolidation\\TestUtils\\": "tests/src"
}
},
"require": {
"php": ">=5.4.0",
"symfony/console": "~2.5|~3.0"
},
"require-dev": {
"phpunit/phpunit": "4.*",
"satooshi/php-coveralls": "^1.0",
"squizlabs/php_codesniffer": "2.*"
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
}
}
PK 4AV~i tests/testFormatterOptions.phpnu W+A bind($definition);
return $input;
}
public function testFormatterOptions() {
$configurationData = [
FormatterOptions::DEFAULT_FORMAT => 'table',
'test' => 'one',
'try' => 'two',
];
$userOptions = [
'try' => 'three',
];
$defaults = [
FormatterOptions::DEFAULT_FORMAT => 'var_export',
'try' => 'four',
'default-only' => 'defaulty',
];
// Create a StringInput object and ensure that Symfony Console is working right.
$input = $this->createStringInput('test --format=yaml --include-field-labels');
$testValue = $input->getOption(FormatterOptions::INCLUDE_FIELD_LABELS);
$this->assertTrue($testValue);
$testValue = $input->getOption(FormatterOptions::FORMAT);
$this->assertEquals('yaml', $testValue);
// $options->get() only returns the default parameter is there is
// no matching key in configuration, userOptions or defaults.
$options = new FormatterOptions($configurationData, $userOptions);
$this->assertEquals('', $options->get('default-only'));
$this->assertEquals('defaulty', $options->get('default-only', $defaults));
$this->assertEquals('defaulty', $options->get('default-only', $defaults, 'irrelevant'));
$this->assertEquals('three', $options->get('try'));
$this->assertEquals('three', $options->get('try', $defaults));
$this->assertEquals('three', $options->get('try', $defaults, 'irrelevant'));
$this->assertFalse($options->get('no-such-key'));
$this->assertFalse($options->get('no-such-key', $defaults));
$this->assertEquals('last-chance', $options->get('no-such-key', $defaults, 'last-chance'));
// Change a user option
$options = new FormatterOptions($configurationData, $userOptions);
$options->setOption('try', 'changed');
$this->assertEquals('changed', $options->get('try'));
$this->assertEquals('changed', $options->get('try', $defaults));
$this->assertEquals('changed', $options->get('try', $defaults, 'irrelevant'));
// Configuration has higher priority than defaults
$options = new FormatterOptions($configurationData, $userOptions);
$this->assertEquals('table', $options->getFormat());
$this->assertEquals('table', $options->getFormat($defaults));
// Override has higher priority than configuration and defaults
$options = new FormatterOptions($configurationData, $userOptions);
$newOptions = $options->override([FormatterOptions::DEFAULT_FORMAT => 'json']);
$this->assertEquals('json', $newOptions->getFormat());
$this->assertEquals('json', $newOptions->getFormat($defaults));
$options = new FormatterOptions($configurationData, $userOptions);
$options->setConfigurationDefault(FormatterOptions::DEFAULT_FORMAT, 'php');
$this->assertEquals('table', $options->getFormat());
$options = new FormatterOptions($configurationData, $userOptions);
$options->setConfigurationData([]);
$this->assertEquals('', $options->getFormat());
// It is only possible to override options that appear in '$default'
// with $input; if there are no defaults, then the --format=yaml
// option will not be picked up.
$options = new FormatterOptions($configurationData, $userOptions);
$options->setInput($input);
$this->assertEquals('table', $options->get(FormatterOptions::DEFAULT_FORMAT));
$this->assertEquals('table', $options->get(FormatterOptions::DEFAULT_FORMAT, $defaults, 'irrelevant'));
// We won't see the default value unless the configuration value is empty.
$options = new FormatterOptions([], $userOptions);
$this->assertEquals('var_export', $options->get(FormatterOptions::DEFAULT_FORMAT, $defaults, 'irrelevant'));
}
}
PK 4AV*Y Y tests/testFormatters.phpnu W+A formatterManager = new FormatterManager();
}
function assertFormattedOutputMatches($expected, $format, $data, FormatterOptions $options = null, $userOptions = []) {
if (!$options) {
$options = new FormatterOptions();
}
$options->setOptions($userOptions);
$output = new BufferedOutput();
$this->formatterManager->write($output, $format, $data, $options);
$actual = preg_replace('#[ \t]*$#sm', '', $output->fetch());
$this->assertEquals(rtrim($expected), rtrim($actual));
}
function testSimpleYaml()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<assertFormattedOutputMatches($expected, 'yaml', $data);
}
function testNestedYaml()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = <<assertFormattedOutputMatches($expected, 'yaml', $data);
}
function testSimpleJson()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<assertFormattedOutputMatches($expected, 'json', $data);
}
function testSerializeFormat()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = 'a:3:{s:3:"one";s:1:"a";s:3:"two";s:1:"b";s:5:"three";s:1:"c";}';
$this->assertFormattedOutputMatches($expected, 'php', $data);
}
function testNestedJson()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = <<assertFormattedOutputMatches($expected, 'json', $data);
}
function testSimplePrintR()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = << a
[two] => b
[three] => c
)
EOT;
$this->assertFormattedOutputMatches($expected, 'print-r', $data);
}
function testNestedPrintR()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = << Array
(
[i] => Array
(
[0] => a
[1] => b
[2] => c
)
)
[two] => Array
(
[ii] => Array
(
[0] => q
[1] => r
[2] => s
)
)
[three] => Array
(
[iii] => Array
(
[0] => t
[1] => u
[2] => v
)
)
)
EOT;
$this->assertFormattedOutputMatches($expected, 'print-r', $data);
}
function testSimpleVarExport()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = << 'a',
'two' => 'b',
'three' => 'c',
)
EOT;
$this->assertFormattedOutputMatches($expected, 'var_export', $data);
}
function testNestedVarExport()
{
$data = [
'one' => [
'i' => ['a', 'b', 'c'],
],
'two' => [
'ii' => ['q', 'r', 's'],
],
'three' => [
'iii' => ['t', 'u', 'v'],
],
];
$expected = <<
array (
'i' =>
array (
0 => 'a',
1 => 'b',
2 => 'c',
),
),
'two' =>
array (
'ii' =>
array (
0 => 'q',
1 => 'r',
2 => 's',
),
),
'three' =>
array (
'iii' =>
array (
0 => 't',
1 => 'u',
2 => 'v',
),
),
)
EOT;
$this->assertFormattedOutputMatches($expected, 'var_export', $data);
}
function testList()
{
$data = [
'one' => 'a',
'two' => 'b',
'three' => 'c',
];
$expected = <<assertFormattedOutputMatches($expected, 'list', $data);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\UnknownFormatException
* @expectedExceptionCode 1
* @expectedExceptionMessage The requested format, 'no-such-format', is not available.
*/
function testBadFormat()
{
$this->assertFormattedOutputMatches('Will fail, not return', 'no-such-format', ['a' => 'b']);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
* @expectedExceptionCode 1
* @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\CsvFormatter must be one of an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields, an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList or an array. Instead, a string was provided.
*/
function testBadDataTypeForCsv()
{
$this->assertFormattedOutputMatches('Will fail, not return', 'csv', 'String cannot be converted to csv');
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
* @expectedExceptionCode 1
* @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\JsonFormatter must be an array. Instead, a string was provided.
*/
function testBadDataTypeForJson()
{
$this->assertFormattedOutputMatches('Will fail, not return', 'json', 'String cannot be converted to json');
}
function testSimpleCsv()
{
$data = ['a', 'b', 'c'];
$expected = "a,b,c";
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testLinesOfCsv()
{
$data = [['a', 'b', 'c'], ['x', 'y', 'z']];
$expected = "a,b,c\nx,y,z";
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testCsvWithEscapedValues()
{
$data = ["Red apple", "Yellow lemon"];
$expected = '"Red apple","Yellow lemon"';
$this->assertFormattedOutputMatches($expected, 'csv', $data);
}
function testCsvWithEmbeddedSingleQuote()
{
$data = ["John's book", "Mary's laptop"];
$expected = <<assertFormattedOutputMatches($expected, 'csv', $data);
}
function testCsvWithEmbeddedDoubleQuote()
{
$data = ['The "best" solution'];
$expected = <<assertFormattedOutputMatches($expected, 'csv', $data);
}
function testNoFormatterSelected()
{
$data = 'Hello';
$expected = $data;
$this->assertFormattedOutputMatches($expected, '', $data);
}
function testCsvBothKindsOfQuotes()
{
$data = ["John's \"new\" book", "Mary's \"modified\" laptop"];
$expected = <<assertFormattedOutputMatches($expected, 'csv', $data);
}
protected function missingCellTableExampleData()
{
$data = [
[
'one' => 'a',
'two' => 'b',
'three' => 'c',
],
[
'one' => 'x',
'three' => 'z',
],
];
return new RowsOfFields($data);
}
function testTableWithMissingCell()
{
$data = $this->missingCellTableExampleData();
$expected = <<assertFormattedOutputMatches($expected, 'table', $data);
$expectedCsv = <<assertFormattedOutputMatches($expectedCsv, 'csv', $data);
}
protected function simpleTableExampleData()
{
$data = [
'id-123' =>
[
'one' => 'a',
'two' => 'b',
'three' => 'c',
],
'id-456' =>
[
'one' => 'x',
'two' => 'y',
'three' => 'z',
],
];
return new RowsOfFields($data);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
* @expectedExceptionCode 1
* @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\TableFormatter must be either an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields or an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList. Instead, an array was provided.
*/
function testIncompatibleDataForTableFormatter()
{
$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()
{
$data = $this->simpleTableExampleData();
$expected = <<assertFormattedOutputMatches($expected, 'table', $data);
$expectedBorderless = <<assertFormattedOutputMatches($expectedBorderless, 'table', $data, new FormatterOptions(['table-style' => 'borderless']));
$expectedJson = <<assertFormattedOutputMatches($expectedJson, 'json', $data);
$expectedCsv = <<assertFormattedOutputMatches($expectedCsv, 'csv', $data);
$expectedList = <<assertFormattedOutputMatches($expectedList, 'list', $data);
}
protected function tableWithAlternativesExampleData()
{
$data = [
'id-123' =>
[
'one' => 'a',
'two' => ['this', 'that', 'the other thing'],
'three' => 'c',
],
'id-456' =>
[
'one' => 'x',
'two' => 'y',
'three' => ['apples', 'oranges'],
],
];
return new RowsOfFieldsWithAlternatives($data);
}
function testTableWithAlternatives()
{
$data = $this->tableWithAlternativesExampleData();
$expected = <<assertFormattedOutputMatches($expected, 'table', $data);
$expectedBorderless = <<assertFormattedOutputMatches($expectedBorderless, 'table', $data, new FormatterOptions(['table-style' => 'borderless']));
$expectedJson = <<assertFormattedOutputMatches($expectedJson, 'json', $data);
$expectedCsv = <<assertFormattedOutputMatches($expectedCsv, 'csv', $data);
$expectedList = <<assertFormattedOutputMatches($expectedList, 'list', $data);
}
function testSimpleTableWithFieldLabels()
{
$data = $this->simpleTableExampleData();
$configurationData = new FormatterOptions(
[
'field-labels' => ['one' => 'Ichi', 'two' => 'Ni', 'three' => 'San'],
'row-labels' => ['id-123' => 'Walrus', 'id-456' => 'Carpenter'],
]
);
$configurationDataAnnotationFormat = new FormatterOptions(
[
'field-labels' => "one: Uno\ntwo: Dos\nthree: Tres",
]
);
$expected = <<assertFormattedOutputMatches($expected, 'table', $data, $configurationData);
$expectedSidewaysTable = <<assertFormattedOutputMatches($expectedSidewaysTable, 'table', $data, $configurationData->override(['list-orientation' => true]));
$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 = <<assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
}
protected function simpleListExampleData()
{
$data = [
'one' => 'apple',
'two' => 'banana',
'three' => 'carrot',
];
return new AssociativeList($data);
}
/**
* @expectedException \Consolidation\OutputFormatters\Exception\IncompatibleDataException
* @expectedExceptionCode 1
* @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\TableFormatter must be either an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields or an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList. Instead, an array was provided.
*/
function testIncompatibleListDataForTableFormatter()
{
$data = $this->simpleListExampleData();
$this->assertFormattedOutputMatches('Should throw an exception before comparing the table data', 'table', $data->getArrayCopy());
}
function testSimpleList()
{
$data = $this->simpleListExampleData();
$expected = <<assertFormattedOutputMatches($expected, 'table', $data);
$expectedRotated = <<assertFormattedOutputMatches($expectedRotated, 'table', $data, new FormatterOptions(['list-orientation' => false]));
$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($expectedCsvNoHeaders, 'csv', $data, new FormatterOptions(), ['include-field-labels' => false]);
// Next, configure the formatter options with 'include-field-labels',
// but set --include-field-labels to turn the option back on again.
$options = new FormatterOptions(['include-field-labels' => false]);
$input = new StringInput('test --include-field-labels');
$optionDefinitions = [
new InputArgument('unused', InputArgument::REQUIRED),
new InputOption('include-field-labels', null, InputOption::VALUE_NONE),
];
$definition = new InputDefinition($optionDefinitions);
$input->bind($definition);
$testValue = $input->getOption('include-field-labels');
$this->assertTrue($testValue);
$hasFieldLabels = $input->hasOption('include-field-labels');
$this->assertTrue($hasFieldLabels);
$this->assertFormattedOutputMatches($expectedCsvNoHeaders, 'csv', $data, $options);
$options->setInput($input);
$this->assertFormattedOutputMatches($expectedCsv, 'csv', $data, $options);
}
protected function associativeListWithCsvCells()
{
$data = [
'one' => 'apple',
'two' => ['banana', 'plantain'],
'three' => 'carrot',
'four' => ['peaches', 'pumpkin pie'],
];
return new AssociativeListWithCsvCells($data);
}
function testAssociativeListWithCsvCells()
{
$data = $this->associativeListWithCsvCells();
$expected = <<assertFormattedOutputMatches($expected, 'table', $data);
$expectedList = <<< EOT
apple
banana,plantain
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($expectedCsvNoHeaders, 'csv', $data, new FormatterOptions(), ['include-field-labels' => false]);
}
function testSimpleListWithFieldLabels()
{
$data = $this->simpleListExampleData();
$configurationData = new FormatterOptions(
[
'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 = <<assertFormattedOutputMatches($expectedJson, 'json', $data, $configurationData, ['fields' => ['San', 'Ichi']]);
}
}
PK 4AVhn
tests/testIncompatibleData.phpnu W+A formatterManager = new FormatterManager();
}
protected function assertIncompatibleDataMessage($expected, $formatter, $data)
{
$e = new IncompatibleDataException($formatter, $data, $formatter->validDataTypes());
$this->assertEquals($expected, $e->getMessage());
}
public function testIncompatibleData()
{
$tableFormatter = $this->formatterManager->getFormatter('table');
$this->assertIncompatibleDataMessage('Data provided to Consolidation\OutputFormatters\Formatters\TableFormatter must be either an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields or an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList. Instead, a string was provided.', $tableFormatter, 'a string');
$this->assertIncompatibleDataMessage('Data provided to Consolidation\OutputFormatters\Formatters\TableFormatter must be either an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields or an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList. Instead, an instance of Consolidation\OutputFormatters\FormatterManager was provided.', $tableFormatter, $this->formatterManager);
$this->assertIncompatibleDataMessage('Data provided to Consolidation\OutputFormatters\Formatters\TableFormatter must be either an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields or an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList. Instead, an array was provided.', $tableFormatter, []);
$this->assertIncompatibleDataMessage('Data provided to Consolidation\OutputFormatters\Formatters\TableFormatter must be either an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields or an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList. Instead, an instance of Consolidation\OutputFormatters\StructuredData\AssociativeList was provided.', $tableFormatter, new AssociativeList([]));
}
/**
* @expectedException \Exception
* @expectedExceptionMessage Undescribable data error: NULL
*/
public function testUndescribableData()
{
$tableFormatter = $this->formatterManager->getFormatter('table');
$this->assertIncompatibleDataMessage('Will throw before comparing.', $tableFormatter, null);
}
}
PK 4AVa1 * tests/src/RowsOfFieldsWithAlternatives.phpnu W+A formatterManager = new FormatterManager();
}
function testValidFormats()
{
$arrayObjectRef = new \ReflectionClass('\ArrayObject');
$associativeListRef = new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\AssociativeList');
$rowsOfFieldsRef = new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\RowsOfFields');
$notADataType = new \ReflectionClass('\Consolidation\OutputFormatters\FormatterManager');
$jsonFormatter = $this->formatterManager->getFormatter('json');
$isValid = $this->formatterManager->isValidFormat($jsonFormatter, $notADataType);
$this->assertFalse($isValid);
$isValid = $this->formatterManager->isValidFormat($jsonFormatter, new \ArrayObject());
$this->assertTrue($isValid);
$isValid = $this->formatterManager->isValidFormat($jsonFormatter, $arrayObjectRef);
$this->assertTrue($isValid);
$isValid = $this->formatterManager->isValidFormat($jsonFormatter, []);
$this->assertTrue($isValid);
$isValid = $this->formatterManager->isValidFormat($jsonFormatter, $associativeListRef);
$this->assertTrue($isValid);
$isValid = $this->formatterManager->isValidFormat($jsonFormatter, $rowsOfFieldsRef);
$this->assertTrue($isValid);
$sectionsFormatter = $this->formatterManager->getFormatter('sections');
$isValid = $this->formatterManager->isValidFormat($sectionsFormatter, $notADataType);
$this->assertFalse($isValid);
$isValid = $this->formatterManager->isValidFormat($sectionsFormatter, []);
$this->assertFalse($isValid);
$isValid = $this->formatterManager->isValidFormat($sectionsFormatter, $arrayObjectRef);
$this->assertFalse($isValid);
$isValid = $this->formatterManager->isValidFormat($sectionsFormatter, $rowsOfFieldsRef);
$this->assertTrue($isValid);
$isValid = $this->formatterManager->isValidFormat($sectionsFormatter, $associativeListRef);
$this->assertFalse($isValid);
// Check to see which formats can handle a simple array
$validFormats = $this->formatterManager->validFormats([]);
$this->assertEquals('csv,json,list,php,print-r,var_export,yaml', implode(',', $validFormats));
// Check to see which formats can handle an AssociativeList
$validFormats = $this->formatterManager->validFormats($associativeListRef);
$this->assertEquals('csv,json,list,php,print-r,table,var_export,yaml', implode(',', $validFormats));
// Check to see which formats can handle an RowsOfFields
$validFormats = $this->formatterManager->validFormats($rowsOfFieldsRef);
$this->assertEquals('csv,json,list,php,print-r,sections,table,var_export,yaml', implode(',', $validFormats));
// Test error case: no formatter should handle something that is not a data type.
$validFormats = $this->formatterManager->validFormats($notADataType);
$this->assertEquals('', implode(',', $validFormats));
}
}
PK 4AVY: :
.gitignorenu W+A .DS_Store
phpunit.xml
build
vendor
composer.lock
main.php
PK 4AV>) README.mdnu W+A # Consolidation\OutputFormatters
Apply transformations to structured data to write output in different formats.
[![Travis CI](https://travis-ci.org/consolidation-org/output-formatters.svg?branch=master)](https://travis-ci.org/consolidation-org/output-formatters) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/consolidation-org/output-formatters/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/consolidation-org/output-formatters/?branch=master) [![Coverage Status](https://coveralls.io/repos/github/consolidation-org/output-formatters/badge.svg?branch=master)](https://coveralls.io/github/consolidation-org/output-formatters?branch=master) [![License](https://poser.pugx.org/consolidation/output-formatters/license)](https://packagist.org/packages/consolidation/output-formatters)
## Component Status
Currently in use in [Robo](https://github.com/Codegyre/Robo).
## Motivation
Formatters are used to allow simple commandline tool commands to be implemented in a manner that is completely independent from the Symfony Console output interfaces. A command receives its input via its method parameters, and returns its result as structured data (e.g. a php standard object or array). The structured data is then formatted by a formatter, and the result is printed.
This process is managed by the [Consolidation/AnnotationCommand](https://github.com/consolidation-org/annotation-command) project.
## Example Formatter
Simple formatters are very easy to write.
```
class YamlFormatter implements FormatterInterface
{
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
$dumper = new Dumper();
$output->writeln($dumper->dump($data));
}
}
```
The formatter is passed the set of `$options` that the user provided on the command line. These may optionally be examined to alter the behavior of the formatter, if needed.
## Structured Data
Most formatters will operate on any array or ArrayObject data. Some formatters require that specific data types be used. The following data types, all of which are subclasses of ArrayObject, are available for use:
- RowsOfFields: Each row contains an associative array of field:value pairs. It is also assumed that the fields of each row are the same for every row. This format is ideal for displaying in a table, with labels in the top row.
- AssociativeList: Each row contains a field:value pair. Each field is unique. This format is ideal for displaying in a table, with labels in the first column and values in the second common.
Commands that return structured data with fields can be filtered and/or re-ordered by using the --fields option. These structured data types can also be formatted into a more generic type such as yaml or json, even after being filtered. This capabilities are not available if the data is returned in a bare php array.
## Rendering Table Cells
By default, both the RowsOfFields and AssociativeList data types presume that the contents of each cell is a simple string. To render more complicated cell contents, create a custom structured data class by extending either RowsOfFields or AssociativeList, as desired, and implement RenderCellInterface. The `renderCell()` method of your class will then be called for each cell, and you may act on it as appropriate.
```
public function renderCell($key, $cellData, FormatterOptions $options)
{
// 'my-field' is always an array; convert it to a comma-separated list.
if ($key == 'my-field') {
return implode(',', $cellData);
}
// MyStructuredCellType has its own render function
if ($cellData instanceof MyStructuredCellType) {
return $cellData->myRenderfunction();
}
// If we do not recognize the cell data, return it unchnaged.
return $cellData;
}
```
Note that if your data structure is printed with some formatter other than the table formatter, it will still be reordered per the selected fields, but cell rendering will **not** be done.
## API Usage
It is recommended to use [Consolidation/AnnotationCommand](https://github.com/consolidation-org/annotation-command) to manage commands and formatters. See the [AnnotationCommand API Usage](https://github.com/consolidation-org/annotation-command#api-usage) for details.
The FormatterManager may also be used directly, if desired:
```
/**
* @param OutputInterface $output Output stream to write to
* @param string $format Data format to output in
* @param mixed $structuredOutput Data to output
* @param FormatterOptions $options Configuration informatin and User options
*/
function doFormat(
OutputInterface $output,
string $format,
array $data,
FormatterOptions $options)
{
$formatterManager = new FormatterManager();
$formatterManager->write(output, $format, $data, $options);
}
```
## Comparison to Existing Solutions
Formatters have been in use in Drush since version 5. Drush allows formatters to be defined using simple classes, some of which may be configured using metadata. Furthermore, nested formatters are also allowed; for example, a list formatter may be given another formatter to use to format each of its rows. Nested formatters also require nested metadata, causing the code that constructed formatters to become very complicated and unweildy.
Consolidation/OutputFormatters maintains the simplicity of use provided by Drush formatters, but abandons nested metadata configuration in favor of using code in the formatter to configure itself, in order to keep the code simpler.
PK 4AV8C C src/FormatterOptions.phpnu W+A configurationData = $configurationData;
$this->options = $options;
}
public function override($configurationData)
{
$override = new self();
$override
->setConfigurationData($configurationData + $this->getConfigurationData())
->setOptions($this->getOptions());
return $override;
}
public function get($key, $defaults = [], $default = false)
{
$value = $this->fetch($key, $defaults, $default);
return $this->parse($key, $value);
}
public function getFormat($defaults = [])
{
return $this->get(self::FORMAT, $defaults, $this->get(self::DEFAULT_FORMAT, $defaults, ''));
}
protected function fetch($key, $defaults = [], $default = false)
{
$values = array_merge(
$defaults,
$this->getConfigurationData(),
$this->getOptions(),
$this->getInputOptions($defaults)
);
if (array_key_exists($key, $values)) {
return $values[$key];
}
return $default;
}
protected function parse($key, $value)
{
$optionFormat = $this->getOptionFormat($key);
if ($optionFormat) {
return $this->$optionFormat($value);
}
return $value;
}
public function parsePropertyList($value)
{
return PropertyParser::parse($value);
}
protected function getOptionFormat($key)
{
$propertyFormats = [
self::ROW_LABELS => 'PropertyList',
self::FIELD_LABELS => 'PropertyList',
self::DEFAULT_FIELDS => 'PropertyList',
];
if (array_key_exists($key, $propertyFormats)) {
return "parse{$propertyFormats[$key]}";
}
return false;
}
public function setConfigurationData($configurationData)
{
$this->configurationData = $configurationData;
return $this;
}
protected function setConfigurationValue($key, $value)
{
$this->configurationData[$key] = $value;
return $this;
}
public function setConfigurationDefault($key, $value)
{
if (!array_key_exists($key, $this->configurationData)) {
return $this->setConfigurationValue($key, $value);
}
return $this;
}
public function getConfigurationData()
{
return $this->configurationData;
}
public function setOptions($options)
{
$this->options = $options;
return $this;
}
public function setOption($key, $value)
{
$this->options[$key] = $value;
return $this;
}
public function getOptions()
{
return $this->options;
}
public function setInput(InputInterface $input)
{
$this->input = $input;
}
public function getInputOptions($defaults)
{
if (!isset($this->input)) {
return [];
}
$options = [];
foreach ($defaults as $key => $value) {
if ($this->input->hasOption($key)) {
$result = $this->input->getOption($key);
if (isset($result)) {
$options[$key] = $this->input->getOption($key);
}
}
}
return $options;
}
}
PK 4AVfӖV V ( src/Exception/UnknownFormatException.phpnu W+A getName() == 'ArrayObject')) {
return 'an array';
}
return 'an instance of ' . $data->getName();
}
if (is_string($data)) {
return 'a string';
}
if (is_object($data)) {
return 'an instance of ' . get_class($data);
}
throw new \Exception("Undescribable data error: " . var_export($data, true));
}
protected static function describeAllowedTypes($allowedTypes)
{
if (is_array($allowedTypes) && !empty($allowedTypes)) {
if (count($allowedTypes) > 1) {
return static::describeListOfAllowedTypes($allowedTypes);
}
$allowedTypes = $allowedTypes[0];
}
return static::describeDataType($allowedTypes);
}
protected static function describeListOfAllowedTypes($allowedTypes)
{
$descriptions = [];
foreach ($allowedTypes as $oneAllowedType) {
$descriptions[] = static::describeDataType($oneAllowedType);
}
if (count($descriptions) == 2) {
return "either {$descriptions[0]} or {$descriptions[1]}";
}
$lastDescription = array_pop($descriptions);
$otherDescriptions = implode(', ', $descriptions);
return "one of $otherDescriptions or $lastDescription";
}
}
PK 4AVmK{P P src/RestructureInterface.phpnu W+A getSelectedFieldKeys($fields, $fieldLabels);
if (empty($fields)) {
return $fieldLabels;
}
return $this->reorderFieldLabels($fields, $fieldLabels, $data);
}
protected function reorderFieldLabels($fields, $fieldLabels, $data)
{
$result = [];
$firstRow = reset($data);
foreach ($fields as $field) {
if (array_key_exists($field, $firstRow)) {
if (array_key_exists($field, $fieldLabels)) {
$result[$field] = $fieldLabels[$field];
}
}
}
return $result;
}
protected function getSelectedFieldKeys($fields, $fieldLabels)
{
if (is_string($fields)) {
$fields = explode(',', $fields);
}
$fieldLablesReverseMap = array_combine(array_values($fieldLabels), array_keys($fieldLabels));
$selectedFields = [];
foreach ($fields as $field) {
if (array_key_exists($field, $fieldLabels)) {
$selectedFields[] = $field;
} elseif (array_key_exists($field, $fieldLablesReverseMap)) {
$selectedFields[] = $fieldLablesReverseMap[$field];
}
}
return $selectedFields;
}
}
PK 4AV٣s &