PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/symfony/src/Symfony/Component/DependencyInjection/Container.php

https://github.com/casoetan/ServerGroveLiveChat
PHP | 395 lines | 179 code | 50 blank | 166 comment | 24 complexity | 0e2767c5566f1d2622c0b238a3ae9b55 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, ISC, BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection;
  11. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  12. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  13. use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
  14. /**
  15. * Container is a dependency injection container.
  16. *
  17. * It gives access to object instances (services).
  18. *
  19. * Services and parameters are simple key/pair stores.
  20. *
  21. * Parameter and service keys are case insensitive.
  22. *
  23. * A service id can contain lowercased letters, digits, underscores, and dots.
  24. * Underscores are used to separate words, and dots to group services
  25. * under namespaces:
  26. *
  27. * <ul>
  28. * <li>request</li>
  29. * <li>mysql_session_storage</li>
  30. * <li>symfony.mysql_session_storage</li>
  31. * </ul>
  32. *
  33. * A service can also be defined by creating a method named
  34. * getXXXService(), where XXX is the camelized version of the id:
  35. *
  36. * <ul>
  37. * <li>request -> getRequestService()</li>
  38. * <li>mysql_session_storage -> getMysqlSessionStorageService()</li>
  39. * <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li>
  40. * </ul>
  41. *
  42. * The container can have three possible behaviors when a service does not exist:
  43. *
  44. * * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
  45. * * NULL_ON_INVALID_REFERENCE: Returns null
  46. * * IGNORE_ON_INVALID_REFERENCE: Ignores the wrapping command asking for the reference
  47. * (for instance, ignore a setter if the service does not exist)
  48. *
  49. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  50. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  51. */
  52. class Container implements ContainerInterface
  53. {
  54. protected $parameterBag;
  55. protected $services;
  56. protected $scopes;
  57. protected $scopeChildren;
  58. protected $scopedServices;
  59. protected $scopeStacks;
  60. protected $loading = array();
  61. /**
  62. * Constructor.
  63. *
  64. * @param ParameterBagInterface $parameterBag A ParameterBagInterface instance
  65. */
  66. public function __construct(ParameterBagInterface $parameterBag = null)
  67. {
  68. $this->parameterBag = null === $parameterBag ? new ParameterBag() : $parameterBag;
  69. $this->services =
  70. $this->scopes =
  71. $this->scopeChildren =
  72. $this->scopedServices =
  73. $this->scopeStacks = array();
  74. $this->set('service_container', $this);
  75. }
  76. /**
  77. * Compiles the container.
  78. *
  79. * This method does two things:
  80. *
  81. * * Parameter values are resolved;
  82. * * The parameter bag is frozen.
  83. */
  84. public function compile()
  85. {
  86. $this->parameterBag->resolve();
  87. $this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
  88. }
  89. /**
  90. * Returns true if the container parameter bag are frozen.
  91. *
  92. * @return Boolean true if the container parameter bag are frozen, false otherwise
  93. */
  94. public function isFrozen()
  95. {
  96. return $this->parameterBag instanceof FrozenParameterBag;
  97. }
  98. /**
  99. * Gets the service container parameter bag.
  100. *
  101. * @return ParameterBagInterface A ParameterBagInterface instance
  102. */
  103. public function getParameterBag()
  104. {
  105. return $this->parameterBag;
  106. }
  107. /**
  108. * Gets a parameter.
  109. *
  110. * @param string $name The parameter name
  111. *
  112. * @return mixed The parameter value
  113. *
  114. * @throws \InvalidArgumentException if the parameter is not defined
  115. */
  116. public function getParameter($name)
  117. {
  118. return $this->parameterBag->get($name);
  119. }
  120. /**
  121. * Checks if a parameter exists.
  122. *
  123. * @param string $name The parameter name
  124. *
  125. * @return Boolean The presence of parameter in container
  126. */
  127. public function hasParameter($name)
  128. {
  129. return $this->parameterBag->has($name);
  130. }
  131. /**
  132. * Sets a parameter.
  133. *
  134. * @param string $name The parameter name
  135. * @param mixed $parameters The parameter value
  136. */
  137. public function setParameter($name, $value)
  138. {
  139. $this->parameterBag->set($name, $value);
  140. }
  141. /**
  142. * Sets a service.
  143. *
  144. * @param string $id The service identifier
  145. * @param object $service The service instance
  146. * @param string $scope The scope of the service
  147. */
  148. public function set($id, $service, $scope = self::SCOPE_CONTAINER)
  149. {
  150. if (self::SCOPE_PROTOTYPE === $scope) {
  151. throw new \InvalidArgumentException('You cannot set services of scope "prototype".');
  152. }
  153. $id = strtolower($id);
  154. if (self::SCOPE_CONTAINER !== $scope) {
  155. if (!isset($this->scopedServices[$scope])) {
  156. throw new \RuntimeException('You cannot set services of inactive scopes.');
  157. }
  158. $this->scopedServices[$scope][$id] = $service;
  159. }
  160. $this->services[$id] = $service;
  161. }
  162. /**
  163. * Returns true if the given service is defined.
  164. *
  165. * @param string $id The service identifier
  166. *
  167. * @return Boolean true if the service is defined, false otherwise
  168. */
  169. public function has($id)
  170. {
  171. $id = strtolower($id);
  172. return isset($this->services[$id]) || method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_')).'Service');
  173. }
  174. /**
  175. * Gets a service.
  176. *
  177. * If a service is both defined through a set() method and
  178. * with a set*Service() method, the former has always precedence.
  179. *
  180. * @param string $id The service identifier
  181. * @param int $invalidBehavior The behavior when the service does not exist
  182. *
  183. * @return object The associated service
  184. *
  185. * @throws \InvalidArgumentException if the service is not defined
  186. *
  187. * @see Reference
  188. */
  189. public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
  190. {
  191. $id = strtolower($id);
  192. if (isset($this->services[$id])) {
  193. return $this->services[$id];
  194. }
  195. if (isset($this->loading[$id])) {
  196. throw new \LogicException(sprintf('Circular reference detected for service "%s" (services currently loading: %s).', $id, implode(', ', array_keys($this->loading))));
  197. }
  198. if (method_exists($this, $method = 'get'.strtr($id, array('_' => '', '.' => '_')).'Service')) {
  199. $this->loading[$id] = true;
  200. $service = $this->$method();
  201. unset($this->loading[$id]);
  202. return $service;
  203. }
  204. if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
  205. throw new \InvalidArgumentException(sprintf('The service "%s" does not exist.', $id));
  206. }
  207. }
  208. /**
  209. * Gets all service ids.
  210. *
  211. * @return array An array of all defined service ids
  212. */
  213. public function getServiceIds()
  214. {
  215. $ids = array();
  216. $r = new \ReflectionClass($this);
  217. foreach ($r->getMethods() as $method) {
  218. if (preg_match('/^get(.+)Service$/', $method->getName(), $match)) {
  219. $ids[] = self::underscore($match[1]);
  220. }
  221. }
  222. return array_merge($ids, array_keys($this->services));
  223. }
  224. /**
  225. * This is called when you enter a scope
  226. *
  227. * @param string $name
  228. * @return void
  229. */
  230. public function enterScope($name)
  231. {
  232. if (!isset($this->scopes[$name])) {
  233. throw new \InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
  234. }
  235. if (self::SCOPE_CONTAINER !== $this->scopes[$name] && !isset($this->scopedServices[$this->scopes[$name]])) {
  236. throw new \RuntimeException(sprintf('The parent scope "%s" must be active when entering this scope.', $this->scopes[$name]));
  237. }
  238. // check if a scope of this name is already active, if so we need to
  239. // remove all services of this scope, and those of any of its child
  240. // scopes from the global services map
  241. if (isset($this->scopedServices[$name])) {
  242. $services = array($this->services, $name => $this->scopedServices[$name]);
  243. unset($this->scopedServices[$name]);
  244. foreach ($this->scopeChildren[$name] as $child) {
  245. $services[$child] = $this->scopedServices[$child];
  246. unset($this->scopedServices[$child]);
  247. }
  248. // update global map
  249. $this->services = call_user_func_array('array_diff_key', $services);
  250. array_shift($services);
  251. // add stack entry for this scope so we can restore the removed services later
  252. if (!isset($this->scopeStacks[$name])) {
  253. $this->scopeStacks[$name] = new \SplStack();
  254. }
  255. $this->scopeStacks[$name]->push($services);
  256. }
  257. $this->scopedServices[$name] = array();
  258. }
  259. /**
  260. * This is called to leave the current scope, and move back to the parent
  261. * scope.
  262. *
  263. * @return void
  264. */
  265. public function leaveScope($name)
  266. {
  267. if (!isset($this->scopedServices[$name])) {
  268. throw new \InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
  269. }
  270. // remove all services of this scope, or any of its child scopes from
  271. // the global service map
  272. $services = array($this->services, $this->scopedServices[$name]);
  273. unset($this->scopedServices[$name]);
  274. foreach ($this->scopeChildren[$name] as $child) {
  275. if (!isset($this->scopedServices[$child])) {
  276. continue;
  277. }
  278. $services[] = $this->scopedServices[$child];
  279. unset($this->scopedServices[$child]);
  280. }
  281. $this->services = call_user_func_array('array_diff_key', $services);
  282. // check if we need to restore services of a previous scope of this type
  283. if (isset($this->scopeStacks[$name]) && count($this->scopeStacks[$name]) > 0) {
  284. $services = $this->scopeStacks[$name]->pop();
  285. $this->scopedServices += $services;
  286. array_unshift($services, $this->services);
  287. $this->services = call_user_func_array('array_merge', $services);
  288. }
  289. }
  290. /**
  291. * Adds a scope to the container
  292. *
  293. * @param string $name
  294. * @param string $parentScope
  295. * @return void
  296. */
  297. public function addScope($name, $parentScope = self::SCOPE_CONTAINER)
  298. {
  299. if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
  300. throw new \InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
  301. }
  302. if (isset($this->scopes[$name])) {
  303. throw new \InvalidArgumentException(sprintf('A scope with name "%s" already exists.', $name));
  304. }
  305. if (self::SCOPE_CONTAINER !== $parentScope && !isset($this->scopes[$parentScope])) {
  306. throw new \InvalidArgumentException(sprintf('The parent scope "%s" does not exist, or is invalid.', $parentScope));
  307. }
  308. $this->scopes[$name] = $parentScope;
  309. $this->scopeChildren[$name] = array();
  310. // normalize the child relations
  311. while ($parentScope !== self::SCOPE_CONTAINER) {
  312. $this->scopeChildren[$parentScope][] = $name;
  313. $parentScope = $this->scopes[$parentScope];
  314. }
  315. }
  316. /**
  317. * Returns whether this container has a certain scope
  318. *
  319. * @return Boolean
  320. */
  321. public function hasScope($name)
  322. {
  323. return isset($this->scopes[$name]);
  324. }
  325. /**
  326. * Returns whether this scope is currently active
  327. *
  328. * This does not actually check if the passed scope actually exists.
  329. *
  330. * @param string $name
  331. * @return Boolean
  332. */
  333. public function isScopeActive($name)
  334. {
  335. return isset($this->scopedServices[$name]);
  336. }
  337. static public function camelize($id)
  338. {
  339. return preg_replace(array('/(?:^|_)+(.)/e', '/\.(.)/e'), array("strtoupper('\\1')", "'_'.strtoupper('\\1')"), $id);
  340. }
  341. static public function underscore($id)
  342. {
  343. return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($id, '_', '.')));
  344. }
  345. }