Config::loadConfiguration()   B
last analyzed

Complexity

Conditions 6
Paths 2

Size

Total Lines 41
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 41
rs 8.439
c 0
b 0
f 0
cc 6
eloc 32
nc 2
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the dotfiles project.
7
 *
8
 *     (c) Anthonius Munthi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Dotfiles\Core\Config;
15
16
use Dotfiles\Core\Util\Toolkit;
17
use Symfony\Component\Config\ConfigCache;
18
use Symfony\Component\Config\Definition\ConfigurationInterface;
19
use Symfony\Component\Config\Definition\Processor;
20
use Symfony\Component\Config\Resource\FileResource;
21
use Symfony\Component\Finder\Finder;
22
use Symfony\Component\Yaml\Yaml;
23
24
/**
25
 * Class Config.
26
 *
27
 * @covers \Dotfiles\Core\Config\Config
28
 */
29
class Config implements \ArrayAccess
30
{
31
    private $configDirs = array();
32
33
    private $configs = array();
34
35
    private $defaults = array();
36
37
    /**
38
     * @var ConfigurationInterface[]
39
     */
40
    private $definitions = array();
41
42
    private $files = array();
43
44
    private $flattened = array();
45
46
    /**
47
     * @param $directory
48
     *
49
     * @return Config
50
     */
51
    public function addConfigDir($directory): self
52
    {
53
        if (!is_dir($directory)) {
54
            throw new \InvalidArgumentException("Directory ${directory} not exists");
55
        }
56
        if (!in_array($directory, $this->configDirs)) {
57
            $this->configDirs[] = $directory;
58
        }
59
60
        return $this;
61
    }
62
63
    public function addDefinition(ConfigurationInterface $config): self
64
    {
65
        $builder = $config->getConfigTreeBuilder();
66
        $name = $builder->buildTree()->getName();
67
        $this->definitions[$name] = $config;
68
        $this->defaults[$name] = array();
69
70
        return $this;
71
    }
72
73
    public function get($name)
74
    {
75
        if (array_key_exists($name, $this->configs)) {
76
            return $this->configs[$name];
77
        } elseif (array_key_exists($name, $this->flattened)) {
78
            return $this->flattened[$name];
79
        } else {
80
            throw new \InvalidArgumentException('Unknown config key: "'.$name.'"');
81
        }
82
    }
83
84
    public function getAll($flattened = false)
85
    {
86
        return $flattened ? $this->flattened : $this->configs;
87
    }
88
89
    /**
90
     * @return array
91
     */
92
    public function getConfigDirs(): array
93
    {
94
        return $this->configDirs;
95
    }
96
97
    /**
98
     * Load configuration from files and default value.
99
     */
100
    public function loadConfiguration(): void
101
    {
102
        $cachePath = Toolkit::getCachePathPrefix().'/config.php';
103
        $cache = new ConfigCache($cachePath, true);
104
        $env = getenv('DOTFILES_ENV');
105
        if (!$cache->isFresh() || 'dev' === $env) {
106
            $processor = new Processor();
107
            $configs = $this->processFiles();
108
            $generated = array();
109
            foreach ($configs as $rootKey => $values) {
110
                if (!isset($this->definitions[$rootKey])) {
111
                    continue;
112
                }
113
                $temp = array();
114
                $config = $this->definitions[$rootKey];
115
                $temp[$rootKey] = $values;
116
                $processed = $processor->processConfiguration($config, $temp);
117
                if (!isset($generated[$rootKey])) {
118
                    $generated[$rootKey] = array();
119
                }
120
                $generated[$rootKey] = array_merge_recursive($generated[$rootKey], $processed);
121
            }
122
            $expConfig = var_export($generated, true);
123
            $flattened = $generated;
124
            Toolkit::flattenArray($flattened);
125
            $expFlattened = var_export($flattened, true);
126
127
            /* provide a way to handle normalize config */
128
            $this->normalizeConfig($flattened, $expConfig);
129
            $this->normalizeConfig($flattened, $expConfig);
130
            $this->normalizeConfig($flattened, $expFlattened);
131
            $this->normalizeConfig($flattened, $expFlattened);
132
133
            $code = <<<EOC
134
<?php
135
\$this->configs = ${expConfig};
136
\$this->flattened = ${expFlattened};
137
EOC;
138
            $cache->write($code, $this->files);
139
        }
140
        require $cachePath;
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function offsetExists($offset)
147
    {
148
        return isset($this->configs[$offset]);
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    public function offsetGet($offset)
155
    {
156
        return $this->configs[$offset];
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function offsetSet($offset, $value): void
163
    {
164
        $this->configs[$offset] = $value;
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170
    public function offsetUnset($offset): void
171
    {
172
        unset($this->configs[$offset]);
173
    }
174
175
    public function set($name, $value): void
176
    {
177
        $this->flattened[$name] = $value;
178
    }
179
180
    private function normalizeConfig($flattened, &$config): void
181
    {
182
        foreach ($flattened as $name => $value) {
183
            $format = '%'.$name.'%';
184
            $config = strtr($config, array($format => $value));
185
        }
186
    }
187
188
    private function processFiles()
189
    {
190
        $configs = $this->defaults;
191
        if (!count($this->configDirs) > 0) {
192
            return $configs;
193
        }
194
        $finder = Finder::create()
195
            ->name('*.yaml')
196
            ->name('*.yml')
197
        ;
198
        foreach ($this->configDirs as $dir) {
199
            $finder->in($dir);
200
        }
201
        /* @var \Symfony\Component\Finder\SplFileInfo $file */
202
        foreach ($finder->files() as $file) {
203
            $parsed = Yaml::parseFile($file->getRealPath());
204
            if (is_array($parsed)) {
205
                $configs = array_merge_recursive($configs, $parsed);
206
            }
207
            $this->files[] = new FileResource($file->getRealPath());
208
        }
209
210
        return $configs;
211
    }
212
}
213