FormatterOptions::fetch()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
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_TABLE_FIELDS = 'default-table-fields';
48
    const DEFAULT_STRING_FIELD = 'default-string-field';
49
    const DELIMITER = 'delimiter';
50
    const CSV_ENCLOSURE = 'csv-enclosure';
51
    const CSV_ESCAPE_CHAR = 'csv-escape-char';
52
    const LIST_DELIMITER = 'list-delimiter';
53
    const TERMINAL_WIDTH = 'width';
54
    const METADATA_TEMPLATE = 'metadata-template';
55
    const HUMAN_READABLE = 'human-readable';
56
57
    /**
58
     * Create a new FormatterOptions with the configuration data and the
59
     * user-specified options for this request.
60
     *
61
     * @see FormatterOptions::setInput()
62
     * @param array $configurationData
63
     * @param array $options
64
     */
65
    public function __construct($configurationData = [], $options = [])
66
    {
67
        $this->configurationData = $configurationData;
68
        $this->options = $options;
69
    }
70
71
    /**
72
     * Create a new FormatterOptions object with new configuration data (provided),
73
     * and the same options data as this instance.
74
     *
75
     * @param array $configurationData
76
     * @return FormatterOptions
77
     */
78
    public function override($configurationData)
79
    {
80
        $override = new self();
81
        $override
82
            ->setConfigurationData($configurationData + $this->getConfigurationData())
83
            ->setOptions($this->getOptions());
84
        return $override;
85
    }
86
87
    public function setTableStyle($style)
88
    {
89
        return $this->setConfigurationValue(self::TABLE_STYLE, $style);
90
    }
91
92
    public function setDelimiter($delimiter)
93
    {
94
        return $this->setConfigurationValue(self::DELIMITER, $delimiter);
95
    }
96
97
    public function setCsvEnclosure($enclosure)
98
    {
99
        return $this->setConfigurationValue(self::CSV_ENCLOSURE, $enclosure);
100
    }
101
102
    public function setCsvEscapeChar($escapeChar)
103
    {
104
        return $this->setConfigurationValue(self::CSV_ESCAPE_CHAR, $escapeChar);
105
    }
106
107
    public function setListDelimiter($listDelimiter)
108
    {
109
        return $this->setConfigurationValue(self::LIST_DELIMITER, $listDelimiter);
110
    }
111
112
113
114
    public function setIncludeFieldLables($includFieldLables)
115
    {
116
        return $this->setConfigurationValue(self::INCLUDE_FIELD_LABELS, $includFieldLables);
117
    }
118
119
    public function setListOrientation($listOrientation)
120
    {
121
        return $this->setConfigurationValue(self::LIST_ORIENTATION, $listOrientation);
122
    }
123
124
    public function setRowLabels($rowLabels)
125
    {
126
        return $this->setConfigurationValue(self::ROW_LABELS, $rowLabels);
127
    }
128
129
    public function setDefaultFields($fields)
130
    {
131
        return $this->setConfigurationValue(self::DEFAULT_FIELDS, $fields);
132
    }
133
134
    public function setFieldLabels($fieldLabels)
135
    {
136
        return $this->setConfigurationValue(self::FIELD_LABELS, $fieldLabels);
137
    }
138
139
    public function setDefaultStringField($defaultStringField)
140
    {
141
        return $this->setConfigurationValue(self::DEFAULT_STRING_FIELD, $defaultStringField);
142
    }
143
144
    public function setWidth($width)
145
    {
146
        return $this->setConfigurationValue(self::TERMINAL_WIDTH, $width);
147
    }
148
149
    public function setHumanReadable($isHumanReadable = true)
150
    {
151
        return $this->setConfigurationValue(self::HUMAN_READABLE, $isHumanReadable);
152
    }
153
154
    /**
155
     * Get a formatter option
156
     *
157
     * @param string $key
158
     * @param array $defaults
159
     * @param mixed $default
160
     * @return mixed
161
     */
162
    public function get($key, $defaults = [], $default = false)
163
    {
164
        $value = $this->fetch($key, $defaults, $default);
165
        return $this->parse($key, $value);
166
    }
167
168
    /**
169
     * Return the XmlSchema to use with --format=xml for data types that support
170
     * that.  This is used when an array needs to be converted into xml.
171
     *
172
     * @return XmlSchema
173
     */
174
    public function getXmlSchema()
175
    {
176
        return new XmlSchema();
177
    }
178
179
    /**
180
     * Determine the format that was requested by the caller.
181
     *
182
     * @param array $defaults
183
     * @return string
184
     */
185
    public function getFormat($defaults = [])
186
    {
187
        return $this->get(self::FORMAT, [], $this->get(self::DEFAULT_FORMAT, $defaults, ''));
188
    }
189
190
    /**
191
     * Look up a key, and return its raw value.
192
     *
193
     * @param string $key
194
     * @param array $defaults
195
     * @param mixed $default
196
     * @return mixed
197
     */
198
    protected function fetch($key, $defaults = [], $default = false)
199
    {
200
        $defaults = $this->defaultsForKey($key, $defaults, $default);
201
        $values = $this->fetchRawValues($defaults);
202
        return $values[$key];
203
    }
