Completed
Push — master ( 216ca8...2dc9c5 )
by Robbie
11s
created

DumpCommand::execute()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
rs 8.5806
cc 4
eloc 17
nc 3
nop 2
1
<?php
2
3
namespace SilverLeague\Console\Command\Config;
4
5
use SilverLeague\Console\Command\Config\AbstractConfigCommand;
6
use Symfony\Component\Console\Helper\Table;
7
use Symfony\Component\Console\Input\InputInterface;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Output\OutputInterface;
10
11
/**
12
 * Outputs a combined representation of all SilverStripe configuration
13
 *
14
 * @package silverstripe-console
15
 * @author  Robbie Averill <[email protected]>
16
 */
17
class DumpCommand extends AbstractConfigCommand
18
{
19
    /**
20
     * The supported configuration sources
21
     *
22
     * @var array
23
     */
24
    protected $configTypes = ['all', 'yaml', 'static', 'overrides'];
25
26
    /**
27
     * @var string
28
     */
29
    protected $configType;
30
31
    /**
32
     * @var string|null
33
     */
34
    protected $filter;
35
36
    /**
37
     * {@inheritDoc}
38
     */
39
    protected function configure()
40
    {
41
        $this
42
            ->setName('config:dump')
43
            ->setDescription('Dumps all of the processed configuration properties and their values')
44
            ->addArgument('type', null, implode(', ', $this->configTypes), 'all')
45
            ->addOption('filter', null, InputOption::VALUE_REQUIRED, 'Filter the results (search)');
46
47
        $this->setHelp(<<<HELP
48
Dumps all of the processed configuration properties and their values. You can optionally filter the type to
49
control the source of data, for example use "yaml" to only return configuration values that were defined in
50
YAML configuration files. You can also add the --filter option with a search value to narrow the results.
51
HELP
52
        );
53
    }
54
55
    /**
56
     * {@inheritDoc}
57
     * @param InputInterface $input
58
     * @param OutputInterface $output
59
     * @throws InvalidArgumentException If an invalid configuration type is provided
60
     */
61
    protected function execute(InputInterface $input, OutputInterface $output)
62
    {
63
        if ($input->getArgument('type') && !in_array($input->getArgument('type'), $this->configTypes)) {
64
            throw new \InvalidArgumentException(
65
                sprintf(
66
                    '%s is not a valid config type, options: %s',
67
                    $input->getArgument('type'),
68
                    implode(', ', $this->configTypes)
69
                )
70
            );
71
        }
72
73
        $this->filter = $input->getOption('filter');
74
        $this->configType = $input->getArgument('type');
75
76
        $data = $this->getParsedOutput();
77
        if ($this->filter) {
78
            $data = $this->filterOutput($data, $this->filter);
79
        }
80
81
        $table = new Table($output);
82
        $table
83
            ->setHeaders(['Class name', 'Property', 'Key', 'Value'])
84
            ->setRows($data)
85
            ->render();
86
    }
87
88
    /**
89
     * Get source configuration data by the optional "type"
90
     *
91
     * @return array
92
     */
93
    protected function getSourceData()
94
    {
95
        switch ($this->configType) {
96
            case 'yaml':
97
                $output = $this->getYamlConfig();
98
                break;
99
            case 'static':
100
                $output = $this->getStaticConfig();
101
                break;
102
            case 'overrides':
103
                $output = $this->getConfigOverrides();
104
                break;
105
            case 'all':
106
            default:
107
                $output = $this->getMergedData();
108
                break;
109
        }
110
        return $output;
111
    }
112
113
    /**
114
     * Merge together the config manifests data in the same manner as \SilverStripe\Core\Config\Config::getUncached
115
     *
116
     * @return array
117
     */
118
    protected function getMergedData()
119
    {
120
        // Statics are the lowest priority
121
        $output = $this->getStaticConfig();
122
123
        // Then YAML is added
124
        foreach ($this->getYamlConfig() as $class => $property) {
125
            if (!array_key_exists($class, $output)) {
126
                $output[$class] = [];
127
            }
128
            $output[$class] = array_merge($property, $output[$class]);
129
        }
130
131
        // Then overrides are added last
132
        foreach ($this->getConfigOverrides() as $class => $values) {
133
            foreach ($values as $property => $value) {
134
                $output[$class][$property] = $value;
135
            }
136
        }
137
138
        return $output;
139
    }
140
141
    /**
142
     * Creates a table-friendly output array from the input configuration sources
143
     *
144
     * @return array
145
     */
146
    protected function getParsedOutput()
147
    {
148
        $output = [];
149
        foreach ($this->getSourceData() as $className => $classInfo) {
150
            foreach ($classInfo as $property => $values) {
151
                $row = [$className, $property];
152
                if (is_array($values)) {
153
                    foreach ($values as $key => $value) {
154
                        $row[] = is_numeric($key) ? '' : $key;
155
                        $row[] = is_array($value) ? json_encode($value, JSON_PRETTY_PRINT) : $value;
156
                        $output[] = $row;
157
                        // We need the class and property data for second level values if we're filtering.
158
                        if ($this->filter !== null) {
159
                            $row = [$className, $property];
160
                        } else {
161
                            $row = ['', ''];
162
                        }
163
                    }
164
                } else {
165
                    $row[] = '';
166
                    $row[] = $values;
167
                }
168
                $output[] = $row;
169
            }
170
        }
171
        return $output;
172
    }
173
174
    /**
175
     * Apply a search filter to the results
176
     *
177
     * @param  array  $data   The pre-parsed output data
178
     * @param  string $filter The string to search on
179
     * @return array          Rows that have a string match on any of their fields
180
     */
181
    protected function filterOutput($data, $filter)
182
    {
183
        $output = [];
184
        foreach ($data as $values) {
185
            foreach ($values as $value) {
186
                if (is_string($value) && stripos($value, $filter) !== false) {
187
                    $output[] = $values;
188
                }
189
            }
190
        }
191
        return $output;
192
    }
193
}
194