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

FormatterOptions::setIncludeFieldLables()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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