Passed
Push — master ( 56ccd2...ba754a )
by Andy
02:56
created

Resolver::resolveParameter()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 37
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7.0099

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 4
nop 1
dl 0
loc 37
ccs 16
cts 17
cp 0.9412
crap 7.0099
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
namespace Palmtree\Container;
4
5
use Palmtree\Container\Exception\ParameterNotFoundException;
6
use Palmtree\Container\Exception\ServiceNotFoundException;
7
use Palmtree\Container\Exception\ServiceNotPublicException;
8
9
class Resolver
10
{
11
    /** Regex for single parameters e.g '%my.parameter%' */
12
    private const PATTERN_PARAMETER = '/^%([^%\s]+)%$/';
13
    /** Regex for multiple parameters in a string */
14
    private const PATTERN_MULTI_PARAMETER = '/%%|%([^%\s]+)%/';
15
    /** @var Container */
16
    private $container;
17
    /** @var array */
18
    private $containerServices;
19
    /** @var array */
20
    private $envCache = [];
21
22 27
    public function __construct(Container $container, array &$containerServices)
23
    {
24 27
        $this->container         = $container;
25 27
        $this->containerServices = &$containerServices;
26 27
    }
27
28 27
    public function resolveArgs(array $args): array
29
    {
30 27
        foreach ($args as $key => &$arg) {
31 25
            if (\is_array($arg)) {
32 24
                $arg = $this->resolveArgs($arg);
33
            } else {
34 25
                $arg = $this->resolveArg($arg);
35
            }
36
        }
37
38 27
        return $args;
39
    }
40
41
    /**
42
     * @param mixed $arg
43
     *
44
     * @return mixed
45
     *
46
     * @throws ServiceNotFoundException
47
     * @throws ParameterNotFoundException
48
     */
49 26
    public function resolveArg($arg)
50
    {
51 26
        if (!\is_string($arg)) {
52 23
            return $arg;
53
        }
54
55 26
        if ($arg[0] === '@') {
56 23
            return $this->inject(\substr($arg, 1));
57
        }
58
59 26
        return $this->resolveParameter($arg);
60
    }
61
62
    /**
63
     * @param string $key
64
     *
65
     * @return mixed
66
     *
67
     * @throws ServiceNotFoundException
68
     */
69 23
    private function inject(string $key)
70
    {
71
        try {
72 23
            $this->container->get($key);
73 23
        } catch (ServiceNotPublicException $e) {
74
            // Ensures the service is created. Private services are allowed to be injected.
75
        }
76
77 23
        return $this->containerServices[$key];
78
    }
79
80
    /**
81
     * @param string $arg
82
     *
83
     * @return mixed
84
     *
85
     * @throws ParameterNotFoundException
86
     */
87 26
    private function resolveParameter($arg)
88
    {
89
        // Resolve a single parameter value e.g %my_param%
90
        // Used for non-string values (boolean, integer etc)
91 26
        if (\preg_match(self::PATTERN_PARAMETER, $arg, $matches)) {
92 23
            $envKey = $this->getEnvParameterKey($matches[1]);
93
94 23
            if ($envKey !== null) {
95 23
                return $this->getEnv($envKey);
96
            }
97
98 23
            $constKey = $this->getConstParameterKey($matches[1]);
99
100 23
            if ($constKey !== null) {
101 23
                return \constant($constKey);
102
            }
103
104 23
            return $this->container->getParameter($matches[1]);
105
        }
106
107
        // Resolve multiple parameters in a string e.g /%parent_dir%/somewhere/%child_dir%
108
        return \preg_replace_callback(self::PATTERN_MULTI_PARAMETER, function ($matches) {
109
            // Skip %% to allow escaping percent signs
110 23
            if (!isset($matches[1])) {
111 23
                return '%';
112
            }
113
114 23
            if ($envKey = $this->getEnvParameterKey($matches[1])) {
115 23
                return $this->getEnv($envKey);
116
            }
117
118 23
            if ($constKey = $this->getConstParameterKey($matches[1])) {
119
                return \constant($constKey);
120
            }
121
122 23
            return $this->container->getParameter($matches[1]);
123 26
        }, $arg);
124
    }
125
126 23
    private function getEnvParameterKey(string $value): ?string
127
    {
128 23
        if (\strpos($value, 'env(') === 0 && \substr($value, -1) === ')' && $value !== 'env()') {
129 23
            return \substr($value, 4, -1);
130
        }
131
132 23
        return null;
133
    }
134
135 23
    private function getConstParameterKey(string $value): ?string
136
    {
137 23
        if (\strpos($value, 'constant(') === 0 && \substr($value, -1) === ')' && $value !== 'constant()') {
138 23
            return \substr($value, 9, -1);
139
        }
140
141 23
        return null;
142
    }
143
144
    /**
145
     * @param string $key
146
     *
147
     * @return string|bool
148
     */
149 23
    private function getEnv(string $key)
150
    {
151 23
        if (isset($this->envCache[$key]) || \array_key_exists($key, $this->envCache)) {
152 23
            return $this->envCache[$key];
153
        }
154
155 23
        if (!$envVar = \getenv($key)) {
156
            try {
157 22
                $envVar = $this->resolveArg($this->container->getParameter("env($key)"));
158
            } catch (ParameterNotFoundException $exception) {
159
                // do nothing
160
            }
161
        }
162
163 23
        $this->envCache[$key] = $envVar;
164
165 23
        return $this->envCache[$key];
166
    }
167
}
168