Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
15
vendor/consolidation/output-formatters/.editorconfig
vendored
Normal file
15
vendor/consolidation/output-formatters/.editorconfig
vendored
Normal 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
|
||||
|
104
vendor/consolidation/output-formatters/CHANGELOG.md
vendored
Normal file
104
vendor/consolidation/output-formatters/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
# Change Log
|
||||
|
||||
### 3.4.0 - 19 October 2018
|
||||
|
||||
- Add an UnstucturedInterface marker interface, and update the 'string' format to not accept data types that implement this interface unless they also implement StringTransformationInterface.
|
||||
|
||||
### 3.3.2 - 18 October 2018
|
||||
|
||||
- Add a 'null' output formatter that accepts all data types and never produces output
|
||||
|
||||
### 3.3.0 & 3.3.1 - 15 October 2018
|
||||
|
||||
- Add UnstructuredListData and UnstructuredData to replace deprecated ListDataFromKeys
|
||||
- Support --field and --fields in commands that return UnstructuredData / UnstructuredListData
|
||||
- Support field remapping, e.g. `--fields=original as remapped`
|
||||
- Support field addressing, e.g. `--fields=a.b.c`
|
||||
- Automatically convert from RowsOfFields to UnstruturedListData and from PropertyList to UnstructuredData when user utilizes field remapping or field addressing features.
|
||||
|
||||
### 3.2.1 - 25 May 2018
|
||||
|
||||
- Rename g1a/composer-test-scenarios
|
||||
|
||||
### 3.2.0 - 20 March 2018
|
||||
|
||||
- Add RowsOfFieldsWithMetadata: allows commands to return an object with metadata that shows up in yaml/json (& etc.) formats, but is not shown in table/csv (& etc.).
|
||||
- Add NumericCellRenderer: allows commands to attach a renderer that will right-justify and add commas to numbers in a column.
|
||||
- Add optional var_dump output format.
|
||||
|
||||
### 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.
|
31
vendor/consolidation/output-formatters/CONTRIBUTING.md
vendored
Normal file
31
vendor/consolidation/output-formatters/CONTRIBUTING.md
vendored
Normal 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.
|
18
vendor/consolidation/output-formatters/LICENSE
vendored
Normal file
18
vendor/consolidation/output-formatters/LICENSE
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
Copyright (c) 2016-2018 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.
|
||||
|
||||
DEPENDENCY LICENSES:
|
||||
|
||||
Name Version License
|
||||
dflydev/dot-access-data v1.1.0 MIT
|
||||
psr/log 1.0.2 MIT
|
||||
symfony/console v3.2.3 MIT
|
||||
symfony/debug v3.4.17 MIT
|
||||
symfony/finder v3.4.17 MIT
|
||||
symfony/polyfill-mbstring v1.9.0 MIT
|
330
vendor/consolidation/output-formatters/README.md
vendored
Normal file
330
vendor/consolidation/output-formatters/README.md
vendored
Normal file
|
@ -0,0 +1,330 @@
|
|||
# Consolidation\OutputFormatters
|
||||
|
||||
Apply transformations to structured data to write output in different formats.
|
||||
|
||||
[](https://travis-ci.org/consolidation/output-formatters)
|
||||
[](https://ci.appveyor.com/project/greg-1-anderson/output-formatters)
|
||||
[](https://scrutinizer-ci.com/g/consolidation/output-formatters/?branch=master)
|
||||
[](https://coveralls.io/github/consolidation/output-formatters?branch=master)
|
||||
[](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.
|
||||
- `UnstructuredInterface`: A formatter that implements this interface will not be able to be formatted by the `string` formatter by default. Data structures that do not implement this interface will be automatically converted to a string when applicable; if this conversion fails, then no output is produced.
|
||||
- `StringTransformationInterface`: Implementing this interface allows a data type to provide a specific implementation for the conversion of the data to a string. Data types that implement both `UnstructuredInterface` and `StringTransformationInterface` may be used with the `string` format.
|
||||
|
||||
## Configuring Formats for a Command
|
||||
|
||||
Commands declare what type of data they return using a `@return` annotation, as usual:
|
||||
```php
|
||||
/**
|
||||
* Demonstrate formatters. Default format is 'table'.
|
||||
*
|
||||
* @field-labels
|
||||
* first: I
|
||||
* second: II
|
||||
* third: III
|
||||
* @default-string-field second
|
||||
* @usage try:formatters --format=yaml
|
||||
* @usage try:formatters --format=csv
|
||||
* @usage try:formatters --fields=first,third
|
||||
* @usage try:formatters --fields=III,II
|
||||
*
|
||||
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
|
||||
*/
|
||||
public function tryFormatters($somthing = 'default', $options = ['format' => 'table', 'fields' => ''])
|
||||
{
|
||||
$outputData = [
|
||||
'en' => [ 'first' => 'One', 'second' => 'Two', 'third' => 'Three' ],
|
||||
'de' => [ 'first' => 'Eins', 'second' => 'Zwei', 'third' => 'Drei' ],
|
||||
'jp' => [ 'first' => 'Ichi', 'second' => 'Ni', 'third' => 'San' ],
|
||||
'es' => [ 'first' => 'Uno', 'second' => 'Dos', 'third' => 'Tres' ],
|
||||
];
|
||||
return new RowsOfFields($outputData);
|
||||
}
|
||||
```
|
||||
The output-formatters library determines which output formats are applicable to the command by querying all available formats, and selecting any that are able to process the data type that is returned. Thus, if a new format is added to a program, it will automatically be available via any command that it works with. It is not necessary to hand-select the available formats on every command individually.
|
||||
|
||||
### 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.
|
||||
- `RowsOfFieldsWithMetadata`: Equivalent to `RowsOfFields`, but allows for metadata to be attached to the result. The metadata is not displayed in table format, but is evident if the data is converted to another format (e.g. `yaml` or `json`). The table data may either be nested inside of a specially-designated element, with other elements being used as metadata, or, alternately, the metadata may be nested inside of an element, with all other elements being used as data.
|
||||
- `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.
|
||||
- `UnstructuredListData`: The result is assumed to be a list of items, with the key of each row being used as the row id. The data elements may contain any sort of array data. The elements on each row do not need to be uniform, and the data may be nested to arbitrary depths.
|
||||
- `UnstruturedData`: The result is an unstructured array nested to arbitrary levels.
|
||||
- `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.
|
||||
- `ListDataFromKeys`: This data structure is deprecated. Use `UnstructuredListData` instead.
|
||||
|
||||
Commands that need to produce XML output should return a DOMDocument as its return type. The formatter manager will do its best to convert from an array to a DOMDocument, or from a DOMDocument to an array, as needed. 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()`.
|
||||
|
||||
### Fields
|
||||
|
||||
Some commands produce output that contain *fields*. A field may be either the key in a key/value pair, or it may be the label used in tabular output and so on.
|
||||
|
||||
#### Declaring Default Fields
|
||||
|
||||
If a command declares a very large number of fields, it is possible to display only a subset of the available options by way of the `@default-fields` annotation. The following example comes from Drush:
|
||||
```php
|
||||
/**
|
||||
* @command cache:get
|
||||
* @field-labels
|
||||
* cid: Cache ID
|
||||
* data: Data
|
||||
* created: Created
|
||||
* expire: Expire
|
||||
* tags: Tags
|
||||
* checksum: Checksum
|
||||
* valid: Valid
|
||||
* @default-fields cid,data,created,expire,tags
|
||||
* @return \Consolidation\OutputFormatters\StructuredData\PropertyList
|
||||
*/
|
||||
public function get($cid, $bin = 'default', $options = ['format' => 'json'])
|
||||
{
|
||||
$result = ...
|
||||
return new PropertyList($result);
|
||||
}
|
||||
```
|
||||
All of the available fields will be listed in the `help` output for the command, and may be selected by listing the desired fields explicitly via the `--fields` option.
|
||||
|
||||
To include all avalable fields, use `--fields=*`.
|
||||
|
||||
#### Reordering Fields
|
||||
|
||||
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. One of `RowsOfFields`, `PropertyList` or `UnstructuredListData` (or similar) must be used.
|
||||
|
||||
When the `--fields` option is provided, the user may stipulate the exact fields to list on each row, and what order they should appear in. For example, if a command usually produces output using the `RowsOfFields` data type, as shown below:
|
||||
```
|
||||
$ ./app try:formatters
|
||||
------ ------ -------
|
||||
I II III
|
||||
------ ------ -------
|
||||
One Two Three
|
||||
Eins Zwei Drei
|
||||
Ichi Ni San
|
||||
Uno Dos Tres
|
||||
------ ------ -------
|
||||
```
|
||||
Then the third and first fields may be selected as follows:
|
||||
```
|
||||
$ ./app try:formatters --fields=III,I
|
||||
------- ------
|
||||
III I
|
||||
------- ------
|
||||
Three One
|
||||
Drei Eins
|
||||
San Ichi
|
||||
Tres Uno
|
||||
------- ------
|
||||
```
|
||||
To select a single column and strip away all formatting, use the `--field` option:
|
||||
```
|
||||
$ ./app try:formatters --field=II
|
||||
Two
|
||||
Zwei
|
||||
Ni
|
||||
Dos
|
||||
```
|
||||
Commands that produce deeply-nested data structures using the `UnstructuredData` and `UnstructuredListData` data type may also be manipulated using the `--fields` and `--field` options. It is possible to address items deep in the heirarchy using dot notation.
|
||||
|
||||
The `UnstructuredData` type represents a single nested array with no requirements for uniform structure. The `UnstructuredListData` type is similar; it represents a list of `UnstructuredData` types. It is not required for the different elements in the list to have all of the same fields or structure, although it is expected that there will be a certain degree of similarity.
|
||||
|
||||
In the example below, a command returns a list of stores of different kinds. Each store has common top-level elements such as `name`, `products` and `sale-items`. Each store might have different sorts of products with different attributes:
|
||||
```
|
||||
$ ./app try:nested
|
||||
bills-hardware:
|
||||
name: 'Bill''s Hardware'
|
||||
products:
|
||||
tools:
|
||||
electric-drill:
|
||||
price: '79.98'
|
||||
screwdriver:
|
||||
price: '8.99'
|
||||
sale-items:
|
||||
screwdriver: '4.99'
|
||||
alberts-supermarket:
|
||||
name: 'Albert''s Supermarket'
|
||||
products:
|
||||
fruits:
|
||||
strawberries:
|
||||
price: '2'
|
||||
units: lbs
|
||||
watermellons:
|
||||
price: '5'
|
||||
units: each
|
||||
sale-items:
|
||||
watermellons: '4.50'
|
||||
```
|
||||
Just as is the case with tabular output, it is possible to select only a certain set of fields to display with each output item:
|
||||
```
|
||||
$ ./app try:nested --fields=sale-items
|
||||
bills-hardware:
|
||||
sale-items:
|
||||
screwdriver: '4.99'
|
||||
alberts-supermarket:
|
||||
sale-items:
|
||||
watermellons: '4.50'
|
||||
```
|
||||
With unstructured data, it is also possible to remap the name of the field to something else:
|
||||
```
|
||||
$ ./robo try:nested --fields='sale-items as items'
|
||||
bills-hardware:
|
||||
items:
|
||||
screwdriver: '4.99'
|
||||
alberts-supermarket:
|
||||
items:
|
||||
watermellons: '4.50'
|
||||
```
|
||||
The field name `.` is special, though: it indicates that the named element should be omitted, and its value or children should be applied directly to the result row:
|
||||
```
|
||||
$ ./app try:nested --fields='sale-items as .'
|
||||
bills-hardware:
|
||||
screwdriver: '4.99'
|
||||
alberts-supermarket:
|
||||
watermellons: '4.50'
|
||||
```
|
||||
Finally, it is also possible to reach down into nested data structures and pull out information about an element or elements identified using "dot" notation:
|
||||
```
|
||||
$ ./app try:nested --fields=products.fruits.strawberries
|
||||
bills-hardware: { }
|
||||
alberts-supermarket:
|
||||
strawberries:
|
||||
price: '2'
|
||||
units: lbs
|
||||
```
|
||||
Commands that use `RowsOfFields` or `PropertyList` return type will be automatically converted to `UnstructuredListData` or `UnstructuredData`, respectively, whenever any field remapping is done. This will only work for data types such as `yaml` or `json` that can render unstructured data types. It is not possible to render unstructured data in a table, even if the resulting data happens to be uniform.
|
||||
|
||||
### Filtering Specific Rows
|
||||
|
||||
A command may allow the user to filter specific rows of data using simple boolean logic and/or regular expressions. For details, see the external library [consolidation/filter-via-dot-access-data](https://github.com/consolidation/filter-via-dot-access-data) that provides this capability.
|
||||
|
||||
## 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.
|
||||
|
||||
The RowsOfFields and PropertyList data types also allow objects that implement RenderCellInterface, as well as anonymous functions to be added directly to the data structure object itself. If this is done, then the renderer will be called for each cell in the table. An example of an attached renderer implemented as an anonymous function is shown below.
|
||||
```php
|
||||
return (new RowsOfFields($data))->addRendererFunction(
|
||||
function ($key, $cellData, FormatterOptions $options, $rowData) {
|
||||
if ($key == 'my-field') {
|
||||
return implode(',', $cellData);
|
||||
}
|
||||
return $cellData;
|
||||
}
|
||||
);
|
||||
```
|
||||
This project also provides a built-in cell renderer, NumericCellRenderer, that adds commas at the thousands place and right-justifies columns identified as numeric. An example of a numeric renderer attached to two columns of a data set is shown below.
|
||||
```php
|
||||
use Consolidation\OutputFormatters\StructuredData\NumericCellRenderer;
|
||||
...
|
||||
return (new RowsOfFields($data))->addRenderer(
|
||||
new NumericCellRenderer($data, ['population','cats-per-capita'])
|
||||
);
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
73
vendor/consolidation/output-formatters/composer.json
vendored
Normal file
73
vendor/consolidation/output-formatters/composer.json
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"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",
|
||||
"dflydev/dot-access-data": "^1.1.0",
|
||||
"symfony/console": "^2.8|^3|^4",
|
||||
"symfony/finder": "^2.5|^3|^4"
|
||||
},
|
||||
"require-dev": {
|
||||
"g1a/composer-test-scenarios": "^2",
|
||||
"satooshi/php-coveralls": "^2",
|
||||
"phpunit/phpunit": "^5.7.27",
|
||||
"squizlabs/php_codesniffer": "^2.7",
|
||||
"symfony/console": "3.2.3",
|
||||
"symfony/var-dumper": "^2.8|^3|^4",
|
||||
"victorjonsson/markdowndocs": "^1.3"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/var-dumper": "For using the var_dump formatter"
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"sort-packages": true,
|
||||
"platform": {
|
||||
"php": "5.6.32"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"api": "phpdoc-md generate src > docs/api.md",
|
||||
"cs": "phpcs --standard=PSR2 -n src",
|
||||
"cbf": "phpcbf --standard=PSR2 -n src",
|
||||
"unit": "phpunit --colors=always",
|
||||
"lint": [
|
||||
"find src -name '*.php' -print0 | xargs -0 -n1 php -l",
|
||||
"find tests/src -name '*.php' -print0 | xargs -0 -n1 php -l"
|
||||
],
|
||||
"test": [
|
||||
"@lint",
|
||||
"@unit",
|
||||
"@cs"
|
||||
],
|
||||
"scenario": "scenarios/install",
|
||||
"post-update-cmd": [
|
||||
"create-scenario symfony4 'symfony/console:^4.0' 'phpunit/phpunit:^6' --platform-php '7.1.3'",
|
||||
"create-scenario symfony3 'symfony/console:^3.4' 'symfony/finder:^3.4' 'symfony/var-dumper:^3.4' --platform-php '5.6.32'",
|
||||
"create-scenario symfony2 'symfony/console:^2.8' 'phpunit/phpunit:^4.8.36' --remove 'satooshi/php-coveralls' --platform-php '5.4' --no-lockfile",
|
||||
"dependency-licenses"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
2433
vendor/consolidation/output-formatters/composer.lock
generated
vendored
Normal file
2433
vendor/consolidation/output-formatters/composer.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
7
vendor/consolidation/output-formatters/mkdocs.yml
vendored
Normal file
7
vendor/consolidation/output-formatters/mkdocs.yml
vendored
Normal 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
|
29
vendor/consolidation/output-formatters/phpunit.xml.dist
vendored
Normal file
29
vendor/consolidation/output-formatters/phpunit.xml.dist
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<phpunit bootstrap="vendor/autoload.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="formatters">
|
||||
<directory prefix="" suffix="Test.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>
|
57
vendor/consolidation/output-formatters/src/Exception/AbstractDataFormatException.php
vendored
Normal file
57
vendor/consolidation/output-formatters/src/Exception/AbstractDataFormatException.php
vendored
Normal 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";
|
||||
}
|
||||
}
|
19
vendor/consolidation/output-formatters/src/Exception/IncompatibleDataException.php
vendored
Normal file
19
vendor/consolidation/output-formatters/src/Exception/IncompatibleDataException.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
15
vendor/consolidation/output-formatters/src/Exception/InvalidFormatException.php
vendored
Normal file
15
vendor/consolidation/output-formatters/src/Exception/InvalidFormatException.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
14
vendor/consolidation/output-formatters/src/Exception/UnknownFieldException.php
vendored
Normal file
14
vendor/consolidation/output-formatters/src/Exception/UnknownFieldException.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
14
vendor/consolidation/output-formatters/src/Exception/UnknownFormatException.php
vendored
Normal file
14
vendor/consolidation/output-formatters/src/Exception/UnknownFormatException.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
438
vendor/consolidation/output-formatters/src/FormatterManager.php
vendored
Normal file
438
vendor/consolidation/output-formatters/src/FormatterManager.php
vendored
Normal file
|
@ -0,0 +1,438 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters;
|
||||
|
||||
use Consolidation\OutputFormatters\Exception\IncompatibleDataException;
|
||||
use Consolidation\OutputFormatters\Exception\InvalidFormatException;
|
||||
use Consolidation\OutputFormatters\Exception\UnknownFormatException;
|
||||
use Consolidation\OutputFormatters\Formatters\FormatterAwareInterface;
|
||||
use Consolidation\OutputFormatters\Formatters\FormatterInterface;
|
||||
use Consolidation\OutputFormatters\Formatters\MetadataFormatterInterface;
|
||||
use Consolidation\OutputFormatters\Formatters\RenderDataInterface;
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\Options\OverrideOptionsInterface;
|
||||
use Consolidation\OutputFormatters\StructuredData\MetadataInterface;
|
||||
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;
|
||||
use Consolidation\OutputFormatters\StructuredData\ListDataFromKeys;
|
||||
use Consolidation\OutputFormatters\StructuredData\ConversionInterface;
|
||||
|
||||
/**
|
||||
* 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 = [
|
||||
'null' => '\Consolidation\OutputFormatters\Formatters\NoOutputFormatter',
|
||||
'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',
|
||||
];
|
||||
if (class_exists('Symfony\Component\VarDumper\Dumper\CliDumper')) {
|
||||
$defaultFormatters['var_dump'] = '\Consolidation\OutputFormatters\Formatters\VarDumpFormatter';
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
$dataTypeClass = ($dataType instanceof \ReflectionClass) ? $dataType : new \ReflectionClass($dataType);
|
||||
|
||||
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);
|
||||
} elseif ($dataTypeClass->implementsInterface('Consolidation\OutputFormatters\StructuredData\RestructureInterface')) {
|
||||
$automaticOptions[FormatterOptions::FIELDS] = new InputOption(FormatterOptions::FIELDS, '', InputOption::VALUE_REQUIRED, 'Limit output to only the listed elements. Name top-level elements by key, e.g. "--fields=name,date", or use dot notation to select a nested element, e.g. "--fields=a.b.c as example".', []);
|
||||
}
|
||||
|
||||
if (isset($automaticOptions[FormatterOptions::FIELDS])) {
|
||||
$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)
|
||||
{
|
||||
// Convert the data to another format (e.g. converting from RowsOfFields to
|
||||
// UnstructuredListData when the fields indicate an unstructured transformation
|
||||
// is requested).
|
||||
$structuredOutput = $this->convertData($structuredOutput, $options);
|
||||
|
||||
// TODO: If the $format is the default format (not selected by the user), and
|
||||
// if `convertData` switched us to unstructured data, then select a new default
|
||||
// format (e.g. yaml) if the selected format cannot render the converted data.
|
||||
$formatter = $this->getFormatter((string)$format);
|
||||
|
||||
// If the data format is not applicable for the selected formatter, throw an error.
|
||||
if (!is_string($structuredOutput) && !$this->isValidFormat($formatter, $structuredOutput)) {
|
||||
$validFormats = $this->validFormats($structuredOutput);
|
||||
throw new InvalidFormatException((string)$format, $structuredOutput, $validFormats);
|
||||
}
|
||||
if ($structuredOutput instanceof FormatterAwareInterface) {
|
||||
$structuredOutput->setFormatter($formatter);
|
||||
}
|
||||
// Give the formatter a chance to override the options
|
||||
$options = $this->overrideOptions($formatter, $structuredOutput, $options);
|
||||
$restructuredOutput = $this->validateAndRestructure($formatter, $structuredOutput, $options);
|
||||
if ($formatter instanceof MetadataFormatterInterface) {
|
||||
$formatter->writeMetadata($output, $structuredOutput, $options);
|
||||
}
|
||||
$formatter->write($output, $restructuredOutput, $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from one format to another if necessary prior to restructuring.
|
||||
*/
|
||||
public function convertData($structuredOutput, FormatterOptions $options)
|
||||
{
|
||||
if ($structuredOutput instanceof ConversionInterface) {
|
||||
return $structuredOutput->convert($options);
|
||||
}
|
||||
return $structuredOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
107
vendor/consolidation/output-formatters/src/Formatters/CsvFormatter.php
vendored
Normal file
107
vendor/consolidation/output-formatters/src/Formatters/CsvFormatter.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
9
vendor/consolidation/output-formatters/src/Formatters/FormatterAwareInterface.php
vendored
Normal file
9
vendor/consolidation/output-formatters/src/Formatters/FormatterAwareInterface.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
interface FormatterAwareInterface
|
||||
{
|
||||
public function setFormatter(FormatterInterface $formatter);
|
||||
public function getFormatter();
|
||||
public function isHumanReadable();
|
||||
}
|
22
vendor/consolidation/output-formatters/src/Formatters/FormatterAwareTrait.php
vendored
Normal file
22
vendor/consolidation/output-formatters/src/Formatters/FormatterAwareTrait.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
trait FormatterAwareTrait
|
||||
{
|
||||
protected $formatter;
|
||||
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->formatter;
|
||||
}
|
||||
|
||||
public function isHumanReadable()
|
||||
{
|
||||
return $this->formatter && $this->formatter instanceof \Consolidation\OutputFormatters\Formatters\HumanReadableFormat;
|
||||
}
|
||||
}
|
18
vendor/consolidation/output-formatters/src/Formatters/FormatterInterface.php
vendored
Normal file
18
vendor/consolidation/output-formatters/src/Formatters/FormatterInterface.php
vendored
Normal 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 OutputInterface output stream to write to
|
||||
* @param mixed $data Structured data to format
|
||||
* @param FormatterOptions formating options
|
||||
*/
|
||||
public function write(OutputInterface $output, $data, FormatterOptions $options);
|
||||
}
|
13
vendor/consolidation/output-formatters/src/Formatters/HumanReadableFormat.php
vendored
Normal file
13
vendor/consolidation/output-formatters/src/Formatters/HumanReadableFormat.php
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
/**
|
||||
* Marker interface that indicates that a cell data renderer
|
||||
* (@see Consolidation\OutputFormatters\SturcturedData\RenderCellInterface)
|
||||
* may test for to determine whether it is allowable to add
|
||||
* human-readable formatting into the cell data
|
||||
* (@see Consolidation\OutputFormatters\SturcturedData\NumericCallRenderer).
|
||||
*/
|
||||
interface HumanReadableFormat
|
||||
{
|
||||
}
|
21
vendor/consolidation/output-formatters/src/Formatters/JsonFormatter.php
vendored
Normal file
21
vendor/consolidation/output-formatters/src/Formatters/JsonFormatter.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
59
vendor/consolidation/output-formatters/src/Formatters/ListFormatter.php
vendored
Normal file
59
vendor/consolidation/output-formatters/src/Formatters/ListFormatter.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
17
vendor/consolidation/output-formatters/src/Formatters/MetadataFormatterInterface.php
vendored
Normal file
17
vendor/consolidation/output-formatters/src/Formatters/MetadataFormatterInterface.php
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
interface MetadataFormatterInterface
|
||||
{
|
||||
/**
|
||||
* Given some metadata, decide how to display it.
|
||||
*
|
||||
* @param OutputInterface output stream to write to
|
||||
* @param array $metadata associative array containing metadata
|
||||
* @param FormatterOptions formating options
|
||||
*/
|
||||
public function writeMetadata(OutputInterface $output, $metadata, FormatterOptions $options);
|
||||
}
|
53
vendor/consolidation/output-formatters/src/Formatters/MetadataFormatterTrait.php
vendored
Normal file
53
vendor/consolidation/output-formatters/src/Formatters/MetadataFormatterTrait.php
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Consolidation\OutputFormatters\StructuredData\MetadataInterface;
|
||||
|
||||
trait MetadataFormatterTrait
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function writeMetadata(OutputInterface $output, $structuredOutput, FormatterOptions $options)
|
||||
{
|
||||
$template = $options->get(FormatterOptions::METADATA_TEMPLATE);
|
||||
if (!$template) {
|
||||
return;
|
||||
}
|
||||
if (!$structuredOutput instanceof MetadataInterface) {
|
||||
return;
|
||||
}
|
||||
$metadata = $structuredOutput->getMetadata();
|
||||
if (empty($metadata)) {
|
||||
return;
|
||||
}
|
||||
$message = $this->interpolate($template, $metadata);
|
||||
return $output->writeln($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates context values into the message placeholders.
|
||||
*
|
||||
* @author PHP Framework Interoperability Group
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function interpolate($message, array $context)
|
||||
{
|
||||
// build a replacement array with braces around the context keys
|
||||
$replace = array();
|
||||
foreach ($context as $key => $val) {
|
||||
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
|
||||
$replace[sprintf('{%s}', $key)] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
// interpolate replacement values into the message and return
|
||||
return strtr($message, $replace);
|
||||
}
|
||||
}
|
40
vendor/consolidation/output-formatters/src/Formatters/NoOutputFormatter.php
vendored
Normal file
40
vendor/consolidation/output-formatters/src/Formatters/NoOutputFormatter.php
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
use Consolidation\OutputFormatters\Validate\ValidationInterface;
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* No output formatter
|
||||
*
|
||||
* This formatter never produces any output. It is useful in cases where
|
||||
* a command should not produce any output by default, but may do so if
|
||||
* the user explicitly includes a --format option.
|
||||
*/
|
||||
class NoOutputFormatter implements FormatterInterface, ValidationInterface
|
||||
{
|
||||
/**
|
||||
* All data types are acceptable.
|
||||
*/
|
||||
public function isValidDataType(\ReflectionClass $dataType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate($structuredData)
|
||||
{
|
||||
return $structuredData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function write(OutputInterface $output, $data, FormatterOptions $options)
|
||||
{
|
||||
}
|
||||
}
|
21
vendor/consolidation/output-formatters/src/Formatters/PrintRFormatter.php
vendored
Normal file
21
vendor/consolidation/output-formatters/src/Formatters/PrintRFormatter.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
19
vendor/consolidation/output-formatters/src/Formatters/RenderDataInterface.php
vendored
Normal file
19
vendor/consolidation/output-formatters/src/Formatters/RenderDataInterface.php
vendored
Normal 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);
|
||||
}
|
29
vendor/consolidation/output-formatters/src/Formatters/RenderTableDataTrait.php
vendored
Normal file
29
vendor/consolidation/output-formatters/src/Formatters/RenderTableDataTrait.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
72
vendor/consolidation/output-formatters/src/Formatters/SectionsFormatter.php
vendored
Normal file
72
vendor/consolidation/output-formatters/src/Formatters/SectionsFormatter.php
vendored
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
21
vendor/consolidation/output-formatters/src/Formatters/SerializeFormatter.php
vendored
Normal file
21
vendor/consolidation/output-formatters/src/Formatters/SerializeFormatter.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
95
vendor/consolidation/output-formatters/src/Formatters/StringFormatter.php
vendored
Normal file
95
vendor/consolidation/output-formatters/src/Formatters/StringFormatter.php
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\Options\OverrideOptionsInterface;
|
||||
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
|
||||
use Consolidation\OutputFormatters\StructuredData\UnstructuredInterface;
|
||||
use Consolidation\OutputFormatters\Transformations\SimplifiedFormatterInterface;
|
||||
use Consolidation\OutputFormatters\Transformations\StringTransformationInterface;
|
||||
use Consolidation\OutputFormatters\Validate\ValidationInterface;
|
||||
use Consolidation\OutputFormatters\Validate\ValidDataTypesTrait;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* By default, we assume that we can convert any data type to `string`,
|
||||
* unless it implements UnstructuredInterface, in which case we won't
|
||||
* allow the `string` format unless the data type also implements
|
||||
* StringTransformationInterface.
|
||||
*/
|
||||
public function isValidDataType(\ReflectionClass $dataType)
|
||||
{
|
||||
if ($dataType->implementsInterface('\Consolidation\OutputFormatters\StructuredData\UnstructuredInterface') && !$dataType->implementsInterface('\Consolidation\OutputFormatters\Transformations\StringTransformationInterface')) {
|
||||
return false;
|
||||
}
|
||||
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 in a simplified form (by default, TSV).
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param mixed $data
|
||||
* @param FormatterOptions $options
|
||||
*/
|
||||
protected function reduceToSigleFieldAndWrite(OutputInterface $output, $data, FormatterOptions $options)
|
||||
{
|
||||
if ($data instanceof StringTransformationInterface) {
|
||||
$simplified = $data->simplifyToString($options);
|
||||
return $output->write($simplified);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
145
vendor/consolidation/output-formatters/src/Formatters/TableFormatter.php
vendored
Normal file
145
vendor/consolidation/output-formatters/src/Formatters/TableFormatter.php
vendored
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?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;
|
||||
use Consolidation\OutputFormatters\Formatters\HumanReadableFormat;
|
||||
|
||||
/**
|
||||
* 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, MetadataFormatterInterface, HumanReadableFormat
|
||||
{
|
||||
use ValidDataTypesTrait;
|
||||
use RenderTableDataTrait;
|
||||
use MetadataFormatterTrait;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
40
vendor/consolidation/output-formatters/src/Formatters/TsvFormatter.php
vendored
Normal file
40
vendor/consolidation/output-formatters/src/Formatters/TsvFormatter.php
vendored
Normal 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
|
||||
));
|
||||
}
|
||||
}
|
40
vendor/consolidation/output-formatters/src/Formatters/VarDumpFormatter.php
vendored
Normal file
40
vendor/consolidation/output-formatters/src/Formatters/VarDumpFormatter.php
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Consolidation\OutputFormatters\Formatters;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||
|
||||
/**
|
||||
* Var_dump formatter
|
||||
*
|
||||
* Run provided data through Symfony VarDumper component.
|
||||
*/
|
||||
class VarDumpFormatter implements FormatterInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function write(OutputInterface $output, $data, FormatterOptions $options)
|
||||
{
|
||||
$dumper = new CliDumper();
|
||||
$cloned_data = (new VarCloner())->cloneVar($data);
|
||||
|
||||
if ($output instanceof StreamOutput) {
|
||||
// When stream output is used the dumper is smart enough to
|
||||
// determine whether or not to apply colors to the dump.
|
||||
// @see Symfony\Component\VarDumper\Dumper\CliDumper::supportsColors
|
||||
$dumper->dump($cloned_data, $output->getStream());
|
||||
} else {
|
||||
// @todo Use dumper return value to get output once we stop support
|
||||
// VarDumper v2.
|
||||
$stream = fopen('php://memory', 'r+b');
|
||||
$dumper->dump($cloned_data, $stream);
|
||||
$output->writeln(stream_get_contents($stream, -1, 0));
|
||||
fclose($stream);
|
||||
}
|
||||
}
|
||||
}
|
21
vendor/consolidation/output-formatters/src/Formatters/VarExportFormatter.php
vendored
Normal file
21
vendor/consolidation/output-formatters/src/Formatters/VarExportFormatter.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
79
vendor/consolidation/output-formatters/src/Formatters/XmlFormatter.php
vendored
Normal file
79
vendor/consolidation/output-formatters/src/Formatters/XmlFormatter.php
vendored
Normal 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());
|
||||
}
|
||||
}
|
27
vendor/consolidation/output-formatters/src/Formatters/YamlFormatter.php
vendored
Normal file
27
vendor/consolidation/output-formatters/src/Formatters/YamlFormatter.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
386
vendor/consolidation/output-formatters/src/Options/FormatterOptions.php
vendored
Normal file
386
vendor/consolidation/output-formatters/src/Options/FormatterOptions.php
vendored
Normal file
|
@ -0,0 +1,386 @@
|
|||
<?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';
|
||||
const METADATA_TEMPLATE = 'metadata-template';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
17
vendor/consolidation/output-formatters/src/Options/OverrideOptionsInterface.php
vendored
Normal file
17
vendor/consolidation/output-formatters/src/Options/OverrideOptionsInterface.php
vendored
Normal 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);
|
||||
}
|
61
vendor/consolidation/output-formatters/src/StructuredData/AbstractListData.php
vendored
Normal file
61
vendor/consolidation/output-formatters/src/StructuredData/AbstractListData.php
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\Transformations\ReorderFields;
|
||||
|
||||
/**
|
||||
* Base class for all list data types.
|
||||
*/
|
||||
class AbstractListData extends \ArrayObject implements ListDataInterface
|
||||
{
|
||||
public function __construct($data)
|
||||
{
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
public function getListData(FormatterOptions $options)
|
||||
{
|
||||
return array_keys($this->getArrayCopy());
|
||||
}
|
||||
|
||||
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 => [],
|
||||
];
|
||||
}
|
||||
}
|
52
vendor/consolidation/output-formatters/src/StructuredData/AbstractStructuredList.php
vendored
Normal file
52
vendor/consolidation/output-formatters/src/StructuredData/AbstractStructuredList.php
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\StructuredData\ListDataInterface;
|
||||
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 AbstractListData 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 defaultOptions()
|
||||
{
|
||||
return [
|
||||
FormatterOptions::ROW_LABELS => [],
|
||||
FormatterOptions::DEFAULT_FIELDS => [],
|
||||
] + parent::defaultOptions();
|
||||
}
|
||||
}
|
12
vendor/consolidation/output-formatters/src/StructuredData/AssociativeList.php
vendored
Normal file
12
vendor/consolidation/output-formatters/src/StructuredData/AssociativeList.php
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
/**
|
||||
* Old name for PropertyList class.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
class AssociativeList extends PropertyList
|
||||
{
|
||||
|
||||
}
|
23
vendor/consolidation/output-formatters/src/StructuredData/CallableRenderer.php
vendored
Normal file
23
vendor/consolidation/output-formatters/src/StructuredData/CallableRenderer.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
15
vendor/consolidation/output-formatters/src/StructuredData/ConversionInterface.php
vendored
Normal file
15
vendor/consolidation/output-formatters/src/StructuredData/ConversionInterface.php
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
interface ConversionInterface
|
||||
{
|
||||
/**
|
||||
* Allow structured data to be converted -- i.e. from
|
||||
* RowsOfFields to UnstructuredListData.
|
||||
*
|
||||
* @param FormatterOptions $options Formatting options
|
||||
*/
|
||||
public function convert(FormatterOptions $options);
|
||||
}
|
39
vendor/consolidation/output-formatters/src/StructuredData/FieldProcessor.php
vendored
Normal file
39
vendor/consolidation/output-formatters/src/StructuredData/FieldProcessor.php
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
|
||||
use Consolidation\OutputFormatters\Transformations\UnstructuredDataListTransformation;
|
||||
|
||||
/**
|
||||
* FieldProcessor will do various alterations on field sets.
|
||||
*/
|
||||
class FieldProcessor
|
||||
{
|
||||
public static function processFieldAliases($fields)
|
||||
{
|
||||
if (!is_array($fields)) {
|
||||
$fields = array_filter(explode(',', $fields));
|
||||
}
|
||||
$transformed_fields = [];
|
||||
foreach ($fields as $field) {
|
||||
list($machine_name,$label) = explode(' as ', $field) + [$field, preg_replace('#.*\.#', '', $field)];
|
||||
$transformed_fields[$machine_name] = $label;
|
||||
}
|
||||
return $transformed_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the data structure has unstructured field access,
|
||||
* e.g. `a.b.c` or `foo as bar`.
|
||||
* @param type $fields
|
||||
* @return type
|
||||
*/
|
||||
public static function hasUnstructuredFieldAccess($fields)
|
||||
{
|
||||
if (is_array($fields)) {
|
||||
$fields = implode(',', $fields);
|
||||
}
|
||||
return (strpos($fields, ' as ') !== false) || (strpos($fields, '.') !== false);
|
||||
}
|
||||
}
|
16
vendor/consolidation/output-formatters/src/StructuredData/HelpDocument.php
vendored
Normal file
16
vendor/consolidation/output-formatters/src/StructuredData/HelpDocument.php
vendored
Normal 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()
|
||||
{
|
||||
}
|
||||
}
|
9
vendor/consolidation/output-formatters/src/StructuredData/ListDataFromKeys.php
vendored
Normal file
9
vendor/consolidation/output-formatters/src/StructuredData/ListDataFromKeys.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
/**
|
||||
* @deprecated Use UnstructuredListData
|
||||
*/
|
||||
class ListDataFromKeys extends AbstractListData
|
||||
{
|
||||
}
|
16
vendor/consolidation/output-formatters/src/StructuredData/ListDataInterface.php
vendored
Normal file
16
vendor/consolidation/output-formatters/src/StructuredData/ListDataInterface.php
vendored
Normal 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);
|
||||
}
|
15
vendor/consolidation/output-formatters/src/StructuredData/MetadataHolderInterface.php
vendored
Normal file
15
vendor/consolidation/output-formatters/src/StructuredData/MetadataHolderInterface.php
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
interface MetadataHolderInterface
|
||||
{
|
||||
public function getDataKey();
|
||||
public function setDataKey($key);
|
||||
public function getMetadataKey();
|
||||
public function setMetadataKey($key);
|
||||
public function extractData($data);
|
||||
public function extractMetadata($data);
|
||||
public function reconstruct($data, $metadata);
|
||||
}
|
101
vendor/consolidation/output-formatters/src/StructuredData/MetadataHolderTrait.php
vendored
Normal file
101
vendor/consolidation/output-formatters/src/StructuredData/MetadataHolderTrait.php
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
/**
|
||||
* A structured data object may contains some elements that
|
||||
* are actually metadata. Metadata is not included in the
|
||||
* output of tabular data formatters (e.g. table, csv), although
|
||||
* some of these (e.g. table) may render the metadata alongside
|
||||
* the data. Raw data formatters (e.g. yaml, json) will render
|
||||
* both the data and the metadata.
|
||||
*
|
||||
* There are two possible options for the data format; either the
|
||||
* data is nested inside some element, and ever other item is
|
||||
* metadata, or the metadata may be nested inside some element,
|
||||
* and every other item is the data rows.
|
||||
*
|
||||
* Example 1: nested data
|
||||
*
|
||||
* [
|
||||
* 'data' => [ ... rows of field data ... ],
|
||||
* 'metadata1' => '...',
|
||||
* 'metadata2' => '...',
|
||||
* ]
|
||||
*
|
||||
* Example 2: nested metadata
|
||||
*
|
||||
* [
|
||||
* 'metadata' => [ ... metadata items ... ],
|
||||
* 'rowid1' => [ ... ],
|
||||
* 'rowid2' => [ ... ],
|
||||
* ]
|
||||
*
|
||||
* It is, of course, also possible that both the data and
|
||||
* the metadata may be nested inside subelements.
|
||||
*/
|
||||
trait MetadataHolderTrait
|
||||
{
|
||||
protected $dataKey = false;
|
||||
protected $metadataKey = false;
|
||||
|
||||
public function getDataKey()
|
||||
{
|
||||
return $this->dataKey;
|
||||
}
|
||||
|
||||
public function setDataKey($key)
|
||||
{
|
||||
$this->dataKey = $key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMetadataKey()
|
||||
{
|
||||
return $this->metadataKey;
|
||||
}
|
||||
|
||||
public function setMetadataKey($key)
|
||||
{
|
||||
$this->metadataKey = $key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function extractData($data)
|
||||
{
|
||||
if ($this->metadataKey) {
|
||||
unset($data[$this->metadataKey]);
|
||||
}
|
||||
if ($this->dataKey) {
|
||||
if (!isset($data[$this->dataKey])) {
|
||||
return [];
|
||||
}
|
||||
return $data[$this->dataKey];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function extractMetadata($data)
|
||||
{
|
||||
if (!$this->dataKey && !$this->metadataKey) {
|
||||
return [];
|
||||
}
|
||||
if ($this->dataKey) {
|
||||
unset($data[$this->dataKey]);
|
||||
}
|
||||
if ($this->metadataKey) {
|
||||
if (!isset($data[$this->metadataKey])) {
|
||||
return [];
|
||||
}
|
||||
return $data[$this->metadataKey];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function reconstruct($data, $metadata)
|
||||
{
|
||||
$reconstructedData = ($this->dataKey) ? [$this->dataKey => $data] : $data;
|
||||
$reconstructedMetadata = ($this->metadataKey) ? [$this->metadataKey => $metadata] : $metadata;
|
||||
|
||||
return $reconstructedData + $reconstructedMetadata;
|
||||
}
|
||||
}
|
12
vendor/consolidation/output-formatters/src/StructuredData/MetadataInterface.php
vendored
Normal file
12
vendor/consolidation/output-formatters/src/StructuredData/MetadataInterface.php
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
interface MetadataInterface
|
||||
{
|
||||
/**
|
||||
* Return the metadata associated with the structured data (if any)
|
||||
*/
|
||||
public function getMetadata();
|
||||
}
|
137
vendor/consolidation/output-formatters/src/StructuredData/NumericCellRenderer.php
vendored
Normal file
137
vendor/consolidation/output-formatters/src/StructuredData/NumericCellRenderer.php
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
use Consolidation\OutputFormatters\Formatters\FormatterAwareInterface;
|
||||
use Consolidation\OutputFormatters\Formatters\FormatterAwareTrait;
|
||||
|
||||
/**
|
||||
* Create a formatter to add commas to numeric data.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* -------
|
||||
* Value
|
||||
* -------
|
||||
* 2,384
|
||||
* 143,894
|
||||
* 23
|
||||
* 98,538
|
||||
*
|
||||
* This formatter may also be re-used for other purposes where right-justified
|
||||
* data is desired by simply making a subclass. See method comments below.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* return (new RowsOfFields($data))->addRenderer(
|
||||
* new NumericCellRenderer($data, ['value'])
|
||||
* );
|
||||
*
|
||||
*/
|
||||
class NumericCellRenderer implements RenderCellInterface, FormatterAwareInterface
|
||||
{
|
||||
use FormatterAwareTrait;
|
||||
|
||||
protected $data;
|
||||
protected $renderedColumns;
|
||||
protected $widths = [];
|
||||
|
||||
/**
|
||||
* NumericCellRenderer constructor
|
||||
*/
|
||||
public function __construct($data, $renderedColumns)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->renderedColumns = $renderedColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function renderCell($key, $cellData, FormatterOptions $options, $rowData)
|
||||
{
|
||||
if (!$this->isRenderedFormat($options) || !$this->isRenderedColumn($key)) {
|
||||
return $cellData;
|
||||
}
|
||||
if ($this->isRenderedData($cellData)) {
|
||||
$cellData = $this->formatCellData($cellData);
|
||||
}
|
||||
return $this->justifyCellData($key, $cellData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Right-justify the cell data.
|
||||
*/
|
||||
protected function justifyCellData($key, $cellData)
|
||||
{
|
||||
return str_pad($cellData, $this->columnWidth($key), " ", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this format is to be formatted.
|
||||
*/
|
||||
protected function isRenderedFormat(FormatterOptions $options)
|
||||
{
|
||||
return $this->isHumanReadable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this is a column that should be formatted.
|
||||
*/
|
||||
protected function isRenderedColumn($key)
|
||||
{
|
||||
return array_key_exists($key, $this->renderedColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore cell data that should not be formatted.
|
||||
*/
|
||||
protected function isRenderedData($cellData)
|
||||
{
|
||||
return is_numeric($cellData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the cell data.
|
||||
*/
|
||||
protected function formatCellData($cellData)
|
||||
{
|
||||
return number_format($this->convertCellDataToString($cellData));
|
||||
}
|
||||
|
||||
/**
|
||||
* This formatter only works with columns whose columns are strings.
|
||||
* To use this formatter for another purpose, override this method
|
||||
* to ensure that the cell data is a string before it is formatted.
|
||||
*/
|
||||
protected function convertCellDataToString($cellData)
|
||||
{
|
||||
return $cellData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cached column width for the provided key.
|
||||
*/
|
||||
protected function columnWidth($key)
|
||||
{
|
||||
if (!isset($this->widths[$key])) {
|
||||
$this->widths[$key] = $this->calculateColumnWidth($key);
|
||||
}
|
||||
return $this->widths[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the cached table data, calculate the largest width
|
||||
* for the data in the table for use when right-justifying.
|
||||
*/
|
||||
protected function calculateColumnWidth($key)
|
||||
{
|
||||
$width = isset($this->renderedColumns[$key]) ? $this->renderedColumns[$key] : 0;
|
||||
foreach ($this->data as $row) {
|
||||
$data = $this->formatCellData($row[$key]);
|
||||
$width = max(strlen($data), $width);
|
||||
}
|
||||
return $width;
|
||||
}
|
||||
}
|
11
vendor/consolidation/output-formatters/src/StructuredData/OriginalDataInterface.php
vendored
Normal file
11
vendor/consolidation/output-formatters/src/StructuredData/OriginalDataInterface.php
vendored
Normal 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();
|
||||
}
|
71
vendor/consolidation/output-formatters/src/StructuredData/PropertyList.php
vendored
Normal file
71
vendor/consolidation/output-formatters/src/StructuredData/PropertyList.php
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?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 implements ConversionInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function convert(FormatterOptions $options)
|
||||
{
|
||||
$defaults = $this->defaultOptions();
|
||||
$fields = $this->getFields($options, $defaults);
|
||||
if (FieldProcessor::hasUnstructuredFieldAccess($fields)) {
|
||||
return new UnstructuredData($this->getArrayCopy());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
18
vendor/consolidation/output-formatters/src/StructuredData/RenderCellCollectionInterface.php
vendored
Normal file
18
vendor/consolidation/output-formatters/src/StructuredData/RenderCellCollectionInterface.php
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Formatters\FormatterAwareInterface;
|
||||
|
||||
interface RenderCellCollectionInterface extends RenderCellInterface, FormatterAwareInterface
|
||||
{
|
||||
const PRIORITY_FIRST = 'first';
|
||||
const PRIORITY_NORMAL = 'normal';
|
||||
const PRIORITY_FALLBACK = 'fallback';
|
||||
|
||||
/**
|
||||
* Add a renderer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addRenderer(RenderCellInterface $renderer);
|
||||
}
|
62
vendor/consolidation/output-formatters/src/StructuredData/RenderCellCollectionTrait.php
vendored
Normal file
62
vendor/consolidation/output-formatters/src/StructuredData/RenderCellCollectionTrait.php
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\Formatters\FormatterAwareInterface;
|
||||
use Consolidation\OutputFormatters\Formatters\FormatterAwareTrait;
|
||||
|
||||
trait RenderCellCollectionTrait
|
||||
{
|
||||
use FormatterAwareTrait;
|
||||
|
||||
/** @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) {
|
||||
if ($renderer instanceof FormatterAwareInterface) {
|
||||
$renderer->setFormatter($this->getFormatter());
|
||||
}
|
||||
$cellData = $renderer->renderCell($key, $cellData, $options, $rowData);
|
||||
}
|
||||
return $cellData;
|
||||
}
|
||||
}
|
22
vendor/consolidation/output-formatters/src/StructuredData/RenderCellInterface.php
vendored
Normal file
22
vendor/consolidation/output-formatters/src/StructuredData/RenderCellInterface.php
vendored
Normal 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);
|
||||
}
|
15
vendor/consolidation/output-formatters/src/StructuredData/RestructureInterface.php
vendored
Normal file
15
vendor/consolidation/output-formatters/src/StructuredData/RestructureInterface.php
vendored
Normal 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);
|
||||
}
|
52
vendor/consolidation/output-formatters/src/StructuredData/RowsOfFields.php
vendored
Normal file
52
vendor/consolidation/output-formatters/src/StructuredData/RowsOfFields.php
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?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 implements ConversionInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function convert(FormatterOptions $options)
|
||||
{
|
||||
$defaults = $this->defaultOptions();
|
||||
$fields = $this->getFields($options, $defaults);
|
||||
if (FieldProcessor::hasUnstructuredFieldAccess($fields)) {
|
||||
return new UnstructuredListData($this->getArrayCopy());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
39
vendor/consolidation/output-formatters/src/StructuredData/RowsOfFieldsWithMetadata.php
vendored
Normal file
39
vendor/consolidation/output-formatters/src/StructuredData/RowsOfFieldsWithMetadata.php
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
/**
|
||||
* A RowsOfFields data structure that also contains metadata.
|
||||
* @see MetadataHolderTrait
|
||||
*/
|
||||
class RowsOfFieldsWithMetadata extends RowsOfFields implements MetadataInterface, MetadataHolderInterface
|
||||
{
|
||||
use MetadataHolderTrait;
|
||||
|
||||
public function __constructor($data)
|
||||
{
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restructure this data for output by converting it into a table
|
||||
* transformation object. First, though, remove any metadata items.
|
||||
*
|
||||
* @param FormatterOptions $options Options that affect output formatting.
|
||||
* @return Consolidation\OutputFormatters\Transformations\TableTransformation
|
||||
*/
|
||||
public function restructure(FormatterOptions $options)
|
||||
{
|
||||
$originalData = $this->getArrayCopy();
|
||||
$data = $this->extractData($originalData);
|
||||
$tableTranformer = $this->createTableTransformation($data, $options);
|
||||
$tableTranformer->setOriginalData($this);
|
||||
return $tableTranformer;
|
||||
}
|
||||
|
||||
public function getMetadata()
|
||||
{
|
||||
return $this->extractMetadata($this->getArrayCopy());
|
||||
}
|
||||
}
|
16
vendor/consolidation/output-formatters/src/StructuredData/TableDataInterface.php
vendored
Normal file
16
vendor/consolidation/output-formatters/src/StructuredData/TableDataInterface.php
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
interface TableDataInterface
|
||||
{
|
||||
/**
|
||||
* 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);
|
||||
}
|
30
vendor/consolidation/output-formatters/src/StructuredData/UnstructuredData.php
vendored
Normal file
30
vendor/consolidation/output-formatters/src/StructuredData/UnstructuredData.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
|
||||
use Consolidation\OutputFormatters\Transformations\UnstructuredDataTransformation;
|
||||
|
||||
/**
|
||||
* Represents aribtrary unstructured array data where the
|
||||
* data to display in --list format comes from the array keys.
|
||||
*
|
||||
* Unstructured list data can have variable keys in every rown (unlike
|
||||
* RowsOfFields, which expects uniform rows), and the data elements may
|
||||
* themselves be deep arrays.
|
||||
*/
|
||||
class UnstructuredData extends AbstractListData implements UnstructuredInterface, RestructureInterface
|
||||
{
|
||||
public function __construct($data)
|
||||
{
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
public function restructure(FormatterOptions $options)
|
||||
{
|
||||
$defaults = $this->defaultOptions();
|
||||
$fields = $this->getFields($options, $defaults);
|
||||
|
||||
return new UnstructuredDataTransformation($this->getArrayCopy(), FieldProcessor::processFieldAliases($fields));
|
||||
}
|
||||
}
|
14
vendor/consolidation/output-formatters/src/StructuredData/UnstructuredInterface.php
vendored
Normal file
14
vendor/consolidation/output-formatters/src/StructuredData/UnstructuredInterface.php
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
/**
|
||||
* UnstructuredInterface is a marker interface that indicates that the
|
||||
* data type is unstructured, and has no default conversion to a string.
|
||||
* Unstructured data supports the `string` format only if it also implements
|
||||
* StringTransformationInterface.
|
||||
*/
|
||||
interface UnstructuredInterface
|
||||
{
|
||||
}
|
30
vendor/consolidation/output-formatters/src/StructuredData/UnstructuredListData.php
vendored
Normal file
30
vendor/consolidation/output-formatters/src/StructuredData/UnstructuredListData.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\StructuredData\RestructureInterface;
|
||||
use Consolidation\OutputFormatters\Transformations\UnstructuredDataListTransformation;
|
||||
|
||||
/**
|
||||
* Represents aribtrary unstructured array data where the
|
||||
* data to display in --list format comes from the array keys.
|
||||
*
|
||||
* Unstructured list data can have variable keys in every rown (unlike
|
||||
* RowsOfFields, which expects uniform rows), and the data elements may
|
||||
* themselves be deep arrays.
|
||||
*/
|
||||
class UnstructuredListData extends AbstractListData implements UnstructuredInterface, RestructureInterface
|
||||
{
|
||||
public function __construct($data)
|
||||
{
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
public function restructure(FormatterOptions $options)
|
||||
{
|
||||
$defaults = $this->defaultOptions();
|
||||
$fields = $this->getFields($options, $defaults);
|
||||
|
||||
return new UnstructuredDataListTransformation($this->getArrayCopy(), FieldProcessor::processFieldAliases($fields));
|
||||
}
|
||||
}
|
12
vendor/consolidation/output-formatters/src/StructuredData/Xml/DomDataInterface.php
vendored
Normal file
12
vendor/consolidation/output-formatters/src/StructuredData/Xml/DomDataInterface.php
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\StructuredData\Xml;
|
||||
|
||||
interface DomDataInterface
|
||||
{
|
||||
/**
|
||||
* Convert data into a \DomDocument.
|
||||
*
|
||||
* @return \DomDocument
|
||||
*/
|
||||
public function getDomData();
|
||||
}
|
116
vendor/consolidation/output-formatters/src/StructuredData/Xml/XmlSchema.php
vendored
Normal file
116
vendor/consolidation/output-formatters/src/StructuredData/Xml/XmlSchema.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
73
vendor/consolidation/output-formatters/src/StructuredData/Xml/XmlSchemaInterface.php
vendored
Normal file
73
vendor/consolidation/output-formatters/src/StructuredData/Xml/XmlSchemaInterface.php
vendored
Normal 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);
|
||||
}
|
237
vendor/consolidation/output-formatters/src/Transformations/DomToArraySimplifier.php
vendored
Normal file
237
vendor/consolidation/output-formatters/src/Transformations/DomToArraySimplifier.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
17
vendor/consolidation/output-formatters/src/Transformations/OverrideRestructureInterface.php
vendored
Normal file
17
vendor/consolidation/output-formatters/src/Transformations/OverrideRestructureInterface.php
vendored
Normal 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);
|
||||
}
|
11
vendor/consolidation/output-formatters/src/Transformations/PropertyListTableTransformation.php
vendored
Normal file
11
vendor/consolidation/output-formatters/src/Transformations/PropertyListTableTransformation.php
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Transformations;
|
||||
|
||||
class PropertyListTableTransformation extends TableTransformation
|
||||
{
|
||||
public function getOriginalData()
|
||||
{
|
||||
$data = $this->getArrayCopy();
|
||||
return $data[0];
|
||||
}
|
||||
}
|
38
vendor/consolidation/output-formatters/src/Transformations/PropertyParser.php
vendored
Normal file
38
vendor/consolidation/output-formatters/src/Transformations/PropertyParser.php
vendored
Normal 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;
|
||||
}
|
||||
}
|
129
vendor/consolidation/output-formatters/src/Transformations/ReorderFields.php
vendored
Normal file
129
vendor/consolidation/output-formatters/src/Transformations/ReorderFields.php
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?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 (empty($fieldLabels)) {
|
||||
return [];
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
26
vendor/consolidation/output-formatters/src/Transformations/SimplifyToArrayInterface.php
vendored
Normal file
26
vendor/consolidation/output-formatters/src/Transformations/SimplifyToArrayInterface.php
vendored
Normal 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);
|
||||
}
|
13
vendor/consolidation/output-formatters/src/Transformations/StringTransformationInterface.php
vendored
Normal file
13
vendor/consolidation/output-formatters/src/Transformations/StringTransformationInterface.php
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Transformations;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
interface StringTransformationInterface
|
||||
{
|
||||
/**
|
||||
* simplifyToString is called by the string formatter to convert
|
||||
* structured data to a simple string.
|
||||
*/
|
||||
public function simplifyToString(FormatterOptions $options);
|
||||
}
|
153
vendor/consolidation/output-formatters/src/Transformations/TableTransformation.php
vendored
Normal file
153
vendor/consolidation/output-formatters/src/Transformations/TableTransformation.php
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Transformations;
|
||||
|
||||
use Consolidation\OutputFormatters\StructuredData\TableDataInterface;
|
||||
use Consolidation\OutputFormatters\StructuredData\OriginalDataInterface;
|
||||
use Consolidation\OutputFormatters\StructuredData\MetadataHolderInterface;
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
use Consolidation\OutputFormatters\Formatters\TsvFormatter;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
|
||||
class TableTransformation extends \ArrayObject implements TableDataInterface, StringTransformationInterface, OriginalDataInterface
|
||||
{
|
||||
protected $headers;
|
||||
protected $rowLabels;
|
||||
protected $layout;
|
||||
/** @var MetadataHolderInterface */
|
||||
protected $originalData;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function simplifyToString(FormatterOptions $options)
|
||||
{
|
||||
$alternateFormatter = new TsvFormatter();
|
||||
$output = new BufferedOutput();
|
||||
|
||||
try {
|
||||
$data = $alternateFormatter->validate($this->getArrayCopy());
|
||||
$alternateFormatter->write($output, $this->getArrayCopy(), $options);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
return $output->fetch();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if (isset($this->originalData)) {
|
||||
return $this->originalData->reconstruct($this->getArrayCopy(), $this->originalData->getMetadata());
|
||||
}
|
||||
return $this->getArrayCopy();
|
||||
}
|
||||
|
||||
public function setOriginalData(MetadataHolderInterface $data)
|
||||
{
|
||||
$this->originalData = $data;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
36
vendor/consolidation/output-formatters/src/Transformations/UnstructuredDataFieldAccessor.php
vendored
Normal file
36
vendor/consolidation/output-formatters/src/Transformations/UnstructuredDataFieldAccessor.php
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Transformations;
|
||||
|
||||
use Dflydev\DotAccessData\Data;
|
||||
|
||||
class UnstructuredDataFieldAccessor
|
||||
{
|
||||
protected $data;
|
||||
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function get($fields)
|
||||
{
|
||||
$data = new Data($this->data);
|
||||
$result = new Data();
|
||||
foreach ($fields as $key => $label) {
|
||||
$item = $data->get($key);
|
||||
if (isset($item)) {
|
||||
if ($label == '.') {
|
||||
if (!is_array($item)) {
|
||||
return $item;
|
||||
}
|
||||
foreach ($item as $key => $value) {
|
||||
$result->set($key, $value);
|
||||
}
|
||||
} else {
|
||||
$result->set($label, $data->get($key));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result->export();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Transformations;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
class UnstructuredDataListTransformation extends \ArrayObject implements StringTransformationInterface
|
||||
{
|
||||
public function __construct($data, $fields)
|
||||
{
|
||||
$this->originalData = $data;
|
||||
$rows = static::transformRows($data, $fields);
|
||||
parent::__construct($rows);
|
||||
}
|
||||
|
||||
protected static function transformRows($data, $fields)
|
||||
{
|
||||
$rows = [];
|
||||
foreach ($data as $rowid => $row) {
|
||||
$rows[$rowid] = UnstructuredDataTransformation::transformRow($row, $fields);
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function simplifyToString(FormatterOptions $options)
|
||||
{
|
||||
$result = '';
|
||||
$iterator = $this->getIterator();
|
||||
while ($iterator->valid()) {
|
||||
$simplifiedRow = UnstructuredDataTransformation::simplifyRow($iterator->current());
|
||||
if (isset($simplifiedRow)) {
|
||||
$result .= "$simplifiedRow\n";
|
||||
}
|
||||
|
||||
$iterator->next();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
52
vendor/consolidation/output-formatters/src/Transformations/UnstructuredDataTransformation.php
vendored
Normal file
52
vendor/consolidation/output-formatters/src/Transformations/UnstructuredDataTransformation.php
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
namespace Consolidation\OutputFormatters\Transformations;
|
||||
|
||||
use Consolidation\OutputFormatters\Options\FormatterOptions;
|
||||
|
||||
class UnstructuredDataTransformation extends \ArrayObject implements StringTransformationInterface
|
||||
{
|
||||
protected $originalData;
|
||||
|
||||
public function __construct($data, $fields)
|
||||
{
|
||||
$this->originalData = $data;
|
||||
$rows = static::transformRow($data, $fields);
|
||||
parent::__construct($rows);
|
||||
}
|
||||
|
||||
public function simplifyToString(FormatterOptions $options)
|
||||
{
|
||||
return static::simplifyRow($this->getArrayCopy());
|
||||
}
|
||||
|
||||
public static function transformRow($row, $fields)
|
||||
{
|
||||
if (empty($fields)) {
|
||||
return $row;
|
||||
}
|
||||
$fieldAccessor = new UnstructuredDataFieldAccessor($row);
|
||||
return $fieldAccessor->get($fields);
|
||||
}
|
||||
|
||||
public static function simplifyRow($row)
|
||||
{
|
||||
if (is_string($row)) {
|
||||
return $row;
|
||||
}
|
||||
if (static::isSimpleArray($row)) {
|
||||
return implode("\n", $row);
|
||||
}
|
||||
// No good way to simplify - just dump a json fragment
|
||||
return json_encode($row);
|
||||
}
|
||||
|
||||
protected static function isSimpleArray($row)
|
||||
{
|
||||
foreach ($row as $item) {
|
||||
if (!is_string($item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
122
vendor/consolidation/output-formatters/src/Transformations/WordWrapper.php
vendored
Normal file
122
vendor/consolidation/output-formatters/src/Transformations/WordWrapper.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
141
vendor/consolidation/output-formatters/src/Transformations/Wrap/CalculateWidths.php
vendored
Normal file
141
vendor/consolidation/output-formatters/src/Transformations/Wrap/CalculateWidths.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
264
vendor/consolidation/output-formatters/src/Transformations/Wrap/ColumnWidths.php
vendored
Normal file
264
vendor/consolidation/output-formatters/src/Transformations/Wrap/ColumnWidths.php
vendored
Normal 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);
|
||||
}
|
||||
}
|
28
vendor/consolidation/output-formatters/src/Validate/ValidDataTypesInterface.php
vendored
Normal file
28
vendor/consolidation/output-formatters/src/Validate/ValidDataTypesInterface.php
vendored
Normal 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();
|
||||
}
|
34
vendor/consolidation/output-formatters/src/Validate/ValidDataTypesTrait.php
vendored
Normal file
34
vendor/consolidation/output-formatters/src/Validate/ValidDataTypesTrait.php
vendored
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
28
vendor/consolidation/output-formatters/src/Validate/ValidationInterface.php
vendored
Normal file
28
vendor/consolidation/output-formatters/src/Validate/ValidationInterface.php
vendored
Normal 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);
|
||||
}
|
20
vendor/consolidation/output-formatters/test.php
vendored
Normal file
20
vendor/consolidation/output-formatters/test.php
vendored
Normal 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);
|
||||
|
Reference in a new issue