First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,15 @@
# 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

View file

@ -0,0 +1,11 @@
### Steps to reproduce
What did you do?
### Expected behavior
Tell us what should happen
### Actual behavior
Tell us what happens instead
### System Configuration
Which O.S. and PHP version are you using?

View file

@ -0,0 +1,13 @@
### Overview
This pull request:
- [ ] Fixes a bug
- [ ] Adds a feature
- [ ] Breaks backwards compatibility
- [ ] Has tests that cover changes
### Summary
Short overview of what changed.
### Description
Any additional information.

View file

@ -0,0 +1,6 @@
.DS_Store
.idea
phpunit.xml
build
vendor
main.php

View file

@ -0,0 +1,49 @@
language: php
branches:
# Only test the master branch and SemVer tags.
only:
- master
- /^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+.*$/
matrix:
include:
-
php: 7.1
env: 'HIGHEST_LOWEST="update" STABILITY="RC"'
-
php: 7.0.11
-
php: 5.6
-
php: 5.5
-
php: 5.4
env: 'HIGHEST_LOWEST="update --prefer-lowest"'
sudo: false
cache:
directories:
- vendor
- $HOME/.composer/cache
before_script:
# If running a highest/lowest dependencies test, get rid of composer.lock
- |
if [ -n "$HIGHEST_LOWEST" ] ; then
rm composer.lock
composer config --unset platform.php
composer config minimum-stability ${STABILITY-stable}
fi
- 'composer -n ${HIGHEST_LOWEST-install} --prefer-dist'
- composer why symfony/console
# Print out all of the installed packages in alphabetical order, with versions
- composer licenses
script:
- vendor/bin/phpunit
- vendor/bin/phpcs --standard=PSR2 -n src
after_success:
- travis_retry php vendor/bin/coveralls -v

View file

