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

FormatterOptions::getListOrientation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
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
     * Get a formatter option. If the option does not exist, then fetch
96
     * a fallback option instead.
97
     *
98
     * @param string $key
99
     * @param string $fallbackKey
100
     * @param array $defaults
101
     * @param mixed $default
102
     * @return mixed
103
     */
104
    protected function getWithFallback($key, $fallbackKey, $defaults = [], $default = false)
105
    {
106
        return $this->get($key, [], $this->get($fallbackKey, $defaults, $default));
107
    }
108
109
    /**
110
     * Return the XmlSchema to use with --format=xml for data types that support
111
     * that.  This is used when an array needs to be converted into xml.
112
     *
113
     * @return XmlSchema
114
     */
115
    public function getXmlSchema()
116
    {
117
        return new XmlSchema();
118
    }
119
120
    /**
121
     * Determine the format that was requested by the caller.
122
     *
123
     * @param array $defaults
124
     * @return string
125
     */
126
    public function getFormat($defaults = [])
127
    {
128
        return $this->getWithFallback(self::FORMAT, self::DEFAULT_FORMAT, $defaults, '');
129
    }
130
131
    /**
132
     * Get the table style. Used by the table formatter to set the Symfony Table style.
133
     *
134
     * @param array $defaults
135
     * @return string
136
     */
137
    public function getTableStyle($defaults = [])
138
    {
139
        return $this->get(self::TABLE_STYLE, $defaults);
140
    }
141
142
    /**
143
     * Determine whether or not field labels should be included.
144
     *
145
     * @param array $defaults
146
     * @return boolean
147
     */
148
    public function getIncludeFieldLables($defaults = [])
149
    {
150
        return $this->get(self::INCLUDE_FIELD_LABELS, $defaults);
151
    }
152
153
    /**
154
     * Set the table orientation. The RowsOfFields data type uses 'horizontal'
155
     * orientation, which means the headers (keys) are in the first row.  The
156
     * AssociativeList data type uses 'vertical' orientation, which means that
157
     * the headers (keys) are in the first column.
158
     *
159
     * @param array $defaults
160
     * @return string
161
     */
162
    public function getListOrientation($defaults = [])
163
    {
164
        return $this->get(self::LIST_ORIENTATION, $defaults);
165
    }
166
167
    /**
168
     * Get the row labels. These are used by structured list data structure during
169
     * list tranformation to replace row machine IDs with human-readable labels
170
     *
171
     * @param array $defaults
172
     * @return string
173
     */
174
    public function getRowLabels($defaults = [])
175
    {
176
        return $this->get(self::ROW_LABELS, $defaults);
177
    }
178
179
    /**
180
     * Get the user-specified set of fields to include in the table.
181
     *
182
     * @param array $defaults
183
     * @return string
184
     */
185
    public function getFields($defaults = [])
186
    {
187
        return $this->getWithFallback(self::FIELDS, self::DEFAULT_FIELDS, $defaults, '');
188
    }
189
190
    /**
191
     * Get the list of fields that are displayed when the user does not
192
     * explicitly request specific fields.
193
     *
194
     * @param array $defaults
195
     * @return string
196
     */
197
    public function getDefaultFields($defaults = [])
198
    {
199
        return $this->get(self::DEFAULT_FIELDS, $defaults, '');
200
    }
201
202
    /**
203
     * Get the single-field user selection, specified by --field. The
204
     * single-field option is just like the regular --fields option,
205
     * except that it also forces the output format to 'string'.
206
     *
207
     * @param array $defaults
208
     * @return string
209
     */
210
    public function getField($defaults = [])
211
    {
212
        return $this->get(self::FIELD, $defaults);
213
    }
214
215
    /**
216
     * Get the field labels
217
     *
218
     * @param array $defaults
219
     * @return string
220
     */
221
    public function getFieldLabels($defaults = [])
222
    {
223
        return $this->get(self::FIELD_LABELS, $defaults);
224
    }
225
226
    /**
227
     * Get the single field that should be returned when a table is requested
228
     * in 'string' format.
229
     *
230
     * @param array $defaults
231
     * @return string
232
     */
233
    public function getDefaultStringField($defaults = [])
234
    {
235
        return $this->get(self::DEFAULT_STRING_FIELD, $defaults, '');
236
    }
237
238
    /**
239
     * Get the delimiter to use in a list
240
     *
241
     * @param array $defaults
242
     * @return string
243
     */
244
    public function getDelimiter($defaults = [])
245
    {
246
        return $this->get(self::DELIMITER, $defaults);
247
    }
248
249
    /**
250
     * Look up a key, and return its raw value.
251
     *
252
     * @param string $key
253
     * @param array $defaults
254
     * @param mixed $default
255
     * @return mixed
256
     */
257
    protected function fetch($key, $defaults = [], $default = false)
258
    {
259
        $defaults = $this->defaultsForKey($key, $defaults, $default);
260
        $values = $this->fetchRawValues($defaults);
261
        return $values[$key];
262
    }
