Processor::processConfig()   B
last analyzed

Complexity

Conditions 6
Paths 8

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.9137
c 0
b 0
f 0
cc 6
nc 8
nop 1
1
<?php
2
3
namespace Incenteev\ParameterHandler;
4
5
use Composer\IO\IOInterface;
6
7
class Processor
8
{
9
    /**
10
     * @var IOInterface
11
     */
12
    protected $io;
13
14
    /**
15
     * @var FileHandlerInterface
16
     */
17
    protected $fileHandler;
18
19
    public function __construct(IOInterface $io)
20
    {
21
        $this->io = $io;
22
    }
23
24
    public function processFile(array $config)
25
    {
26
        $config = $this->processConfig($config);
27
28
        $realFile = $config['file'];
29
        $this->fileHandler = FileHandlerFactory::createFileHandler($config['file-type']);
30
        $parameterKey = $config['parameter-key'];
31
32
        $exists = is_file($realFile);
33
34
        $action = $exists ? 'Updating' : 'Creating';
35
        $this->io->write(sprintf('<info>%s the "%s" file</info>', $action, $realFile));
36
37
        // Find the expected params
38
        $expectedValues = $this->fileHandler->load($config['dist-file']);
39
        if (!isset($expectedValues[$parameterKey])) {
40
            throw new \InvalidArgumentException(sprintf('The top-level key %s is missing.', $parameterKey));
41
        }
42
        $expectedParams = (array) $expectedValues[$parameterKey];
43
44
        // find the actual params
45
        $actualValues = array_merge(
46
            // Preserve other top-level keys than `$parameterKey` in the file
47
            $expectedValues,
48
            [$parameterKey => []]
49
        );
50
        if ($exists) {
51
            $existingValues = $this->fileHandler->load($realFile);
52
            if ($existingValues === null) {
53
                $existingValues = [];
54
            }
55
            if (!is_array($existingValues)) {
56
                throw new \InvalidArgumentException(sprintf('The existing "%s" file does not contain an array', $realFile));
57
            }
58
            $actualValues = array_merge($actualValues, $existingValues);
59
        }
60
61
        $actualValues[$parameterKey] = $this->processParams($config, $expectedParams, (array) $actualValues[$parameterKey]);
62
63
        if (!is_dir($dir = dirname($realFile))) {
64
            mkdir($dir, 0755, true);
65
        }
66
67
        $this->fileHandler->save($realFile, $actualValues);
68
    }
69
70
    protected function processConfig(array $config)
71
    {
72
        if (empty($config['file'])) {
73
            throw new \InvalidArgumentException('The extra.incenteev-parameters.file setting is required to use this script handler.');
74
        }
75
76
        if (empty($config['file-type'])) {
77
            throw new \InvalidArgumentException('The extra.incenteev-parameters.file-type setting is required to use this script handler.');
78
        }
79
80
        if (empty($config['dist-file'])) {
81
            $config['dist-file'] = $config['file'] . '.dist';
82
        }
83
84
        if (!is_file($config['dist-file'])) {
85
            throw new \InvalidArgumentException(sprintf('The dist file "%s" does not exist. Check your dist-file config or create it.', $config['dist-file']));
86
        }
87
88
        if (empty($config['parameter-key'])) {
89
            $config['parameter-key'] = 'parameters';
90
        }
91
92
        return $config;
93
    }
94
95
    protected function processParams(array $config, array $expectedParams, array $actualParams)
96
    {
97
        // Grab values for parameters that were renamed
98
        $renameMap = empty($config['rename-map']) ? [] : (array) $config['rename-map'];
99
        $actualParams = array_replace($actualParams, $this->processRenamedValues($renameMap, $actualParams));
100
101
        $keepOutdatedParams = false;
102
        if (isset($config['keep-outdated'])) {
103
            $keepOutdatedParams = (boolean) $config['keep-outdated'];
104
        }
105
106
        if (!$keepOutdatedParams) {
107
            $actualParams = array_intersect_key($actualParams, $expectedParams);
108
        }
109
110
        $envMap = empty($config['env-map']) ? [] : (array) $config['env-map'];
111
112
        // Add the params coming from the environment values
113
        $actualParams = array_replace($actualParams, $this->getEnvValues($envMap));
114
115
        return $this->getParams($expectedParams, $actualParams);
116
    }
117
118
    protected function getEnvValues(array $envMap)
119
    {
120
        $params = [];
121
        foreach ($envMap as $param => $env) {
122
            $value = getenv($env);
123
124
            if (!$value) {
125
                continue;
126
            }
127
128
            if (false !== strpos($param, '.')) {
129
                $this->setValueByPath($params, $param, $this->fileHandler->parseInline($value));
130
131
                continue;
132
            }
133
134
            $params[$param] = $this->fileHandler->parseInline($value);
135
        }
136
137
        return $params;
138
    }
139
140
    protected function setValueByPath(array &$array, $path, $value)
141
    {
142
        $index = &$array;
143
144
        foreach (explode('.', $path) as $level) {
145
            $index = &$index[$level];
146
        }
147
148
        $index = $value;
149
    }
150
151
    protected function processRenamedValues(array $renameMap, array $actualParams)
152
    {
153
        foreach ($renameMap as $param => $oldParam) {
154
            if (array_key_exists($param, $actualParams)) {
155
                continue;
156
            }
157
158
            if (!array_key_exists($oldParam, $actualParams)) {
159
                continue;
160
            }
161
162
            $actualParams[$param] = $actualParams[$oldParam];
163
        }
164
165
        return $actualParams;
166
    }
167
168
    protected function getParams(array $expectedParams, array $actualParams)
169
    {
170
        // Simply use the expectedParams value as default for the missing params.
171
        if (!$this->io->isInteractive()) {
172
            return array_replace($expectedParams, $actualParams);
173
        }
174
175
        $isStarted = false;
176
177
        foreach ($expectedParams as $key => $message) {
178
            if (array_key_exists($key, $actualParams)) {
179
                continue;
180
            }
181
182
            if (!$isStarted) {
183
                $isStarted = true;
184
                $this->io->write('<comment>Some parameters are missing. Please provide them.</comment>');
185
            }
186
187
            $default = $this->fileHandler->dumpInline($message);
188
189
            if (is_array($default)) {
190
                $actualParams[$key] = $default;
191
192
                continue;
193
            }
194
195
            $value = $this->io->ask(sprintf('<question>%s</question> (<comment>%s</comment>): ', $key, $default), $default);
196
197
            $actualParams[$key] = $this->fileHandler->parseInline($value);
198
        }
199
200
        return $actualParams;
201
    }
202
}
203