Issues (6)

src/Config.php (1 issue)

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) {
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']) {
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
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