Completed
Pull Request — master (#84)
by Nick
01:52
created

YamlConfigFileLoader::load()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 9.536
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php declare(strict_types=1);
2
3
4
namespace Shopware\Psh\Config;
5
6
use Symfony\Component\Yaml\Parser;
7
8
/**
9
 * Load the config data from a yaml file
10
 */
11
class YamlConfigFileLoader implements ConfigLoader
12
{
13
    const KEY_HEADER = 'header';
14
15
    const KEY_DYNAMIC_VARIABLES = 'dynamic';
16
17
    const KEY_CONST_VARIABLES = 'const';
18
19
    const KEY_DOTENV_PATHS = 'dotenv';
20
21
    const KEY_COMMAND_PATHS = 'paths';
22
23
    const KEY_ENVIRONMENTS = 'environments';
24
25
    const KEY_TEMPLATES = 'templates';
26
27
    /**
28
     * @var Parser
29
     */
30
    private $yamlReader;
31
32
    /**
33
     * @var ConfigBuilder
34
     */
35
    private $configBuilder;
36
37
    /**
38
     * @var string
39
     */
40
    private $applicationRootDirectory;
41
42
    /**
43
     * @param Parser $yamlReader
44
     * @param ConfigBuilder $configBuilder
45
     * @param string $applicationRootDirectory
46
     */
47
    public function __construct(Parser $yamlReader, ConfigBuilder $configBuilder, string $applicationRootDirectory)
48
    {
49
        $this->yamlReader = $yamlReader;
50
        $this->configBuilder = $configBuilder;
51
        $this->applicationRootDirectory = $applicationRootDirectory;
52
    }
53
54
    /**
55
     * @inheritdoc
56
     */
57
    public function isSupported(string $file): bool
58
    {
59
        return in_array(pathinfo($file, PATHINFO_EXTENSION), ['yaml', 'yml', 'dist', 'override'], true);
60
    }
61
62
    /**
63
     * @inheritdoc
64
     */
65
    public function load(string $file, array $params): Config
66
    {
67
        $contents = $this->loadFileContents($file);
68
        $rawConfigData = $this->parseFileContents($contents);
69
70
        $this->configBuilder->start();
71
72
        $this->configBuilder
73
            ->setHeader(
74
                $this->extractData(self::KEY_HEADER, $rawConfigData, '')
75
            );
76
77
        $this->setConfigData($file, $rawConfigData);
78
79
        $environments = $this->extractData(self::KEY_ENVIRONMENTS, $rawConfigData, []);
80
81
        foreach ($environments as $name => $data) {
82
            $this->configBuilder->start($name);
83
            $this->setConfigData($file, $data);
84
        }
85
86
        return $this->configBuilder
87
            ->create($params);
88
    }
89
90
    /**
91
     * @param string $file
92
     * @param array $rawConfigData
93
     */
94
    private function setConfigData(string $file, array $rawConfigData)
95
    {
96
        $this->configBuilder->setCommandPaths(
97
            $this->extractPaths($file, $rawConfigData, self::KEY_COMMAND_PATHS)
98
        );
99
100
        $this->configBuilder->setDynamicVariables(
101
            $this->extractData(self::KEY_DYNAMIC_VARIABLES, $rawConfigData, [])
102
        );
103
104
        $this->configBuilder->setConstants(
105
            $this->extractData(self::KEY_CONST_VARIABLES, $rawConfigData, [])
106
        );
107
108
        $this->configBuilder->setTemplates(
109
            $this->extractTemplates($file, $rawConfigData)
110
        );
111
112
        $this->configBuilder->setDotenvPaths(
113
            $this->extractPaths($file, $rawConfigData, self::KEY_DOTENV_PATHS)
114
        );
115
    }
116
117
    /**
118
     * @param string $key
119
     * @param array $rawConfig
120
     * @param mixed $default
121
     * @return mixed|null
122
     */
123
    private function extractData(string $key, array $rawConfig, $default = false)
124
    {
125
        if (!array_key_exists($key, $rawConfig)) {
126
            return $default;
127
        }
128
129
        return $rawConfig[$key];
130
    }
131
132
    /**
133
     * @param string $file
134
     * @return string
135
     */
136
    private function loadFileContents(string $file): string
137
    {
138
        return file_get_contents($file);
139
    }
140
141
    /**
142
     * @param string $contents
143
     * @return array
144
     */
145
    private function parseFileContents(string $contents): array
146
    {
147
        return $this->yamlReader->parse($contents);
148
    }
149
150
    /**
151
     * @param string $file
152
     * @param array $rawConfigData
153
     * @param string $key
154
     *
155
     * @return array
156
     */
157
    private function extractPaths(string $file, array $rawConfigData, string $key): array
158
    {
159
        $paths = $this->extractData($key, $rawConfigData, []);
160
161
        return array_map(function ($path) use ($file) {
162
            return $this->fixPath($path, $file);
163
        }, $paths);
164
    }
165
166
    /**
167
     * @param string $file
168
     * @param array $rawConfigData
169
     * @return array
170
     */
171
    private function extractTemplates(string $file, array $rawConfigData): array
172
    {
173
        $templates = $this->extractData(self::KEY_TEMPLATES, $rawConfigData, []);
174
175
        return array_map(function ($template) use ($file) {
176
            $template['source'] = $this->fixPath($template['source'], $file);
177
            $template['destination'] = $this->makeAbsolutePath($file, $template['destination']);
178
179
            return $template;
180
        }, $templates);
181
    }
182
183
    /**
184
     * @param string $absoluteOrRelativePath
185
     * @param string $baseFile
186
     * @return string
187
     * @throws \InvalidArgumentException
188
     */
189
    private function fixPath(string $absoluteOrRelativePath, string $baseFile): string
190
    {
191
        $possiblyValidFiles = [
192
            $this->applicationRootDirectory . '/' . $absoluteOrRelativePath,
193
            $this->makeAbsolutePath($baseFile, $absoluteOrRelativePath),
194
            $absoluteOrRelativePath,
195
        ];
196
197
        foreach ($possiblyValidFiles as $file) {
198
            if (file_exists($file)) {
199
                return $file;
200
            }
201
        }
202
203
        throw new \InvalidArgumentException(sprintf(
204
            'Unable to find a file referenced by "%s", tried: %s',
205
            $absoluteOrRelativePath,
206
            print_r($possiblyValidFiles, true)
207
        ));
208
    }
209
210
    /**
211
     * @param string $baseFile
212
     * @param string $path
213
     * @return string
214
     */
215
    private function makeAbsolutePath(string $baseFile, string $path): string
216
    {
217
        return pathinfo($baseFile, PATHINFO_DIRNAME) . '/' . $path;
218
    }
219
}
220