Completed
Push — master ( a5918e...ee8ab2 )
by Raffael
07:32
created

Config::getConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Micro\Container
7
 *
8
 * @copyright   Copryright (c) 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
     * @var ContainerInterface
36
     */
37
    protected $container;
38
39
    /**
40
     * Create container.
41
     *
42
     * @param iterable $config
43
     */
44 37
    public function __construct(Iterable $config, ContainerInterface $container)
45
    {
46 37
        $this->config = $config;
47 37
        $this->container = $container;
48 37
    }
49
50
    /**
51
     * Get config.
52
     *
53
     * @return iterable
54
     */
55 26
    public function getConfig(): Iterable
56
    {
57 26
        return $this->config;
58
    }
59
60
    /**
61
     * Check if service is known to container config.
62
     *
63
     * @param string $name
64
     *
65
     * @return bool
66
     */
67 30
    public function has(string $name): bool
68
    {
69 30
        return isset($this->config[$name]);
70
    }
71
72
    /**
73
     * Get service configuration.
74
     *
75
     * @param string $name
76
     *
77
     * @return array
78
     */
79 29
    public function get(string $name): array
80
    {
81 29
        if (isset($this->compiled[$name])) {
82 19
            $config = $this->compiled[$name];
83
        } else {
84 29
            $this->compiled[$name] = $this->createServiceConfig($name);
85 28
            $config = $this->compiled[$name];
86
        }
87
88 28
        if (!isset($config['use'])) {
89 26
            $config['use'] = $name;
90
        }
91
92 28
        return $config;
93
    }
94
95
    /**
96
     * Parse env param.
97
     *
98
     * @param string $param
99
     *
100
     * @return string
101
     */
102 21
    public function getEnv(string $param): string
103
    {
104 21
        if (preg_match_all('#\{ENV\(([A-Za-z0-9_]+)(?:(,?)([^}]*))\)\}#', $param, $matches)) {
105 5
            if (4 !== count($matches)) {
106
                return $param;
107
            }
108
109 5
            for ($i = 0; $i < count($matches[0]); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
110 5
                $param = $this->parseEnv($param, $matches, $i);
111
            }
112
113 4
            return $param;
114
        }
115
116 16
        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 5
    protected function parseEnv(string $param, array $variables, int $key): string
129
    {
130 5
        $env = getenv($variables[1][$key]);
131 5
        if (false === $env && !empty($variables[3][$key])) {
132 1
            return str_replace($variables[0][$key], $variables[3][$key], $param);
133
        }
134 4
        if (false === $env) {
135 1
            throw new Exception\EnvVariableNotFound('env variable '.$variables[1][$key].' required but it is neither set not a default value exists');
136
        }
137
138 3
        return str_replace($variables[0][$key], $env, $param);
139
    }
140
141
    /**
142
     * Create service config.
143
     *
144
     * @param string $name
145
     *
146
     * @return array
147
     */
148 29
    protected function createServiceConfig(string $name): array
149
    {
150 29
        $config = [];
151 29
        if ($this->has($name)) {
152 26
            $config = $this->config[$name];
153
        }
154
155 29
        $class = $name;
156 29
        if (isset($config['use'])) {
157 5
            if (!is_string($config['use'])) {
158 1
                throw new Exception\InvalidConfiguration('use must be a string for service '.$name);
159
            }
160
161 4
            $class = $config['use'];
162
        }
163
164 28
        if (preg_match('#^\{(.*)\}$#', $class)) {
165
            return $config;
166
        }
167
168 28
        return $this->mergeServiceConfig($name, $class, $config);
169
    }
170
171
    /**
172
     * Get service defaults.
173
     *
174
     * @return array
175
     */
176 28
    protected function getServiceDefaults(): array
177
    {
178
        return [
179 28
            'merge' => true,
180
            'singleton' => false,
181
            'lazy' => false,
182
        ];
183
    }
184
185
    /**
186
     * Find parent classes or interfaces and merge service configurations.
187
     *
188
     * @param string $name
189
     * @param string $class
190
     * @param array  $config
191
     *
192
     * @return array
193
     */
194 28
    protected function mergeServiceConfig(string $name, string $class, array $config): array
195
    {
196 28
        $config = array_merge($this->getServiceDefaults(), $config);
197
198 28
        if (!class_exists($class) && !interface_exists($class)) {
199 1
            return $config;
200
        }
201
202 27
        if (false === $config['merge']) {
203 1
            return $this->config[$name];
204
        }
205
206 26
        $tree = $this->getConfigTree();
207 26
        $parents = array_merge(class_implements($class), class_parents($class));
208 26
        foreach ($tree as $parent_config) {
209 26
            foreach ($parents as $parent) {
210 7
                if (isset($parent_config[$parent])) {
211 7
                    $config = array_replace_recursive($config, $parent_config[$parent]);
212
                }
213
            }
214
215 26
            if (isset($parent_config[$name])) {
216 26
                $config = array_replace_recursive($config, $parent_config[$name]);
217
            }
218
        }
219
220 26
        return $config;
221
    }
222
223
    /**
224
     * Get config tree.
225
     *
226
     * @return array
227
     */
228 26
    protected function getConfigTree(): array
229
    {
230 26
        $tree = [$this->getConfig()];
231 26
        $parent = $this->container;
232 26
        while ($parent = $parent->getParent()) {
233 1
            $tree[] = $parent->getConfig()->getConfig();
234
        }
235
236 26
        return $tree;
237
    }
238
}
239