Completed
Pull Request — master (#36)
by Greg
02:29
created

FormatterOptions   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 304
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 3
dl 0
loc 304
rs 10
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A override() 0 8 1
A get() 0 5 1
A getXmlSchema() 0 4 1
A getFormat() 0 4 1
A fetch() 0 6 1
A defaultsForKey() 0 7 2
A fetchRawValues() 0 9 1
A parse() 0 8 2
A parsePropertyList() 0 4 1
A getOptionFormat() 0 11 2
A setConfigurationData() 0 5 1
A setConfigurationValue() 0 5 1
A setConfigurationDefault() 0 7 2
A getConfigurationData() 0 4 1
A setOptions() 0 5 1
A setOption() 0 5 1
A getOptions() 0 4 1
A setInput() 0 4 1
B getInputOptions() 0 16 5
1
<?php
2
namespace Consolidation\OutputFormatters\Options;
3
4
use Symfony\Component\Console\Input\InputInterface;
5
use Consolidation\OutputFormatters\Transformations\PropertyParser;
6
use Consolidation\OutputFormatters\StructuredData\Xml\XmlSchema;
7
use Consolidation\OutputFormatters\StructuredData\Xml\XmlSchemaInterface;
8
9
/**
10
 * FormetterOptions holds information that affects the way a formatter
11
 * renders its output.
12
 *
13
 * There are three places where a formatter might get options from:
14
 *
15
 * 1. Configuration associated with the command that produced the output.
16
 *    This is passed in to FormatterManager::write() along with the data
17
 *    to format.  It might originally come from annotations on the command,
18
 *    or it might come from another source.  Examples include the field labels
19
 *    for a table, or the default list of fields to display.
20
 *
21
 * 2. Options specified by the user, e.g. by commandline options.
22
 *
23
 * 3. Default values associated with the formatter itself.
24
 *
25
 * This class caches configuration from sources (1) and (2), and expects
26
 * to be provided the defaults, (3), whenever a value is requested.
27
 */
28
class FormatterOptions
29
{
30
    /** var array */
31
    protected $configurationData = [];
32
    /** var array */
33
    protected $options = [];
34
    /** var InputInterface */
35
    protected $input;
36
37
    const FORMAT = 'format';
38
    const DEFAULT_FORMAT = 'default-format';
39
    const TABLE_STYLE = 'table-style';
40
    const LIST_ORIENTATION = 'list-orientation';
41
    const FIELDS = 'fields';
42
    const FIELD = 'field';
43
    const INCLUDE_FIELD_LABELS = 'include-field-labels';
44
    const ROW_LABELS = 'row-labels';
45
    const FIELD_LABELS = 'field-labels';
46
    const DEFAULT_FIELDS = 'default-fields';
47
    const DEFAULT_STRING_FIELD = 'default-string-field';
48
    const DELIMITER = 'delimiter';
49
50
    /**
51
     * Create a new FormatterOptions with the configuration data and the
52
     * user-specified options for this request.
53
     *
54
     * @see FormatterOptions::setInput()
55
     * @param array $configurationData
56
     * @param array $options
57
     */
58
    public function __construct($configurationData = [], $options = [])
59
    {
60
        $this->configurationData = $configurationData;
61
        $this->options = $options;
62
    }
63
64
    /**
65
     * Create a new FormatterOptions object with new configuration data (provided),
66
     * and the same options data as this instance.
67
     *
68
     * @param array $configurationData
69
     * @return FormatterOptions
70
     */
71
    public function override($configurationData)
72
    {
73
        $override = new self();
74
        $override
75
            ->setConfigurationData($configurationData + $this->getConfigurationData())
76
            ->setOptions($this->getOptions());
77
        return $override;
78
    }
79
80
    /**
81
     * Get a formatter option
82
     *
83
     * @param string $key
84
     * @param array $defaults
85
     * @param mixed $default
86
     * @return mixed
87
     */
88
    public function get($key, $defaults = [], $default = false)
89
    {
90
        $value = $this->fetch($key, $defaults, $default);
91
        return $this->parse($key, $value);
92
    }
93
94
    /**
95
     * Return the XmlSchema to use with --format=xml for data types that support
96
     * that.  This is used when an array needs to be converted into xml.
97
     *
98
     * @return XmlSchema
99
     */
100
    public function getXmlSchema()
101
    {
102
        return new XmlSchema();
103
    }
104
105
    /**
106
     * Determine the format that was requested by the caller.
107
     *
108
     * @param array $defaults
109
     * @return string
110
     */
111
    public function getFormat($defaults = [])
112
    {
113
        return $this->get(self::FORMAT, [], $this->get(self::DEFAULT_FORMAT, $defaults, ''));
114
    }
115
116
    /**
117
     * Look up a key, and return its raw value.
118
     *
119
     * @param string $key
120
     * @param array $defaults
121
     * @param mixed $default
122
     * @return mixed
123
     */
124
    protected function fetch($key, $defaults = [], $default = false)
125
    {
126
        $defaults = $this->defaultsForKey($key, $defaults, $default);
127
        $values = $this->fetchRawValues($defaults);
128
        return $values[$key];
129
    }
130
131
    /**
132
     * Reduce provided defaults to the single item identified by '$key',
133
     * if it exists, or an empty array otherwise.
134
     *
135
     * @param string $key
136
     * @param array $defaults
137
     * @return array
138
     */
139
    protected function defaultsForKey($key, $defaults, $default = false)
140
    {
141
        if (array_key_exists($key, $defaults)) {
142
            return [$key => $defaults[$key]];
143
        }
144
        return [$key => $default];
145
    }
146
147
    /**
148
     * Look up all of the items associated with the provided defaults.
149
     *
150
     * @param array $defaults
151
     * @return array
152
     */
153
    protected function fetchRawValues($defaults = [])
154
    {
155
        return array_merge(
156
            $defaults,
157
            $this->getConfigurationData(),
158
            $this->getOptions(),
159
            $this->getInputOptions($defaults)
160
        );
161
    }
162
163
    /**
164
     * Given the raw value for a specific key, do any type conversion
165
     * (e.g. from a textual list to an array) needed for the data.
166
     *
167
     * @param string $key
168
     * @param mixed $value
169
     * @return mixed
170
     */
171
    protected function parse($key, $value)
172
    {
173
        $optionFormat = $this->getOptionFormat($key);
174
        if (!empty($optionFormat)) {
175
            return $this->$optionFormat($value);
176
        }
177
        return $value;
178
    }
179
180
    /**
181
     * Convert from a textual list to an array
182
     *
183
     * @param string $value
184
     * @return array
185
     */
186
    public function parsePropertyList($value)
187
    {
188
        return PropertyParser::parse($value);
189
    }
190
191
    /**
192
     * Given a specific key, return the class method name of the
193
     * parsing method for data stored under this key.
194
     *
195
     * @param string $key
196
     * @return string
197
     */
198
    protected function getOptionFormat($key)
199
    {
200
        $propertyFormats = [
201
            self::ROW_LABELS => 'PropertyList',
202
            self::FIELD_LABELS => 'PropertyList',
203
        ];
204
        if (array_key_exists($key, $propertyFormats)) {
205
            return "parse{$propertyFormats[$key]}";
206
        }
207
        return '';
208
    }
209
210
    /**
211
     * Change the configuration data for this formatter options object.
212
     *
213
     * @param array $configurationData
214
     * @return FormatterOptions
215
     */
216
    public function setConfigurationData($configurationData)
217
    {
218
        $this->configurationData = $configurationData;
219
        return $this;
220
    }
221
222
    /**
223
     * Change one configuration value for this formatter option.
224
     *
225
     * @param string $key
226
     * @param mixed $value
227
     * @return FormetterOptions
228
     */
229
    protected function setConfigurationValue($key, $value)
230
    {
231
        $this->configurationData[$key] = $value;
232
        return $this;
233
    }
234
235
    /**
236
     * Change one configuration value for this formatter option, but only
237
     * if it does not already have a value set.
238
     *
239
     * @param string $key
240
     * @param mixed $value
241
     * @return FormetterOptions
242
     */
243
    public function setConfigurationDefault($key, $value)
244
    {
245
        if (!array_key_exists($key, $this->configurationData)) {
246
            return $this->setConfigurationValue($key, $value);
247
        }
248
        return $this;
249
    }
250
251
    /**
252
     * Return a reference to the configuration data for this object.
253
     *
254
     * @return array
255
     */
256
    public function getConfigurationData()
257
    {
258
        return $this->configurationData;
259
    }
260
261
    /**
262
     * Set all of the options that were specified by the user for this request.
263
     *
264
     * @param array $options
265
     * @return FormatterOptions
266
     */
267
    public function setOptions($options)
268
    {
269
        $this->options = $options;
270
        return $this;
271
    }
272
273
    /**
274
     * Change one option value specified by the user for this request.
275
     *
276
     * @param string $key
277
     * @param mixed $value
278
     * @return FormatterOptions
279
     */
280
    public function setOption($key, $value)
281
    {
282
        $this->options[$key] = $value;
283
        return $this;
284
    }
285
286
    /**
287
     * Return a reference to the user-specified options for this request.
288
     *
289
     * @return array
290
     */
291
    public function getOptions()
292
    {
293
        return $this->options;
294
    }
295
296
    /**
297
     * Provide a Symfony Console InputInterface containing the user-specified
298
     * options for this request.
299
     *
300
     * @param InputInterface $input
301
     * @return type
302
     */
303
    public function setInput(InputInterface $input)
304
    {
305
        $this->input = $input;
306
    }
307
308
    /**
309
     * Return all of the options from the provided $defaults array that
310
     * exist in our InputInterface object.
311
     *
312
     * @param array $defaults
313
     * @return array
314
     */
315
    public function getInputOptions($defaults)
316
    {
317
        if (!isset($this->input)) {
318
            return [];
319
        }
320
        $options = [];
321
        foreach ($defaults as $key => $value) {
322
            if ($this->input->hasOption($key)) {
323
                $result = $this->input->getOption($key);
324
                if (isset($result)) {
325
                    $options[$key] = $this->input->getOption($key);
326
                }
327
            }
328
        }
329
        return $options;
330
    }
331
}
332