Source for file ServiceLocator.php

Documentation is available at ServiceLocator.php

  1. 1: <?php
  2. 2:  
  3. 3: /**
  4. 4:  * Nette Framework
  5. 5:  *
  6. 6:  * Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
  7. 7:  *
  8. 8:  * This source file is subject to the "Nette license" that is bundled
  9. 9:  * with this package in the file license.txt.
  10. 10:  *
  11. 11:  * For more information please see https://nette.org
  12. 12:  *
  13. 13:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  14. 14:  * @license    https://nette.org/license  Nette license
  15. 15:  * @link       https://nette.org
  16. 16:  * @category   Nette
  17. 17:  * @package    Nette
  18. 18:  * @version    $Id$
  19. 19:  */
  20. 20:  
  21. 21:  
  22. 22:  
  23. 23: require_once dirname(__FILE__'/IServiceLocator.php';
  24. 24:  
  25. 25: require_once dirname(__FILE__'/Object.php';
  26. 26:  
  27. 27:  
  28. 28:  
  29. 29: /**
  30. 30:  * Service locator pattern implementation.
  31. 31:  *
  32. 32:  * @author     David Grudl
  33. 33:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  34. 34:  * @package    Nette
  35. 35:  */
  36. 36: class ServiceLocator extends Object implements IServiceLocator
  37. 37: {
  38. 38:     /** @var IServiceLocator */
  39. 39:     private $parent;
  40. 40:  
  41. 41:     /** @var array  storage for shared objects */
  42. 42:     private $registry array();
  43. 43:  
  44. 44:     /** @var array  storage for shared objects */
  45. 45:     private $factories array();
  46. 46:  
  47. 47:  
  48. 48:  
  49. 49:     /**
  50. 50:      * @param  IServiceLocator 
  51. 51:      */
  52. 52:     public function __construct(IServiceLocator $parent NULL)
  53. 53:     {
  54. 54:         $this->parent $parent;
  55. 55:     }
  56. 56:  
  57. 57:  
  58. 58:  
  59. 59:     /**
  60. 60:      * Adds the specified service to the service container.
  61. 61:      * @param  mixed  object, class name or service factory callback
  62. 62:      * @param  string optional service name (for factories is not optional)
  63. 63:      * @param  bool   promote to higher level?
  64. 64:      * @return void 
  65. 65:      * @throws InvalidArgumentException, AmbiguousServiceException
  66. 66:      */
  67. 67:     public function addService($service$name NULL$promote FALSE)
  68. 68:     {
  69. 69:         if (is_object($service)) {
  70. 70:             if ($name === NULL$name get_class($service);
  71. 71:  
  72. 72:         elseif (is_string($service)) {
  73. 73:             if ($name === NULL$name $service;
  74. 74:  
  75. 75:         elseif (is_callable($serviceTRUE)) {
  76. 76:             if (empty($name)) {
  77. 77:                 throw new InvalidArgumentException('When factory callback is given, service name must be specified.');
  78. 78:             }
  79. 79:  
  80. 80:         else {
  81. 81:             throw new InvalidArgumentException('Service must be name, object or factory callback.');
  82. 82:         }
  83. 83:  
  84. 84:         $lower strtolower($name);
  85. 85:         if (isset($this->registry[$lower])) {
  86. 86:             throw new AmbiguousServiceException("Service named '$name' has been already registered.");
  87. 87:         }
  88. 88:  
  89. 89:         if (is_object($service)) {
  90. 90:             $this->registry[$lower$service;
  91. 91:  
  92. 92:         else {
  93. 93:             $this->factories[$lower$service;
  94. 94:         }
  95. 95:  
  96. 96:         if ($promote && $this->parent !== NULL{
  97. 97:             $this->parent->addService($service$nameTRUE);
  98. 98:         }
  99. 99:     }
  100. 100:  
  101. 101:  
  102. 102:  
  103. 103:     /**
  104. 104:      * Removes the specified service type from the service container.
  105. 105:      * @param  bool   promote to higher level?
  106. 106:      * @return void 
  107. 107:      */
  108. 108:     public function removeService($name$promote TRUE)
  109. 109:     {
  110. 110:         if (!is_string($name|| $name === ''{
  111. 111:             throw new InvalidArgumentException("Service name must be a non-empty string, " gettype($name" given.");
  112. 112:         }
  113. 113:  
  114. 114:         $lower strtolower($name);
  115. 115:         unset($this->registry[$lower]$this->factories[$lower]);
  116. 116:  
  117. 117:         if ($promote && $this->parent !== NULL{
  118. 118:             $this->parent->removeService($nameTRUE);
  119. 119:         }
  120. 120:     }
  121. 121:  
  122. 122:  
  123. 123:  
  124. 124:     /**
  125. 125:      * Gets the service object of the specified type.
  126. 126:      * @param  string service name
  127. 127:      * @param  bool   throw exception if service doesn't exist?
  128. 128:      * @return mixed 
  129. 129:      */
  130. 130:     public function getService($name$need TRUE)
  131. 131:     {
  132. 132:         if (!is_string($name|| $name === ''{
  133. 133:             throw new InvalidArgumentException("Service name must be a non-empty string, " gettype($name" given.");
  134. 134:         }
  135. 135:  
  136. 136:         $lower strtolower($name);
  137. 137:  
  138. 138:         if (isset($this->registry[$lower])) {
  139. 139:             return $this->registry[$lower];
  140. 140:  
  141. 141:         elseif (isset($this->factories[$lower])) {
  142. 142:             $service $this->factories[$lower];
  143. 143:  
  144. 144:             if (is_string($service)) {
  145. 145:                 if (substr($service-2=== '()'{
  146. 146:                     // trick to pass callback as string
  147. 147:                     $service substr($service0-2);
  148. 148:  
  149. 149:                 else {
  150. 150:                     fixNamespace($service);
  151. 151:  
  152. 152:                     if (!class_exists($service)) {
  153. 153:                         throw new AmbiguousServiceException("Cannot instantiate service '$name', class '$service' not found.");
  154. 154:                     }
  155. 155:                     return $this->registry[$lowernew $service;
  156. 156:                 }
  157. 157:             }
  158. 158:  
  159. 159:             fixCallback($service);
  160. 160:             if (!is_callable($service)) {
  161. 161:                 $able is_callable($serviceTRUE$textual);
  162. 162:                 throw new AmbiguousServiceException("Cannot instantiate service '$name', handler '$textual' is not ($able 'callable.' 'valid PHP callback.'));
  163. 163:             }
  164. 164:  
  165. 165:             return $this->registry[$lowercall_user_func($service);
  166. 166:         }
  167. 167:  
  168. 168:         if ($this->parent !== NULL{
  169. 169:             return $this->parent->getService($name$need);
  170. 170:  
  171. 171:         elseif ($need{
  172. 172:             throw new InvalidStateException("Service '$name' not found.");
  173. 173:  
  174. 174:         else {
  175. 175:             return NULL;
  176. 176:         }
  177. 177:     }
  178. 178:  
  179. 179:  
  180. 180:  
  181. 181:     /**
  182. 182:      * Returns the parent container if any.
  183. 183:      * @return IServiceLocator|NULL
  184. 184:      */
  185. 185:     public function getParent()
  186. 186:     {
  187. 187:         return $this->parent;
  188. 188:     }
  189. 189:  
  190. 191:  
  191. 192:  
  192. 193:  
  193. 194: /**
  194. 195:  * Ambiguous service resolution exception.
  195. 196:  *
  196. 197:  * @author     David Grudl
  197. 198:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  198. 199:  * @package    Nette
  199. 200:  */
  200. 201: class AmbiguousServiceException extends Exception