1 | <?php |
||
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 | } |
||
45 | 5 | return $this->resolvePath($configPath) ?? $default; |
|
46 | } |
||
47 | |||
48 | 1 | public function has(string $path): bool |
|
49 | { |
||
50 | 1 | return $this->get($path) !== null; |
|
51 | } |
||
52 | |||
53 | 6 | private function loadScope(string $scope) |
|
54 | { |
||
55 | 6 | $this->preLoadInterpolations[$scope] = true; |
|
56 | 6 | $locations = $this->params->getLocations($scope); |
|
57 | 6 | $sources = $this->params->getSources($scope); |
|
58 | 6 | $loader = $this->params->getLoader($scope); |
|
59 | 6 | if (!$loader instanceof ArrayConfigLoader) { |
|
60 | 2 | $sources = $this->interpolateConfigValues($sources); |
|
61 | } |
||
62 | 5 | $locations = $this->interpolateConfigValues($locations); |
|
63 | 5 | unset($this->preLoadInterpolations[$scope]); |
|
64 | |||
65 | 5 | $this->config[$scope] = $loader->load($locations, $sources); |
|
66 | 5 | return $this->interpolateConfigValues($this->config[$scope]); |
|
67 | } |
||
68 | |||
69 | 5 | private function resolvePath(ConfigPathInterface $path) |
|
70 | { |
||
71 | 5 | $scope = $path->getScope(); |
|
72 | 5 | if (!isset($this->config[$scope])) { |
|
73 | 2 | return null; |
|
74 | } |
||
75 | 5 | $value = &$this->config[$scope]; |
|
76 | 5 | $pathParts = $path->getParts(); |
|
77 | 5 | $pathLen = $path->getLength(); |
|
78 | 5 | $pathPos = 0; |
|
79 | 5 | while (!empty($pathParts)) { |
|
80 | 5 | $pathPart = array_shift($pathParts); |
|
81 | 5 | $pathPos++; |
|
82 | 5 | if (!isset($value[$pathPart])) { |
|
83 | 2 | if ($pathPos === $pathLen) { |
|
84 | 1 | return null; |
|
85 | } else { |
||
86 | 2 | array_unshift($pathParts, $pathPart.$path->getSeparator().array_shift($pathParts)); |
|
87 | 2 | continue; |
|
88 | } |
||
89 | } |
||
90 | 5 | Assertion::isArray($value, sprintf('Trying to traverse non array-value with path: "%s"', $path)); |
|
91 | 5 | $value = &$value[$pathPart]; |
|
92 | } |
||
93 | 5 | return $value; |
|
94 | } |
||
95 | |||
96 | 6 | private function interpolateConfigValues(array $config): array |
|
111 | } |
||
112 |