263
264
    /**
265
     * Reduce provided defaults to the single item identified by '$key',
266
     * if it exists, or an empty array otherwise.
267
     *
268
     * @param string $key
269
     * @param array $defaults
270
     * @return array
271
     */
272
    protected function defaultsForKey($key, $defaults, $default = false)
273
    {
274
        if (array_key_exists($key, $defaults)) {
275
            return [$key => $defaults[$key]];
276
        }
277
        return [$key => $default];
278
    }
279
280
    /**
281
     * Look up all of the items associated with the provided defaults.
282
     *
283
     * @param array $defaults
284
     * @return array
285
     */
286
    protected function fetchRawValues($defaults = [])
287
    {
288
        return array_merge(
289
            $defaults,
290
            $this->getConfigurationData(),
291
            $this->getOptions(),
292
            $this->getInputOptions($defaults)
293
        );
294
    }
295
296
    /**
297
     * Given the raw value for a specific key, do any type conversion
298
     * (e.g. from a textual list to an array) needed for the data.
299
     *
300
     * @param string $key
301
     * @param mixed $value
302
     * @return mixed
303
     */
304
    protected function parse($key, $value)
305
    {
306
        $optionFormat = $this->getOptionFormat($key);
307
        if (!empty($optionFormat)) {
308
            return $this->$optionFormat($value);
309
        }
310
        return $value;
311
    }
312
313
    /**
314
     * Convert from a textual list to an array
315
     *
316
     * @param string $value
317
     * @return array
318
     */
319
    public function parsePropertyList($value)
320
    {
321
        return PropertyParser::parse($value);
322
    }
323
324
    /**
325
     * Given a specific key, return the class method name of the
326
     * parsing method for data stored under this key.
327
     *
328
     * @param string $key
329
     * @return string
330
     */
331
    protected function getOptionFormat($key)
332
    {
333
        $propertyFormats = [
334
            self::ROW_LABELS => 'PropertyList',
335
            self::FIELD_LABELS => 'PropertyList',
336
        ];
337
        if (array_key_exists($key, $propertyFormats)) {
338
            return "parse{$propertyFormats[$key]}";
339
        }
340
        return '';
341
    }
342
343
    /**
344
     * Change the configuration data for this formatter options object.
345
     *
346
     * @param array $configurationData
347
     * @return FormatterOptions
348
     */
349
    public function setConfigurationData($configurationData)
350
    {
351
        $this->configurationData = $configurationData;
352
        return $this;
353
    }
354
355
    /**
356
     * Change one configuration value for this formatter option.
357
     *
358
     * @param string $key
359
     * @param mixed $value
360
     * @return FormetterOptions
361
     */
362
    protected function setConfigurationValue($key, $value)
363
    {
364
        $this->configurationData[$key] = $value;
365
        return $this;
366
    }
367
368
    /**
369
     * Change one configuration value for this formatter option, but only
370
     * if it does not already have a value set.
371
     *
372
     * @param string $key
373
     * @param mixed $value
374
     * @return FormetterOptions
375
     */
376
    public function setConfigurationDefault($key, $value)
377
    {
378
        if (!array_key_exists($key, $this->configurationData)) {
379
            return $this->setConfigurationValue($key, $value);
380
        }
381
        return $this;
382
    }
383
384
    /**
385
     * Return a reference to the configuration data for this object.
386
     *
387
     * @return array
388
     */
389
    public function getConfigurationData()
390
    {
391
        return $this->configurationData;
392
    }
393
394
    /**
395
     * Set all of the options that were specified by the user for this request.
396
     *
397
     * @param array $options
398
     * @return FormatterOptions
399
     */
400
    public function setOptions($options)
401
    {
402
        $this->options = $options;
403
        return $this;
404
    }
405
406
    /**
407
     * Change one option value specified by the user for this request.
408
     *
409
     * @param string $key
410
     * @param mixed $value
411
     * @return FormatterOptions
412
     */
413
    public function setOption($key, $value)
414
    {
415
        $this->options[$key] = $value;
416
        return $this;
417
    }
418
419
    /**
420
     * Return a reference to the user-specified options for this request.
421
     *
422
     * @return array
423
     */
424
    public function getOptions()
425
    {
426
        return $this->options;
427
    }
428
429
    /**
430
     * Provide a Symfony Console InputInterface containing the user-specified
431
     * options for this request.
432
     *
433
     * @param InputInterface $input
434
     * @return FormatterOptions
435
     */
436
    public function setInput(InputInterface $input)
437
    {
438
        $this->input = $input;
439
        return $this;
440
    }
441
442
    /**
443
     * Return all of the options from the provided $defaults array that
444
     * exist in our InputInterface object.
445
     *
446
     * @param array $defaults
447
     * @return array
448
     */
449
    public function getInputOptions($defaults)
450
    {
451
        if (!isset($this->input)) {
452
            return [];
453
        }
454
        $options = [];
455
        foreach ($defaults as $key => $value) {
456
            if ($this->input->hasOption($key)) {
457
                $result = $this->input->getOption($key);
458
                if (isset($result)) {
459
                    $options[$key] = $this->input->getOption($key);
460
                }
461
            }
462
        }
463
        return $options;
464
    }
465
}
466