Completed
Pull Request — master (#35)
by Robbie
02:13
created

DumpCommand::getMergedData()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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