PageRenderTime 40ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/www/libs/nette-dev/ServiceLocator.php

https://github.com/bazo/Mokuji
PHP | 202 lines | 104 code | 43 blank | 55 comment | 33 complexity | 9db01140223ef5a0dd8abfd449b5428d MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nettephp.com/license Nette license
  7. * @link http://nettephp.com
  8. * @category Nette
  9. * @package Nette
  10. */
  11. /**
  12. * Service locator pattern implementation.
  13. *
  14. * @copyright Copyright (c) 2004, 2010 David Grudl
  15. * @package Nette
  16. */
  17. class ServiceLocator extends Object implements IServiceLocator
  18. {
  19. /** @var IServiceLocator */
  20. private $parent;
  21. /** @var array storage for shared objects */
  22. private $registry = array();
  23. /** @var array storage for service factories */
  24. private $factories = array();
  25. /**
  26. * @param IServiceLocator
  27. */
  28. public function __construct(IServiceLocator $parent = NULL)
  29. {
  30. $this->parent = $parent;
  31. }
  32. /**
  33. * Adds the specified service to the service container.
  34. * @param string service name
  35. * @param mixed object, class name or factory callback
  36. * @param bool is singleton?
  37. * @param array factory options
  38. * @return void
  39. */
  40. public function addService($name, $service, $singleton = TRUE, array $options = NULL)
  41. {
  42. if (!is_string($name) || $name === '') {
  43. throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
  44. }
  45. $lower = strtolower($name);
  46. if (isset($this->registry[$lower])) { // only for instantiated services?
  47. throw new AmbiguousServiceException("Service named '$name' has been already registered.");
  48. }
  49. if (is_object($service)) {
  50. if (!$singleton || $options) {
  51. throw new InvalidArgumentException("Service named '$name' is an instantiated object and must therefore be singleton without options.");
  52. }
  53. $this->registry[$lower] = $service;
  54. } else {
  55. if (!$service) {
  56. throw new InvalidArgumentException("Service named '$name' is empty.");
  57. }
  58. $this->factories[$lower] = array($service, $singleton, $options);
  59. }
  60. }
  61. /**
  62. * Removes the specified service type from the service container.
  63. * @return void
  64. */
  65. public function removeService($name)
  66. {
  67. if (!is_string($name) || $name === '') {
  68. throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
  69. }
  70. $lower = strtolower($name);
  71. unset($this->registry[$lower], $this->factories[$lower]);
  72. }
  73. /**
  74. * Gets the service object of the specified type.
  75. * @param string service name
  76. * @param array options in case service is not singleton
  77. * @return mixed
  78. */
  79. public function getService($name, array $options = NULL)
  80. {
  81. if (!is_string($name) || $name === '') {
  82. throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
  83. }
  84. $lower = strtolower($name);
  85. if (isset($this->registry[$lower])) { // instantiated singleton
  86. if ($options) {
  87. throw new InvalidArgumentException("Service named '$name' is singleton and therefore can not have options.");
  88. }
  89. return $this->registry[$lower];
  90. } elseif (isset($this->factories[$lower])) {
  91. list($factory, $singleton, $defOptions) = $this->factories[$lower];
  92. if ($singleton && $options) {
  93. throw new InvalidArgumentException("Service named '$name' is singleton and therefore can not have options.");
  94. } elseif ($defOptions) {
  95. $options = $options ? $options + $defOptions : $defOptions;
  96. }
  97. if (is_string($factory) && strpos($factory, ':') === FALSE) { // class name
  98. Framework::fixNamespace($factory);
  99. if (!class_exists($factory)) {
  100. throw new AmbiguousServiceException("Cannot instantiate service '$name', class '$factory' not found.");
  101. }
  102. $service = new $factory;
  103. if ($options && method_exists($service, 'setOptions')) {
  104. $service->setOptions($options); // TODO: better!
  105. }
  106. } else { // factory callback
  107. $factory = callback($factory);
  108. if (!$factory->isCallable()) {
  109. throw new InvalidStateException("Cannot instantiate service '$name', handler '$factory' is not callable.");
  110. }
  111. $service = $factory->invoke($options);
  112. if (!is_object($service)) {
  113. throw new AmbiguousServiceException("Cannot instantiate service '$name', value returned by '$factory' is not object.");
  114. }
  115. }
  116. if ($singleton) {
  117. $this->registry[$lower] = $service;
  118. unset($this->factories[$lower]);
  119. }
  120. return $service;
  121. }
  122. if ($this->parent !== NULL) {
  123. return $this->parent->getService($name, $options);
  124. } else {
  125. throw new InvalidStateException("Service '$name' not found.");
  126. }
  127. }
  128. /**
  129. * Exists the service?
  130. * @param string service name
  131. * @param bool must be created yet?
  132. * @return bool
  133. */
  134. public function hasService($name, $created = FALSE)
  135. {
  136. if (!is_string($name) || $name === '') {
  137. throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
  138. }
  139. $lower = strtolower($name);
  140. return isset($this->registry[$lower]) || (!$created && isset($this->factories[$lower])) || ($this->parent !== NULL && $this->parent->hasService($name, $created));
  141. }
  142. /**
  143. * Returns the parent container if any.
  144. * @return IServiceLocator|NULL
  145. */
  146. public function getParent()
  147. {
  148. return $this->parent;
  149. }
  150. }
  151. /**
  152. * Ambiguous service resolution exception.
  153. *
  154. * @copyright Copyright (c) 2004, 2010 David Grudl
  155. * @package Nette
  156. */
  157. class AmbiguousServiceException extends Exception
  158. {
  159. }