Passed
Push — master ( 162783...12f0d3 )
by Thorsten
01:40
created

ConfigProvider::resolvePath()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 16
cts 16
cp 1
rs 9.0534
c 0
b 0
f 0
cc 4
eloc 16
nc 4
nop 1
crap 4
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
use Assert\Assertion;
14
15
final class ConfigProvider implements ConfigProviderInterface
16
{
17
    private const INTERPOLATION_PATTERN = '/(\$\{(.*?)\})/';
18
19
    private $config;
20
21
    private $params;
22
23
    private $preLoadInterpolations;
24
25 3
    public function __construct(ConfigProviderParamsInterface $params)
26
    {
27 3
        $this->params = $params;
28 3
        $this->config = [];
29 3
        $this->preLoadInterpolations = [];
30 3
    }
31
32 6
    public function get(string $path, $default = null)
33
    {
34 6
        $configPath = ConfigPath::fromString($path);
35 6
        $scope = $configPath->getScope();
36 6
        Assertion::keyNotExists(
37 6
            $this->preLoadInterpolations,
38 6
            $scope,
39
            'Recursive interpolations are not allowed when interpolating "locations" or "sources". '.
40 6
            sprintf('Trying to recurse into scope: "%s"', $scope)
41
        );
42 6
        if (!isset($this->config[$scope]) && $this->params->hasScope($scope)) {
43 6
            $this->config[$scope] = $this->loadScope($scope);
44 5
        } elseif (!isset($this->config[$scope])) {
45 2
            return $default;
46
        }
47 5
        return $this->resolvePath($configPath) ?? $default;
48
    }
49
50 1
    public function has(string $path): bool
51
    {
52 1
        return $this->get($path) !== null;
53
    }
54
55 6
    private function loadScope(string $scope)
56
    {
57 6
        $this->preLoadInterpolations[$scope] = true;
58 6
        $locations = $this->params->getLocations($scope);
59 6
        $sources = $this->params->getSources($scope);
60 6
        $loader = $this->params->getLoader($scope);
61 6
        if (!$loader instanceof ArrayConfigLoader) {
62 2
            $sources = $this->interpolateConfigValues($sources);
63
        }
64 5
        $locations = $this->interpolateConfigValues($locations);
65 5
        unset($this->preLoadInterpolations[$scope]);
66
67 5
        $this->config[$scope] = $loader->load($locations, $sources);
68 5
        return $this->interpolateConfigValues($this->config[$scope]);
69
    }
70
71 5
    private function resolvePath(ConfigPathInterface $path)
72
    {
73 5
        $pathPos = 0;
74 5
        $pathLen = $path->getLength();
75 5
        $pathParts = $path->getParts();
76 5
        $value = &$this->config[$path->getScope()];
77 5
        while (!empty($pathParts)) {
78 5
            $pathPos++;
79 5
            $pathPart = array_shift($pathParts);
80 5
            if (!isset($value[$pathPart])) {
81 2
                if ($pathPos === $pathLen) {
82 1
                    return null;
83
                }
84 2
                array_unshift($pathParts, $pathPart.$path->getSeparator().array_shift($pathParts));
85 2
                continue;
86
            }
87 5
            Assertion::isArray($value, sprintf('Trying to traverse non array-value with path: "%s"', $path));
88 5
            $value = &$value[$pathPart];
89
        }
90 5
        return $value;
91
    }
92
93 6
    private function interpolateConfigValues(array $config): array
94
    {
95 6
        foreach ($config as $key => $value) {
96 6
            if (is_array($value)) {
97 5
                $config[$key] = $this->interpolateConfigValues($value);
98 6
            } elseif (is_string($value) && preg_match_all(self::INTERPOLATION_PATTERN, $value, $matches)) {
99 3
                $replacements = [];
100 3
                foreach ($matches[2] as $configKey) {
101 3
                    $replacements[] = $this->get($configKey);
102
                }
103 2
                $config[$key] = str_replace($matches[0], $replacements, $value);
104
            }
105
        }
106 5
        return $config;
107
    }
108
}
109