Passed
Push — master ( db3e5d...b85596 )
by Thorsten
01:45
created

ConfigProvider   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 98.25%

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 4
dl 0
loc 99
ccs 56
cts 57
cp 0.9825
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A get() 0 15 4
A has() 0 4 1
A loadScope() 0 15 2
B resolvePath() 0 28 6
B interpolateConfigValues() 0 15 6
1
<?php
2
/**
3
 * This file is part of the daikon-cqrs/config project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
declare(strict_types=1);
10
11
namespace Daikon\Config;
12
13
final class ConfigProvider implements ConfigProviderInterface
14
{
15
    private const INTERPOLATION_PATTERN = '/(\$\{(.*?)\})/';
16
17
    private $config;
18
19
    private $params;
20
21
    private $preLoadInterpolations;
22
23 3
    public function __construct(ConfigProviderParamsInterface $params)
24
    {
25 3
        $this->params = $params;
26 3
        $this->config = [];
27 3
        $this->preLoadInterpolations = [];
28 3
    }
29
30 6
    public function get(string $path, $default = null)
31
    {
32 6
        $configPath = ConfigPath::fromString($path);
33 6
        $scope = $configPath->getScope();
34 6
        if (isset($this->preLoadInterpolations[$scope])) {
35 1
            throw new \Exception(
36
                'Recursive interpolations are not allowed when interpolating "locations" or "sources". '.
37 1
                sprintf('Trying to recurse into scope: "%s"', $scope)
38
            );
39
        }
40 6
        if (!isset($this->config[$scope]) && $this->params->hasScope($scope)) {
41 6
            $this->config[$scope] = $this->loadScope($scope);
42
        }
43 5
        return $this->resolvePath($configPath) ?? $default;
44
    }
45
46 1
    public function has(string $path): bool
47
    {
48 1
        return $this->get($path) !== null;
49
    }
50
51 6
    private function loadScope(string $scope)
52
    {
53 6
        $this->preLoadInterpolations[$scope] = true;
54 6
        $locations = $this->params->getLocations($scope);
55 6
        $sources = $this->params->getSources($scope);
56 6
        $loader = $this->params->getLoader($scope);
57 6
        if (!$loader instanceof ArrayConfigLoader) {
58 2
            $sources = $this->interpolateConfigValues($sources);
59
        }
60 5
        $locations = $this->interpolateConfigValues($locations);
61 5
        unset($this->preLoadInterpolations[$scope]);
62
63 5
        $this->config[$scope] = $loader->load($locations, $sources);
64 5
        return $this->interpolateConfigValues($this->config[$scope]);
65
    }
66
67 5
    private function resolvePath(ConfigPathInterface $path)
68
    {
69 5
        $scope = $path->getScope();
70 5
        if (!isset($this->config[$scope])) {
71 2
            return null;
72
        }
73 5
        $value = &$this->config[$scope];
74 5
        $pathParts = $path->getParts();
75 5
        $pathLen = $path->getLength();
76 5
        $pathPos = 0;
77 5
        while (!empty($pathParts)) {
78 5
            $pathPart = array_shift($pathParts);
79 5
            $pathPos++;
80 5
            if (!isset($value[$pathPart])) {
81 2
                if ($pathPos === $pathLen) {
82 1
                    return null;
83
                } else {
84 2
                    array_unshift($pathParts, $pathPart.$path->getSeparator().array_shift($pathParts));
85 2
                    continue;
86
                }
87
            }
88 5
            if (!is_array($value)) {
89
                throw new \Exception(sprintf('Trying to traverse non array-value with path: "%s"', $path));
90
            }
91 5
            $value = &$value[$pathPart];
92
        }
93 5
        return $value;
94
    }
95
96 6
    private function interpolateConfigValues(array $config): array
97
    {
98 6
        foreach ($config as $key => $value) {
99 6
            if (is_array($value)) {
100 5
                $config[$key] = $this->interpolateConfigValues($value);
101 6
            } elseif (is_string($value) && preg_match_all(self::INTERPOLATION_PATTERN, $value, $matches)) {
102 3
                $replacements = [];
103 3
                foreach ($matches[2] as $configKey) {
104 3
                    $replacements[] = $this->get($configKey);
105
                }
106 2
                $config[$key] = str_replace($matches[0], $replacements, $value);
107
            }
108
        }
109 5
        return $config;
110
    }
111
}
112