Passed
Branch master (a5918e)
by Raffael
02:18
created

Config::getConfigTree()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 9
ccs 0
cts 0
cp 0
crap 6
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Micro
7
 *
8
 * @copyright   Copryright (c) 2015-2018 gyselroth GmbH (https://gyselroth.com)
9
 * @license     MIT https://opensource.org/licenses/MIT
10
 */
11
12
namespace Micro\Container;
13
14
use Psr\Container\ContainerInterface;
15
16
class Config
17
{
18
    /**
19
     * Config.
20
     *
21
     * @var iterable
22
     */
23
    protected $config = [];
24
25
    /**
26
     * Compiled config.
27
     *
28
     * @var array
29
     */
30
    protected $compiled = [];
31
32
    /**
33
     * Container.
34
     *
35 21
     * @var ContainerInterface
36
     */
37 21
    protected $container;
38 21
39
    /**
40
     * Create container.
41
     *
42
     * @param iterable $config
43
     */
44
    public function __construct(Iterable $config, ContainerInterface $container)
45
    {
46
        $this->config = $config;
47 17
        $this->container = $container;
48
    }
49 17
50
    /**
51
     * Get config.
52
     *
53
     * @return iterable
54
     */
55
    public function getConfig(): Iterable
56
    {
57
        return $this->config;
58
    }
59 17
60
    /**
61 17
     * Check if service is known to container config.
62 13
     *
63
     * @param string $name
64 17
     *
65 16
     * @return bool
66
     */
67
    public function has(string $name): bool
68 16
    {
69 14
        return isset($this->config[$name]);
70
    }
71
72 16
    /**
73
     * Get service configuration.
74
     *
75
     * @param string $name
76
     *
77
     * @return array
78
     */
79
    public function get(string $name): array
80
    {
81
        if (isset($this->compiled[$name])) {
82 12
            $config = $this->compiled[$name];
83
        } else {
84 12
            $this->compiled[$name] = $this->createServiceConfig($name);
85
            $config = $this->compiled[$name];
86
        }
87
88
        if (!isset($config['use'])) {
89
            $config['use'] = $name;
90
        }
91
92
        return $config;
93
    }
94
95
    /**
96 12
     * Parse env param.
97
     *
98
     * @param string $param
99
     *
100
     * @return string
101
     */
102
    public function getEnv(string $param): string
103
    {
104
        if (preg_match_all('#\{ENV\(([A-Za-z0-9_]+)(?:(,?)([^}]*))\)\}#', $param, $matches)) {
105
            if (4 !== count($matches)) {
106
                return $param;
107
            }
108
109
            for ($i = 0; $i < 1; ++$i) {
110
                $param = $this->parseEnv($param, $matches, $i);
111
            }
112
113
            return $param;
114
        }
115
116
        return $param;
117
    }
118
119
    /**
120
     * Parse env.
121
     *
122
     * @param string $param
123
     * @param array  $variables
124
     * @param int    $key
125
     *
126
     * @return string
127
     */
128 17
    protected function parseEnv(string $param, array $variables, int $key): string
129
    {
130 17
        $env = getenv($variables[1][$key]);
131 17
        if (false === $env && !empty($variables[3][$key])) {
132 14
            return str_replace($variables[0][$key], $variables[3][$key], $param);
133
        }
134
        if (false === $env) {
135 17
            throw new Exception\EnvVariableNotFound('env variable '.$variables[1][$key].' required but it is neither set not a default value exists');
136 17
        }
137 5
138 1
        return str_replace($variables[0][$key], $env, $param);
139
    }
140
141 4
    /**
142
     * Create service config.
143
     *
144 16
     * @param string $name
145
     *
146
     * @return array
147
     */
148 16
    protected function createServiceConfig(string $name): array
149
    {
150
        $config = [];
151
        if ($this->has($name)) {
152
            $config = $this->config[$name];
153
        }
154
155
        $class = $name;
156
        if (isset($config['use'])) {
157
            if (!is_string($config['use'])) {
158
                throw new Exception\InvalidConfiguration('use must be a string for service '.$name);
159
            }
160 16
161
            $class = $config['use'];
162 16
        }
163 1
164
        if (preg_match('#^\{(.*)\}$#', $class)) {
165
            return $config;
166 15
        }
167 15
168 5
        return $this->mergeServiceConfig($name, $class, $config);
169 5
    }
170
171
    /**
172
     * Find parent classes or interfaces and merge service configurations.
173 15
     *
174 13
     * @param string $name
175
     * @param string $class
176
     * @param array  $config
177 15
     *
178
     * @return array
179
     */
180
    protected function mergeServiceConfig(string $name, string $class, array $config): array
181
    {
182
        if (!class_exists($class) && !interface_exists($class)) {
183
            return $config;
184
        }
185
186
        if (isset($this->config[$name]['merge']) && $this->config[$name]['merge'] === false) {
187
            return $this->config[$name];
188
        }
189
190
        $tree = $this->getConfigTree();
191
        $parents = array_merge(class_implements($class), class_parents($class));
192
        foreach ($tree as $parent_config) {
193
            foreach ($parents as $parent) {
194
                if (isset($parent_config[$parent])) {
195
                    $config = array_replace_recursive($config, $parent_config[$parent]);
196
                }
197
            }
198
199
            if (isset($parent_config[$name])) {
200
                $config = array_replace_recursive($config, $parent_config[$name]);
201
            }
202
        }
203
204
        return $config;
205
    }
206
207
    /**
208
     * Get config tree.
209
     *
210
     * @return array
211
     */
212
    protected function getConfigTree(): array
213
    {
214
        $tree = [$this->getConfig()];
215
        $parent = $this->container;
216
        while ($parent = $parent->getParent()) {
217
            $tree[] = $parent->getConfig()->getConfig();
218
        }
219
220
        return $tree;
221
    }
222
}
223