204
205
    /**
206
     * Reduce provided defaults to the single item identified by '$key',
207
     * if it exists, or an empty array otherwise.
208
     *
209
     * @param string $key
210
     * @param array $defaults
211
     * @return array
212
     */
213
    protected function defaultsForKey($key, $defaults, $default = false)
214
    {
215
        if (array_key_exists($key, $defaults)) {
216
            return [$key => $defaults[$key]];
217
        }
218
        return [$key => $default];
219
    }
220
221
    /**
222
     * Look up all of the items associated with the provided defaults.
223
     *
224
     * @param array $defaults
225
     * @return array
226
     */
227
    protected function fetchRawValues($defaults = [])
228
    {
229
        return array_merge(
230
            $defaults,
231
            $this->getConfigurationData(),
232
            $this->getOptions(),
233
            $this->getInputOptions($defaults)
234
        );
235
    }
236
237
    /**
238
     * Given the raw value for a specific key, do any type conversion
239
     * (e.g. from a textual list to an array) needed for the data.
240
     *
241
     * @param string $key
242
     * @param mixed $value
243
     * @return mixed
244
     */
245
    protected function parse($key, $value)
246
    {
247
        $optionFormat = $this->getOptionFormat($key);
248
        if (!empty($optionFormat) && is_string($value)) {
249
            return $this->$optionFormat($value);
250
        }
251
        return $value;
252
    }
253
254
    /**
255
     * Convert from a textual list to an array
256
     *
257
     * @param string $value
258
     * @return array
259
     */
260
    public function parsePropertyList($value)
261
    {
262
        return PropertyParser::parse($value);
263
    }
264
265
    /**
266
     * Given a specific key, return the class method name of the
267
     * parsing method for data stored under this key.
268
     *
269
     * @param string $key
270
     * @return string
271
     */
272
    protected function getOptionFormat($key)
273
    {
274
        $propertyFormats = [
275
            self::ROW_LABELS => 'PropertyList',
276
            self::FIELD_LABELS => 'PropertyList',
277
        ];
278
        if (array_key_exists($key, $propertyFormats)) {
279
            return "parse{$propertyFormats[$key]}";
280
        }
281
        return '';
282
    }
283
284
    /**
285
     * Change the configuration data for this formatter options object.
286
     *
287
     * @param array $configurationData
288
     * @return FormatterOptions
289
     */
290
    public function setConfigurationData($configurationData)
291
    {
292
        $this->configurationData = $configurationData;
293
        return $this;
294
    }
295
296
    /**
297
     * Change one configuration value for this formatter option.
298
     *
299
     * @param string $key
300
     * @param mixed $value
301
     * @return FormetterOptions
302
     */
303
    protected function setConfigurationValue($key, $value)
304
    {
305
        $this->configurationData[$key] = $value;
306
        return $this;
307
    }
308
309
    /**
310
     * Change one configuration value for this formatter option, but only
311
     * if it does not already have a value set.
312
     *
313
     * @param string $key
314
     * @param mixed $value
315
     * @return FormetterOptions
316
     */
317
    public function setConfigurationDefault($key, $value)
318
    {
319
        if (!array_key_exists($key, $this->configurationData)) {
320
            return $this->setConfigurationValue($key, $value);
321
        }
322
        return $this;
323
    }
324
325
    /**
326
     * Return a reference to the configuration data for this object.
327
     *
328
     * @return array
329
     */
330
    public function getConfigurationData()
331
    {
332
        return $this->configurationData;
333
    }
334
335
    /**
336
     * Set all of the options that were specified by the user for this request.
337
     *
338
     * @param array $options
339
     * @return FormatterOptions
340
     */
341
    public function setOptions($options)
342
    {
343
        $this->options = $options;
344
        return $this;
345
    }
346
347
    /**
348
     * Change one option value specified by the user for this request.
349
     *
350
     * @param string $key
351
     * @param mixed $value
352
     * @return FormatterOptions
353
     */
354
    public function setOption($key, $value)
355
    {
356
        $this->options[$key] = $value;
357
        return $this;
358
    }
359
360
    /**
361
     * Return a reference to the user-specified options for this request.
362
     *
363
     * @return array
364
     */
365
    public function getOptions()
366
    {
367
        return $this->options;
368
    }
369
370
    /**
371
     * Provide a Symfony Console InputInterface containing the user-specified
372
     * options for this request.
373
     *
374
     * @param InputInterface $input
375
     * @return type
376
     */
377
    public function setInput(InputInterface $input)
378
    {
379
        $this->input = $input;
380
    }
381
382
    /**
383
     * Return all of the options from the provided $defaults array that
384
     * exist in our InputInterface object.
385
     *
386
     * @param array $defaults
387
     * @return array
388
     */
389
    public function getInputOptions($defaults)
390
    {
391
        if (!isset($this->input)) {
392
            return [];
393
        }
394
        $options = [];
395
        foreach ($defaults as $key => $value) {
396
            if ($this->input->hasOption($key)) {
397
                $result = $this->input->getOption($key);
398
                if (isset($result)) {
399
                    $options[$key] = $this->input->getOption($key);
400
                }
401
            }
402
        }
403
        return $options;
404
    }
405
}
406