@ -0,0 +1,78 @@
# Change Log
### 3.1.13 - 29 November 2017
- Allow XML output for RowsOfFields (#60).
- Allow Symfony 4 components and add make tests run on three versions of Symfony.
### 3.1.12 - 12 October 2017
- Bugfix: Use InputOption::VALUE_REQUIRED instead of InputOption::VALUE_OPTIONAL
for injected options such as --format and --fields.
- Bugfix: Ignore empty properties in the property parser.
### 3.1.11 - 17 August 2017
- Add ListDataFromKeys marker data type.
### 3.1.10 - 6 June 2017
- Typo in CalculateWidths::distributeLongColumns causes failure for some column width distributions
### 3.1.9 - 8 May 2017
- Improve wrapping algorithm
### 3.1.7 - 20 Jan 2017
- Add Windows testing
### 3.1.6 - 8 Jan 2017
- Move victorjonsson/markdowndocs to require-dev
### 3.1.5 - 23 November 2016
- When converting from XML to an array, use the 'id' or 'name' element as the array key value.
### 3.1.4 - 20 November 2016
- Add a 'list delimiter' formatter option, so that we can create a Drush-style table for property lists.
### 3.1.1 ~ 3.1.3 - 18 November 2016
- Fine-tune wordwrapping.
### 3.1.0 - 17 November 2016
- Add wordwrapping to table formatter.
### 3.0.0 - 14 November 2016
- **Breaking** The RenderCellInterface is now provided a reference to the entire row data. Existing clients need only add the new parameter to their method defnition to update.
- Rename AssociativeList to PropertyList, as many people seemed to find the former name confusing. AssociativeList is still available for use to preserve backwards compatibility, but it is deprecated.
### 2.1.0 - 7 November 2016
- Add RenderCellCollections to structured lists, so that commands may add renderers to structured data without defining a new structured data subclass.
- Throw an exception if the client requests a field that does not exist.
- Remove unwanted extra layer of nesting when formatting an PropertyList with an array formatter (json, yaml, etc.).
### 2.0.0 - 30 September 2016
- **Breaking** The default `string` format now converts non-string results into a tab-separated-value table if possible. Commands may select a single field to emit in this instance with an annotation: `@default-string-field email`. By this means, a given command may by default emit a single value, but also provide more rich output that may be shown by selecting --format=table, --format=yaml or the like. This change might cause some commands to produce output in situations that previously were not documented as producing output.
- **Breaking** FormatterManager::addFormatter() now takes the format identifier and a FormatterInterface, rather than an identifier and a Formatter classname (string).
- --field is a synonym for --fields with a single field.
- Wildcards and regular expressions can now be used in --fields expressions.
### 1.1.0 - 14 September 2016
Add tab-separated-value (tsv) formatter.
### 1.0.0 - 19 May 2016
First stable release.

View file

@ -0,0 +1,31 @@
# 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/output-formatters/)
It is easy to run the unit tests and code sniffer locally; just run:
- composer cs
To run the code beautifier, which will fix many of the problems reported by phpcs:
- composer cbf
These two commands (`composer cs` and `composer cbf`) are defined in the `scripts` section of [composer.json](composer.json).
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 need to be addressed.
Pull requests must pass phpcs and phpunit in order to be merged; ideally, new functionality will also include new unit tests.

View file

@ -0,0 +1,8 @@
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.

View file

@ -0,0 +1,135 @@
# Consolidation\OutputFormatters
Apply transformations to structured data to write output in different formats.
[![Travis CI](https://travis-ci.org/consolidation/output-formatters.svg?branch=master)](https://travis-ci.org/consolidation/output-formatters)
[![Windows CI](https://ci.appveyor.com/api/projects/status/umyfuujca6d2g2k6?svg=true)](https://ci.appveyor.com/project/greg-1-anderson/output-formatters)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/consolidation/output-formatters/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/consolidation/output-formatters/?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/consolidation/output-formatters/badge.svg?branch=master)](https://coveralls.io/github/consolidation/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/consolidation/Robo) (1.x+), [Drush](https://github.com/drush-ops/drush) (9.x+) and [Terminus](https://github.com/pantheon-systems/terminus) (1.x+).
## 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/annotation-command) project.
## Library Usage
This is a library intended to be used in some other project. Require from your composer.json file:
```
"require": {
"consolidation/output-formatters": "~3"
},
```
If you require the feature that allows a data table to be automatically reduced to a single element when the `string` format is selected, then you should require version "~2" instead. In most other respects, the 1.x and 2.x versions are compatible. See the [CHANGELOG](CHANGELOG.md) for details.
## Example Formatter
Simple formatters are very easy to write.
```php
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.
Formatters may also implement different interfaces to alter the behavior of the rendering engine.
- `ValidationInterface`: A formatter should implement this interface to test to see if the provided data type can be processed. Any formatter that does **not** implement this interface is presumed to operate exclusively on php arrays. The formatter manager will always convert any provided data into an array before passing it to a formatter that does not implement ValidationInterface. These formatters will not be made available when the returned data type cannot be converted into an array.
- `OverrideRestructureInterface`: A formatter that implements this interface will be given the option to act on the provided structured data object before it restructures itself. See the section below on structured data for details on data restructuring.
## 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.
- `PropertyList`: 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.
- `ListDataFromKeys`: The result may be structured or unstructured data. When formatted with the --format=list formatter, the result will come from the array keys instead of the array values.
- `DOMDocument`: The standard PHP DOM document class may be used by functions that need to be able to presicely specify the exact attributes and children when the XML output format is used.
Commands that return table 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.
The formatter manager will do its best to convert from an array to a DOMDocument, or from a DOMDocument to an array. It is important to note that a DOMDocument does not have a 1-to-1 mapping with a PHP array. DOM elements contain both attributes and elements; a simple string property 'foo' may be represented either as <element foo="value"/> or <element><foo>value</foo></element>. Also, there may be multiple XML elements with the same name, whereas php associative arrays must always have unique keys. When converting from an array to a DOM document, the XML formatter will default to representing the string properties of an array as attributes of the element. Sets of elements with the same name may be used only if they are wrapped in a containing parent element--e.g. <element><foos><foo>one</foo><foo>two</foo></foos></element>. The XMLSchema class may be used to provide control over whether a property is rendered as an attribute or an element; however, in instances where the schema of the XML output is important, it is best for a function to return its result as a DOMDocument rather than an array.
A function may also define its own structured data type to return, usually by extending one of the types mentioned above. If a custom structured data class implements an appropriate interface, then it can provide its own conversion function to one of the other data types:
- `DomDataInterface`: The data object may produce a DOMDocument via its `getDomData()` method, which will be called in any instance where a DOM document is needed--typically with the xml formatter.
- `ListDataInterface`: Any structured data object that implements this interface may use the `getListData()` method to produce the data set that will be used with the list formatter.
- `TableDataInterface`: Any structured data object that implements this interface may use the `getTableData()` method to produce the data set that will be used with the table formatter.
- `RenderCellInterface`: Structured data can also provide fine-grain control over how each cell in a table is rendered by implementing the RenderCellInterface. See the section below for information on how this is done.
- `RestructureInterface`: The restructure interface can be implemented by a structured data object to restructure the data in response to options provided by the user. For example, the RowsOfFields and PropertyList data types use this interface to select and reorder the fields that were selected to appear in the output. Custom data types usually will not need to implement this interface, as they can inherit this behavior by extending RowsOfFields or PropertyList.
Additionally, structured data may be simplified to arrays via an array simplification object. To provide an array simplifier, implement `SimplifyToArrayInterface`, and register the simplifier via `FormatterManager::addSimplifier()`.
## Rendering Table Cells
By default, both the RowsOfFields and PropertyList 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 PropertyList, 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.
```php
public function renderCell($key, $cellData, FormatterOptions $options, $rowData)
{
// '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 a formatter other than one such as 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/annotation-command) to manage commands and formatters. See the [AnnotationCommand API Usage](https://github.com/consolidation/annotation-command#api-usage) for details.
The FormatterManager may also be used directly, if desired:
```php
/**
* @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);
}
```
The FormatterOptions class is used to hold the configuration for the command output--things such as the default field list for tabular output, and so on--and also the current user-selected options to use during rendering, which may be provided using a Symfony InputInterface object:
```
public function execute(InputInterface $input, OutputInterface $output)
{
$options = new FormatterOptions();
$options
->setInput($input)
->setFieldLabels(['id' => 'ID', 'one' => 'First', 'two' => 'Second'])
->setDefaultStringField('id');
$data = new RowsOfFields($this->getSomeData($input));
return $this->doFormat($output, $options->getFormat(), $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.

View file

@ -0,0 +1,68 @@
build: false
shallow_clone: true
platform: 'x86'
clone_folder: C:\projects\output-formatters
branches:
only:
- master
## Cache composer bits
cache:
- '%LOCALAPPDATA%\Composer\files -> composer.lock'
init:
#https://github.com/composer/composer/blob/master/appveyor.yml
#- SET ANSICON=121x90 (121x90)
# Inspired by https://github.com/Codeception/base/blob/master/appveyor.yml and https://github.com/phpmd/phpmd/blob/master/appveyor.yml
install:
- cinst -y curl
- SET PATH=C:\Program Files\curl;%PATH%
#which is only needed by the test suite.
- cinst -y which
- SET PATH=C:\Program Files\which;%PATH%
- git clone -q https://github.com/acquia/DevDesktopCommon.git #For tar, cksum, ...
- SET PATH=%APPVEYOR_BUILD_FOLDER%/DevDesktopCommon/bintools-win/msys/bin;%PATH%
- SET PATH=C:\Program Files\MySql\MySQL Server 5.7\bin\;%PATH%
#Install PHP per https://blog.wyrihaximus.net/2016/11/running-php-unit-tests-on-windows-using-appveyor-and-chocolatey/
- ps: appveyor-retry cinst --ignore-checksums -y php --version ((choco search php --exact --all-versions -r | select-string -pattern $Env:php_ver_target | Select-Object -first 1) -replace '[php|]','')
- cd c:\tools\php70
- copy php.ini-production php.ini
- echo extension_dir=ext >> php.ini
- echo extension=php_openssl.dll >> php.ini
- echo date.timezone="UTC" >> php.ini
- echo variables_order="EGPCS" >> php.ini #May be unneeded.
- echo mbstring.http_input=pass >> php.ini
- echo mbstring.http_output=pass >> php.ini
- echo sendmail_path=nul >> php.ini
- echo extension=php_mbstring.dll >> php.ini
- echo extension=php_curl.dll >> php.ini
- echo extension=php_pdo_mysql.dll >> php.ini
- echo extension=php_pdo_pgsql.dll >> php.ini
- echo extension=php_pdo_sqlite.dll >> php.ini
- echo extension=php_pgsql.dll >> php.ini
- echo extension=php_gd2.dll >> php.ini
- SET PATH=C:\tools\php70;%PATH%
#Install Composer
- cd %APPVEYOR_BUILD_FOLDER%
#- appveyor DownloadFile https://getcomposer.org/composer.phar
- php -r "readfile('http://getcomposer.org/installer');" | php
#Install dependencies via Composer.
#Newer versions of the dependencies have whitespace differences that break tests.
#Maybe we should fix and do highest/lowest here someday.
- copy composer.windows.lock composer.lock
- php composer.phar -q install --prefer-dist -n
- SET PATH=%APPVEYOR_BUILD_FOLDER%;%APPVEYOR_BUILD_FOLDER%/vendor/bin;%PATH%
#Create a sandbox for testing. Don't think we need this.
- mkdir c:\test_temp
test_script:
- php composer.phar test
- php composer.phar cs
# environment variables
environment:
global:
php_ver_target: 7.0

View file

@ -0,0 +1,48 @@
{
"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.8|^3|^4",
"symfony/finder": "^2.5|^3|^4"
},
"require-dev": {
"phpunit/phpunit": "^4.8",
"satooshi/php-coveralls": "^1.0.2 | dev-master",
"squizlabs/php_codesniffer": "^2.7",
"victorjonsson/markdowndocs": "^1.3"
},
"scripts": {
"api": "phpdoc-md generate src > docs/api.md",
"cs": "phpcs --standard=PSR2 -n src",
"cbf": "phpcbf --standard=PSR2 -n src",
"test": "phpunit --colors=always"
},
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"config": {
"platform": {
"php": "5.6"
}
}
}

2017
vendor/consolidation/output-formatters/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,781 @@
## Table of contents
- [\Consolidation\OutputFormatters\FormatterManager](#class-consolidationoutputformattersformattermanager)
- [\Consolidation\OutputFormatters\Exception\UnknownFormatException](#class-consolidationoutputformattersexceptionunknownformatexception)
- [\Consolidation\OutputFormatters\Exception\AbstractDataFormatException (abstract)](#class-consolidationoutputformattersexceptionabstractdataformatexception-abstract)
- [\Consolidation\OutputFormatters\Exception\IncompatibleDataException](#class-consolidationoutputformattersexceptionincompatibledataexception)
- [\Consolidation\OutputFormatters\Exception\InvalidFormatException](#class-consolidationoutputformattersexceptioninvalidformatexception)
- [\Consolidation\OutputFormatters\Exception\UnknownFieldException](#class-consolidationoutputformattersexceptionunknownfieldexception)
- [\Consolidation\OutputFormatters\Formatters\ListFormatter](#class-consolidationoutputformattersformatterslistformatter)
- [\Consolidation\OutputFormatters\Formatters\SectionsFormatter](#class-consolidationoutputformattersformatterssectionsformatter)
- [\Consolidation\OutputFormatters\Formatters\JsonFormatter](#class-consolidationoutputformattersformattersjsonformatter)
- [\Consolidation\OutputFormatters\Formatters\FormatterInterface (interface)](#interface-consolidationoutputformattersformattersformatterinterface)
- [\Consolidation\OutputFormatters\Formatters\CsvFormatter](#class-consolidationoutputformattersformatterscsvformatter)
- [\Consolidation\OutputFormatters\Formatters\SerializeFormatter](#class-consolidationoutputformattersformattersserializeformatter)
- [\Consolidation\OutputFormatters\Formatters\StringFormatter](#class-consolidationoutputformattersformattersstringformatter)
- [\Consolidation\OutputFormatters\Formatters\VarExportFormatter](#class-consolidationoutputformattersformattersvarexportformatter)
- [\Consolidation\OutputFormatters\Formatters\YamlFormatter](#class-consolidationoutputformattersformattersyamlformatter)
- [\Consolidation\OutputFormatters\Formatters\TableFormatter](#class-consolidationoutputformattersformatterstableformatter)
- [\Consolidation\OutputFormatters\Formatters\XmlFormatter](#class-consolidationoutputformattersformattersxmlformatter)
- [\Consolidation\OutputFormatters\Formatters\PrintRFormatter](#class-consolidationoutputformattersformattersprintrformatter)
- [\Consolidation\OutputFormatters\Formatters\RenderDataInterface (interface)](#interface-consolidationoutputformattersformattersrenderdatainterface)
- [\Consolidation\OutputFormatters\Formatters\TsvFormatter](#class-consolidationoutputformattersformatterstsvformatter)
- [\Consolidation\OutputFormatters\Options\OverrideOptionsInterface (interface)](#interface-consolidationoutputformattersoptionsoverrideoptionsinterface)
- [\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)
- [\Consolidation\OutputFormatters\StructuredData\ListDataInterface (interface)](#interface-consolidationoutputformattersstructureddatalistdatainterface)
- [\Consolidation\OutputFormatters\StructuredData\TableDataInterface (interface)](#interface-consolidationoutputformattersstructureddatatabledatainterface)
- [\Consolidation\OutputFormatters\StructuredData\HelpDocument](#class-consolidationoutputformattersstructureddatahelpdocument)
- [\Consolidation\OutputFormatters\StructuredData\OriginalDataInterface (interface)](#interface-consolidationoutputformattersstructureddataoriginaldatainterface)
- [\Consolidation\OutputFormatters\StructuredData\RowsOfFields](#class-consolidationoutputformattersstructureddatarowsoffields)
- [\Consolidation\OutputFormatters\StructuredData\RestructureInterface (interface)](#interface-consolidationoutputformattersstructureddatarestructureinterface)
- [\Consolidation\OutputFormatters\StructuredData\AbstractStructuredList (abstract)](#class-consolidationoutputformattersstructureddataabstractstructuredlist-abstract)
- [\Consolidation\OutputFormatters\StructuredData\ListDataFromKeys](#class-consolidationoutputformattersstructureddatalistdatafromkeys)
- [\Consolidation\OutputFormatters\StructuredData\PropertyList](#class-consolidationoutputformattersstructureddatapropertylist)
- [\Consolidation\OutputFormatters\StructuredData\RenderCellInterface (interface)](#interface-consolidationoutputformattersstructureddatarendercellinterface)
- [\Consolidation\OutputFormatters\StructuredData\CallableRenderer](#class-consolidationoutputformattersstructureddatacallablerenderer)
- [\Consolidation\OutputFormatters\StructuredData\RenderCellCollectionInterface (interface)](#interface-consolidationoutputformattersstructureddatarendercellcollectioninterface)
- [\Consolidation\OutputFormatters\StructuredData\AssociativeList](#class-consolidationoutputformattersstructureddataassociativelist)
- [\Consolidation\OutputFormatters\StructuredData\Xml\XmlSchemaInterface (interface)](#interface-consolidationoutputformattersstructureddataxmlxmlschemainterface)
- [\Consolidation\OutputFormatters\StructuredData\Xml\DomDataInterface (interface)](#interface-consolidationoutputformattersstructureddataxmldomdatainterface)
- [\Consolidation\OutputFormatters\StructuredData\Xml\XmlSchema](#class-consolidationoutputformattersstructureddataxmlxmlschema)
- [\Consolidation\OutputFormatters\Transformations\PropertyParser](#class-consolidationoutputformatterstransformationspropertyparser)
- [\Consolidation\OutputFormatters\Transformations\PropertyListTableTransformation](#class-consolidationoutputformatterstransformationspropertylisttabletransformation)
- [\Consolidation\OutputFormatters\Transformations\TableTransformation](#class-consolidationoutputformatterstransformationstabletransformation)
- [\Consolidation\OutputFormatters\Transformations\ReorderFields](#class-consolidationoutputformatterstransformationsreorderfields)
- [\Consolidation\OutputFormatters\Transformations\DomToArraySimplifier](#class-consolidationoutputformatterstransformationsdomtoarraysimplifier)
- [\Consolidation\OutputFormatters\Transformations\WordWrapper](#class-consolidationoutputformatterstransformationswordwrapper)
- [\Consolidation\OutputFormatters\Transformations\OverrideRestructureInterface (interface)](#interface-consolidationoutputformatterstransformationsoverriderestructureinterface)
- [\Consolidation\OutputFormatters\Transformations\SimplifyToArrayInterface (interface)](#interface-consolidationoutputformatterstransformationssimplifytoarrayinterface)
- [\Consolidation\OutputFormatters\Transformations\Wrap\CalculateWidths](#class-consolidationoutputformatterstransformationswrapcalculatewidths)
- [\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)
- [\Consolidation\OutputFormatters\Validate\ValidationInterface (interface)](#interface-consolidationoutputformattersvalidatevalidationinterface)
- [\Consolidation\OutputFormatters\Validate\ValidDataTypesInterface (interface)](#interface-consolidationoutputformattersvalidatevaliddatatypesinterface)
<hr />
### Class: \Consolidation\OutputFormatters\FormatterManager
> Manage a collection of formatters; return one on request.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct()</strong> : <em>void</em> |
| public | <strong>addDefaultFormatters()</strong> : <em>void</em> |
| public | <strong>addDefaultSimplifiers()</strong> : <em>void</em> |
| public | <strong>addFormatter(</strong><em>string</em> <strong>$key</strong>, <em>string/[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>)</strong> : <em>[\Consolidation\OutputFormatters\FormatterManager](#class-consolidationoutputformattersformattermanager)</em><br /><em>Add a formatter</em> |
| public | <strong>addSimplifier(</strong><em>[\Consolidation\OutputFormatters\Transformations\SimplifyToArrayInterface](#interface-consolidationoutputformatterstransformationssimplifytoarrayinterface)</em> <strong>$simplifier</strong>)</strong> : <em>[\Consolidation\OutputFormatters\FormatterManager](#class-consolidationoutputformattersformattermanager)</em><br /><em>Add a simplifier</em> |
| public | <strong>automaticOptions(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>, <em>mixed</em> <strong>$dataType</strong>)</strong> : <em>\Symfony\Component\Console\Input\InputOption[]</em><br /><em>Return a set of InputOption based on the annotations of a command.</em> |
| public | <strong>getFormatter(</strong><em>string</em> <strong>$format</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em><br /><em>Fetch the requested formatter.</em> |
| public | <strong>hasFormatter(</strong><em>mixed</em> <strong>$format</strong>)</strong> : <em>bool</em><br /><em>Test to see if the stipulated format exists</em> |
| public | <strong>isValidDataType(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em> |
| public | <strong>isValidFormat(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>mixed</em> <strong>$dataType</strong>)</strong> : <em>bool</em> |
| public | <strong>overrideOptions(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em><br /><em>Allow the formatter to mess with the configuration options before any transformations et. al. get underway.</em> |
| public | <strong>overrideRestructure(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Allow the formatter access to the raw structured data prior to restructuring. For example, the 'list' formatter may wish to display the row keys when provided table output. If this function returns a result that does not evaluate to 'false', then that result will be used as-is, and restructuring and validation will not occur.</em> |
| public | <strong>renderData(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Render the data as necessary (e.g. to select or reorder fields).</em> |
| public | <strong>restructureData(</strong><em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Restructure the data as necessary (e.g. to select or reorder fields).</em> |
| public | <strong>validFormats(</strong><em>mixed</em> <strong>$dataType</strong>)</strong> : <em>array</em><br /><em>Return the identifiers for all valid data types that have been registered.</em> |
| public | <strong>validateData(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Determine if the provided data is compatible with the formatter being used.</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>string</em> <strong>$format</strong>, <em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em><br /><em>Format and write output</em> |
| protected | <strong>availableFieldsList(</strong><em>mixed</em> <strong>$availableFields</strong>)</strong> : <em>string[]</em><br /><em>Given a list of available fields, return a list of field descriptions.</em> |
| protected | <strong>canSimplifyToArray(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$structuredOutput</strong>)</strong> : <em>bool</em> |
| protected | <strong>simplifyToArray(</strong><em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
| protected | <strong>validateAndRestructure(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Exception\UnknownFormatException
> Indicates that the requested format does not exist.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>mixed</em> <strong>$format</strong>)</strong> : <em>void</em> |
*This class extends \Exception*
*This class implements \Throwable*
<hr />
### Class: \Consolidation\OutputFormatters\Exception\AbstractDataFormatException (abstract)
> Contains some helper functions used by exceptions in this project.
| Visibility | Function |
|:-----------|:---------|
| protected static | <strong>describeAllowedTypes(</strong><em>mixed</em> <strong>$allowedTypes</strong>)</strong> : <em>void</em> |
| protected static | <strong>describeDataType(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$data</strong>)</strong> : <em>string</em><br /><em>Return a description of the data type represented by the provided parameter. \ArrayObject is used as a proxy to mean an array primitive (or an ArrayObject).</em> |
| protected static | <strong>describeListOfAllowedTypes(</strong><em>mixed</em> <strong>$allowedTypes</strong>)</strong> : <em>void</em> |
*This class extends \Exception*
*This class implements \Throwable*
<hr />
### Class: \Consolidation\OutputFormatters\Exception\IncompatibleDataException
> Represents an incompatibility between the output data and selected formatter.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>[\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)</em> <strong>$formatter</strong>, <em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$allowedTypes</strong>)</strong> : <em>void</em> |
*This class extends [\Consolidation\OutputFormatters\Exception\AbstractDataFormatException](#class-consolidationoutputformattersexceptionabstractdataformatexception-abstract)*
*This class implements \Throwable*
<hr />
### Class: \Consolidation\OutputFormatters\Exception\InvalidFormatException
> Represents an incompatibility between the output data and selected formatter.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>mixed</em> <strong>$format</strong>, <em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$validFormats</strong>)</strong> : <em>void</em> |
*This class extends [\Consolidation\OutputFormatters\Exception\AbstractDataFormatException](#class-consolidationoutputformattersexceptionabstractdataformatexception-abstract)*
*This class implements \Throwable*
<hr />
### Class: \Consolidation\OutputFormatters\Exception\UnknownFieldException
> Indicates that the requested format does not exist.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>mixed</em> <strong>$field</strong>)</strong> : <em>void</em> |
*This class extends \Exception*
*This class implements \Throwable*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\ListFormatter
> Display the data in a simple list. This formatter prints a plain, unadorned list of data, with each data item appearing on a separate line. If you wish your list to contain headers, then use the table formatter, and wrap your data in an PropertyList.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>overrideRestructure(</strong><em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Select data to use directly from the structured output, before the restructure operation has been executed.</em> |
| public | <strong>renderData(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Convert the contents of the output data just before it is to be printed, prior to output but after restructuring and validation.</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
| protected | <strong>renderEachCell(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface), [\Consolidation\OutputFormatters\Transformations\OverrideRestructureInterface](#interface-consolidationoutputformatterstransformationsoverriderestructureinterface), [\Consolidation\OutputFormatters\Formatters\RenderDataInterface](#interface-consolidationoutputformattersformattersrenderdatainterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\SectionsFormatter
> Display sections of data. This formatter takes data in the RowsOfFields data type. Each row represents one section; the data in each section is rendered in two columns, with the key in the first column and the value in the second column.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>isValidDataType(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em><br /><em>Return the list of data types acceptable to this formatter</em> |
| public | <strong>renderData(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Convert the contents of the output data just before it is to be printed, prior to output but after restructuring and validation.</em> |
| public | <strong>validDataTypes()</strong> : <em>void</em> |
| public | <strong>validate(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>mixed</em><br /><em>Throw an IncompatibleDataException if the provided data cannot be processed by this formatter. Return the source data if it is valid. The data may be encapsulated or converted if necessary.</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
| protected | <strong>renderEachCell(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface), [\Consolidation\OutputFormatters\Validate\ValidDataTypesInterface](#interface-consolidationoutputformattersvalidatevaliddatatypesinterface), [\Consolidation\OutputFormatters\Validate\ValidationInterface](#interface-consolidationoutputformattersvalidatevalidationinterface), [\Consolidation\OutputFormatters\Formatters\RenderDataInterface](#interface-consolidationoutputformattersformattersrenderdatainterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\JsonFormatter
> Json formatter Convert an array or ArrayObject into Json.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\Formatters\FormatterInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\CsvFormatter
> Comma-separated value formatters Display the provided structured data in a comma-separated list. If there are multiple records provided, then they will be printed one per line. The primary data types accepted are RowsOfFields and PropertyList. The later behaves exactly like the former, save for the fact that it contains but a single row. This formmatter can also accept a PHP array; this is also interpreted as a single-row of data with no header.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>isValidDataType(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em><br /><em>Return the list of data types acceptable to this formatter</em> |
| public | <strong>renderData(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Convert the contents of the output data just before it is to be printed, prior to output but after restructuring and validation.</em> |
| public | <strong>validDataTypes()</strong> : <em>void</em> |
| public | <strong>validate(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>void</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
| protected | <strong>csvEscape(</strong><em>mixed</em> <strong>$data</strong>, <em>string</em> <strong>$delimiter=`','`</strong>)</strong> : <em>void</em> |
| protected | <strong>getDefaultFormatterOptions()</strong> : <em>array</em><br /><em>Return default values for formatter options</em> |
| protected | <strong>renderEachCell(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
| protected | <strong>writeOneLine(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$options</strong>)</strong> : <em>void</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface), [\Consolidation\OutputFormatters\Validate\ValidDataTypesInterface](#interface-consolidationoutputformattersvalidatevaliddatatypesinterface), [\Consolidation\OutputFormatters\Validate\ValidationInterface](#interface-consolidationoutputformattersvalidatevalidationinterface), [\Consolidation\OutputFormatters\Formatters\RenderDataInterface](#interface-consolidationoutputformattersformattersrenderdatainterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\SerializeFormatter
> Serialize formatter Run provided date thruogh serialize.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\StringFormatter
> String formatter This formatter is used as the default action when no particular formatter is requested. It will print the provided data only if it is a string; if any other type is given, then nothing is printed.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>isValidDataType(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em><br /><em>All data types are acceptable.</em> |
| public | <strong>overrideOptions(</strong><em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em><br /><em>Allow the formatter to mess with the configuration options before any transformations et. al. get underway.</em> |
| public | <strong>validate(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>void</em><br /><em>Always validate any data, though. This format will never cause an error if it is selected for an incompatible data type; at worse, it simply does not print any data.</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
| protected | <strong>reduceToSigleFieldAndWrite(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em><br /><em>If the data provided to a 'string' formatter is a table, then try to emit it as a TSV value.</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface), [\Consolidation\OutputFormatters\Validate\ValidationInterface](#interface-consolidationoutputformattersvalidatevalidationinterface), [\Consolidation\OutputFormatters\Options\OverrideOptionsInterface](#interface-consolidationoutputformattersoptionsoverrideoptionsinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\VarExportFormatter
> Var_export formatter Run provided date thruogh var_export.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\YamlFormatter
> Yaml formatter Convert an array or ArrayObject into Yaml.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\TableFormatter
> Display a table of data with the Symfony Table class. This formatter takes data of either the RowsOfFields or PropertyList data type. Tables can be rendered with the rows running either vertically (the normal orientation) or horizontally. By default, associative lists will be displayed as two columns, with the key in the first column and the value in the second column.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct()</strong> : <em>void</em> |
| public | <strong>isValidDataType(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em><br /><em>Return the list of data types acceptable to this formatter</em> |
| public | <strong>renderData(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Convert the contents of the output data just before it is to be printed, prior to output but after restructuring and validation.</em> |
| public | <strong>validDataTypes()</strong> : <em>void</em> |
| public | <strong>validate(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>mixed</em><br /><em>Throw an IncompatibleDataException if the provided data cannot be processed by this formatter. Return the source data if it is valid. The data may be encapsulated or converted if necessary.</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
| protected static | <strong>addCustomTableStyles(</strong><em>mixed</em> <strong>$table</strong>)</strong> : <em>void</em><br /><em>Add our custom table style(s) to the table.</em> |
| protected | <strong>renderEachCell(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
| protected | <strong>wrap(</strong><em>mixed</em> <strong>$headers</strong>, <em>array</em> <strong>$data</strong>, <em>\Symfony\Component\Console\Helper\TableStyle</em> <strong>$tableStyle</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>array</em><br /><em>Wrap the table data</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface), [\Consolidation\OutputFormatters\Validate\ValidDataTypesInterface](#interface-consolidationoutputformattersvalidatevaliddatatypesinterface), [\Consolidation\OutputFormatters\Validate\ValidationInterface](#interface-consolidationoutputformattersvalidatevalidationinterface), [\Consolidation\OutputFormatters\Formatters\RenderDataInterface](#interface-consolidationoutputformattersformattersrenderdatainterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\XmlFormatter
> Display a table of data with the Symfony Table class. This formatter takes data of either the RowsOfFields or PropertyList data type. Tables can be rendered with the rows running either vertically (the normal orientation) or horizontally. By default, associative lists will be displayed as two columns, with the key in the first column and the value in the second column.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct()</strong> : <em>void</em> |
| public | <strong>isValidDataType(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em><br /><em>Return the list of data types acceptable to this formatter</em> |
| public | <strong>validDataTypes()</strong> : <em>void</em> |
| public | <strong>validate(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>mixed</em><br /><em>Throw an IncompatibleDataException if the provided data cannot be processed by this formatter. Return the source data if it is valid. The data may be encapsulated or converted if necessary.</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface), [\Consolidation\OutputFormatters\Validate\ValidDataTypesInterface](#interface-consolidationoutputformattersvalidatevaliddatatypesinterface), [\Consolidation\OutputFormatters\Validate\ValidationInterface](#interface-consolidationoutputformattersvalidatevalidationinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\PrintRFormatter
> Print_r formatter Run provided date thruogh print_r.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
*This class implements [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\Formatters\RenderDataInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>renderData(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Convert the contents of the output data just before it is to be printed, prior to output but after restructuring and validation.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Formatters\TsvFormatter
> Tab-separated value formatters Display the provided structured data in a tab-separated list. Output escaping is much lighter, since there is no allowance for altering the delimiter.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>renderData(</strong><em>mixed</em> <strong>$originalData</strong>, <em>mixed</em> <strong>$restructuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Convert the contents of the output data just before it is to be printed, prior to output but after restructuring and validation.</em> |
| public | <strong>write(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>string</em><br /><em>Given structured data, apply appropriate formatting, and return a printable string.</em> |
| protected | <strong>getDefaultFormatterOptions()</strong> : <em>mixed</em> |
| protected | <strong>tsvEscape(</strong><em>mixed</em> <strong>$data</strong>)</strong> : <em>void</em> |
| protected | <strong>writeOneLine(</strong><em>\Symfony\Component\Console\Output\OutputInterface</em> <strong>$output</strong>, <em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$options</strong>)</strong> : <em>void</em> |
*This class extends [\Consolidation\OutputFormatters\Formatters\CsvFormatter](#class-consolidationoutputformattersformatterscsvformatter)*
*This class implements [\Consolidation\OutputFormatters\Formatters\RenderDataInterface](#interface-consolidationoutputformattersformattersrenderdatainterface), [\Consolidation\OutputFormatters\Validate\ValidationInterface](#interface-consolidationoutputformattersvalidatevalidationinterface), [\Consolidation\OutputFormatters\Validate\ValidDataTypesInterface](#interface-consolidationoutputformattersvalidatevaliddatatypesinterface), [\Consolidation\OutputFormatters\Formatters\FormatterInterface](#interface-consolidationoutputformattersformattersformatterinterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\Options\OverrideOptionsInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>overrideOptions(</strong><em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em><br /><em>Allow the formatter to mess with the configuration options before any transformations et. al. get underway.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Options\FormatterOptions
> FormetterOptions holds information that affects the way a formatter renders its output. There are three places where a formatter might get options from: 1. Configuration associated with the command that produced the output. This is passed in to FormatterManager::write() along with the data to format. It might originally come from annotations on the command, or it might come from another source. Examples include the field labels for a table, or the default list of fields to display. 2. Options specified by the user, e.g. by commandline options. 3. Default values associated with the formatter itself. This class caches configuration from sources (1) and (2), and expects to be provided the defaults, (3), whenever a value is requested.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>array</em> <strong>$configurationData=array()</strong>, <em>array</em> <strong>$options=array()</strong>)</strong> : <em>void</em><br /><em>Create a new FormatterOptions with the configuration data and the user-specified options for this request.</em> |
| public | <strong>get(</strong><em>string</em> <strong>$key</strong>, <em>array</em> <strong>$defaults=array()</strong>, <em>bool/mixed</em> <strong>$default=false</strong>)</strong> : <em>mixed</em><br /><em>Get a formatter option</em> |
| public | <strong>getConfigurationData()</strong> : <em>array</em><br /><em>Return a reference to the configuration data for this object.</em> |
| public | <strong>getFormat(</strong><em>array</em> <strong>$defaults=array()</strong>)</strong> : <em>string</em><br /><em>Determine the format that was requested by the caller.</em> |
| public | <strong>getInputOptions(</strong><em>array</em> <strong>$defaults</strong>)</strong> : <em>array</em><br /><em>Return all of the options from the provided $defaults array that exist in our InputInterface object.</em> |
| public | <strong>getOptions()</strong> : <em>array</em><br /><em>Return a reference to the user-specified options for this request.</em> |
| public | <strong>getXmlSchema()</strong> : <em>[\Consolidation\OutputFormatters\StructuredData\Xml\XmlSchema](#class-consolidationoutputformattersstructureddataxmlxmlschema)</em><br /><em>Return the XmlSchema to use with --format=xml for data types that support that. This is used when an array needs to be converted into xml.</em> |
| public | <strong>override(</strong><em>array</em> <strong>$configurationData</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em><br /><em>Create a new FormatterOptions object with new configuration data (provided), and the same options data as this instance.</em> |
| public | <strong>parsePropertyList(</strong><em>string</em> <strong>$value</strong>)</strong> : <em>array</em><br /><em>Convert from a textual list to an array</em> |
| public | <strong>setConfigurationData(</strong><em>array</em> <strong>$configurationData</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em><br /><em>Change the configuration data for this formatter options object.</em> |
| public | <strong>setConfigurationDefault(</strong><em>string</em> <strong>$key</strong>, <em>mixed</em> <strong>$value</strong>)</strong> : <em>\Consolidation\OutputFormatters\Options\FormetterOptions</em><br /><em>Change one configuration value for this formatter option, but only if it does not already have a value set.</em> |
| public | <strong>setDefaultFields(</strong><em>mixed</em> <strong>$fields</strong>)</strong> : <em>void</em> |
| public | <strong>setDefaultStringField(</strong><em>mixed</em> <strong>$defaultStringField</strong>)</strong> : <em>void</em> |
| public | <strong>setDelimiter(</strong><em>mixed</em> <strong>$delimiter</strong>)</strong> : <em>void</em> |
| public | <strong>setFieldLabels(</strong><em>mixed</em> <strong>$fieldLabels</strong>)</strong> : <em>void</em> |
| public | <strong>setIncludeFieldLables(</strong><em>mixed</em> <strong>$includFieldLables</strong>)</strong> : <em>void</em> |
| public | <strong>setInput(</strong><em>\Symfony\Component\Console\Input\InputInterface</em> <strong>$input</strong>)</strong> : <em>\Consolidation\OutputFormatters\Options\type</em><br /><em>Provide a Symfony Console InputInterface containing the user-specified options for this request.</em> |
| public | <strong>setListDelimiter(</strong><em>mixed</em> <strong>$listDelimiter</strong>)</strong> : <em>void</em> |
| public | <strong>setListOrientation(</strong><em>mixed</em> <strong>$listOrientation</strong>)</strong> : <em>void</em> |
| public | <strong>setOption(</strong><em>string</em> <strong>$key</strong>, <em>mixed</em> <strong>$value</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em><br /><em>Change one option value specified by the user for this request.</em> |
| public | <strong>setOptions(</strong><em>array</em> <strong>$options</strong>)</strong> : <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em><br /><em>Set all of the options that were specified by the user for this request.</em> |
| public | <strong>setRowLabels(</strong><em>mixed</em> <strong>$rowLabels</strong>)</strong> : <em>void</em> |
| public | <strong>setTableStyle(</strong><em>mixed</em> <strong>$style</strong>)</strong> : <em>void</em> |
| public | <strong>setWidth(</strong><em>mixed</em> <strong>$width</strong>)</strong> : <em>void</em> |
| protected | <strong>defaultsForKey(</strong><em>string</em> <strong>$key</strong>, <em>array</em> <strong>$defaults</strong>, <em>bool</em> <strong>$default=false</strong>)</strong> : <em>array</em><br /><em>Reduce provided defaults to the single item identified by '$key', if it exists, or an empty array otherwise.</em> |
| protected | <strong>fetch(</strong><em>string</em> <strong>$key</strong>, <em>array</em> <strong>$defaults=array()</strong>, <em>bool/mixed</em> <strong>$default=false</strong>)</strong> : <em>mixed</em><br /><em>Look up a key, and return its raw value.</em> |
| protected | <strong>fetchRawValues(</strong><em>array</em> <strong>$defaults=array()</strong>)</strong> : <em>array</em><br /><em>Look up all of the items associated with the provided defaults.</em> |
| protected | <strong>getOptionFormat(</strong><em>string</em> <strong>$key</strong>)</strong> : <em>string</em><br /><em>Given a specific key, return the class method name of the parsing method for data stored under this key.</em> |
| protected | <strong>parse(</strong><em>string</em> <strong>$key</strong>, <em>mixed</em> <strong>$value</strong>)</strong> : <em>mixed</em><br /><em>Given the raw value for a specific key, do any type conversion (e.g. from a textual list to an array) needed for the data.</em> |
| protected | <strong>setConfigurationValue(</strong><em>string</em> <strong>$key</strong>, <em>mixed</em> <strong>$value</strong>)</strong> : <em>\Consolidation\OutputFormatters\Options\FormetterOptions</em><br /><em>Change one configuration value for this formatter option.</em> |
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\ListDataInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getListData(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>array</em><br /><em>Convert data to a format suitable for use in a list. By default, the array values will be used. Implement ListDataInterface to use some other criteria (e.g. array keys).</em> |
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\TableDataInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getOriginalData()</strong> : <em>mixed</em><br /><em>Return the original data for this table. Used by any formatter that is -not- a table.</em> |
| public | <strong>getTableData(</strong><em>bool/boolean</em> <strong>$includeRowKey=false</strong>)</strong> : <em>array</em><br /><em>Convert structured data into a form suitable for use by the table formatter. key from each row.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\HelpDocument
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getDomData()</strong> : <em>[\DomDocument](http://php.net/manual/en/class.domdocument.php)</em><br /><em>Convert data into a \DomDocument.</em> |
*This class implements [\Consolidation\OutputFormatters\StructuredData\Xml\DomDataInterface](#interface-consolidationoutputformattersstructureddataxmldomdatainterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\OriginalDataInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getOriginalData()</strong> : <em>mixed</em><br /><em>Return the original data for this table. Used by any formatter that expects an array.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\RowsOfFields
> Holds an array where each element of the array is one row, and each row contains an associative array where the keys are the field names, and the values are the field data. It is presumed that every row contains the same keys.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getListData(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em> |
| public | <strong>restructure(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>\Consolidation\OutputFormatters\StructuredData\Consolidation\OutputFormatters\Transformations\TableTransformation</em><br /><em>Restructure this data for output by converting it into a table transformation object.</em> |
| protected | <strong>defaultOptions()</strong> : <em>void</em> |
*This class extends [\Consolidation\OutputFormatters\StructuredData\AbstractStructuredList](#class-consolidationoutputformattersstructureddataabstractstructuredlist-abstract)*
*This class implements [\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface), [\Consolidation\OutputFormatters\StructuredData\RenderCellCollectionInterface](#interface-consolidationoutputformattersstructureddatarendercellcollectioninterface), [\Consolidation\OutputFormatters\StructuredData\RestructureInterface](#interface-consolidationoutputformattersstructureddatarestructureinterface), \Countable, \Serializable, \ArrayAccess, \Traversable, \IteratorAggregate, [\Consolidation\OutputFormatters\StructuredData\ListDataInterface](#interface-consolidationoutputformattersstructureddatalistdatainterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\RestructureInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>restructure(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em><br /><em>Allow structured data to be restructured -- i.e. to select fields to show, reorder fields, etc.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\AbstractStructuredList (abstract)
> Holds an array where each element of the array is one row, and each row contains an associative array where the keys are the field names, and the values are the field data. It is presumed that every row contains the same keys.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>mixed</em> <strong>$data</strong>)</strong> : <em>void</em> |
| public | <strong>addRenderer(</strong><em>[\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface)</em> <strong>$renderer</strong>, <em>string</em> <strong>$priority=`'normal'`</strong>)</strong> : <em>\Consolidation\OutputFormatters\StructuredData\$this</em><br /><em>Add a renderer</em> |
| public | <strong>addRendererFunction(</strong><em>\callable</em> <strong>$rendererFn</strong>, <em>string</em> <strong>$priority=`'normal'`</strong>)</strong> : <em>\Consolidation\OutputFormatters\StructuredData\$this</em><br /><em>Add a callable as a renderer</em> |
| public | <strong>renderCell(</strong><em>mixed</em> <strong>$key</strong>, <em>mixed</em> <strong>$cellData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>, <em>mixed</em> <strong>$rowData</strong>)</strong> : <em>void</em> |
| public | <strong>abstract restructure(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
| protected | <strong>createTableTransformation(</strong><em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$options</strong>)</strong> : <em>mixed</em> |
| protected | <strong>defaultOptions()</strong> : <em>array</em><br /><em>A structured list may provide its own set of default options. These will be used in place of the command's default options (from the annotations) in instances where the user does not provide the options explicitly (on the commandline) or implicitly (via a configuration file).</em> |
| protected | <strong>getFields(</strong><em>mixed</em> <strong>$options</strong>, <em>mixed</em> <strong>$defaults</strong>)</strong> : <em>mixed</em> |
| protected | <strong>getReorderedFieldLabels(</strong><em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$options</strong>, <em>mixed</em> <strong>$defaults</strong>)</strong> : <em>mixed</em> |
| protected | <strong>instantiateTableTransformation(</strong><em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$fieldLabels</strong>, <em>mixed</em> <strong>$rowLabels</strong>)</strong> : <em>void</em> |
*This class extends [\Consolidation\OutputFormatters\StructuredData\ListDataFromKeys](#class-consolidationoutputformattersstructureddatalistdatafromkeys)*
*This class implements [\Consolidation\OutputFormatters\StructuredData\ListDataInterface](#interface-consolidationoutputformattersstructureddatalistdatainterface), \IteratorAggregate, \Traversable, \ArrayAccess, \Serializable, \Countable, [\Consolidation\OutputFormatters\StructuredData\RestructureInterface](#interface-consolidationoutputformattersstructureddatarestructureinterface), [\Consolidation\OutputFormatters\StructuredData\RenderCellCollectionInterface](#interface-consolidationoutputformattersstructureddatarendercellcollectioninterface), [\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\ListDataFromKeys
> Represents aribtrary array data (structured or unstructured) where the data to display in --list format comes from the array keys.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>mixed</em> <strong>$data</strong>)</strong> : <em>void</em> |
| public | <strong>getListData(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em> |
*This class extends \ArrayObject*
*This class implements \Countable, \Serializable, \ArrayAccess, \Traversable, \IteratorAggregate, [\Consolidation\OutputFormatters\StructuredData\ListDataInterface](#interface-consolidationoutputformattersstructureddatalistdatainterface)*
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\PropertyList
> Holds an array where each element of the array is one key : value pair. The keys must be unique, as is typically the case for associative arrays.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getListData(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em> |
| public | <strong>restructure(</strong><em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>\Consolidation\OutputFormatters\StructuredData\Consolidation\OutputFormatters\Transformations\TableTransformation</em><br /><em>Restructure this data for output by converting it into a table transformation object.</em> |
| protected | <strong>defaultOptions()</strong> : <em>void</em> |
| protected | <strong>instantiateTableTransformation(</strong><em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$fieldLabels</strong>, <em>mixed</em> <strong>$rowLabels</strong>)</strong> : <em>void</em> |
*This class extends [\Consolidation\OutputFormatters\StructuredData\AbstractStructuredList](#class-consolidationoutputformattersstructureddataabstractstructuredlist-abstract)*
*This class implements [\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface), [\Consolidation\OutputFormatters\StructuredData\RenderCellCollectionInterface](#interface-consolidationoutputformattersstructureddatarendercellcollectioninterface), [\Consolidation\OutputFormatters\StructuredData\RestructureInterface](#interface-consolidationoutputformattersstructureddatarestructureinterface), \Countable, \Serializable, \ArrayAccess, \Traversable, \IteratorAggregate, [\Consolidation\OutputFormatters\StructuredData\ListDataInterface](#interface-consolidationoutputformattersstructureddatalistdatainterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\RenderCellInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>renderCell(</strong><em>string</em> <strong>$key</strong>, <em>mixed</em> <strong>$cellData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>, <em>array</em> <strong>$rowData</strong>)</strong> : <em>mixed</em><br /><em>Convert the contents of one table cell into a string, so that it may be placed in the table. Renderer should return the $cellData passed to it if it does not wish to process it.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\CallableRenderer
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>\callable</em> <strong>$renderFunction</strong>)</strong> : <em>void</em> |
| public | <strong>renderCell(</strong><em>mixed</em> <strong>$key</strong>, <em>mixed</em> <strong>$cellData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>, <em>mixed</em> <strong>$rowData</strong>)</strong> : <em>void</em> |
*This class implements [\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\RenderCellCollectionInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>addRenderer(</strong><em>[\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface)</em> <strong>$renderer</strong>)</strong> : <em>\Consolidation\OutputFormatters\StructuredData\$this</em><br /><em>Add a renderer</em> |
*This class implements [\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\AssociativeList
> Old name for PropertyList class.
| Visibility | Function |
|:-----------|:---------|
*This class extends [\Consolidation\OutputFormatters\StructuredData\PropertyList](#class-consolidationoutputformattersstructureddatapropertylist)*
*This class implements [\Consolidation\OutputFormatters\StructuredData\ListDataInterface](#interface-consolidationoutputformattersstructureddatalistdatainterface), \IteratorAggregate, \Traversable, \ArrayAccess, \Serializable, \Countable, [\Consolidation\OutputFormatters\StructuredData\RestructureInterface](#interface-consolidationoutputformattersstructureddatarestructureinterface), [\Consolidation\OutputFormatters\StructuredData\RenderCellCollectionInterface](#interface-consolidationoutputformattersstructureddatarendercellcollectioninterface), [\Consolidation\OutputFormatters\StructuredData\RenderCellInterface](#interface-consolidationoutputformattersstructureddatarendercellinterface)*
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\Xml\XmlSchemaInterface
> When using arrays, we could represent XML data in a number of different ways. For example, given the following XML data strucutre: <document id="1" name="doc"> <foobars> <foobar id="123"> <name>blah</name> <widgets> <widget> <foo>a</foo> <bar>b</bar> <baz>c</baz> </widget> </widgets> </foobar> </foobars> </document> This could be: [ 'id' => 1, 'name' => 'doc', 'foobars' => [ [ 'id' => '123', 'name' => 'blah', 'widgets' => [ [ 'foo' => 'a', 'bar' => 'b', 'baz' => 'c', ] ], ], ] ] The challenge is more in going from an array back to the more structured xml format. Note that any given key => string mapping could represent either an attribute, or a simple XML element containing only a string value. In general, we do *not* want to add extra layers of nesting in the data structure to disambiguate between these kinds of data, as we want the source data to render cleanly into other formats, e.g. yaml, json, et. al., and we do not want to force every data provider to have to consider the optimal xml schema for their data. Our strategy, therefore, is to expect clients that wish to provide a very specific xml representation to return a DOMDocument, and, for other data structures where xml is a secondary concern, then we will use some default heuristics to convert from arrays to xml.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>arrayToXml(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>[\DOMDocument](http://php.net/manual/en/class.domdocument.php)</em><br /><em>Convert data to a format suitable for use in a list. By default, the array values will be used. Implement ListDataInterface to use some other criteria (e.g. array keys).</em> |
<hr />
### Interface: \Consolidation\OutputFormatters\StructuredData\Xml\DomDataInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getDomData()</strong> : <em>[\DomDocument](http://php.net/manual/en/class.domdocument.php)</em><br /><em>Convert data into a \DomDocument.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\StructuredData\Xml\XmlSchema
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>array</em> <strong>$elementList=array()</strong>)</strong> : <em>void</em> |
| public | <strong>arrayToXML(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>void</em> |
| protected | <strong>addXmlChildren(</strong><em>[\DOMDocument](http://php.net/manual/en/class.domdocument.php)</em> <strong>$dom</strong>, <em>mixed</em> <strong>$xmlParent</strong>, <em>mixed</em> <strong>$elementName</strong>, <em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>void</em> |
| protected | <strong>addXmlData(</strong><em>[\DOMDocument](http://php.net/manual/en/class.domdocument.php)</em> <strong>$dom</strong>, <em>mixed</em> <strong>$xmlParent</strong>, <em>mixed</em> <strong>$elementName</strong>, <em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>void</em> |
| protected | <strong>addXmlDataOrAttribute(</strong><em>[\DOMDocument](http://php.net/manual/en/class.domdocument.php)</em> <strong>$dom</strong>, <em>mixed</em> <strong>$xmlParent</strong>, <em>mixed</em> <strong>$elementName</strong>, <em>mixed</em> <strong>$key</strong>, <em>mixed</em> <strong>$value</strong>)</strong> : <em>void</em> |
| protected | <strong>determineElementName(</strong><em>mixed</em> <strong>$key</strong>, <em>mixed</em> <strong>$childElementName</strong>, <em>mixed</em> <strong>$value</strong>)</strong> : <em>void</em> |
| protected | <strong>getDefaultElementName(</strong><em>mixed</em> <strong>$parentElementName</strong>)</strong> : <em>mixed</em> |
| protected | <strong>getTopLevelElementName(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>mixed</em> |
| protected | <strong>inElementList(</strong><em>mixed</em> <strong>$parentElementName</strong>, <em>mixed</em> <strong>$elementName</strong>)</strong> : <em>void</em> |
| protected | <strong>isAssoc(</strong><em>mixed</em> <strong>$data</strong>)</strong> : <em>bool</em> |
| protected | <strong>isAttribute(</strong><em>mixed</em> <strong>$parentElementName</strong>, <em>mixed</em> <strong>$elementName</strong>, <em>mixed</em> <strong>$value</strong>)</strong> : <em>bool</em> |
| protected | <strong>singularForm(</strong><em>mixed</em> <strong>$name</strong>)</strong> : <em>void</em> |
*This class implements [\Consolidation\OutputFormatters\StructuredData\Xml\XmlSchemaInterface](#interface-consolidationoutputformattersstructureddataxmlxmlschemainterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\PropertyParser
> Transform a string of properties into a PHP associative array. Input: one: red two: white three: blue Output: [ 'one' => 'red', 'two' => 'white', 'three' => 'blue', ]
| Visibility | Function |
|:-----------|:---------|
| public static | <strong>parse(</strong><em>mixed</em> <strong>$data</strong>)</strong> : <em>void</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\PropertyListTableTransformation
| Visibility | Function |
|:-----------|:---------|
| public | <strong>getOriginalData()</strong> : <em>mixed</em> |
*This class extends [\Consolidation\OutputFormatters\Transformations\TableTransformation](#class-consolidationoutputformatterstransformationstabletransformation)*
*This class implements [\Consolidation\OutputFormatters\StructuredData\OriginalDataInterface](#interface-consolidationoutputformattersstructureddataoriginaldatainterface), [\Consolidation\OutputFormatters\StructuredData\TableDataInterface](#interface-consolidationoutputformattersstructureddatatabledatainterface), \IteratorAggregate, \Traversable, \ArrayAccess, \Serializable, \Countable*
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\TableTransformation
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$fieldLabels</strong>, <em>array</em> <strong>$rowLabels=array()</strong>)</strong> : <em>void</em> |
| public | <strong>getHeader(</strong><em>mixed</em> <strong>$key</strong>)</strong> : <em>mixed</em> |
| public | <strong>getHeaders()</strong> : <em>mixed</em> |
| public | <strong>getLayout()</strong> : <em>mixed</em> |
| public | <strong>getOriginalData()</strong> : <em>mixed</em> |
| public | <strong>getRowLabel(</strong><em>mixed</em> <strong>$rowid</strong>)</strong> : <em>mixed</em> |
| public | <strong>getRowLabels()</strong> : <em>mixed</em> |
| public | <strong>getTableData(</strong><em>bool</em> <strong>$includeRowKey=false</strong>)</strong> : <em>mixed</em> |
| public | <strong>isList()</strong> : <em>bool</em> |
| public | <strong>setLayout(</strong><em>mixed</em> <strong>$layout</strong>)</strong> : <em>void</em> |
| protected | <strong>convertTableToList()</strong> : <em>void</em> |
| protected | <strong>getRowDataWithKey(</strong><em>mixed</em> <strong>$data</strong>)</strong> : <em>mixed</em> |
| protected static | <strong>transformRow(</strong><em>mixed</em> <strong>$row</strong>, <em>mixed</em> <strong>$fieldLabels</strong>)</strong> : <em>void</em> |
| protected static | <strong>transformRows(</strong><em>mixed</em> <strong>$data</strong>, <em>mixed</em> <strong>$fieldLabels</strong>)</strong> : <em>void</em> |
*This class extends \ArrayObject*
*This class implements \Countable, \Serializable, \ArrayAccess, \Traversable, \IteratorAggregate, [\Consolidation\OutputFormatters\StructuredData\TableDataInterface](#interface-consolidationoutputformattersstructureddatatabledatainterface), [\Consolidation\OutputFormatters\StructuredData\OriginalDataInterface](#interface-consolidationoutputformattersstructureddataoriginaldatainterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\ReorderFields
> Reorder the field labels based on the user-selected fields to display.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>reorder(</strong><em>string/array</em> <strong>$fields</strong>, <em>array</em> <strong>$fieldLabels</strong>, <em>array</em> <strong>$data</strong>)</strong> : <em>array</em><br /><em>Given a simple list of user-supplied field keys or field labels, return a reordered version of the field labels matching the user selection. key to the field label</em> |
| protected | <strong>convertToRegex(</strong><em>mixed</em> <strong>$str</strong>)</strong> : <em>void</em><br /><em>Convert the provided string into a regex suitable for use in preg_match. Matching occurs in the same way as the Symfony Finder component: http://symfony.com/doc/current/components/finder.html#file-name</em> |
| protected | <strong>getSelectedFieldKeys(</strong><em>mixed</em> <strong>$fields</strong>, <em>mixed</em> <strong>$fieldLabels</strong>)</strong> : <em>mixed</em> |
| protected | <strong>isRegex(</strong><em>string</em> <strong>$str</strong>)</strong> : <em>bool Whether the given string is a regex</em><br /><em>Checks whether the string is a regex. This function is copied from MultiplePcreFilterIterator in the Symfony Finder component.</em> |
| protected | <strong>matchFieldInLabelMap(</strong><em>mixed</em> <strong>$field</strong>, <em>mixed</em> <strong>$fieldLabels</strong>)</strong> : <em>void</em> |
| protected | <strong>reorderFieldLabels(</strong><em>mixed</em> <strong>$fields</strong>, <em>mixed</em> <strong>$fieldLabels</strong>, <em>mixed</em> <strong>$data</strong>)</strong> : <em>void</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\DomToArraySimplifier
> Simplify a DOMDocument to an array.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct()</strong> : <em>void</em> |
| public | <strong>canSimplify(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em> |
| public | <strong>simplifyToArray(</strong><em>mixed</em> <strong>$structuredData</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>void</em> |
| protected | <strong>elementToArray(</strong><em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$element</strong>)</strong> : <em>array</em><br /><em>Recursively convert the provided DOM element into a php array.</em> |
| protected | <strong>getIdOfValue(</strong><em>mixed</em> <strong>$value</strong>)</strong> : <em>string</em><br /><em>If the object has an 'id' or 'name' element, then use that as the array key when storing this value in its parent.</em> |
| protected | <strong>getNodeAttributes(</strong><em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$element</strong>)</strong> : <em>array</em><br /><em>Get all of the attributes of the provided element.</em> |
| protected | <strong>getNodeChildren(</strong><em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$element</strong>)</strong> : <em>array</em><br /><em>Get all of the children of the provided element, with simplification.</em> |
| protected | <strong>getNodeChildrenData(</strong><em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$element</strong>)</strong> : <em>array</em><br /><em>Get the data from the children of the provided node in preliminary form.</em> |
| protected | <strong>getUniformChildren(</strong><em>string</em> <strong>$parentKey</strong>, <em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$element</strong>)</strong> : <em>array</em><br /><em>Convert the children of the provided DOM element into an array. Here, 'uniform' means that all of the element names of the children are identical, and further, the element name of the parent is the plural form of the child names. When the children are uniform in this way, then the parent element name will be used as the key to store the children in, and the child list will be returned as a simple list with their (duplicate) element names omitted.</em> |
| protected | <strong>getUniqueChildren(</strong><em>string</em> <strong>$parentKey</strong>, <em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$element</strong>)</strong> : <em>array</em><br /><em>Convert the children of the provided DOM element into an array. Here, 'unique' means that all of the element names of the children are different. Since the element names will become the key of the associative array that is returned, so duplicates are not supported. If there are any duplicates, then an exception will be thrown.</em> |
| protected | <strong>hasUniformChildren(</strong><em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$element</strong>)</strong> : <em>boolean</em><br /><em>Determine whether the children of the provided element are uniform.</em> |
| protected | <strong>valueCanBeSimplified(</strong><em>[\DOMNode](http://php.net/manual/en/class.domnode.php)</em> <strong>$value</strong>)</strong> : <em>boolean</em><br /><em>Determine whether the provided value has additional unnecessary nesting. {"color": "red"} is converted to "red". No other simplification is done.</em> |
*This class implements [\Consolidation\OutputFormatters\Transformations\SimplifyToArrayInterface](#interface-consolidationoutputformatterstransformationssimplifytoarrayinterface)*
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\WordWrapper
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>mixed</em> <strong>$width</strong>)</strong> : <em>void</em> |
| public | <strong>minimumWidth(</strong><em>mixed</em> <strong>$colkey</strong>, <em>mixed</em> <strong>$width</strong>)</strong> : <em>void</em><br /><em>Set the minimum width of just one column</em> |
| public | <strong>setMinimumWidths(</strong><em>array</em> <strong>$minimumWidths</strong>)</strong> : <em>void</em><br /><em>If columns have minimum widths, then set them here.</em> |
| public | <strong>setPaddingFromStyle(</strong><em>\Symfony\Component\Console\Helper\TableStyle</em> <strong>$style</strong>)</strong> : <em>void</em><br /><em>Calculate our padding widths from the specified table style.</em> |
| public | <strong>wrap(</strong><em>array</em> <strong>$rows</strong>, <em>array</em> <strong>$widths=array()</strong>)</strong> : <em>array</em><br /><em>Wrap the cells in each part of the provided data table</em> |
| protected | <strong>calculateWidths(</strong><em>mixed</em> <strong>$rows</strong>, <em>array</em> <strong>$widths=array()</strong>)</strong> : <em>void</em><br /><em>Determine what widths we'll use for wrapping.</em> |
| protected | <strong>wrapCell(</strong><em>mixed</em> <strong>$cell</strong>, <em>string</em> <strong>$cellWidth</strong>)</strong> : <em>mixed</em><br /><em>Wrap one cell. Guard against modifying non-strings and then call through to wordwrap().</em> |
<hr />
### Interface: \Consolidation\OutputFormatters\Transformations\OverrideRestructureInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>overrideRestructure(</strong><em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>mixed</em><br /><em>Select data to use directly from the structured output, before the restructure operation has been executed.</em> |
<hr />
### Interface: \Consolidation\OutputFormatters\Transformations\SimplifyToArrayInterface
| Visibility | Function |
|:-----------|:---------|
| public | <strong>canSimplify(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$structuredOutput</strong>)</strong> : <em>bool</em><br /><em>Indicate whether or not the given data type can be simplified to an array</em> |
| public | <strong>simplifyToArray(</strong><em>mixed</em> <strong>$structuredOutput</strong>, <em>[\Consolidation\OutputFormatters\Options\FormatterOptions](#class-consolidationoutputformattersoptionsformatteroptions)</em> <strong>$options</strong>)</strong> : <em>array</em><br /><em>Convert structured data into a generic array, usable by generic array-based formatters. Objects that implement this interface may be attached to the FormatterManager, and will be used on any data structure that needs to be simplified into an array. An array simplifier should take no action other than to return its input data if it cannot simplify the provided data into an array.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\Wrap\CalculateWidths
> Calculate column widths for table cells. Influenced by Drush and webmozart/console.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct()</strong> : <em>void</em> |
| public | <strong>calculate(</strong><em>mixed</em> <strong>$availableWidth</strong>, <em>[\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)</em> <strong>$dataWidths</strong>, <em>[\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)</em> <strong>$minimumWidths</strong>)</strong> : <em>void</em><br /><em>Given the total amount of available space, and the width of the columns to place, calculate the optimum column widths to use.</em> |
| public | <strong>calculateLongestCell(</strong><em>mixed</em> <strong>$rows</strong>)</strong> : <em>void</em><br /><em>Calculate the longest cell data from any row of each of the cells.</em> |
| public | <strong>calculateLongestWord(</strong><em>mixed</em> <strong>$rows</strong>)</strong> : <em>void</em><br /><em>Calculate the longest word and longest line in the provided data.</em> |
| public | <strong>distributeLongColumns(</strong><em>mixed</em> <strong>$availableWidth</strong>, <em>[\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)</em> <strong>$dataWidths</strong>, <em>[\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)</em> <strong>$minimumWidths</strong>)</strong> : <em>void</em><br /><em>Distribute the remainig space among the columns that were not included in the list of "short" columns.</em> |
| public | <strong>getShortColumns(</strong><em>mixed</em> <strong>$availableWidth</strong>, <em>[\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)</em> <strong>$dataWidths</strong>, <em>[\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)</em> <strong>$minimumWidths</strong>)</strong> : <em>mixed</em><br /><em>Return all of the columns whose longest line length is less than or equal to the average width.</em> |
| protected | <strong>calculateColumnWidths(</strong><em>mixed</em> <strong>$rows</strong>, <em>\callable</em> <strong>$fn</strong>)</strong> : <em>void</em> |
| protected static | <strong>longestWordLength(</strong><em>string</em> <strong>$str</strong>)</strong> : <em>int</em><br /><em>Return the length of the longest word in the string.</em> |
<hr />
### Class: \Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths
> Calculate the width of data in table cells in preparation for word wrapping.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>__construct(</strong><em>array</em> <strong>$widths=array()</strong>)</strong> : <em>void</em> |
| public | <strong>adjustMinimumWidths(</strong><em>mixed</em> <strong>$availableWidth</strong>, <em>mixed</em> <strong>$dataCellWidths</strong>)</strong> : <em>void</em><br /><em>If the widths specified by this object do not fit within the provided avaiable width, then reduce them all proportionally.</em> |
| public | <strong>averageWidth(</strong><em>mixed</em> <strong>$availableWidth</strong>)</strong> : <em>void</em><br /><em>Calculate how much space is available on average for all columns.</em> |
| public | <strong>combine(</strong><em>[\Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths](#class-consolidationoutputformatterstransformationswrapcolumnwidths)</em> <strong>$combineWith</strong>)</strong> : <em>void</em><br /><em>Combine this set of widths with another set, and return a new set that contains the entries from both.</em> |
| public | <strong>count()</strong> : <em>void</em><br /><em>Return the number of columns.</em> |
| public | <strong>distribute(</strong><em>mixed</em> <strong>$availableWidth</strong>)</strong> : <em>void</em><br /><em>Return proportional weights</em> |
| public | <strong>enforceMinimums(</strong><em>mixed</em> <strong>$minimumWidths</strong>)</strong> : <em>void</em><br /><em>Ensure that every item in $widths that has a corresponding entry in $minimumWidths is as least as large as the minimum value held there.</em> |
| public | <strong>findShortColumns(</strong><em>mixed</em> <strong>$thresholdWidth</strong>)</strong> : <em>mixed</em><br /><em>Find all of the columns that are shorter than the specified threshold.</em> |
| public | <strong>findUndersizedColumns(</strong><em>mixed</em> <strong>$minimumWidths</strong>)</strong> : <em>mixed</em><br /><em>Find all of the columns that are shorter than the corresponding minimum widths.</em> |
| public | <strong>isEmpty()</strong> : <em>bool</em><br /><em>Return true if there is no data in this object</em> |
| public | <strong>keys()</strong> : <em>void</em><br /><em>Return the available keys (column identifiers) from the calculated data set.</em> |
| public | <strong>lastColumn()</strong> : <em>void</em> |
| public | <strong>paddingSpace(</strong><em>mixed</em> <strong>$paddingInEachCell</strong>, <em>mixed</em> <strong>$extraPaddingAtEndOfLine</strong>, <em>mixed</em> <strong>$extraPaddingAtBeginningOfLine</strong>)</strong> : <em>void</em> |
| public | <strong>removeColumns(</strong><em>mixed</em> <strong>$columnKeys</strong>)</strong> : <em>void</em><br /><em>Remove all of the specified columns from this data structure.</em> |
| public | <strong>selectColumns(</strong><em>mixed</em> <strong>$columnKeys</strong>)</strong> : <em>void</em><br /><em>Select all columns that exist in the provided list of keys.</em> |
| public | <strong>setWidth(</strong><em>mixed</em> <strong>$key</strong>, <em>mixed</em> <strong>$width</strong>)</strong> : <em>void</em><br /><em>Set the length of the specified column.</em> |
| public static | <strong>sumWidth(</strong><em>mixed</em> <strong>$widths</strong>)</strong> : <em>void</em><br /><em>Return the sum of the lengths of the provided widths.</em> |
| public | <strong>totalWidth()</strong> : <em>void</em><br /><em>Return the sum of the lengths of the provided widths.</em> |
| public | <strong>width(</strong><em>mixed</em> <strong>$key</strong>)</strong> : <em>void</em><br /><em>Return the length of the specified column.</em> |
| public | <strong>widths()</strong> : <em>void</em><br /><em>Return all of the lengths</em> |
| protected | <strong>findColumnsUnderThreshold(</strong><em>array</em> <strong>$thresholdWidths</strong>)</strong> : <em>mixed</em> |
<hr />
### Interface: \Consolidation\OutputFormatters\Validate\ValidationInterface
> Formatters may implement ValidationInterface in order to indicate whether a particular data structure is supported. Any formatter that does not implement ValidationInterface is assumed to only operate on arrays, or data types that implement SimplifyToArrayInterface.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>isValidDataType(</strong><em>[\ReflectionClass](http://php.net/manual/en/class.reflectionclass.php)</em> <strong>$dataType</strong>)</strong> : <em>bool</em><br /><em>Return true if the specified format is valid for use with this formatter.</em> |
| public | <strong>validate(</strong><em>mixed</em> <strong>$structuredData</strong>)</strong> : <em>mixed</em><br /><em>Throw an IncompatibleDataException if the provided data cannot be processed by this formatter. Return the source data if it is valid. The data may be encapsulated or converted if necessary.</em> |
<hr />
### Interface: \Consolidation\OutputFormatters\Validate\ValidDataTypesInterface
> Formatters may implement ValidDataTypesInterface in order to indicate exactly which formats they support. The validDataTypes method can be called to retrieve a list of data types useful in providing hints in exception messages about which data types can be used with the formatter. Note that it is OPTIONAL for formatters to implement this interface. If a formatter implements only ValidationInterface, then clients that request the formatter via FormatterManager::write() will still get a list (via an InvalidFormatException) of all of the formats that are usable with the provided data type. Implementing ValidDataTypesInterface is benefitial to clients who instantiate a formatter directly (via `new`). Formatters that implement ValidDataTypesInterface may wish to use ValidDataTypesTrait.
| Visibility | Function |
|:-----------|:---------|
| public | <strong>validDataTypes()</strong> : <em>[\ReflectionClass[]](http://php.net/manual/en/class.reflectionclass.php)</em><br /><em>Return the list of data types acceptable to this formatter</em> |
*This class implements [\Consolidation\OutputFormatters\Validate\ValidationInterface](#interface-consolidationoutputformattersvalidatevalidationinterface)*

View file

@ -0,0 +1,3 @@
# Consolidation Output Formatters
This is a placeholder for the output formatters documentation.

View file

@ -0,0 +1,7 @@
site_name: Consolidation Output Formatters docs
theme: readthedocs
repo_url: https://github.com/consolidation/output-formatters
include_search: true
pages:
- Home: index.md
- API: api.md

View file

@ -0,0 +1,29 @@
<phpunit bootstrap="vendor/autoload.php" colors="true">
<testsuites>
<testsuite name="formatters">
<directory prefix="test" suffix=".php">tests</directory>
</testsuite>
</testsuites>
<logging>
<!--
<log type="coverage-html" target="build/logs/coverage" lowUpperBound="35"
highLowerBound="70"/>
-->
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
<exclude>
<file suffix=".php">FormatterInterface.php.php</file>
<file suffix=".php">OverrideRestructureInterface.php.php</file>
<file suffix=".php">RestructureInterface.php.php</file>
<file suffix=".php">ValidationInterface.php</file>
<file suffix=".php">Formatters/RenderDataInterface.php</file>
<file suffix=".php">StructuredData/ListDataInterface.php.php</file>
<file suffix=".php">StructuredData/RenderCellInterface.php.php</file>
<file suffix=".php">StructuredData/TableDataInterface.php.php</file>
</exclude>
</whitelist>
</filter>
</phpunit>

View file

@ -0,0 +1,57 @@
<?php
namespace Consolidation\OutputFormatters\Exception;
/**
* Contains some helper functions used by exceptions in this project.
*/
abstract class AbstractDataFormatException extends \Exception
{
/**
* Return a description of the data type represented by the provided parameter.
*
* @param \ReflectionClass $data The data type to describe. Note that
* \ArrayObject is used as a proxy to mean an array primitive (or an ArrayObject).
* @return string
*/
protected static function describeDataType($data)
{
if (is_array($data) || ($data instanceof \ReflectionClass)) {
if (is_array($data) || ($data->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";
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Consolidation\OutputFormatters\Exception;
use Consolidation\OutputFormatters\Formatters\FormatterInterface;
/**
* Represents an incompatibility between the output data and selected formatter.
*/
class IncompatibleDataException extends AbstractDataFormatException
{
public function __construct(FormatterInterface $formatter, $data, $allowedTypes)
{
$formatterDescription = get_class($formatter);
$dataDescription = static::describeDataType($data);
$allowedTypesDescription = static::describeAllowedTypes($allowedTypes);
$message = "Data provided to $formatterDescription must be $allowedTypesDescription. Instead, $dataDescription was provided.";
parent::__construct($message, 1);
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace Consolidation\OutputFormatters\Exception;
/**
* Represents an incompatibility between the output data and selected formatter.
*/
class InvalidFormatException extends AbstractDataFormatException
{
public function __construct($format, $data, $validFormats)
{
$dataDescription = static::describeDataType($data);
$message = "The format $format cannot be used with the data produced by this command, which was $dataDescription. Valid formats are: " . implode(',', $validFormats);
parent::__construct($message, 1);
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace Consolidation\OutputFormatters\Exception;
/**
* Indicates that the requested format does not exist.
*/
class UnknownFieldException extends \Exception
{
public function __construct($field)
{
$message = "The requested field, '$field', is not defined.";
parent::__construct($message, 1);
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace Consolidation\OutputFormatters\Exception;
/**
* Indicates that the requested format does not exist.
*/
class UnknownFormatException extends \Exception
{
public function __construct($format)
{
$message = "The requested format, '$format', is not available.";
parent::__construct($message, 1);
}
}

View file

@ -0,0 +1,395 @@
<?php
namespace Consolidation\OutputFormatters;
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
use Consolidation\OutputFormatters\Exception\InvalidFormatException;
use Consolidation\OutputFormatters\Exception\UnknownFormatException;
use Consolidation\OutputFormatters\Formatters\FormatterInterface;
use Consolidation\OutputFormatters\Formatters\RenderDataInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\Options\OverrideOptionsInterface;
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
use Consolidation\OutputFormatters\Transformations\DomToArraySimplifier;
use Consolidation\OutputFormatters\Transformations\OverrideRestructureInterface;
use Consolidation\OutputFormatters\Transformations\SimplifyToArrayInterface;
use Consolidation\OutputFormatters\Validate\ValidationInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Consolidation\OutputFormatters\StructuredData\OriginalDataInterface;
/**
* Manage a collection of formatters; return one on request.
*/
class FormatterManager
{
/** var FormatterInterface[] */
protected $formatters = [];
/** var SimplifyToArrayInterface[] */
protected $arraySimplifiers = [];
public function __construct()
{
}
public function addDefaultFormatters()
{
$defaultFormatters = [
'string' => '\Consolidation\OutputFormatters\Formatters\StringFormatter',
'yaml' => '\Consolidation\OutputFormatters\Formatters\YamlFormatter',
'xml' => '\Consolidation\OutputFormatters\Formatters\XmlFormatter',
'json' => '\Consolidation\OutputFormatters\Formatters\JsonFormatter',
'print-r' => '\Consolidation\OutputFormatters\Formatters\PrintRFormatter',
'php' => '\Consolidation\OutputFormatters\Formatters\SerializeFormatter',
'var_export' => '\Consolidation\OutputFormatters\Formatters\VarExportFormatter',
'list' => '\Consolidation\OutputFormatters\Formatters\ListFormatter',
'csv' => '\Consolidation\OutputFormatters\Formatters\CsvFormatter',
'tsv' => '\Consolidation\OutputFormatters\Formatters\TsvFormatter',
'table' => '\Consolidation\OutputFormatters\Formatters\TableFormatter',
'sections' => '\Consolidation\OutputFormatters\Formatters\SectionsFormatter',
];
foreach ($defaultFormatters as $id => $formatterClassname) {
$formatter = new $formatterClassname;
$this->addFormatter($id, $formatter);
}
$this->addFormatter('', $this->formatters['string']);
}
public function addDefaultSimplifiers()
{
// Add our default array simplifier (DOMDocument to array)
$this->addSimplifier(new DomToArraySimplifier());
}
/**
* Add a formatter
*
* @param string $key the identifier of the formatter to add
* @param string $formatter the class name of the formatter to add
* @return FormatterManager
*/
public function addFormatter($key, FormatterInterface $formatter)
{
$this->formatters[$key] = $formatter;
return $this;
}
/**
* Add a simplifier
*
* @param SimplifyToArrayInterface $simplifier the array simplifier to add
* @return FormatterManager
*/
public function addSimplifier(SimplifyToArrayInterface $simplifier)
{
$this->arraySimplifiers[] = $simplifier;
return $this;
}
/**
* Return a set of InputOption based on the annotations of a command.
* @param FormatterOptions $options
* @return InputOption[]
*/
public function automaticOptions(FormatterOptions $options, $dataType)
{
$automaticOptions = [];
// At the moment, we only support automatic options for --format
// and --fields, so exit if the command returns no data.
if (!isset($dataType)) {
return [];
}
$validFormats = $this->validFormats($dataType);
if (empty($validFormats)) {
return [];
}
$availableFields = $options->get(FormatterOptions::FIELD_LABELS);
$hasDefaultStringField = $options->get(FormatterOptions::DEFAULT_STRING_FIELD);
$defaultFormat = $hasDefaultStringField ? 'string' : ($availableFields ? 'table' : 'yaml');
if (count($validFormats) > 1) {
// Make an input option for --format
$description = 'Format the result data. Available formats: ' . implode(',', $validFormats);
$automaticOptions[FormatterOptions::FORMAT] = new InputOption(FormatterOptions::FORMAT, '', InputOption::VALUE_REQUIRED, $description, $defaultFormat);
}
if ($availableFields) {
$defaultFields = $options->get(FormatterOptions::DEFAULT_FIELDS, [], '');
$description = 'Available fields: ' . implode(', ', $this->availableFieldsList($availableFields));
$automaticOptions[FormatterOptions::FIELDS] = new InputOption(FormatterOptions::FIELDS, '', InputOption::VALUE_REQUIRED, $description, $defaultFields);
$automaticOptions[FormatterOptions::FIELD] = new InputOption(FormatterOptions::FIELD, '', InputOption::VALUE_REQUIRED, "Select just one field, and force format to 'string'.", '');
}
return $automaticOptions;
}
/**
* Given a list of available fields, return a list of field descriptions.
* @return string[]
*/
protected function availableFieldsList($availableFields)
{
return array_map(
function ($key) use ($availableFields) {
return $availableFields[$key] . " ($key)";
},
array_keys($availableFields)
);
}
/**
* Return the identifiers for all valid data types that have been registered.
*
* @param mixed $dataType \ReflectionObject or other description of the produced data type
* @return array
*/
public function validFormats($dataType)
{
$validFormats = [];
foreach ($this->formatters as $formatId => $formatterName) {
$formatter = $this->getFormatter($formatId);
if (!empty($formatId) && $this->isValidFormat($formatter, $dataType)) {
$validFormats[] = $formatId;
}
}
sort($validFormats);
return $validFormats;
}
public function isValidFormat(FormatterInterface $formatter, $dataType)
{
if (is_array($dataType)) {
$dataType = new \ReflectionClass('\ArrayObject');
}
if (!is_object($dataType) && !class_exists($dataType)) {
return false;
}
if (!$dataType instanceof \ReflectionClass) {
$dataType = new \ReflectionClass($dataType);
}
return $this->isValidDataType($formatter, $dataType);
}
public function isValidDataType(FormatterInterface $formatter, \ReflectionClass $dataType)
{
if ($this->canSimplifyToArray($dataType)) {
if ($this->isValidFormat($formatter, [])) {
return true;
}
}
// If the formatter does not implement ValidationInterface, then
// it is presumed that the formatter only accepts arrays.
if (!$formatter instanceof ValidationInterface) {
return $dataType->isSubclassOf('ArrayObject') || ($dataType->getName() == 'ArrayObject');
}
return $formatter->isValidDataType($dataType);
}
/**
* Format and write output
*
* @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 Formatting options
*/
public function write(OutputInterface $output, $format, $structuredOutput, FormatterOptions $options)
{
$formatter = $this->getFormatter((string)$format);
if (!is_string($structuredOutput) && !$this->isValidFormat($formatter, $structuredOutput)) {
$validFormats = $this->validFormats($structuredOutput);
throw new InvalidFormatException((string)$format, $structuredOutput, $validFormats);
}
// Give the formatter a chance to override the options
$options = $this->overrideOptions($formatter, $structuredOutput, $options);
$structuredOutput = $this->validateAndRestructure($formatter, $structuredOutput, $options);
$formatter->write($output, $structuredOutput, $options);
}
protected function validateAndRestructure(FormatterInterface $formatter, $structuredOutput, FormatterOptions $options)
{
// Give the formatter a chance to do something with the
// raw data before it is restructured.
$overrideRestructure = $this->overrideRestructure($formatter, $structuredOutput, $options);
if ($overrideRestructure) {
return $overrideRestructure;
}
// Restructure the output data (e.g. select fields to display, etc.).
$restructuredOutput = $this->restructureData($structuredOutput, $options);
// Make sure that the provided data is in the correct format for the selected formatter.
$restructuredOutput = $this->validateData($formatter, $restructuredOutput, $options);
// Give the original data a chance to re-render the structured
// output after it has been restructured and validated.
$restructuredOutput = $this->renderData($formatter, $structuredOutput, $restructuredOutput, $options);
return $restructuredOutput;
}
/**
* Fetch the requested formatter.
*
* @param string $format Identifier for requested formatter
* @return FormatterInterface
*/
public function getFormatter($format)
{
// The client must inject at least one formatter before asking for
// any formatters; if not, we will provide all of the usual defaults
// as a convenience.
if (empty($this->formatters)) {
$this->addDefaultFormatters();
$this->addDefaultSimplifiers();
}
if (!$this->hasFormatter($format)) {
throw new UnknownFormatException($format);
}
$formatter = $this->formatters[$format];
return $formatter;
}
/**
* Test to see if the stipulated format exists
*/
public function hasFormatter($format)
{
return array_key_exists($format, $this->formatters);
}
/**
* Render the data as necessary (e.g. to select or reorder fields).
*
* @param FormatterInterface $formatter
* @param mixed $originalData
* @param mixed $restructuredData
* @param FormatterOptions $options Formatting options
* @return mixed
*/
public function renderData(FormatterInterface $formatter, $originalData, $restructuredData, FormatterOptions $options)
{
if ($formatter instanceof RenderDataInterface) {
return $formatter->renderData($originalData, $restructuredData, $options);
}
return $restructuredData;
}
/**
* Determine if the provided data is compatible with the formatter being used.
*
* @param FormatterInterface $formatter Formatter being used
* @param mixed $structuredOutput Data to validate
* @return mixed
*/
public function validateData(FormatterInterface $formatter, $structuredOutput, FormatterOptions $options)
{
// If the formatter implements ValidationInterface, then let it
// test the data and throw or return an error
if ($formatter instanceof ValidationInterface) {
return $formatter->validate($structuredOutput);
}
// If the formatter does not implement ValidationInterface, then
// it will never be passed an ArrayObject; we will always give
// it a simple array.
$structuredOutput = $this->simplifyToArray($structuredOutput, $options);
// If we could not simplify to an array, then throw an exception.
// We will never give a formatter anything other than an array
// unless it validates that it can accept the data type.
if (!is_array($structuredOutput)) {
throw new IncompatibleDataException(
$formatter,
$structuredOutput,
[]
);
}
return $structuredOutput;
}
protected function simplifyToArray($structuredOutput, FormatterOptions $options)
{
// We can do nothing unless the provided data is an object.
if (!is_object($structuredOutput)) {
return $structuredOutput;
}
// Check to see if any of the simplifiers can convert the given data
// set to an array.
$outputDataType = new \ReflectionClass($structuredOutput);
foreach ($this->arraySimplifiers as $simplifier) {
if ($simplifier->canSimplify($outputDataType)) {
$structuredOutput = $simplifier->simplifyToArray($structuredOutput, $options);
}
}
// Convert data structure back into its original form, if necessary.
if ($structuredOutput instanceof OriginalDataInterface) {
return $structuredOutput->getOriginalData();
}
// Convert \ArrayObjects to a simple array.
if ($structuredOutput instanceof \ArrayObject) {
return $structuredOutput->getArrayCopy();
}
return $structuredOutput;
}
protected function canSimplifyToArray(\ReflectionClass $structuredOutput)
{
foreach ($this->arraySimplifiers as $simplifier) {
if ($simplifier->canSimplify($structuredOutput)) {
return true;
}
}
return false;
}
/**
* Restructure the data as necessary (e.g. to select or reorder fields).
*
* @param mixed $structuredOutput
* @param FormatterOptions $options
* @return mixed
*/
public function restructureData($structuredOutput, FormatterOptions $options)
{
if ($structuredOutput instanceof RestructureInterface) {
return $structuredOutput->restructure($options);
}
return $structuredOutput;
}
/**
* Allow the formatter access to the raw structured data prior
* to restructuring. For example, the 'list' formatter may wish
* to display the row keys when provided table output. If this
* function returns a result that does not evaluate to 'false',
* then that result will be used as-is, and restructuring and
* validation will not occur.
*
* @param mixed $structuredOutput
* @param FormatterOptions $options
* @return mixed
*/
public function overrideRestructure(FormatterInterface $formatter, $structuredOutput, FormatterOptions $options)
{
if ($formatter instanceof OverrideRestructureInterface) {
return $formatter->overrideRestructure($structuredOutput, $options);
}
}
/**
* Allow the formatter to mess with the configuration options before any
* transformations et. al. get underway.
* @param FormatterInterface $formatter
* @param mixed $structuredOutput
* @param FormatterOptions $options
* @return FormatterOptions
*/
public function overrideOptions(FormatterInterface $formatter, $structuredOutput, FormatterOptions $options)
{
if ($formatter instanceof OverrideOptionsInterface) {
return $formatter->overrideOptions($structuredOutput, $options);
}
return $options;
}
}

View file

@ -0,0 +1,107 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Validate\ValidDataTypesInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
use Consolidation\OutputFormatters\Transformations\TableTransformation;
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Comma-separated value formatters
*
* Display the provided structured data in a comma-separated list. If
* there are multiple records provided, then they will be printed
* one per line. The primary data types accepted are RowsOfFields and
* PropertyList. The later behaves exactly like the former, save for
* the fact that it contains but a single row. This formmatter can also
* accept a PHP array; this is also interpreted as a single-row of data
* with no header.
*/
class CsvFormatter implements FormatterInterface, ValidDataTypesInterface, RenderDataInterface
{
use ValidDataTypesTrait;
use RenderTableDataTrait;
public function validDataTypes()
{
return
[
new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\RowsOfFields'),
new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\PropertyList'),
new \ReflectionClass('\ArrayObject'),
];
}
public function validate($structuredData)
{
// If the provided data was of class RowsOfFields
// or PropertyList, it will be converted into
// a TableTransformation object.
if (!is_array($structuredData) && (!$structuredData instanceof TableTransformation)) {
throw new IncompatibleDataException(
$this,
$structuredData,
$this->validDataTypes()
);
}
// If the data was provided to us as a single array, then
// convert it to a single row.
if (is_array($structuredData) && !empty($structuredData)) {
$firstRow = reset($structuredData);
if (!is_array($firstRow)) {
return [$structuredData];
}
}
return $structuredData;
}
/**
* Return default values for formatter options
* @return array
*/
protected function getDefaultFormatterOptions()
{
return [
FormatterOptions::INCLUDE_FIELD_LABELS => true,
FormatterOptions::DELIMITER => ',',
];
}
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
$defaults = $this->getDefaultFormatterOptions();
$includeFieldLabels = $options->get(FormatterOptions::INCLUDE_FIELD_LABELS, $defaults);
if ($includeFieldLabels && ($data instanceof TableTransformation)) {
$headers = $data->getHeaders();
$this->writeOneLine($output, $headers, $options);
}
foreach ($data as $line) {
$this->writeOneLine($output, $line, $options);
}
}
protected function writeOneLine(OutputInterface $output, $data, $options)
{
$defaults = $this->getDefaultFormatterOptions();
$delimiter = $options->get(FormatterOptions::DELIMITER, $defaults);
$output->write($this->csvEscape($data, $delimiter));
}
protected function csvEscape($data, $delimiter = ',')
{
$buffer = fopen('php://temp', 'r+');
fputcsv($buffer, $data, $delimiter);
rewind($buffer);
$csv = fgets($buffer);
fclose($buffer);
return $csv;
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Output\OutputInterface;
interface FormatterInterface
{
/**
* Given structured data, apply appropriate
* formatting, and return a printable string.
*
* @param mixed $data Structured data to format
*
* @return string
*/
public function write(OutputInterface $output, $data, FormatterOptions $options);
}

View file

@ -0,0 +1,21 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Json formatter
*
* Convert an array or ArrayObject into Json.
*/
class JsonFormatter implements FormatterInterface
{
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
$output->writeln(json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\ListDataInterface;
use Consolidation\OutputFormatters\StructuredData\RenderCellInterface;
use Consolidation\OutputFormatters\Transformations\OverrideRestructureInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Display the data in a simple list.
*
* This formatter prints a plain, unadorned list of data,
* with each data item appearing on a separate line. If you
* wish your list to contain headers, then use the table
* formatter, and wrap your data in an PropertyList.
*/
class ListFormatter implements FormatterInterface, OverrideRestructureInterface, RenderDataInterface
{
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
$output->writeln(implode("\n", $data));
}
/**
* @inheritdoc
*/
public function overrideRestructure($structuredOutput, FormatterOptions $options)
{
// If the structured data implements ListDataInterface,
// then we will render whatever data its 'getListData'
// method provides.
if ($structuredOutput instanceof ListDataInterface) {
return $this->renderData($structuredOutput, $structuredOutput->getListData($options), $options);
}
}
/**
* @inheritdoc
*/
public function renderData($originalData, $restructuredData, FormatterOptions $options)
{
if ($originalData instanceof RenderCellInterface) {
return $this->renderEachCell($originalData, $restructuredData, $options);
}
return $restructuredData;
}
protected function renderEachCell($originalData, $restructuredData, FormatterOptions $options)
{
foreach ($restructuredData as $key => $cellData) {
$restructuredData[$key] = $originalData->renderCell($key, $cellData, $options, $restructuredData);
}
return $restructuredData;
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Print_r formatter
*
* Run provided date thruogh print_r.
*/
class PrintRFormatter implements FormatterInterface
{
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
$output->writeln(print_r($data, true));
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
interface RenderDataInterface
{
/**
* Convert the contents of the output data just before it
* is to be printed, prior to output but after restructuring
* and validation.
*
* @param mixed $originalData
* @param mixed $restructuredData
* @param FormatterOptions $options Formatting options
* @return mixed
*/
public function renderData($originalData, $restructuredData, FormatterOptions $options);
}

View file

@ -0,0 +1,29 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\RenderCellInterface;
trait RenderTableDataTrait
{
/**
* @inheritdoc
*/
public function renderData($originalData, $restructuredData, FormatterOptions $options)
{
if ($originalData instanceof RenderCellInterface) {
return $this->renderEachCell($originalData, $restructuredData, $options);
}
return $restructuredData;
}
protected function renderEachCell($originalData, $restructuredData, FormatterOptions $options)
{
foreach ($restructuredData as $id => $row) {
foreach ($row as $key => $cellData) {
$restructuredData[$id][$key] = $originalData->renderCell($key, $cellData, $options, $row);
}
}
return $restructuredData;
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\Table;
use Consolidation\OutputFormatters\Validate\ValidDataTypesInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
use Consolidation\OutputFormatters\StructuredData\TableDataInterface;
use Consolidation\OutputFormatters\Transformations\ReorderFields;
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
/**
* Display sections of data.
*
* This formatter takes data in the RowsOfFields data type.
* Each row represents one section; the data in each section
* is rendered in two columns, with the key in the first column
* and the value in the second column.
*/
class SectionsFormatter implements FormatterInterface, ValidDataTypesInterface, RenderDataInterface
{
use ValidDataTypesTrait;
use RenderTableDataTrait;
public function validDataTypes()
{
return
[
new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\RowsOfFields')
];
}
/**
* @inheritdoc
*/
public function validate($structuredData)
{
// If the provided data was of class RowsOfFields
// or PropertyList, it will be converted into
// a TableTransformation object by the restructure call.
if (!$structuredData instanceof TableDataInterface) {
throw new IncompatibleDataException(
$this,
$structuredData,
$this->validDataTypes()
);
}
return $structuredData;
}
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $tableTransformer, FormatterOptions $options)
{
$table = new Table($output);
$table->setStyle('compact');
foreach ($tableTransformer as $rowid => $row) {
$rowLabel = $tableTransformer->getRowLabel($rowid);
$output->writeln('');
$output->writeln($rowLabel);
$sectionData = new PropertyList($row);
$sectionOptions = new FormatterOptions([], $options->getOptions());
$sectionTableTransformer = $sectionData->restructure($sectionOptions);
$table->setRows($sectionTableTransformer->getTableData(true));
$table->render();
}
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Serialize formatter
*
* Run provided date thruogh serialize.
*/
class SerializeFormatter implements FormatterInterface
{
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
$output->writeln(serialize($data));
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Validate\ValidationInterface;
use Consolidation\OutputFormatters\Options\OverrideOptionsInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
use Symfony\Component\Console\Output\OutputInterface;
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
/**
* String formatter
*
* This formatter is used as the default action when no
* particular formatter is requested. It will print the
* provided data only if it is a string; if any other
* type is given, then nothing is printed.
*/
class StringFormatter implements FormatterInterface, ValidationInterface, OverrideOptionsInterface
{
/**
* All data types are acceptable.
*/
public function isValidDataType(\ReflectionClass $dataType)
{
return true;
}
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
if (is_string($data)) {
return $output->writeln($data);
}
return $this->reduceToSigleFieldAndWrite($output, $data, $options);
}
/**
* @inheritdoc
*/
public function overrideOptions($structuredOutput, FormatterOptions $options)
{
$defaultField = $options->get(FormatterOptions::DEFAULT_STRING_FIELD, [], '');
$userFields = $options->get(FormatterOptions::FIELDS, [FormatterOptions::FIELDS => $options->get(FormatterOptions::FIELD)]);
$optionsOverride = $options->override([]);
if (empty($userFields) && !empty($defaultField)) {
$optionsOverride->setOption(FormatterOptions::FIELDS, $defaultField);
}
return $optionsOverride;
}
/**
* If the data provided to a 'string' formatter is a table, then try
* to emit it as a TSV value.
*
* @param OutputInterface $output
* @param mixed $data
* @param FormatterOptions $options
*/
protected function reduceToSigleFieldAndWrite(OutputInterface $output, $data, FormatterOptions $options)
{
$alternateFormatter = new TsvFormatter();
try {
$data = $alternateFormatter->validate($data);
$alternateFormatter->write($output, $data, $options);
} catch (\Exception $e) {
}
}
/**
* Always validate any data, though. This format will never
* cause an error if it is selected for an incompatible data type; at
* worse, it simply does not print any data.
*/
public function validate($structuredData)
{
return $structuredData;
}
}

View file

@ -0,0 +1,143 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableStyle;
use Consolidation\OutputFormatters\Validate\ValidDataTypesInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
use Consolidation\OutputFormatters\StructuredData\TableDataInterface;
use Consolidation\OutputFormatters\Transformations\ReorderFields;
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
use Consolidation\OutputFormatters\Transformations\WordWrapper;
/**
* Display a table of data with the Symfony Table class.
*
* This formatter takes data of either the RowsOfFields or
* PropertyList data type. Tables can be rendered with the
* rows running either vertically (the normal orientation) or
* horizontally. By default, associative lists will be displayed
* as two columns, with the key in the first column and the
* value in the second column.
*/
class TableFormatter implements FormatterInterface, ValidDataTypesInterface, RenderDataInterface
{
use ValidDataTypesTrait;
use RenderTableDataTrait;
protected $fieldLabels;
protected $defaultFields;
public function __construct()
{
}
public function validDataTypes()
{
return
[
new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\RowsOfFields'),
new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\PropertyList')
];
}
/**
* @inheritdoc
*/
public function validate($structuredData)
{
// If the provided data was of class RowsOfFields
// or PropertyList, it will be converted into
// a TableTransformation object by the restructure call.
if (!$structuredData instanceof TableDataInterface) {
throw new IncompatibleDataException(
$this,
$structuredData,
$this->validDataTypes()
);
}
return $structuredData;
}
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $tableTransformer, FormatterOptions $options)
{
$headers = [];
$defaults = [
FormatterOptions::TABLE_STYLE => 'consolidation',
FormatterOptions::INCLUDE_FIELD_LABELS => true,
];
$table = new Table($output);
static::addCustomTableStyles($table);
$table->setStyle($options->get(FormatterOptions::TABLE_STYLE, $defaults));
$isList = $tableTransformer->isList();
$includeHeaders = $options->get(FormatterOptions::INCLUDE_FIELD_LABELS, $defaults);
$listDelimiter = $options->get(FormatterOptions::LIST_DELIMITER, $defaults);
$headers = $tableTransformer->getHeaders();
$data = $tableTransformer->getTableData($includeHeaders && $isList);
if ($listDelimiter) {
if (!empty($headers)) {
array_splice($headers, 1, 0, ':');
}
$data = array_map(function ($item) {
array_splice($item, 1, 0, ':');
return $item;
}, $data);
}
if ($includeHeaders && !$isList) {
$table->setHeaders($headers);
}
// todo: $output->getFormatter();
$data = $this->wrap($headers, $data, $table->getStyle(), $options);
$table->setRows($data);
$table->render();
}
/**
* Wrap the table data
* @param array $data
* @param TableStyle $tableStyle
* @param FormatterOptions $options
* @return array
*/
protected function wrap($headers, $data, TableStyle $tableStyle, FormatterOptions $options)
{
$wrapper = new WordWrapper($options->get(FormatterOptions::TERMINAL_WIDTH));
$wrapper->setPaddingFromStyle($tableStyle);
if (!empty($headers)) {
$headerLengths = array_map(function ($item) {
return strlen($item);
}, $headers);
$wrapper->setMinimumWidths($headerLengths);
}
return $wrapper->wrap($data);
}
/**
* Add our custom table style(s) to the table.
*/
protected static function addCustomTableStyles($table)
{
// The 'consolidation' style is the same as the 'symfony-style-guide'
// style, except it maintains the colored headers used in 'default'.
$consolidationStyle = new TableStyle();
$consolidationStyle
->setHorizontalBorderChar('-')
->setVerticalBorderChar(' ')
->setCrossingChar(' ')
;
$table->setStyleDefinition('consolidation', $consolidationStyle);
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Validate\ValidDataTypesInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\Transformations\TableTransformation;
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Tab-separated value formatters
*
* Display the provided structured data in a tab-separated list. Output
* escaping is much lighter, since there is no allowance for altering
* the delimiter.
*/
class TsvFormatter extends CsvFormatter
{
protected function getDefaultFormatterOptions()
{
return [
FormatterOptions::INCLUDE_FIELD_LABELS => false,
];
}
protected function writeOneLine(OutputInterface $output, $data, $options)
{
$output->writeln($this->tsvEscape($data));
}
protected function tsvEscape($data)
{
return implode("\t", array_map(
function ($item) {
return str_replace(["\t", "\n"], ['\t', '\n'], $item);
},
$data
));
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Var_export formatter
*
* Run provided date thruogh var_export.
*/
class VarExportFormatter implements FormatterInterface
{
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
$output->writeln(var_export($data, true));
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableStyle;
use Consolidation\OutputFormatters\Validate\ValidDataTypesInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
use Consolidation\OutputFormatters\StructuredData\TableDataInterface;
use Consolidation\OutputFormatters\Transformations\ReorderFields;
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
use Consolidation\OutputFormatters\StructuredData\Xml\DomDataInterface;
/**
* Display a table of data with the Symfony Table class.
*
* This formatter takes data of either the RowsOfFields or
* PropertyList data type. Tables can be rendered with the
* rows running either vertically (the normal orientation) or
* horizontally. By default, associative lists will be displayed
* as two columns, with the key in the first column and the
* value in the second column.
*/
class XmlFormatter implements FormatterInterface, ValidDataTypesInterface
{
use ValidDataTypesTrait;
public function __construct()
{
}
public function validDataTypes()
{
return
[
new \ReflectionClass('\DOMDocument'),
new \ReflectionClass('\ArrayObject'),
];
}
/**
* @inheritdoc
*/
public function validate($structuredData)
{
if ($structuredData instanceof \DOMDocument) {
return $structuredData;
}
if ($structuredData instanceof DomDataInterface) {
return $structuredData->getDomData();
}
if ($structuredData instanceof \ArrayObject) {
return $structuredData->getArrayCopy();
}
if (!is_array($structuredData)) {
throw new IncompatibleDataException(
$this,
$structuredData,
$this->validDataTypes()
);
}
return $structuredData;
}
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $dom, FormatterOptions $options)
{
if (is_array($dom)) {
$schema = $options->getXmlSchema();
$dom = $schema->arrayToXML($dom);
}
$dom->formatOutput = true;
$output->writeln($dom->saveXML());
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace Consolidation\OutputFormatters\Formatters;
use Symfony\Component\Yaml\Yaml;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Yaml formatter
*
* Convert an array or ArrayObject into Yaml.
*/
class YamlFormatter implements FormatterInterface
{
/**
* @inheritdoc
*/
public function write(OutputInterface $output, $data, FormatterOptions $options)
{
// Set Yaml\Dumper's default indentation for nested nodes/collections to
// 2 spaces for consistency with Drupal coding standards.
$indent = 2;
// The level where you switch to inline YAML is set to PHP_INT_MAX to
// ensure this does not occur.
$output->writeln(Yaml::dump($data, PHP_INT_MAX, $indent, false, true));
}
}

View file

@ -0,0 +1,385 @@
<?php
namespace Consolidation\OutputFormatters\Options;
use Symfony\Component\Console\Input\InputInterface;
use Consolidation\OutputFormatters\Transformations\PropertyParser;
use Consolidation\OutputFormatters\StructuredData\Xml\XmlSchema;
use Consolidation\OutputFormatters\StructuredData\Xml\XmlSchemaInterface;
/**
* FormetterOptions holds information that affects the way a formatter
* renders its output.
*
* There are three places where a formatter might get options from:
*
* 1. Configuration associated with the command that produced the output.
* This is passed in to FormatterManager::write() along with the data
* to format. It might originally come from annotations on the command,
* or it might come from another source. Examples include the field labels
* for a table, or the default list of fields to display.
*
* 2. Options specified by the user, e.g. by commandline options.
*
* 3. Default values associated with the formatter itself.
*
* This class caches configuration from sources (1) and (2), and expects
* to be provided the defaults, (3), whenever a value is requested.
*/
class FormatterOptions
{
/** var array */
protected $configurationData = [];
/** var array */
protected $options = [];
/** var InputInterface */
protected $input;
const FORMAT = 'format';
const DEFAULT_FORMAT = 'default-format';
const TABLE_STYLE = 'table-style';
const LIST_ORIENTATION = 'list-orientation';
const FIELDS = 'fields';
const FIELD = 'field';
const INCLUDE_FIELD_LABELS = 'include-field-labels';
const ROW_LABELS = 'row-labels';
const FIELD_LABELS = 'field-labels';
const DEFAULT_FIELDS = 'default-fields';
const DEFAULT_STRING_FIELD = 'default-string-field';
const DELIMITER = 'delimiter';
const LIST_DELIMITER = 'list-delimiter';
const TERMINAL_WIDTH = 'width';
/**
* Create a new FormatterOptions with the configuration data and the
* user-specified options for this request.
*
* @see FormatterOptions::setInput()
* @param array $configurationData
* @param array $options
*/
public function __construct($configurationData = [], $options = [])
{
$this->configurationData = $configurationData;
$this->options = $options;
}
/**
* Create a new FormatterOptions object with new configuration data (provided),
* and the same options data as this instance.
*
* @param array $configurationData
* @return FormatterOptions
*/
public function override($configurationData)
{
$override = new self();
$override
->setConfigurationData($configurationData + $this->getConfigurationData())
->setOptions($this->getOptions());
return $override;
}
public function setTableStyle($style)
{
return $this->setConfigurationValue(self::TABLE_STYLE, $style);
}
public function setDelimiter($delimiter)
{
return $this->setConfigurationValue(self::DELIMITER, $delimiter);
}
public function setListDelimiter($listDelimiter)
{
return $this->setConfigurationValue(self::LIST_DELIMITER, $listDelimiter);
}
public function setIncludeFieldLables($includFieldLables)
{
return $this->setConfigurationValue(self::INCLUDE_FIELD_LABELS, $includFieldLables);
}
public function setListOrientation($listOrientation)
{
return $this->setConfigurationValue(self::LIST_ORIENTATION, $listOrientation);
}
public function setRowLabels($rowLabels)
{
return $this->setConfigurationValue(self::ROW_LABELS, $rowLabels);
}
public function setDefaultFields($fields)
{
return $this->setConfigurationValue(self::DEFAULT_FIELDS, $fields);
}
public function setFieldLabels($fieldLabels)
{
return $this->setConfigurationValue(self::FIELD_LABELS, $fieldLabels);
}
public function setDefaultStringField($defaultStringField)
{
return $this->setConfigurationValue(self::DEFAULT_STRING_FIELD, $defaultStringField);
}
public function setWidth($width)
{
return $this->setConfigurationValue(self::TERMINAL_WIDTH, $width);
}
/**
* Get a formatter option
*
* @param string $key
* @param array $defaults
* @param mixed $default
* @return mixed
*/
public function get($key, $defaults = [], $default = false)
{
$value = $this->fetch($key, $defaults, $default);
return $this->parse($key, $value);
}
/**
* Return the XmlSchema to use with --format=xml for data types that support
* that. This is used when an array needs to be converted into xml.
*
* @return XmlSchema
*/
public function getXmlSchema()
{
return new XmlSchema();
}
/**
* Determine the format that was requested by the caller.
*
* @param array $defaults
* @return string
*/
public function getFormat($defaults = [])
{
return $this->get(self::FORMAT, [], $this->get(self::DEFAULT_FORMAT, $defaults, ''));
}
/**
* Look up a key, and return its raw value.
*
* @param string $key
* @param array $defaults
* @param mixed $default
* @return mixed
*/
protected function fetch($key, $defaults = [], $default = false)
{
$defaults = $this->defaultsForKey($key, $defaults, $default);
$values = $this->fetchRawValues($defaults);
return $values[$key];
}
/**
* Reduce provided defaults to the single item identified by '$key',
* if it exists, or an empty array otherwise.
*
* @param string $key
* @param array $defaults
* @return array
*/
protected function defaultsForKey($key, $defaults, $default = false)
{
if (array_key_exists($key, $defaults)) {
return [$key => $defaults[$key]];
}
return [$key => $default];
}
/**
* Look up all of the items associated with the provided defaults.
*
* @param array $defaults
* @return array
*/
protected function fetchRawValues($defaults = [])
{
return array_merge(
$defaults,
$this->getConfigurationData(),
$this->getOptions(),
$this->getInputOptions($defaults)
);
}
/**
* Given the raw value for a specific key, do any type conversion
* (e.g. from a textual list to an array) needed for the data.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function parse($key, $value)
{
$optionFormat = $this->getOptionFormat($key);
if (!empty($optionFormat) && is_string($value)) {
return $this->$optionFormat($value);
}
return $value;
}
/**
* Convert from a textual list to an array
*
* @param string $value
* @return array
*/
public function parsePropertyList($value)
{
return PropertyParser::parse($value);
}
/**
* Given a specific key, return the class method name of the
* parsing method for data stored under this key.
*
* @param string $key
* @return string
*/
protected function getOptionFormat($key)
{
$propertyFormats = [
self::ROW_LABELS => 'PropertyList',
self::FIELD_LABELS => 'PropertyList',
];
if (array_key_exists($key, $propertyFormats)) {
return "parse{$propertyFormats[$key]}";
}
return '';
}
/**
* Change the configuration data for this formatter options object.
*
* @param array $configurationData
* @return FormatterOptions
*/
public function setConfigurationData($configurationData)
{
$this->configurationData = $configurationData;
return $this;
}
/**
* Change one configuration value for this formatter option.
*
* @param string $key
* @param mixed $value
* @return FormetterOptions
*/
protected function setConfigurationValue($key, $value)
{
$this->configurationData[$key] = $value;
return $this;
}
/**
* Change one configuration value for this formatter option, but only
* if it does not already have a value set.
*
* @param string $key
* @param mixed $value
* @return FormetterOptions
*/
public function setConfigurationDefault($key, $value)
{
if (!array_key_exists($key, $this->configurationData)) {
return $this->setConfigurationValue($key, $value);
}
return $this;
}
/**
* Return a reference to the configuration data for this object.
*
* @return array
*/
public function getConfigurationData()
{
return $this->configurationData;
}
/**
* Set all of the options that were specified by the user for this request.
*
* @param array $options
* @return FormatterOptions
*/
public function setOptions($options)
{
$this->options = $options;
return $this;
}
/**
* Change one option value specified by the user for this request.
*
* @param string $key
* @param mixed $value
* @return FormatterOptions
*/
public function setOption($key, $value)
{
$this->options[$key] = $value;
return $this;
}
/**
* Return a reference to the user-specified options for this request.
*
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* Provide a Symfony Console InputInterface containing the user-specified
* options for this request.
*
* @param InputInterface $input
* @return type
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
}
/**
* Return all of the options from the provided $defaults array that
* exist in our InputInterface object.
*
* @param array $defaults
* @return array
*/
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;
}
}

View file

@ -0,0 +1,17 @@
<?php
namespace Consolidation\OutputFormatters\Options;
use Consolidation\OutputFormatters\Options\FormatterOptions;
interface OverrideOptionsInterface
{
/**
* Allow the formatter to mess with the configuration options before any
* transformations et. al. get underway.
*
* @param mixed $structuredOutput Data to restructure
* @param FormatterOptions $options Formatting options
* @return FormatterOptions
*/
public function overrideOptions($structuredOutput, FormatterOptions $options);
}

View file

@ -0,0 +1,87 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\ListDataInterface;
use Consolidation\OutputFormatters\Transformations\ReorderFields;
use Consolidation\OutputFormatters\Transformations\TableTransformation;
/**
* Holds an array where each element of the array is one row,
* and each row contains an associative array where the keys
* are the field names, and the values are the field data.
*
* It is presumed that every row contains the same keys.
*/
abstract class AbstractStructuredList extends ListDataFromKeys implements RestructureInterface, RenderCellCollectionInterface
{
use RenderCellCollectionTrait;
public function __construct($data)
{
parent::__construct($data);
}
abstract public function restructure(FormatterOptions $options);
protected function createTableTransformation($data, $options)
{
$defaults = $this->defaultOptions();
$fieldLabels = $this->getReorderedFieldLabels($data, $options, $defaults);
$tableTransformer = $this->instantiateTableTransformation($data, $fieldLabels, $options->get(FormatterOptions::ROW_LABELS, $defaults));
if ($options->get(FormatterOptions::LIST_ORIENTATION, $defaults)) {
$tableTransformer->setLayout(TableTransformation::LIST_LAYOUT);
}
return $tableTransformer;
}
protected function instantiateTableTransformation($data, $fieldLabels, $rowLabels)
{
return new TableTransformation($data, $fieldLabels, $rowLabels);
}
protected function getReorderedFieldLabels($data, $options, $defaults)
{
$reorderer = new ReorderFields();
$fieldLabels = $reorderer->reorder(
$this->getFields($options, $defaults),
$options->get(FormatterOptions::FIELD_LABELS, $defaults),
$data
);
return $fieldLabels;
}
protected function getFields($options, $defaults)
{
$fieldShortcut = $options->get(FormatterOptions::FIELD);
if (!empty($fieldShortcut)) {
return [$fieldShortcut];
}
$result = $options->get(FormatterOptions::FIELDS, $defaults);
if (!empty($result)) {
return $result;
}
return $options->get(FormatterOptions::DEFAULT_FIELDS, $defaults);
}
/**
* A structured list may provide its own set of default options. These
* will be used in place of the command's default options (from the
* annotations) in instances where the user does not provide the options
* explicitly (on the commandline) or implicitly (via a configuration file).
*
* @return array
*/
protected function defaultOptions()
{
return [
FormatterOptions::FIELDS => [],
FormatterOptions::FIELD_LABELS => [],
FormatterOptions::ROW_LABELS => [],
FormatterOptions::DEFAULT_FIELDS => [],
];
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
/**
* Old name for PropertyList class.
*
* @deprecated
*/
class AssociativeList extends PropertyList
{
}

View file

@ -0,0 +1,23 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
class CallableRenderer implements RenderCellInterface
{
/** @var callable */
protected $renderFunction;
public function __construct(callable $renderFunction)
{
$this->renderFunction = $renderFunction;
}
/**
* {@inheritdoc}
*/
public function renderCell($key, $cellData, FormatterOptions $options, $rowData)
{
return call_user_func($this->renderFunction, $key, $cellData, $options, $rowData);
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\StructuredData\Xml\DomDataInterface;
class HelpDocument implements DomDataInterface
{
/**
* Convert data into a \DomDocument.
*
* @return \DomDocument
*/
public function getDomData()
{
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
/**
* Represents aribtrary array data (structured or unstructured) where the
* data to display in --list format comes from the array keys.
*/
class ListDataFromKeys extends \ArrayObject implements ListDataInterface
{
public function __construct($data)
{
parent::__construct($data);
}
public function getListData(FormatterOptions $options)
{
return array_keys($this->getArrayCopy());
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
interface ListDataInterface
{
/**
* Convert data to a format suitable for use in a list.
* By default, the array values will be used. Implement
* ListDataInterface to use some other criteria (e.g. array keys).
*
* @return array
*/
public function getListData(FormatterOptions $options);
}

View file

@ -0,0 +1,11 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
interface OriginalDataInterface
{
/**
* Return the original data for this table. Used by any
* formatter that expects an array.
*/
public function getOriginalData();
}

View file

@ -0,0 +1,58 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\ListDataInterface;
use Consolidation\OutputFormatters\Transformations\PropertyParser;
use Consolidation\OutputFormatters\Transformations\ReorderFields;
use Consolidation\OutputFormatters\Transformations\TableTransformation;
use Consolidation\OutputFormatters\Transformations\PropertyListTableTransformation;
/**
* Holds an array where each element of the array is one
* key : value pair. The keys must be unique, as is typically
* the case for associative arrays.
*/
class PropertyList extends AbstractStructuredList
{
/**
* Restructure this data for output by converting it into a table
* transformation object.
*
* @param FormatterOptions $options Options that affect output formatting.
* @return Consolidation\OutputFormatters\Transformations\TableTransformation
*/
public function restructure(FormatterOptions $options)
{
$data = [$this->getArrayCopy()];
$options->setConfigurationDefault('list-orientation', true);
$tableTransformer = $this->createTableTransformation($data, $options);
return $tableTransformer;
}
public function getListData(FormatterOptions $options)
{
$data = $this->getArrayCopy();
$defaults = $this->defaultOptions();
$fieldLabels = $this->getReorderedFieldLabels([$data], $options, $defaults);
$result = [];
foreach ($fieldLabels as $id => $label) {
$result[$id] = $data[$id];
}
return $result;
}
protected function defaultOptions()
{
return [
FormatterOptions::LIST_ORIENTATION => true,
] + parent::defaultOptions();
}
protected function instantiateTableTransformation($data, $fieldLabels, $rowLabels)
{
return new PropertyListTableTransformation($data, $fieldLabels, $rowLabels);
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
interface RenderCellCollectionInterface extends RenderCellInterface
{
const PRIORITY_FIRST = 'first';
const PRIORITY_NORMAL = 'normal';
const PRIORITY_FALLBACK = 'fallback';
/**
* Add a renderer
*
* @return $this
*/
public function addRenderer(RenderCellInterface $renderer);
}

View file

@ -0,0 +1,59 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
trait RenderCellCollectionTrait
{
/** @var RenderCellInterface[] */
protected $rendererList = [
RenderCellCollectionInterface::PRIORITY_FIRST => [],
RenderCellCollectionInterface::PRIORITY_NORMAL => [],
RenderCellCollectionInterface::PRIORITY_FALLBACK => [],
];
/**
* Add a renderer
*
* @return $this
*/
public function addRenderer(RenderCellInterface $renderer, $priority = RenderCellCollectionInterface::PRIORITY_NORMAL)
{
$this->rendererList[$priority][] = $renderer;
return $this;
}
/**
* Add a callable as a renderer
*
* @return $this
*/
public function addRendererFunction(callable $rendererFn, $priority = RenderCellCollectionInterface::PRIORITY_NORMAL)
{
$renderer = new CallableRenderer($rendererFn);
return $this->addRenderer($renderer, $priority);
}
/**
* {@inheritdoc}
*/
public function renderCell($key, $cellData, FormatterOptions $options, $rowData)
{
$flattenedRendererList = array_reduce(
$this->rendererList,
function ($carry, $item) {
return array_merge($carry, $item);
},
[]
);
foreach ($flattenedRendererList as $renderer) {
$cellData = $renderer->renderCell($key, $cellData, $options, $rowData);
if (is_string($cellData)) {
return $cellData;
}
}
return $cellData;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
interface RenderCellInterface
{
/**
* Convert the contents of one table cell into a string,
* so that it may be placed in the table. Renderer should
* return the $cellData passed to it if it does not wish to
* process it.
*
* @param string $key Identifier of the cell being rendered
* @param mixed $cellData The data to render
* @param FormatterOptions $options The formatting options
* @param array $rowData The rest of the row data
*
* @return mixed
*/
public function renderCell($key, $cellData, FormatterOptions $options, $rowData);
}

View file

@ -0,0 +1,15 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
interface RestructureInterface
{
/**
* Allow structured data to be restructured -- i.e. to select fields
* to show, reorder fields, etc.
*
* @param FormatterOptions $options Formatting options
*/
public function restructure(FormatterOptions $options);
}

View file

@ -0,0 +1,39 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
use Consolidation\OutputFormatters\Options\FormatterOptions;
/**
* Holds an array where each element of the array is one row,
* and each row contains an associative array where the keys
* are the field names, and the values are the field data.
*
* It is presumed that every row contains the same keys.
*/
class RowsOfFields extends AbstractStructuredList
{
/**
* Restructure this data for output by converting it into a table
* transformation object.
*
* @param FormatterOptions $options Options that affect output formatting.
* @return Consolidation\OutputFormatters\Transformations\TableTransformation
*/
public function restructure(FormatterOptions $options)
{
$data = $this->getArrayCopy();
return $this->createTableTransformation($data, $options);
}
public function getListData(FormatterOptions $options)
{
return array_keys($this->getArrayCopy());
}
protected function defaultOptions()
{
return [
FormatterOptions::LIST_ORIENTATION => false,
] + parent::defaultOptions();
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData;
interface TableDataInterface
{
/**
* Return the original data for this table. Used by any
* formatter that is -not- a table.
*/
public function getOriginalData();
/**
* Convert structured data into a form suitable for use
* by the table formatter.
*
* @param boolean $includeRowKey Add a field containing the
* key from each row.
*
* @return array
*/
public function getTableData($includeRowKey = false);
}

View file

@ -0,0 +1,12 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData\Xml;
interface DomDataInterface
{
/**
* Convert data into a \DomDocument.
*
* @return \DomDocument
*/
public function getDomData();
}

View file

@ -0,0 +1,116 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData\Xml;
class XmlSchema implements XmlSchemaInterface
{
protected $elementList;
public function __construct($elementList = [])
{
$defaultElementList =
[
'*' => ['description'],
];
$this->elementList = array_merge_recursive($elementList, $defaultElementList);
}
public function arrayToXML($structuredData)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$topLevelElement = $this->getTopLevelElementName($structuredData);
$this->addXmlData($dom, $dom, $topLevelElement, $structuredData);
return $dom;
}
protected function addXmlData(\DOMDocument $dom, $xmlParent, $elementName, $structuredData)
{
$element = $dom->createElement($elementName);
$xmlParent->appendChild($element);
if (is_string($structuredData)) {
$element->appendChild($dom->createTextNode($structuredData));
return;
}
$this->addXmlChildren($dom, $element, $elementName, $structuredData);
}
protected function addXmlChildren(\DOMDocument $dom, $xmlParent, $elementName, $structuredData)
{
foreach ($structuredData as $key => $value) {
$this->addXmlDataOrAttribute($dom, $xmlParent, $elementName, $key, $value);
}
}
protected function addXmlDataOrAttribute(\DOMDocument $dom, $xmlParent, $elementName, $key, $value)
{
$childElementName = $this->getDefaultElementName($elementName);
$elementName = $this->determineElementName($key, $childElementName, $value);
if (($elementName != $childElementName) && $this->isAttribute($elementName, $key, $value)) {
$xmlParent->setAttribute($key, $value);
return;
}
$this->addXmlData($dom, $xmlParent, $elementName, $value);
}
protected function determineElementName($key, $childElementName, $value)
{
if (is_numeric($key)) {
return $childElementName;
}
if (is_object($value)) {
$value = (array)$value;
}
if (!is_array($value)) {
return $key;
}
if (array_key_exists('id', $value) && ($value['id'] == $key)) {
return $childElementName;
}
if (array_key_exists('name', $value) && ($value['name'] == $key)) {
return $childElementName;
}
return $key;
}
protected function getTopLevelElementName($structuredData)
{
return 'document';
}
protected function getDefaultElementName($parentElementName)
{
$singularName = $this->singularForm($parentElementName);
if (isset($singularName)) {
return $singularName;
}
return 'item';
}
protected function isAttribute($parentElementName, $elementName, $value)
{
if (!is_string($value)) {
return false;
}
return !$this->inElementList($parentElementName, $elementName) && !$this->inElementList('*', $elementName);
}
protected function inElementList($parentElementName, $elementName)
{
if (!array_key_exists($parentElementName, $this->elementList)) {
return false;
}
return in_array($elementName, $this->elementList[$parentElementName]);
}
protected function singularForm($name)
{
if (substr($name, strlen($name) - 1) == "s") {
return substr($name, 0, strlen($name) - 1);
}
}
protected function isAssoc($data)
{
return array_keys($data) == range(0, count($data));
}
}

View file

@ -0,0 +1,73 @@
<?php
namespace Consolidation\OutputFormatters\StructuredData\Xml;
/**
* When using arrays, we could represent XML data in a number of
* different ways.
*
* For example, given the following XML data strucutre:
*
* <document id="1" name="doc">
* <foobars>
* <foobar id="123">
* <name>blah</name>
* <widgets>
* <widget>
* <foo>a</foo>
* <bar>b</bar>
* <baz>c</baz>
* </widget>
* </widgets>
* </foobar>
* </foobars>
* </document>
*
* This could be:
*
* [
* 'id' => 1,
* 'name' => 'doc',
* 'foobars' =>
* [
* [
* 'id' => '123',
* 'name' => 'blah',
* 'widgets' =>
* [
* [
* 'foo' => 'a',
* 'bar' => 'b',
* 'baz' => 'c',
* ]
* ],
* ],
* ]
* ]
*
* The challenge is more in going from an array back to the more
* structured xml format. Note that any given key => string mapping
* could represent either an attribute, or a simple XML element
* containing only a string value. In general, we do *not* want to add
* extra layers of nesting in the data structure to disambiguate between
* these kinds of data, as we want the source data to render cleanly
* into other formats, e.g. yaml, json, et. al., and we do not want to
* force every data provider to have to consider the optimal xml schema
* for their data.
*
* Our strategy, therefore, is to expect clients that wish to provide
* a very specific xml representation to return a DOMDocument, and,
* for other data structures where xml is a secondary concern, then we
* will use some default heuristics to convert from arrays to xml.
*/
interface XmlSchemaInterface
{
/**
* Convert data to a format suitable for use in a list.
* By default, the array values will be used. Implement
* ListDataInterface to use some other criteria (e.g. array keys).
*
* @return \DOMDocument
*/
public function arrayToXml($structuredData);
}

View file

@ -0,0 +1,237 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\Xml\DomDataInterface;
use Consolidation\OutputFormatters\StructuredData\Xml\XmlSchema;
/**
* Simplify a DOMDocument to an array.
*/
class DomToArraySimplifier implements SimplifyToArrayInterface
{
public function __construct()
{
}
/**
* @param ReflectionClass $dataType
*/
public function canSimplify(\ReflectionClass $dataType)
{
return
$dataType->isSubclassOf('\Consolidation\OutputFormatters\StructuredData\Xml\DomDataInterface') ||
$dataType->isSubclassOf('DOMDocument') ||
($dataType->getName() == 'DOMDocument');
}
public function simplifyToArray($structuredData, FormatterOptions $options)
{
if ($structuredData instanceof DomDataInterface) {
$structuredData = $structuredData->getDomData();
}
if ($structuredData instanceof \DOMDocument) {
// $schema = $options->getXmlSchema();
$simplified = $this->elementToArray($structuredData);
$structuredData = array_shift($simplified);
}
return $structuredData;
}
/**
* Recursively convert the provided DOM element into a php array.
*
* @param \DOMNode $element
* @return array
*/
protected function elementToArray(\DOMNode $element)
{
if ($element->nodeType == XML_TEXT_NODE) {
return $element->nodeValue;
}
$attributes = $this->getNodeAttributes($element);
$children = $this->getNodeChildren($element);
return array_merge($attributes, $children);
}
/**
* Get all of the attributes of the provided element.
*
* @param \DOMNode $element
* @return array
*/
protected function getNodeAttributes($element)
{
if (empty($element->attributes)) {
return [];
}
$attributes = [];
foreach ($element->attributes as $key => $attribute) {
$attributes[$key] = $attribute->nodeValue;
}
return $attributes;
}
/**
* Get all of the children of the provided element, with simplification.
*
* @param \DOMNode $element
* @return array
*/
protected function getNodeChildren($element)
{
if (empty($element->childNodes)) {
return [];
}
$uniformChildrenName = $this->hasUniformChildren($element);
// Check for plurals.
if (in_array($element->nodeName, ["{$uniformChildrenName}s", "{$uniformChildrenName}es"])) {
$result = $this->getUniformChildren($element->nodeName, $element);
} else {
$result = $this->getUniqueChildren($element->nodeName, $element);
}
return array_filter($result);
}
/**
* Get the data from the children of the provided node in preliminary
* form.
*
* @param \DOMNode $element
* @return array
*/
protected function getNodeChildrenData($element)
{
$children = [];
foreach ($element->childNodes as $key => $value) {
$children[$key] = $this->elementToArray($value);
}
return $children;
}
/**
* Determine whether the children of the provided element are uniform.
* @see getUniformChildren(), below.
*
* @param \DOMNode $element
* @return boolean
*/
protected function hasUniformChildren($element)
{
$last = false;
foreach ($element->childNodes as $key => $value) {
$name = $value->nodeName;
if (!$name) {
return false;
}
if ($last && ($name != $last)) {
return false;
}
$last = $name;
}
return $last;
}
/**
* Convert the children of the provided DOM element into an array.
* Here, 'uniform' means that all of the element names of the children
* are identical, and further, the element name of the parent is the
* plural form of the child names. When the children are uniform in
* this way, then the parent element name will be used as the key to
* store the children in, and the child list will be returned as a
* simple list with their (duplicate) element names omitted.
*
* @param string $parentKey
* @param \DOMNode $element
* @return array
*/
protected function getUniformChildren($parentKey, $element)
{
$children = $this->getNodeChildrenData($element);
$simplifiedChildren = [];
foreach ($children as $key => $value) {
if ($this->valueCanBeSimplified($value)) {
$value = array_shift($value);
}
$id = $this->getIdOfValue($value);
if ($id) {
$simplifiedChildren[$parentKey][$id] = $value;
} else {
$simplifiedChildren[$parentKey][] = $value;
}
}
return $simplifiedChildren;
}
/**
* Determine whether the provided value has additional unnecessary
* nesting. {"color": "red"} is converted to "red". No other
* simplification is done.
*
* @param \DOMNode $value
* @return boolean
*/
protected function valueCanBeSimplified($value)
{
if (!is_array($value)) {
return false;
}
if (count($value) != 1) {
return false;
}
$data = array_shift($value);
return is_string($data);
}
/**
* If the object has an 'id' or 'name' element, then use that
* as the array key when storing this value in its parent.
* @param mixed $value
* @return string
*/
protected function getIdOfValue($value)
{
if (!is_array($value)) {
return false;
}
if (array_key_exists('id', $value)) {
return trim($value['id'], '-');
}
if (array_key_exists('name', $value)) {
return trim($value['name'], '-');
}
}
/**
* Convert the children of the provided DOM element into an array.
* Here, 'unique' means that all of the element names of the children are
* different. Since the element names will become the key of the
* associative array that is returned, so duplicates are not supported.
* If there are any duplicates, then an exception will be thrown.
*
* @param string $parentKey
* @param \DOMNode $element
* @return array
*/
protected function getUniqueChildren($parentKey, $element)
{
$children = $this->getNodeChildrenData($element);
if ((count($children) == 1) && (is_string($children[0]))) {
return [$element->nodeName => $children[0]];
}
$simplifiedChildren = [];
foreach ($children as $key => $value) {
if (is_numeric($key) && is_array($value) && (count($value) == 1)) {
$valueKeys = array_keys($value);
$key = $valueKeys[0];
$value = array_shift($value);
}
if (array_key_exists($key, $simplifiedChildren)) {
throw new \Exception("Cannot convert data from a DOM document to an array, because <$key> appears more than once, and is not wrapped in a <{$key}s> element.");
}
$simplifiedChildren[$key] = $value;
}
return $simplifiedChildren;
}
}

View file

@ -0,0 +1,17 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
use Consolidation\OutputFormatters\Options\FormatterOptions;
interface OverrideRestructureInterface
{
/**
* Select data to use directly from the structured output,
* before the restructure operation has been executed.
*
* @param mixed $structuredOutput Data to restructure
* @param FormatterOptions $options Formatting options
* @return mixed
*/
public function overrideRestructure($structuredOutput, FormatterOptions $options);
}

View file

@ -0,0 +1,11 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
class PropertyListTableTransformation extends TableTransformation
{
public function getOriginalData()
{
$data = $this->getArrayCopy();
return $data[0];
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
/**
* Transform a string of properties into a PHP associative array.
*
* Input:
*
* one: red
* two: white
* three: blue
*
* Output:
*
* [
* 'one' => 'red',
* 'two' => 'white',
* 'three' => 'blue',
* ]
*/
class PropertyParser
{
public static function parse($data)
{
if (!is_string($data)) {
return $data;
}
$result = [];
$lines = explode("\n", $data);
foreach ($lines as $line) {
list($key, $value) = explode(':', trim($line), 2) + ['', ''];
if (!empty($key) && !empty($value)) {
$result[$key] = trim($value);
}
}
return $result;
}
}

View file

@ -0,0 +1,126 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
use Symfony\Component\Finder\Glob;
use Consolidation\OutputFormatters\Exception\UnknownFieldException;
/**
* Reorder the field labels based on the user-selected fields
* to display.
*/
class ReorderFields
{
/**
* Given a simple list of user-supplied field keys or field labels,
* return a reordered version of the field labels matching the
* user selection.
*
* @param string|array $fields The user-selected fields
* @param array $fieldLabels An associative array mapping the field
* key to the field label
* @param array $data The data that will be rendered.
*
* @return array
*/
public function reorder($fields, $fieldLabels, $data)
{
$firstRow = reset($data);
if (!$firstRow) {
$firstRow = $fieldLabels;
}
if (empty($fieldLabels) && !empty($data)) {
$fieldLabels = array_combine(array_keys($firstRow), array_map('ucfirst', array_keys($firstRow)));
}
$fields = $this->getSelectedFieldKeys($fields, $fieldLabels);
if (empty($fields)) {
return array_intersect_key($fieldLabels, $firstRow);
}
return $this->reorderFieldLabels($fields, $fieldLabels, $data);
}
protected function reorderFieldLabels($fields, $fieldLabels, $data)
{
$result = [];
$firstRow = reset($data);
if (!$firstRow) {
$firstRow = $fieldLabels;
}
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);
}
$selectedFields = [];
foreach ($fields as $field) {
$matchedFields = $this->matchFieldInLabelMap($field, $fieldLabels);
if (empty($matchedFields)) {
throw new UnknownFieldException($field);
}
$selectedFields = array_merge($selectedFields, $matchedFields);
}
return $selectedFields;
}
protected function matchFieldInLabelMap($field, $fieldLabels)
{
$fieldRegex = $this->convertToRegex($field);
return
array_filter(
array_keys($fieldLabels),
function ($key) use ($fieldRegex, $fieldLabels) {
$value = $fieldLabels[$key];
return preg_match($fieldRegex, $value) || preg_match($fieldRegex, $key);
}
);
}
/**
* Convert the provided string into a regex suitable for use in
* preg_match.
*
* Matching occurs in the same way as the Symfony Finder component:
* http://symfony.com/doc/current/components/finder.html#file-name
*/
protected function convertToRegex($str)
{
return $this->isRegex($str) ? $str : Glob::toRegex($str);
}
/**
* Checks whether the string is a regex. This function is copied from
* MultiplePcreFilterIterator in the Symfony Finder component.
*
* @param string $str
*
* @return bool Whether the given string is a regex
*/
protected function isRegex($str)
{
if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
$start = substr($m[1], 0, 1);
$end = substr($m[1], -1);
if ($start === $end) {
return !preg_match('/[*?[:alnum:] \\\\]/', $start);
}
foreach (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
if ($start === $delimiters[0] && $end === $delimiters[1]) {
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
use Consolidation\OutputFormatters\Options\FormatterOptions;
interface SimplifyToArrayInterface
{
/**
* Convert structured data into a generic array, usable by generic
* array-based formatters. Objects that implement this interface may
* be attached to the FormatterManager, and will be used on any data
* structure that needs to be simplified into an array. An array
* simplifier should take no action other than to return its input data
* if it cannot simplify the provided data into an array.
*
* @param mixed $structuredOutput The data to simplify to an array.
*
* @return array
*/
public function simplifyToArray($structuredOutput, FormatterOptions $options);
/**
* Indicate whether or not the given data type can be simplified to an array
*/
public function canSimplify(\ReflectionClass $structuredOutput);
}

View file

@ -0,0 +1,123 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
use Consolidation\OutputFormatters\StructuredData\TableDataInterface;
use Consolidation\OutputFormatters\StructuredData\OriginalDataInterface;
class TableTransformation extends \ArrayObject implements TableDataInterface, OriginalDataInterface
{
protected $headers;
protected $rowLabels;
protected $layout;
const TABLE_LAYOUT = 'table';
const LIST_LAYOUT = 'list';
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);
}
public function setLayout($layout)
{
$this->layout = $layout;
}
public function getLayout()
{
return $this->layout;
}
public function isList()
{
return $this->layout == self::LIST_LAYOUT;
}
protected static function transformRows($data, $fieldLabels)
{
$rows = [];
foreach ($data as $rowid => $row) {
$rows[$rowid] = static::transformRow($row, $fieldLabels);
}
return $rows;
}
protected static function transformRow($row, $fieldLabels)
{
$result = [];
foreach ($fieldLabels as $key => $label) {
$result[$key] = array_key_exists($key, $row) ? $row[$key] : '';
}
return $result;
}
public function getHeaders()
{
return $this->headers;
}
public function getHeader($key)
{
if (array_key_exists($key, $this->headers)) {
return $this->headers[$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 getOriginalData()
{
return $this->getArrayCopy();
}
public function getTableData($includeRowKey = false)
{
$data = $this->getArrayCopy();
if ($this->isList()) {
$data = $this->convertTableToList();
}
if ($includeRowKey) {
$data = $this->getRowDataWithKey($data);
}
return $data;
}
protected function convertTableToList()
{
$result = [];
foreach ($this as $row) {
foreach ($row as $key => $value) {
$result[$key][] = $value;
}
}
return $result;
}
protected function getRowDataWithKey($data)
{
$result = [];
$i = 0;
foreach ($data as $key => $row) {
array_unshift($row, $this->getHeader($key));
$i++;
$result[$key] = $row;
}
return $result;
}
}

View file

@ -0,0 +1,122 @@
<?php
namespace Consolidation\OutputFormatters\Transformations;
use Consolidation\OutputFormatters\Transformations\Wrap\CalculateWidths;
use Consolidation\OutputFormatters\Transformations\Wrap\ColumnWidths;
use Symfony\Component\Console\Helper\TableStyle;
class WordWrapper
{
protected $width;
protected $minimumWidths;
// For now, hardcode these to match what the Symfony Table helper does.
// Note that these might actually need to be adjusted depending on the
// table style.
protected $extraPaddingAtBeginningOfLine = 0;
protected $extraPaddingAtEndOfLine = 0;
protected $paddingInEachCell = 3;
public function __construct($width)
{
$this->width = $width;
$this->minimumWidths = new ColumnWidths();
}
/**
* Calculate our padding widths from the specified table style.
* @param TableStyle $style
*/
public function setPaddingFromStyle(TableStyle $style)
{
$verticalBorderLen = strlen(sprintf($style->getBorderFormat(), $style->getVerticalBorderChar()));
$paddingLen = strlen($style->getPaddingChar());
$this->extraPaddingAtBeginningOfLine = 0;
$this->extraPaddingAtEndOfLine = $verticalBorderLen;
$this->paddingInEachCell = $verticalBorderLen + $paddingLen + 1;
}
/**
* If columns have minimum widths, then set them here.
* @param array $minimumWidths
*/
public function setMinimumWidths($minimumWidths)
{
$this->minimumWidths = new ColumnWidths($minimumWidths);
}
/**
* Set the minimum width of just one column
*/
public function minimumWidth($colkey, $width)
{
$this->minimumWidths->setWidth($colkey, $width);
}
/**
* Wrap the cells in each part of the provided data table
* @param array $rows
* @return array
*/
public function wrap($rows, $widths = [])
{
$auto_widths = $this->calculateWidths($rows, $widths);
// If no widths were provided, then disable wrapping
if ($auto_widths->isEmpty()) {
return $rows;
}
// Do wordwrap on all cells.
$newrows = array();
foreach ($rows as $rowkey => $row) {
foreach ($row as $colkey => $cell) {
$newrows[$rowkey][$colkey] = $this->wrapCell($cell, $auto_widths->width($colkey));
}
}
return $newrows;
}
/**
* Determine what widths we'll use for wrapping.
*/
protected function calculateWidths($rows, $widths = [])
{
// Widths must be provided in some form or another, or we won't wrap.
if (empty($widths) && !$this->width) {
return new ColumnWidths();
}
// Technically, `$widths`, if provided here, should be used
// as the exact widths to wrap to. For now we'll just treat
// these as minimum widths
$minimumWidths = $this->minimumWidths->combine(new ColumnWidths($widths));
$calculator = new CalculateWidths();
$dataCellWidths = $calculator->calculateLongestCell($rows);
$availableWidth = $this->width - $dataCellWidths->paddingSpace($this->paddingInEachCell, $this->extraPaddingAtEndOfLine, $this->extraPaddingAtBeginningOfLine);
$this->minimumWidths->adjustMinimumWidths($availableWidth, $dataCellWidths);
return $calculator->calculate($availableWidth, $dataCellWidths, $minimumWidths);
}
/**
* Wrap one cell. Guard against modifying non-strings and
* then call through to wordwrap().
*
* @param mixed $cell
* @param string $cellWidth
* @return mixed
*/
protected function wrapCell($cell, $cellWidth)
{
if (!is_string($cell)) {
return $cell;
}
return wordwrap($cell, $cellWidth, "\n", true);
}
}

View file

@ -0,0 +1,141 @@
<?php
namespace Consolidation\OutputFormatters\Transformations\Wrap;
use Symfony\Component\Console\Helper\TableStyle;
/**
* Calculate column widths for table cells.
*
* Influenced by Drush and webmozart/console.
*/
class CalculateWidths
{
public function __construct()
{
}
/**
* Given the total amount of available space, and the width of
* the columns to place, calculate the optimum column widths to use.
*/
public function calculate($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths)
{
// First, check to see if all columns will fit at their full widths.
// If so, do no further calculations. (This may be redundant with
// the short column width calculation.)
if ($dataWidths->totalWidth() <= $availableWidth) {
return $dataWidths->enforceMinimums($minimumWidths);
}
// Get the short columns first. If there are none, then distribute all
// of the available width among the remaining columns.
$shortColWidths = $this->getShortColumns($availableWidth, $dataWidths, $minimumWidths);
if ($shortColWidths->isEmpty()) {
return $this->distributeLongColumns($availableWidth, $dataWidths, $minimumWidths);
}
// If some short columns were removed, then account for the length
// of the removed columns and make a recursive call (since the average
// width may be higher now, if the removed columns were shorter in
// length than the previous average).
$availableWidth -= $shortColWidths->totalWidth();
$remainingWidths = $dataWidths->removeColumns($shortColWidths->keys());
$remainingColWidths = $this->calculate($availableWidth, $remainingWidths, $minimumWidths);
return $shortColWidths->combine($remainingColWidths);
}
/**
* Calculate the longest cell data from any row of each of the cells.
*/
public function calculateLongestCell($rows)
{
return $this->calculateColumnWidths(
$rows,
function ($cell) {
return strlen($cell);
}
);
}
/**
* Calculate the longest word and longest line in the provided data.
*/
public function calculateLongestWord($rows)
{
return $this->calculateColumnWidths(
$rows,
function ($cell) {
return static::longestWordLength($cell);
}
);
}
protected function calculateColumnWidths($rows, callable $fn)
{
$widths = [];
// Examine each row and find the longest line length and longest
// word in each column.
foreach ($rows as $rowkey => $row) {
foreach ($row as $colkey => $cell) {
$value = $fn($cell);
if ((!isset($widths[$colkey]) || ($widths[$colkey] < $value))) {
$widths[$colkey] = $value;
}
}
}
return new ColumnWidths($widths);
}
/**
* Return all of the columns whose longest line length is less than or
* equal to the average width.
*/
public function getShortColumns($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths)
{
$averageWidth = $dataWidths->averageWidth($availableWidth);
$shortColWidths = $dataWidths->findShortColumns($averageWidth);
return $shortColWidths->enforceMinimums($minimumWidths);
}
/**
* Distribute the remainig space among the columns that were not
* included in the list of "short" columns.
*/
public function distributeLongColumns($availableWidth, ColumnWidths $dataWidths, ColumnWidths $minimumWidths)
{
// First distribute the remainder without regard to the minimum widths.
$result = $dataWidths->distribute($availableWidth);
// Find columns that are shorter than their minimum width.
$undersized = $result->findUndersizedColumns($minimumWidths);
// Nothing too small? Great, we're done!
if ($undersized->isEmpty()) {
return $result;
}
// Take out the columns that are too small and redistribute the rest.
$availableWidth -= $undersized->totalWidth();
$remaining = $dataWidths->removeColumns($undersized->keys());
$distributeRemaining = $this->distributeLongColumns($availableWidth, $remaining, $minimumWidths);
return $undersized->combine($distributeRemaining);
}
/**
* Return the length of the longest word in the string.
* @param string $str
* @return int
*/
protected static function longestWordLength($str)
{
$words = preg_split('#[ /-]#', $str);
$lengths = array_map(function ($s) {
return strlen($s);
}, $words);
return max($lengths);
}
}

View file

@ -0,0 +1,264 @@
<?php
namespace Consolidation\OutputFormatters\Transformations\Wrap;
use Symfony\Component\Console\Helper\TableStyle;
/**
* Calculate the width of data in table cells in preparation for word wrapping.
*/
class ColumnWidths
{
protected $widths;
public function __construct($widths = [])
{
$this->widths = $widths;
}
public function paddingSpace(
$paddingInEachCell,
$extraPaddingAtEndOfLine = 0,
$extraPaddingAtBeginningOfLine = 0
) {
return ($extraPaddingAtBeginningOfLine + $extraPaddingAtEndOfLine + (count($this->widths) * $paddingInEachCell));
}
/**
* Find all of the columns that are shorter than the specified threshold.
*/
public function findShortColumns($thresholdWidth)
{
$thresholdWidths = array_fill_keys(array_keys($this->widths), $thresholdWidth);
return $this->findColumnsUnderThreshold($thresholdWidths);
}
/**
* Find all of the columns that are shorter than the corresponding minimum widths.
*/
public function findUndersizedColumns($minimumWidths)
{
return $this->findColumnsUnderThreshold($minimumWidths->widths());
}
protected function findColumnsUnderThreshold(array $thresholdWidths)
{
$shortColWidths = [];
foreach ($this->widths as $key => $maxLength) {
if (isset($thresholdWidths[$key]) && ($maxLength <= $thresholdWidths[$key])) {
$shortColWidths[$key] = $maxLength;
}
}
return new ColumnWidths($shortColWidths);
}
/**
* If the widths specified by this object do not fit within the
* provided avaiable width, then reduce them all proportionally.
*/
public function adjustMinimumWidths($availableWidth, $dataCellWidths)
{
$result = $this->selectColumns($dataCellWidths->keys());
if ($result->isEmpty()) {
return $result;
}
$numberOfColumns = $dataCellWidths->count();
// How many unspecified columns are there?
$unspecifiedColumns = $numberOfColumns - $result->count();
$averageWidth = $this->averageWidth($availableWidth);
// Reserve some space for the columns that have no minimum.
// Make sure they collectively get at least half of the average
// width for each column. Or should it be a quarter?
$reservedSpacePerColumn = ($averageWidth / 2);
$reservedSpace = $reservedSpacePerColumn * $unspecifiedColumns;
// Calculate how much of the available space is remaining for use by
// the minimum column widths after the reserved space is accounted for.
$remainingAvailable = $availableWidth - $reservedSpace;
// Don't do anything if our widths fit inside the available widths.
if ($result->totalWidth() <= $remainingAvailable) {
return $result;
}
// Shrink the minimum widths if the table is too compressed.
return $result->distribute($remainingAvailable);
}
/**
* Return proportional weights
*/
public function distribute($availableWidth)
{
$result = [];
$totalWidth = $this->totalWidth();
$lastColumn = $this->lastColumn();
$widths = $this->widths();
// Take off the last column, and calculate proportional weights
// for the first N-1 columns.
array_pop($widths);
foreach ($widths as $key => $width) {
$result[$key] = round(($width / $totalWidth) * $availableWidth);
}
// Give the last column the rest of the available width
$usedWidth = $this->sumWidth($result);
$result[$lastColumn] = $availableWidth - $usedWidth;
return new ColumnWidths($result);
}
public function lastColumn()
{
$keys = $this->keys();
return array_pop($keys);
}
/**
* Return the number of columns.
*/
public function count()
{
return count($this->widths);
}
/**
* Calculate how much space is available on average for all columns.
*/
public function averageWidth($availableWidth)
{
if ($this->isEmpty()) {
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
return $availableWidth / $this->count();
}
/**
* Return the available keys (column identifiers) from the calculated
* data set.
*/
public function keys()
{
return array_keys($this->widths);
}
/**
* Set the length of the specified column.
*/
public function setWidth($key, $width)
{
$this->widths[$key] = $width;
}
/**
* Return the length of the specified column.
*/
public function width($key)
{
return isset($this->widths[$key]) ? $this->widths[$key] : 0;
}
/**
* Return all of the lengths
*/
public function widths()
{
return $this->widths;
}
/**
* Return true if there is no data in this object
*/
public function isEmpty()
{
return empty($this->widths);
}
/**
* Return the sum of the lengths of the provided widths.
*/
public function totalWidth()
{
return static::sumWidth($this->widths());
}
/**
* Return the sum of the lengths of the provided widths.
*/
public static function sumWidth($widths)
{
return array_reduce(
$widths,
function ($carry, $item) {
return $carry + $item;
}
);
}
/**
* Ensure that every item in $widths that has a corresponding entry
* in $minimumWidths is as least as large as the minimum value held there.
*/
public function enforceMinimums($minimumWidths)
{
$result = [];
if ($minimumWidths instanceof ColumnWidths) {
$minimumWidths = $minimumWidths->widths();
}
$minimumWidths += $this->widths;
foreach ($this->widths as $key => $value) {
$result[$key] = max($value, $minimumWidths[$key]);
}
return new ColumnWidths($result);
}
/**
* Remove all of the specified columns from this data structure.
*/
public function removeColumns($columnKeys)
{
$widths = $this->widths();
foreach ($columnKeys as $key) {
unset($widths[$key]);
}
return new ColumnWidths($widths);
}
/**
* Select all columns that exist in the provided list of keys.
*/
public function selectColumns($columnKeys)
{
$widths = [];
foreach ($columnKeys as $key) {
if (isset($this->widths[$key])) {
$widths[$key] = $this->width($key);
}
}
return new ColumnWidths($widths);
}
/**
* Combine this set of widths with another set, and return
* a new set that contains the entries from both.
*/
public function combine(ColumnWidths $combineWith)
{
// Danger: array_merge renumbers numeric keys; that must not happen here.
$combined = $combineWith->widths();
foreach ($this->widths() as $key => $value) {
$combined[$key] = $value;
}
return new ColumnWidths($combined);
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace Consolidation\OutputFormatters\Validate;
/**
* Formatters may implement ValidDataTypesInterface in order to indicate
* exactly which formats they support. The validDataTypes method can be
* called to retrieve a list of data types useful in providing hints in
* exception messages about which data types can be used with the formatter.
*
* Note that it is OPTIONAL for formatters to implement this interface.
* If a formatter implements only ValidationInterface, then clients that
* request the formatter via FormatterManager::write() will still get a list
* (via an InvalidFormatException) of all of the formats that are usable
* with the provided data type. Implementing ValidDataTypesInterface is
* benefitial to clients who instantiate a formatter directly (via `new`).
*
* Formatters that implement ValidDataTypesInterface may wish to use
* ValidDataTypesTrait.
*/
interface ValidDataTypesInterface extends ValidationInterface
{
/**
* Return the list of data types acceptable to this formatter
*
* @return \ReflectionClass[]
*/
public function validDataTypes();
}

View file

@ -0,0 +1,34 @@
<?php
namespace Consolidation\OutputFormatters\Validate;
/**
* Provides a default implementation of isValidDataType.
*
* Users of this trait are expected to implement ValidDataTypesInterface.
*/
trait ValidDataTypesTrait
{
/**
* Return the list of data types acceptable to this formatter
*
* @return \ReflectionClass[]
*/
public abstract function validDataTypes();
/**
* Return the list of data types acceptable to this formatter
*/
public function isValidDataType(\ReflectionClass $dataType)
{
return array_reduce(
$this->validDataTypes(),
function ($carry, $supportedType) use ($dataType) {
return
$carry ||
($dataType->getName() == $supportedType->getName()) ||
($dataType->isSubclassOf($supportedType->getName()));
},
false
);
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace Consolidation\OutputFormatters\Validate;
/**
* Formatters may implement ValidationInterface in order to indicate
* whether a particular data structure is supported. Any formatter that does
* not implement ValidationInterface is assumed to only operate on arrays,
* or data types that implement SimplifyToArrayInterface.
*/
interface ValidationInterface
{
/**
* Return true if the specified format is valid for use with
* this formatter.
*/
public function isValidDataType(\ReflectionClass $dataType);
/**
* Throw an IncompatibleDataException if the provided data cannot
* be processed by this formatter. Return the source data if it
* is valid. The data may be encapsulated or converted if necessary.
*
* @param mixed $structuredData Data to validate
*
* @return mixed
*/
public function validate($structuredData);
}

View file

@ -0,0 +1,20 @@
<?php
use Consolidation\OutputFormatters\Transformations\WordWrapper;
include 'vendor/autoload.php';
$wrapper = new WordWrapper(78);
$data = [
'name' => ['Name', ':', 'Rex', ],
'species' => ['Species', ':', 'dog', ],
'food' => ['Food', ':', 'kibble', ],
'legs' => ['Legs', ':', '4', ],
'description' => ['Description', ':', 'Rex is a very good dog, Brett. He likes kibble, and has four legs.', ],
];
$result = $wrapper->wrap($data);
var_export($result);

View file

@ -0,0 +1,17 @@
<?php
namespace Consolidation\TestUtils;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use Consolidation\OutputFormatters\StructuredData\RenderCellInterface;
class PropertyListWithCsvCells extends PropertyList implements RenderCellInterface
{
public function renderCell($key, $cellData, FormatterOptions $options, $rowData)
{
if (is_array($cellData)) {
return implode(',', $cellData);
}
return $cellData;
}
}

View file

@ -0,0 +1,17 @@
<?php
namespace Consolidation\TestUtils;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\OutputFormatters\StructuredData\RenderCellInterface;
class RowsOfFieldsWithAlternatives extends RowsOfFields implements RenderCellInterface
{
public function renderCell($key, $cellData, FormatterOptions $options, $rowData)
{
if (is_array($cellData)) {
return implode('|', $cellData);
}
return $cellData;
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Consolidation\OutputFormatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
class APIDocsTests extends \PHPUnit_Framework_TestCase
{
function testAPIDocs()
{
if (getenv('CI')) {
$this->markTestIncomplete(
'API generation has slight variations when run on CI server. This test is therefore skipped on CI until we can make the test results consistent.'
);
}
$testDocs = tempnam(sys_get_temp_dir(), 'TestAPIDocs.md');
$currentDocs = getcwd() . '/docs/api.md';
passthru("vendor/bin/phpdoc-md generate src > $testDocs");
$testDocsContent = file_get_contents($testDocs);
$currentDocsContent = file_get_contents($currentDocs);
$testDocsContent = str_replace (array("\r\n", "\r"), "\n", $testDocsContent);
$currentDocsContent = str_replace (array("\r\n", "\r"), "\n", $currentDocsContent);
$this->assertEquals($testDocsContent, $currentDocsContent, "API docuementation out of date. Run 'composer api' to update.");
}
}

View file

@ -0,0 +1,112 @@
<?php
namespace Consolidation\OutputFormatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
class FormatterOptionsTests extends \PHPUnit_Framework_TestCase
{
public function createStringInput($testCommandline)
{
$input = new StringInput($testCommandline);
$optionDefinitions = [
new InputArgument('unused', InputArgument::REQUIRED),
new InputOption(FormatterOptions::FORMAT, null, InputOption::VALUE_REQUIRED),
new InputOption(FormatterOptions::TABLE_STYLE, null, InputOption::VALUE_REQUIRED),
new InputOption(FormatterOptions::FIELD, null, InputOption::VALUE_REQUIRED),
new InputOption(FormatterOptions::FIELDS, null, InputOption::VALUE_REQUIRED),
new InputOption(FormatterOptions::INCLUDE_FIELD_LABELS, null, InputOption::VALUE_NONE),
new InputOption(FormatterOptions::ROW_LABELS, null, InputOption::VALUE_REQUIRED),
new InputOption(FormatterOptions::FIELD_LABELS, null, InputOption::VALUE_REQUIRED),
// These probably don't make senes to alter via options
new InputOption(FormatterOptions::DEFAULT_FORMAT, null, InputOption::VALUE_REQUIRED),
new InputOption(FormatterOptions::DEFAULT_FIELDS, null, InputOption::VALUE_REQUIRED),
new InputOption(FormatterOptions::LIST_ORIENTATION, null, InputOption::VALUE_NONE),
];
$definition = new InputDefinition($optionDefinitions);
$input->bind($definition);
return $input;
}
protected function getFormat(FormatterOptions $options, $defaults = [])
{
return $options->get(FormatterOptions::FORMAT, [], $options->get(FormatterOptions::DEFAULT_FORMAT, $defaults, ''));
}
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', $this->getFormat($options));
$this->assertEquals('table', $this->getFormat($options, $defaults));
// Override has higher priority than configuration and defaults
$options = new FormatterOptions($configurationData, $userOptions);
$newOptions = $options->override([FormatterOptions::DEFAULT_FORMAT => 'json']);
$this->assertEquals('json', $this->getFormat($newOptions));
$this->assertEquals('json', $this->getFormat($newOptions, $defaults));
$options = new FormatterOptions($configurationData, $userOptions);
$options->setConfigurationDefault(FormatterOptions::DEFAULT_FORMAT, 'php');
$this->assertEquals('table', $this->getFormat($options));
$options = new FormatterOptions($configurationData, $userOptions);
$options->setConfigurationData([]);
$this->assertEquals('', $this->getFormat($options));
// 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'));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
<?php
namespace Consolidation\OutputFormatters;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
class IncompatibleDataTests extends \PHPUnit_Framework_TestCase
{
protected $formatterManager;
function setup() {
$this->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\PropertyList. 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\PropertyList. 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\PropertyList. 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\PropertyList. Instead, an instance of Consolidation\OutputFormatters\StructuredData\PropertyList was provided.', $tableFormatter, new PropertyList([]));
}
/**
* @expectedException \Exception
* @expectedExceptionMessage Undescribable data error: NULL
*/
public function testUndescribableData()
{
$tableFormatter = $this->formatterManager->getFormatter('table');
$data = $tableFormatter->validate(null);
$this->assertEquals('Will throw before comparing.', $data);
}
/**
* @expectedException \Exception
* @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\PropertyList. Instead, a string was provided.
*/
public function testInvalidTableData()
{
$tableFormatter = $this->formatterManager->getFormatter('table');
$data = $tableFormatter->validate('bad data type');
$this->assertEquals('Will throw before comparing.', $data);
}
/**
* @expectedException \Exception
* @expectedExceptionMessage Data provided to Consolidation\OutputFormatters\Formatters\SectionsFormatter must be an instance of Consolidation\OutputFormatters\StructuredData\RowsOfFields. Instead, a string was provided.
*/
public function testInvalidSectionsData()
{
$tableFormatter = $this->formatterManager->getFormatter('sections');
$data = $tableFormatter->validate('bad data type');
$this->assertEquals('Will throw before comparing.', $data);
}
}

View file

@ -0,0 +1,88 @@
<?php
namespace Consolidation\OutputFormatters;
use Consolidation\OutputFormatters\Options\FormatterOptions;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Consolidation\OutputFormatters\StructuredData\PropertyList;
class ValidFormatsTests extends \PHPUnit_Framework_TestCase
{
protected $formatterManager;
function setup() {
$this->formatterManager = new FormatterManager();
$this->formatterManager->addDefaultFormatters();
$this->formatterManager->addDefaultSimplifiers();
}
function testValidFormats()
{
$arrayObjectRef = new \ReflectionClass('\ArrayObject');
$associativeListRef = new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\PropertyList');
$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,string,tsv,var_export,xml,yaml', implode(',', $validFormats));
// Check to see which formats can handle an PropertyList
$validFormats = $this->formatterManager->validFormats($associativeListRef);
$this->assertEquals('csv,json,list,php,print-r,string,table,tsv,var_export,xml,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,string,table,tsv,var_export,xml,yaml', implode(',', $validFormats));
// TODO: it woud be better if this returned an empty set instead of 'string'.
$validFormats = $this->formatterManager->validFormats($notADataType);
$this->assertEquals('string', implode(',', $validFormats));
}
function testAutomaticOptions()
{
$rowsOfFieldsRef = new \ReflectionClass('\Consolidation\OutputFormatters\StructuredData\RowsOfFields');
$formatterOptions = new FormatterOptions(
[
FormatterOptions::FIELD_LABELS => "name: Name\nphone_number: Phone Number",
]
);
$inputOptions = $this->formatterManager->automaticOptions($formatterOptions, $rowsOfFieldsRef);
$this->assertInputOptionDescriptionsEquals("Format the result data. Available formats: csv,json,list,php,print-r,sections,string,table,tsv,var_export,xml,yaml [Default: 'table']\nAvailable fields: Name (name), Phone Number (phone_number) [Default: '']\nSelect just one field, and force format to 'string'. [Default: '']", $inputOptions);
}
function assertInputOptionDescriptionsEquals($expected, $inputOptions)
{
$descriptions = [];
foreach ($inputOptions as $inputOption) {
$descriptions[] = $inputOption->getDescription() . " [Default: '" . $inputOption->getDefault() . "']";
}
$this->assertEquals($expected, implode("\n", $descriptions));
}
}