Completed
Push — master ( 9f08b3...3a6847 )
by Tom
02:14
created

ConfigServiceProvider::fromFiles()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 28
rs 8.8571
cc 2
eloc 16
nc 2
nop 2
1
<?php
2
3
namespace TomPHP\ConfigServiceProvider;
4
5
use League\Container\ServiceProvider\AbstractServiceProvider;
6
use League\Container\ServiceProvider\BootableServiceProviderInterface;
7
use TomPHP\ConfigServiceProvider\Exception\NoMatchingFilesException;
8
9
final class ConfigServiceProvider extends AbstractServiceProvider implements
10
    BootableServiceProviderInterface
11
{
12
    const DEFAULT_PREFIX         = 'config';
13
    const DEFAULT_SEPARATOR      = '.';
14
    const DEFAULT_INFLECTORS_KEY = 'inflectors';
15
    const DEFAULT_DI_KEY         = 'di';
16
17
    const SETTING_PREFIX    = 'prefix';
18
    const SETTING_SEPARATOR = 'separator';
19
20
    /**
21
     * @var array
22
     */
23
    private $config;
24
25
    /**
26
     * @var string
27
     */
28
    private $prefix;
29
30
    /**
31
     * @var string
32
     */
33
    private $separator;
34
35
    /**
36
     * @var ConfigurableServiceProvider[]
37
     */
38
    private $subProviders;
39
40
    /**
41
     * @api
42
     *
43
     * @param array $config
44
     * @param array $settings
45
     *
46
     * @return ConfigServiceProvider
47
     */
48
    public static function fromConfig(array $config, array $settings = [])
49
    {
50
        return new self(
51
            $config,
52
            self::getSettingOrDefault(self::SETTING_PREFIX, $settings, self::DEFAULT_PREFIX),
53
            self::getSettingOrDefault(self::SETTING_SEPARATOR, $settings, self::DEFAULT_SEPARATOR),
54
            [
55
                self::DEFAULT_INFLECTORS_KEY => new InflectorConfigServiceProvider([]),
56
                self::DEFAULT_DI_KEY         => new DIConfigServiceProvider([]),
57
            ]
58
        );
59
    }
60
61
    /**
62
     * @api
63
     *
64
     * @param string[] $patterns
65
     * @param array    $settings
66
     *
67
     * @return ConfigServiceProvider
68
     */
69
    public static function fromFiles(array $patterns, array $settings = [])
70
    {
71
        $locator = new FileLocator();
72
        $files   = $locator->locate($patterns);
73
74
        if (empty($files)) {
75
            throw new NoMatchingFilesException(
76
                'No files found matching patterns: ' . implode(', ', $patterns)
77
            );
78
        }
79
80
        $factory = new ReaderFactory([
81
            '.json' => 'TomPHP\ConfigServiceProvider\JSONFileReader',
82
            '.php'  => 'TomPHP\ConfigServiceProvider\PHPFileReader',
83
        ]);
84
85
        $configs = array_map(
86
            function ($filename) use ($factory) {
87
                $reader = $factory->create($filename);
88
                return $reader->read($filename);
89
            },
90
            $files
91
        );
92
93
        $config = call_user_func_array('array_replace_recursive', $configs);
94
95
        return self::fromConfig($config, $settings);
96
    }
97
98
    /**
99
     * @api
100
     *
101
     * @param array                         $config
102
     * @param string                        $prefix
103
     * @param string                        $separator
104
     * @param ConfigurableServiceProvider[] $subProviders
105
     */
106
    public function __construct(
107
        array $config,
108
        $prefix = self::DEFAULT_PREFIX,
109
        $separator = self::DEFAULT_SEPARATOR,
110
        array $subProviders = []
111
    ) {
112
        $this->prefix       = $prefix;
113
        $this->separator    = $separator;
114
        $this->subProviders = $subProviders;
115
116
        $config = $this->expandSubGroups($config);
117
118
        $this->provides = $this->getKeys($config);
119
120
        $this->config = array_combine($this->provides, array_values($config));
121
122
        foreach ($this->subProviders as $key => $provider) {
123
            $this->configureSubProvider($key, $config, $provider);
124
        }
125
    }
126
127
    public function register()
128
    {
129
        foreach ($this->config as $key => $value) {
130
            $this->getContainer()->add($key, function () use ($value) {
131
                return $value;
132
            });
133
        }
134
135
        foreach ($this->subProviders as $provider) {
136
            $provider->setContainer($this->getContainer());
137
            $provider->register();
138
        }
139
    }
140
141
    public function boot()
142
    {
143
        foreach ($this->subProviders as $provider) {
144
            if (!$provider instanceof BootableServiceProviderInterface) {
145
                continue;
146
            }
147
148
            $provider->setContainer($this->getContainer());
149
            $provider->boot();
150
        }
151
    }
152
153
    /**
154
     * @param array $config
155
     * @return array
156
     */
157
    private function expandSubGroups(array $config)
158
    {
159
        $expanded = [];
160
161
        foreach ($config as $key => $value) {
162
            $expanded += $this->expandSubGroup($key, $value);
163
        }
164
165
        return $expanded;
166
    }
167
168
    /**
169
     * @param string $key
170
     * @param mixed $value
171
     * @return array
172
     */
173
    private function expandSubGroup($key, $value)
174
    {
175
        if (!is_array($value)) {
176
            return [$key => $value];
177
        }
178
179
        $expanded = [$key => $value];
180
181
        foreach ($value as $subkey => $subvalue) {
182
            $expanded += $this->expandSubGroup(
183
                $key . $this->separator . $subkey,
184
                $subvalue
185
            );
186
        }
187
188
        return $expanded;
189
    }
190
191
    /**
192
     * @param array $config
193
     * @return array
194
     */
195
    private function getKeys(array $config)
196
    {
197
        $keys = array_keys($config);
198
199
        if (!empty($this->prefix)) {
200
            $keys = $this->addPrefix($keys);
201
        }
202
203
        return $keys;
204
    }
205
206
    /**
207
     * @param array $keys
208
     * @return array
209
     */
210
    private function addPrefix(array $keys)
211
    {
212
        return array_map(
213
            function ($key) {
214
                return $this->prefix . $this->separator . $key;
215
            },
216
            $keys
217
        );
218
    }
219
220
    /**
221
     * @param string $key
222
     * @param array $config
223
     * @param ConfigurableServiceProvider $provider
224
     */
225
    private function configureSubProvider($key, array $config, ConfigurableServiceProvider $provider)
226
    {
227
        if (!array_key_exists($key, $config)) {
228
            return;
229
        }
230
231
        $provider->configure($config[$key]);
232
233
        $this->provides = array_merge($this->provides, $provider->provides());
234
    }
235
236
    /**
237
     * @param string $name
238
     * @param array  $settings
239
     * @param mixed  $default
240
     *
241
     * @return mixed
242
     */
243
    private static function getSettingOrDefault($name, array $settings, $default)
244
    {
245
        return isset($settings[$name]) ? $settings[$name] : $default;
246
    }
247
}
248