Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/dependency-injection/Container.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of the Symfony package. | |
5 * | |
6 * (c) Fabien Potencier <fabien@symfony.com> | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Symfony\Component\DependencyInjection; | |
13 | |
14 use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException; | |
15 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | |
16 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; | |
17 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; | |
18 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |
19 use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; | |
20 use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; | |
21 | |
22 /** | |
23 * Container is a dependency injection container. | |
24 * | |
25 * It gives access to object instances (services). | |
26 * | |
27 * Services and parameters are simple key/pair stores. | |
28 * | |
29 * Parameter and service keys are case insensitive. | |
30 * | |
31 * A service id can contain lowercased letters, digits, underscores, and dots. | |
32 * Underscores are used to separate words, and dots to group services | |
33 * under namespaces: | |
34 * | |
35 * <ul> | |
36 * <li>request</li> | |
37 * <li>mysql_session_storage</li> | |
38 * <li>symfony.mysql_session_storage</li> | |
39 * </ul> | |
40 * | |
41 * A service can also be defined by creating a method named | |
42 * getXXXService(), where XXX is the camelized version of the id: | |
43 * | |
44 * <ul> | |
45 * <li>request -> getRequestService()</li> | |
46 * <li>mysql_session_storage -> getMysqlSessionStorageService()</li> | |
47 * <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li> | |
48 * </ul> | |
49 * | |
50 * The container can have three possible behaviors when a service does not exist: | |
51 * | |
52 * * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default) | |
53 * * NULL_ON_INVALID_REFERENCE: Returns null | |
54 * * IGNORE_ON_INVALID_REFERENCE: Ignores the wrapping command asking for the reference | |
55 * (for instance, ignore a setter if the service does not exist) | |
56 * | |
57 * @author Fabien Potencier <fabien@symfony.com> | |
58 * @author Johannes M. Schmitt <schmittjoh@gmail.com> | |
59 */ | |
60 class Container implements ResettableContainerInterface | |
61 { | |
62 /** | |
63 * @var ParameterBagInterface | |
64 */ | |
65 protected $parameterBag; | |
66 | |
67 protected $services = array(); | |
68 protected $methodMap = array(); | |
69 protected $privates = array(); | |
70 protected $aliases = array(); | |
71 protected $loading = array(); | |
72 | |
73 private $underscoreMap = array('_' => '', '.' => '_', '\\' => '_'); | |
74 private $envCache = array(); | |
75 | |
76 /** | |
77 * @param ParameterBagInterface $parameterBag A ParameterBagInterface instance | |
78 */ | |
79 public function __construct(ParameterBagInterface $parameterBag = null) | |
80 { | |
81 $this->parameterBag = $parameterBag ?: new EnvPlaceholderParameterBag(); | |
82 } | |
83 | |
84 /** | |
85 * Compiles the container. | |
86 * | |
87 * This method does two things: | |
88 * | |
89 * * Parameter values are resolved; | |
90 * * The parameter bag is frozen. | |
91 */ | |
92 public function compile() | |
93 { | |
94 $this->parameterBag->resolve(); | |
95 | |
96 $this->parameterBag = new FrozenParameterBag($this->parameterBag->all()); | |
97 } | |
98 | |
99 /** | |
100 * Returns true if the container parameter bag are frozen. | |
101 * | |
102 * @return bool true if the container parameter bag are frozen, false otherwise | |
103 */ | |
104 public function isFrozen() | |
105 { | |
106 return $this->parameterBag instanceof FrozenParameterBag; | |
107 } | |
108 | |
109 /** | |
110 * Gets the service container parameter bag. | |
111 * | |
112 * @return ParameterBagInterface A ParameterBagInterface instance | |
113 */ | |
114 public function getParameterBag() | |
115 { | |
116 return $this->parameterBag; | |
117 } | |
118 | |
119 /** | |
120 * Gets a parameter. | |
121 * | |
122 * @param string $name The parameter name | |
123 * | |
124 * @return mixed The parameter value | |
125 * | |
126 * @throws InvalidArgumentException if the parameter is not defined | |
127 */ | |
128 public function getParameter($name) | |
129 { | |
130 return $this->parameterBag->get($name); | |
131 } | |
132 | |
133 /** | |
134 * Checks if a parameter exists. | |
135 * | |
136 * @param string $name The parameter name | |
137 * | |
138 * @return bool The presence of parameter in container | |
139 */ | |
140 public function hasParameter($name) | |
141 { | |
142 return $this->parameterBag->has($name); | |
143 } | |
144 | |
145 /** | |
146 * Sets a parameter. | |
147 * | |
148 * @param string $name The parameter name | |
149 * @param mixed $value The parameter value | |
150 */ | |
151 public function setParameter($name, $value) | |
152 { | |
153 $this->parameterBag->set($name, $value); | |
154 } | |
155 | |
156 /** | |
157 * Sets a service. | |
158 * | |
159 * Setting a service to null resets the service: has() returns false and get() | |
160 * behaves in the same way as if the service was never created. | |
161 * | |
162 * @param string $id The service identifier | |
163 * @param object $service The service instance | |
164 */ | |
165 public function set($id, $service) | |
166 { | |
167 $id = strtolower($id); | |
168 | |
169 if ('service_container' === $id) { | |
170 throw new InvalidArgumentException('You cannot set service "service_container".'); | |
171 } | |
172 | |
173 if (isset($this->aliases[$id])) { | |
174 unset($this->aliases[$id]); | |
175 } | |
176 | |
177 $this->services[$id] = $service; | |
178 | |
179 if (null === $service) { | |
180 unset($this->services[$id]); | |
181 } | |
182 | |
183 if (isset($this->privates[$id])) { | |
184 if (null === $service) { | |
185 @trigger_error(sprintf('Unsetting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.', $id), E_USER_DEPRECATED); | |
186 unset($this->privates[$id]); | |
187 } else { | |
188 @trigger_error(sprintf('Setting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0. A new public service will be created instead.', $id), E_USER_DEPRECATED); | |
189 } | |
190 } | |
191 } | |
192 | |
193 /** | |
194 * Returns true if the given service is defined. | |
195 * | |
196 * @param string $id The service identifier | |
197 * | |
198 * @return bool true if the service is defined, false otherwise | |
199 */ | |
200 public function has($id) | |
201 { | |
202 for ($i = 2;;) { | |
203 if ('service_container' === $id | |
204 || isset($this->aliases[$id]) | |
205 || isset($this->services[$id]) | |
206 ) { | |
207 return true; | |
208 } | |
209 | |
210 if (isset($this->privates[$id])) { | |
211 @trigger_error(sprintf('Checking for the existence of the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.', $id), E_USER_DEPRECATED); | |
212 } | |
213 | |
214 if (isset($this->methodMap[$id])) { | |
215 return true; | |
216 } | |
217 | |
218 if (--$i && $id !== $lcId = strtolower($id)) { | |
219 $id = $lcId; | |
220 continue; | |
221 } | |
222 | |
223 // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder, | |
224 // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper) | |
225 if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this, 'get'.strtr($id, $this->underscoreMap).'Service')) { | |
226 @trigger_error('Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', E_USER_DEPRECATED); | |
227 | |
228 return true; | |
229 } | |
230 | |
231 return false; | |
232 } | |
233 } | |
234 | |
235 /** | |
236 * Gets a service. | |
237 * | |
238 * If a service is defined both through a set() method and | |
239 * with a get{$id}Service() method, the former has always precedence. | |
240 * | |
241 * @param string $id The service identifier | |
242 * @param int $invalidBehavior The behavior when the service does not exist | |
243 * | |
244 * @return object The associated service | |
245 * | |
246 * @throws ServiceCircularReferenceException When a circular reference is detected | |
247 * @throws ServiceNotFoundException When the service is not defined | |
248 * @throws \Exception if an exception has been thrown when the service has been resolved | |
249 * | |
250 * @see Reference | |
251 */ | |
252 public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) | |
253 { | |
254 // Attempt to retrieve the service by checking first aliases then | |
255 // available services. Service IDs are case insensitive, however since | |
256 // this method can be called thousands of times during a request, avoid | |
257 // calling strtolower() unless necessary. | |
258 for ($i = 2;;) { | |
259 if ('service_container' === $id) { | |
260 return $this; | |
261 } | |
262 if (isset($this->aliases[$id])) { | |
263 $id = $this->aliases[$id]; | |
264 } | |
265 // Re-use shared service instance if it exists. | |
266 if (isset($this->services[$id])) { | |
267 return $this->services[$id]; | |
268 } | |
269 | |
270 if (isset($this->loading[$id])) { | |
271 throw new ServiceCircularReferenceException($id, array_keys($this->loading)); | |
272 } | |
273 | |
274 if (isset($this->methodMap[$id])) { | |
275 $method = $this->methodMap[$id]; | |
276 } elseif (--$i && $id !== $lcId = strtolower($id)) { | |
277 $id = $lcId; | |
278 continue; | |
279 } elseif (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this, $method = 'get'.strtr($id, $this->underscoreMap).'Service')) { | |
280 // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder, | |
281 // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper) | |
282 @trigger_error('Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', E_USER_DEPRECATED); | |
283 // $method is set to the right value, proceed | |
284 } else { | |
285 if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) { | |
286 if (!$id) { | |
287 throw new ServiceNotFoundException($id); | |
288 } | |
289 | |
290 $alternatives = array(); | |
291 foreach ($this->getServiceIds() as $knownId) { | |
292 $lev = levenshtein($id, $knownId); | |
293 if ($lev <= strlen($id) / 3 || false !== strpos($knownId, $id)) { | |
294 $alternatives[] = $knownId; | |
295 } | |
296 } | |
297 | |
298 throw new ServiceNotFoundException($id, null, null, $alternatives); | |
299 } | |
300 | |
301 return; | |
302 } | |
303 if (isset($this->privates[$id])) { | |
304 @trigger_error(sprintf('Requesting the "%s" private service is deprecated since Symfony 3.2 and won\'t be supported anymore in Symfony 4.0.', $id), E_USER_DEPRECATED); | |
305 } | |
306 | |
307 $this->loading[$id] = true; | |
308 | |
309 try { | |
310 $service = $this->$method(); | |
311 } catch (\Exception $e) { | |
312 unset($this->services[$id]); | |
313 | |
314 throw $e; | |
315 } finally { | |
316 unset($this->loading[$id]); | |
317 } | |
318 | |
319 return $service; | |
320 } | |
321 } | |
322 | |
323 /** | |
324 * Returns true if the given service has actually been initialized. | |
325 * | |
326 * @param string $id The service identifier | |
327 * | |
328 * @return bool true if service has already been initialized, false otherwise | |
329 */ | |
330 public function initialized($id) | |
331 { | |
332 $id = strtolower($id); | |
333 | |
334 if ('service_container' === $id) { | |
335 return false; | |
336 } | |
337 | |
338 if (isset($this->aliases[$id])) { | |
339 $id = $this->aliases[$id]; | |
340 } | |
341 | |
342 return isset($this->services[$id]); | |
343 } | |
344 | |
345 /** | |
346 * {@inheritdoc} | |
347 */ | |
348 public function reset() | |
349 { | |
350 $this->services = array(); | |
351 } | |
352 | |
353 /** | |
354 * Gets all service ids. | |
355 * | |
356 * @return array An array of all defined service ids | |
357 */ | |
358 public function getServiceIds() | |
359 { | |
360 $ids = array(); | |
361 | |
362 if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class) { | |
363 // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder, | |
364 // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper) | |
365 @trigger_error('Generating a dumped container without populating the method map is deprecated since 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', E_USER_DEPRECATED); | |
366 | |
367 foreach (get_class_methods($this) as $method) { | |
368 if (preg_match('/^get(.+)Service$/', $method, $match)) { | |
369 $ids[] = self::underscore($match[1]); | |
370 } | |
371 } | |
372 } | |
373 $ids[] = 'service_container'; | |
374 | |
375 return array_unique(array_merge($ids, array_keys($this->methodMap), array_keys($this->services))); | |
376 } | |
377 | |
378 /** | |
379 * Camelizes a string. | |
380 * | |
381 * @param string $id A string to camelize | |
382 * | |
383 * @return string The camelized string | |
384 */ | |
385 public static function camelize($id) | |
386 { | |
387 return strtr(ucwords(strtr($id, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => '')); | |
388 } | |
389 | |
390 /** | |
391 * A string to underscore. | |
392 * | |
393 * @param string $id The string to underscore | |
394 * | |
395 * @return string The underscored string | |
396 */ | |
397 public static function underscore($id) | |
398 { | |
399 return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), str_replace('_', '.', $id))); | |
400 } | |
401 | |
402 /** | |
403 * Fetches a variable from the environment. | |
404 * | |
405 * @param string The name of the environment variable | |
406 * | |
407 * @return scalar The value to use for the provided environment variable name | |
408 * | |
409 * @throws EnvNotFoundException When the environment variable is not found and has no default value | |
410 */ | |
411 protected function getEnv($name) | |
412 { | |
413 if (isset($this->envCache[$name]) || array_key_exists($name, $this->envCache)) { | |
414 return $this->envCache[$name]; | |
415 } | |
416 if (isset($_ENV[$name])) { | |
417 return $this->envCache[$name] = $_ENV[$name]; | |
418 } | |
419 if (false !== $env = getenv($name)) { | |
420 return $this->envCache[$name] = $env; | |
421 } | |
422 if (!$this->hasParameter("env($name)")) { | |
423 throw new EnvNotFoundException($name); | |
424 } | |
425 | |
426 return $this->envCache[$name] = $this->getParameter("env($name)"); | |
427 } | |
428 | |
429 private function __clone() | |
430 { | |
431 } | |
432 } |