Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of the Symfony package.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Symfony\Component\DependencyInjection\ParameterBag;
|
Chris@0
|
13
|
Chris@17
|
14 use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
|
Chris@0
|
15 use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
Chris@0
|
16 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
Chris@0
|
17
|
Chris@0
|
18 /**
|
Chris@0
|
19 * Holds parameters.
|
Chris@0
|
20 *
|
Chris@0
|
21 * @author Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
22 */
|
Chris@0
|
23 class ParameterBag implements ParameterBagInterface
|
Chris@0
|
24 {
|
Chris@17
|
25 protected $parameters = [];
|
Chris@0
|
26 protected $resolved = false;
|
Chris@0
|
27
|
Chris@17
|
28 private $normalizedNames = [];
|
Chris@14
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * @param array $parameters An array of parameters
|
Chris@0
|
32 */
|
Chris@17
|
33 public function __construct(array $parameters = [])
|
Chris@0
|
34 {
|
Chris@0
|
35 $this->add($parameters);
|
Chris@0
|
36 }
|
Chris@0
|
37
|
Chris@0
|
38 /**
|
Chris@0
|
39 * Clears all parameters.
|
Chris@0
|
40 */
|
Chris@0
|
41 public function clear()
|
Chris@0
|
42 {
|
Chris@17
|
43 $this->parameters = [];
|
Chris@0
|
44 }
|
Chris@0
|
45
|
Chris@0
|
46 /**
|
Chris@0
|
47 * Adds parameters to the service container parameters.
|
Chris@0
|
48 *
|
Chris@0
|
49 * @param array $parameters An array of parameters
|
Chris@0
|
50 */
|
Chris@0
|
51 public function add(array $parameters)
|
Chris@0
|
52 {
|
Chris@0
|
53 foreach ($parameters as $key => $value) {
|
Chris@14
|
54 $this->set($key, $value);
|
Chris@0
|
55 }
|
Chris@0
|
56 }
|
Chris@0
|
57
|
Chris@0
|
58 /**
|
Chris@0
|
59 * {@inheritdoc}
|
Chris@0
|
60 */
|
Chris@0
|
61 public function all()
|
Chris@0
|
62 {
|
Chris@0
|
63 return $this->parameters;
|
Chris@0
|
64 }
|
Chris@0
|
65
|
Chris@0
|
66 /**
|
Chris@0
|
67 * {@inheritdoc}
|
Chris@0
|
68 */
|
Chris@0
|
69 public function get($name)
|
Chris@0
|
70 {
|
Chris@14
|
71 $name = $this->normalizeName($name);
|
Chris@0
|
72
|
Chris@18
|
73 if (!\array_key_exists($name, $this->parameters)) {
|
Chris@0
|
74 if (!$name) {
|
Chris@0
|
75 throw new ParameterNotFoundException($name);
|
Chris@0
|
76 }
|
Chris@0
|
77
|
Chris@17
|
78 $alternatives = [];
|
Chris@0
|
79 foreach ($this->parameters as $key => $parameterValue) {
|
Chris@0
|
80 $lev = levenshtein($name, $key);
|
Chris@17
|
81 if ($lev <= \strlen($name) / 3 || false !== strpos($key, $name)) {
|
Chris@0
|
82 $alternatives[] = $key;
|
Chris@0
|
83 }
|
Chris@0
|
84 }
|
Chris@0
|
85
|
Chris@0
|
86 $nonNestedAlternative = null;
|
Chris@17
|
87 if (!\count($alternatives) && false !== strpos($name, '.')) {
|
Chris@0
|
88 $namePartsLength = array_map('strlen', explode('.', $name));
|
Chris@0
|
89 $key = substr($name, 0, -1 * (1 + array_pop($namePartsLength)));
|
Chris@17
|
90 while (\count($namePartsLength)) {
|
Chris@0
|
91 if ($this->has($key)) {
|
Chris@17
|
92 if (\is_array($this->get($key))) {
|
Chris@0
|
93 $nonNestedAlternative = $key;
|
Chris@0
|
94 }
|
Chris@0
|
95 break;
|
Chris@0
|
96 }
|
Chris@0
|
97
|
Chris@0
|
98 $key = substr($key, 0, -1 * (1 + array_pop($namePartsLength)));
|
Chris@0
|
99 }
|
Chris@0
|
100 }
|
Chris@0
|
101
|
Chris@0
|
102 throw new ParameterNotFoundException($name, null, null, null, $alternatives, $nonNestedAlternative);
|
Chris@0
|
103 }
|
Chris@0
|
104
|
Chris@0
|
105 return $this->parameters[$name];
|
Chris@0
|
106 }
|
Chris@0
|
107
|
Chris@0
|
108 /**
|
Chris@0
|
109 * Sets a service container parameter.
|
Chris@0
|
110 *
|
Chris@0
|
111 * @param string $name The parameter name
|
Chris@0
|
112 * @param mixed $value The parameter value
|
Chris@0
|
113 */
|
Chris@0
|
114 public function set($name, $value)
|
Chris@0
|
115 {
|
Chris@14
|
116 $this->parameters[$this->normalizeName($name)] = $value;
|
Chris@0
|
117 }
|
Chris@0
|
118
|
Chris@0
|
119 /**
|
Chris@0
|
120 * {@inheritdoc}
|
Chris@0
|
121 */
|
Chris@0
|
122 public function has($name)
|
Chris@0
|
123 {
|
Chris@18
|
124 return \array_key_exists($this->normalizeName($name), $this->parameters);
|
Chris@0
|
125 }
|
Chris@0
|
126
|
Chris@0
|
127 /**
|
Chris@0
|
128 * Removes a parameter.
|
Chris@0
|
129 *
|
Chris@0
|
130 * @param string $name The parameter name
|
Chris@0
|
131 */
|
Chris@0
|
132 public function remove($name)
|
Chris@0
|
133 {
|
Chris@14
|
134 unset($this->parameters[$this->normalizeName($name)]);
|
Chris@0
|
135 }
|
Chris@0
|
136
|
Chris@0
|
137 /**
|
Chris@0
|
138 * {@inheritdoc}
|
Chris@0
|
139 */
|
Chris@0
|
140 public function resolve()
|
Chris@0
|
141 {
|
Chris@0
|
142 if ($this->resolved) {
|
Chris@0
|
143 return;
|
Chris@0
|
144 }
|
Chris@0
|
145
|
Chris@17
|
146 $parameters = [];
|
Chris@0
|
147 foreach ($this->parameters as $key => $value) {
|
Chris@0
|
148 try {
|
Chris@0
|
149 $value = $this->resolveValue($value);
|
Chris@0
|
150 $parameters[$key] = $this->unescapeValue($value);
|
Chris@0
|
151 } catch (ParameterNotFoundException $e) {
|
Chris@0
|
152 $e->setSourceKey($key);
|
Chris@0
|
153
|
Chris@0
|
154 throw $e;
|
Chris@0
|
155 }
|
Chris@0
|
156 }
|
Chris@0
|
157
|
Chris@0
|
158 $this->parameters = $parameters;
|
Chris@0
|
159 $this->resolved = true;
|
Chris@0
|
160 }
|
Chris@0
|
161
|
Chris@0
|
162 /**
|
Chris@0
|
163 * Replaces parameter placeholders (%name%) by their values.
|
Chris@0
|
164 *
|
Chris@0
|
165 * @param mixed $value A value
|
Chris@0
|
166 * @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
|
Chris@0
|
167 *
|
Chris@0
|
168 * @return mixed The resolved value
|
Chris@0
|
169 *
|
Chris@0
|
170 * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
|
Chris@0
|
171 * @throws ParameterCircularReferenceException if a circular reference if detected
|
Chris@14
|
172 * @throws RuntimeException when a given parameter has a type problem
|
Chris@0
|
173 */
|
Chris@17
|
174 public function resolveValue($value, array $resolving = [])
|
Chris@0
|
175 {
|
Chris@14
|
176 if (\is_array($value)) {
|
Chris@17
|
177 $args = [];
|
Chris@0
|
178 foreach ($value as $k => $v) {
|
Chris@14
|
179 $args[\is_string($k) ? $this->resolveValue($k, $resolving) : $k] = $this->resolveValue($v, $resolving);
|
Chris@0
|
180 }
|
Chris@0
|
181
|
Chris@0
|
182 return $args;
|
Chris@0
|
183 }
|
Chris@0
|
184
|
Chris@14
|
185 if (!\is_string($value) || 2 > \strlen($value)) {
|
Chris@0
|
186 return $value;
|
Chris@0
|
187 }
|
Chris@0
|
188
|
Chris@0
|
189 return $this->resolveString($value, $resolving);
|
Chris@0
|
190 }
|
Chris@0
|
191
|
Chris@0
|
192 /**
|
Chris@0
|
193 * Resolves parameters inside a string.
|
Chris@0
|
194 *
|
Chris@0
|
195 * @param string $value The string to resolve
|
Chris@0
|
196 * @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
|
Chris@0
|
197 *
|
Chris@0
|
198 * @return string The resolved string
|
Chris@0
|
199 *
|
Chris@0
|
200 * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
|
Chris@0
|
201 * @throws ParameterCircularReferenceException if a circular reference if detected
|
Chris@14
|
202 * @throws RuntimeException when a given parameter has a type problem
|
Chris@0
|
203 */
|
Chris@17
|
204 public function resolveString($value, array $resolving = [])
|
Chris@0
|
205 {
|
Chris@0
|
206 // we do this to deal with non string values (Boolean, integer, ...)
|
Chris@0
|
207 // as the preg_replace_callback throw an exception when trying
|
Chris@0
|
208 // a non-string in a parameter value
|
Chris@0
|
209 if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
|
Chris@0
|
210 $key = $match[1];
|
Chris@14
|
211 $lcKey = strtolower($key); // strtolower() to be removed in 4.0
|
Chris@0
|
212
|
Chris@0
|
213 if (isset($resolving[$lcKey])) {
|
Chris@0
|
214 throw new ParameterCircularReferenceException(array_keys($resolving));
|
Chris@0
|
215 }
|
Chris@0
|
216
|
Chris@0
|
217 $resolving[$lcKey] = true;
|
Chris@0
|
218
|
Chris@0
|
219 return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
|
Chris@0
|
220 }
|
Chris@0
|
221
|
Chris@0
|
222 return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($resolving, $value) {
|
Chris@0
|
223 // skip %%
|
Chris@0
|
224 if (!isset($match[1])) {
|
Chris@0
|
225 return '%%';
|
Chris@0
|
226 }
|
Chris@0
|
227
|
Chris@0
|
228 $key = $match[1];
|
Chris@14
|
229 $lcKey = strtolower($key); // strtolower() to be removed in 4.0
|
Chris@0
|
230 if (isset($resolving[$lcKey])) {
|
Chris@0
|
231 throw new ParameterCircularReferenceException(array_keys($resolving));
|
Chris@0
|
232 }
|
Chris@0
|
233
|
Chris@0
|
234 $resolved = $this->get($key);
|
Chris@0
|
235
|
Chris@17
|
236 if (!\is_string($resolved) && !is_numeric($resolved)) {
|
Chris@17
|
237 throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, \gettype($resolved), $value));
|
Chris@0
|
238 }
|
Chris@0
|
239
|
Chris@0
|
240 $resolved = (string) $resolved;
|
Chris@0
|
241 $resolving[$lcKey] = true;
|
Chris@0
|
242
|
Chris@0
|
243 return $this->isResolved() ? $resolved : $this->resolveString($resolved, $resolving);
|
Chris@0
|
244 }, $value);
|
Chris@0
|
245 }
|
Chris@0
|
246
|
Chris@0
|
247 public function isResolved()
|
Chris@0
|
248 {
|
Chris@0
|
249 return $this->resolved;
|
Chris@0
|
250 }
|
Chris@0
|
251
|
Chris@0
|
252 /**
|
Chris@0
|
253 * {@inheritdoc}
|
Chris@0
|
254 */
|
Chris@0
|
255 public function escapeValue($value)
|
Chris@0
|
256 {
|
Chris@17
|
257 if (\is_string($value)) {
|
Chris@0
|
258 return str_replace('%', '%%', $value);
|
Chris@0
|
259 }
|
Chris@0
|
260
|
Chris@17
|
261 if (\is_array($value)) {
|
Chris@17
|
262 $result = [];
|
Chris@0
|
263 foreach ($value as $k => $v) {
|
Chris@0
|
264 $result[$k] = $this->escapeValue($v);
|
Chris@0
|
265 }
|
Chris@0
|
266
|
Chris@0
|
267 return $result;
|
Chris@0
|
268 }
|
Chris@0
|
269
|
Chris@0
|
270 return $value;
|
Chris@0
|
271 }
|
Chris@0
|
272
|
Chris@0
|
273 /**
|
Chris@0
|
274 * {@inheritdoc}
|
Chris@0
|
275 */
|
Chris@0
|
276 public function unescapeValue($value)
|
Chris@0
|
277 {
|
Chris@17
|
278 if (\is_string($value)) {
|
Chris@0
|
279 return str_replace('%%', '%', $value);
|
Chris@0
|
280 }
|
Chris@0
|
281
|
Chris@17
|
282 if (\is_array($value)) {
|
Chris@17
|
283 $result = [];
|
Chris@0
|
284 foreach ($value as $k => $v) {
|
Chris@0
|
285 $result[$k] = $this->unescapeValue($v);
|
Chris@0
|
286 }
|
Chris@0
|
287
|
Chris@0
|
288 return $result;
|
Chris@0
|
289 }
|
Chris@0
|
290
|
Chris@0
|
291 return $value;
|
Chris@0
|
292 }
|
Chris@14
|
293
|
Chris@14
|
294 private function normalizeName($name)
|
Chris@14
|
295 {
|
Chris@14
|
296 if (isset($this->normalizedNames[$normalizedName = strtolower($name)])) {
|
Chris@14
|
297 $normalizedName = $this->normalizedNames[$normalizedName];
|
Chris@14
|
298 if ((string) $name !== $normalizedName) {
|
Chris@14
|
299 @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED);
|
Chris@14
|
300 }
|
Chris@14
|
301 } else {
|
Chris@14
|
302 $normalizedName = $this->normalizedNames[$normalizedName] = (string) $name;
|
Chris@14
|
303 }
|
Chris@14
|
304
|
Chris@14
|
305 return $normalizedName;
|
Chris@14
|
306 }
|
Chris@0
|
307 }
|