Config::getConfig()   A
last analyzed

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

216
            $tree[] = $parent->/** @scrutinizer ignore-call */ getConfig()->getConfig();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
217
        }
218
219 58
        return $tree;
220
    }
221
}
222