/library/Symfony/Components/sfServiceContainerBuilder.php

https://bitbucket.org/khuongduybui/openfisma · PHP · 351 lines · 182 code · 41 blank · 128 comment · 24 complexity · eb8cd45ac40e7c1a8cb80a323efffe61 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the symfony framework.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. /**
  11. * sfServiceContainerBuilder is a DI container that provides an interface to build the services.
  12. *
  13. * @package symfony
  14. * @subpackage dependency_injection
  15. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  16. * @version SVN: $Id: sfServiceContainerBuilder.php 269 2009-03-26 20:39:16Z fabien $
  17. */
  18. class sfServiceContainerBuilder extends sfServiceContainer
  19. {
  20. protected
  21. $definitions = array(),
  22. $aliases = array(),
  23. $loading = array();
  24. /**
  25. * Sets a service.
  26. *
  27. * @param string $id The service identifier
  28. * @param object $service The service instance
  29. */
  30. public function setService($id, $service)
  31. {
  32. unset($this->aliases[$id]);
  33. parent::setService($id, $service);
  34. }
  35. /**
  36. * Returns true if the given service is defined.
  37. *
  38. * @param string $id The service identifier
  39. *
  40. * @return Boolean true if the service is defined, false otherwise
  41. */
  42. public function hasService($id)
  43. {
  44. return isset($this->definitions[$id]) || isset($this->aliases[$id]) || parent::hasService($id);
  45. }
  46. /**
  47. * Gets a service.
  48. *
  49. * @param string $id The service identifier
  50. *
  51. * @return object The associated service
  52. *
  53. * @throw InvalidArgumentException if the service is not defined
  54. * @throw LogicException if the service has a circular reference to itself
  55. */
  56. public function getService($id)
  57. {
  58. try
  59. {
  60. return parent::getService($id);
  61. }
  62. catch (InvalidArgumentException $e)
  63. {
  64. if (isset($this->loading[$id]))
  65. {
  66. throw new LogicException(sprintf('The service "%s" has a circular reference to itself.', $id));
  67. }
  68. if (!$this->hasServiceDefinition($id) && isset($this->aliases[$id]))
  69. {
  70. return $this->getService($this->aliases[$id]);
  71. }
  72. $definition = $this->getServiceDefinition($id);
  73. $this->loading[$id] = true;
  74. if ($definition->isShared())
  75. {
  76. $service = $this->services[$id] = $this->createService($definition);
  77. }
  78. else
  79. {
  80. $service = $this->createService($definition);
  81. }
  82. unset($this->loading[$id]);
  83. return $service;
  84. }
  85. }
  86. /**
  87. * Gets all service ids.
  88. *
  89. * @return array An array of all defined service ids
  90. */
  91. public function getServiceIds()
  92. {
  93. return array_unique(array_merge(array_keys($this->getServiceDefinitions()), array_keys($this->aliases), parent::getServiceIds()));
  94. }
  95. /**
  96. * Sets an alias for an existing service.
  97. *
  98. * @param string $alias The alias to create
  99. * @param string $id The service to alias
  100. */
  101. public function setAlias($alias, $id)
  102. {
  103. $this->aliases[$alias] = $id;
  104. }
  105. /**
  106. * Gets all defined aliases.
  107. *
  108. * @return array An array of aliases
  109. */
  110. public function getAliases()
  111. {
  112. return $this->aliases;
  113. }
  114. /**
  115. * Registers a service definition.
  116. *
  117. * This methods allows for simple registration of service definition
  118. * with a fluid interface.
  119. *
  120. * @param string $id The service identifier
  121. * @param string $class The service class
  122. *
  123. * @return sfServiceDefinition A sfServiceDefinition instance
  124. */
  125. public function register($id, $class)
  126. {
  127. return $this->setServiceDefinition($id, new sfServiceDefinition($class));
  128. }
  129. /**
  130. * Adds the service definitions.
  131. *
  132. * @param array $definitions An array of service definitions
  133. */
  134. public function addServiceDefinitions(array $definitions)
  135. {
  136. foreach ($definitions as $id => $definition)
  137. {
  138. $this->setServiceDefinition($id, $definition);
  139. }
  140. }
  141. /**
  142. * Sets the service definitions.
  143. *
  144. * @param array $definitions An array of service definitions
  145. */
  146. public function setServiceDefinitions(array $definitions)
  147. {
  148. $this->definitions = array();
  149. $this->addServiceDefinitions($definitions);
  150. }
  151. /**
  152. * Gets all service definitions.
  153. *
  154. * @return array An array of sfServiceDefinition instances
  155. */
  156. public function getServiceDefinitions()
  157. {
  158. return $this->definitions;
  159. }
  160. /**
  161. * Sets a service definition.
  162. *
  163. * @param string $id The service identifier
  164. * @param sfServiceDefinition $definition A sfServiceDefinition instance
  165. */
  166. public function setServiceDefinition($id, sfServiceDefinition $definition)
  167. {
  168. unset($this->aliases[$id]);
  169. return $this->definitions[$id] = $definition;
  170. }
  171. /**
  172. * Returns true if a service definition exists under the given identifier.
  173. *
  174. * @param string $id The service identifier
  175. *
  176. * @return Boolean true if the service definition exists, false otherwise
  177. */
  178. public function hasServiceDefinition($id)
  179. {
  180. return array_key_exists($id, $this->definitions);
  181. }
  182. /**
  183. * Gets a service definition.
  184. *
  185. * @param string $id The service identifier
  186. *
  187. * @return sfServiceDefinition A sfServiceDefinition instance
  188. *
  189. * @throw InvalidArgumentException if the service definition does not exist
  190. */
  191. public function getServiceDefinition($id)
  192. {
  193. if (!$this->hasServiceDefinition($id))
  194. {
  195. throw new InvalidArgumentException(sprintf('The service definition "%s" does not exist.', $id));
  196. }
  197. return $this->definitions[$id];
  198. }
  199. /**
  200. * Creates a service for a service definition.
  201. *
  202. * @param sfServiceDefinition $definition A service definition instance
  203. *
  204. * @return object The service described by the service definition
  205. */
  206. protected function createService(sfServiceDefinition $definition)
  207. {
  208. if (null !== $definition->getFile())
  209. {
  210. require_once $this->resolveValue($definition->getFile());
  211. }
  212. $r = new ReflectionClass($this->resolveValue($definition->getClass()));
  213. $arguments = $this->resolveServices($this->resolveValue($definition->getArguments()));
  214. if (null !== $definition->getConstructor())
  215. {
  216. $service = call_user_func_array(array($this->resolveValue($definition->getClass()), $definition->getConstructor()), $arguments);
  217. }
  218. else
  219. {
  220. $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
  221. }
  222. foreach ($definition->getMethodCalls() as $call)
  223. {
  224. call_user_func_array(array($service, $call[0]), $this->resolveServices($this->resolveValue($call[1])));
  225. }
  226. if ($callable = $definition->getConfigurator())
  227. {
  228. if (is_array($callable) && is_object($callable[0]) && $callable[0] instanceof sfServiceReference)
  229. {
  230. $callable[0] = $this->getService((string) $callable[0]);
  231. }
  232. elseif (is_array($callable))
  233. {
  234. $callable[0] = $this->resolveValue($callable[0]);
  235. }
  236. if (!is_callable($callable))
  237. {
  238. throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
  239. }
  240. call_user_func($callable, $service);
  241. }
  242. return $service;
  243. }
  244. /**
  245. * Replaces parameter placeholders (%name%) by their values.
  246. *
  247. * @param mixed $value A value
  248. *
  249. * @return mixed The same value with all placeholders replaced by their values
  250. *
  251. * @throw RuntimeException if a placeholder references a parameter that does not exist
  252. */
  253. public function resolveValue($value)
  254. {
  255. if (is_array($value))
  256. {
  257. $args = array();
  258. foreach ($value as $k => $v)
  259. {
  260. $args[$this->resolveValue($k)] = $this->resolveValue($v);
  261. }
  262. $value = $args;
  263. }
  264. else if (is_string($value))
  265. {
  266. if (preg_match('/^%([^%]+)%$/', $value, $match))
  267. {
  268. // we do this to deal with non string values (boolean, integer, ...)
  269. // the preg_replace_callback converts them to strings
  270. if (!$this->hasParameter($name = strtolower($match[1])))
  271. {
  272. throw new RuntimeException(sprintf('The parameter "%s" must be defined.', $name));
  273. }
  274. $value = $this->getParameter($name);
  275. }
  276. else
  277. {
  278. $value = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', array($this, 'replaceParameter'), $value));
  279. }
  280. }
  281. return $value;
  282. }
  283. /**
  284. * Replaces service references by the real service instance.
  285. *
  286. * @param mixed $value A value
  287. *
  288. * @return mixed The same value with all service references replaced by the real service instances
  289. */
  290. public function resolveServices($value)
  291. {
  292. if (is_array($value))
  293. {
  294. $value = array_map(array($this, 'resolveServices'), $value);
  295. }
  296. else if (is_object($value) && $value instanceof sfServiceReference)
  297. {
  298. $value = $this->getService((string) $value);
  299. }
  300. return $value;
  301. }
  302. protected function replaceParameter($match)
  303. {
  304. if (!$this->hasParameter($name = strtolower($match[2])))
  305. {
  306. throw new RuntimeException(sprintf('The parameter "%s" must be defined.', $name));
  307. }
  308. return $this->getParameter($name);
  309. }
  310. }