Packages

  • Nette
    • Application
      • Application\Diagnostics
      • Application\Responses
      • Application\Routers
      • Application\UI
    • Caching
      • Caching\Storages
    • ComponentModel
    • Config
    • Database
      • Database\Diagnostics
      • Database\Drivers
      • Database\Reflection
      • Database\Table
    • DI
    • Diagnostics
    • Forms
      • Forms\Controls
      • Forms\Rendering
    • Http
    • Iterators
    • Latte
      • Latte\Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • None
  • PHP

Classes

  • NDIContainer
  • NDIContainerBuilder
  • NServiceBuilder

Interfaces

  • IDIContainer
  • IServiceBuilder

Exceptions

  • NAmbiguousServiceException
  • NMissingServiceException
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004, 2011 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\DI
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * The dependency injection container default implementation.
 17:  *
 18:  * @author     David Grudl
 19:  * @package Nette\DI
 20:  */
 21: class NDIContainer extends NFreezableObject implements IDIContainer
 22: {
 23:     const TAG_TYPEHINT = 'typeHint';
 24: 
 25:     /** @var array  user parameters */
 26:     public $params = array();
 27: 
 28:     /** @var array  storage for shared objects */
 29:     private $registry = array();
 30: 
 31:     /** @var array  storage for service factories */
 32:     private $factories = array();
 33: 
 34:     /** @var array  */
 35:     private $tags = array();
 36: 
 37:     /** @var array circular reference detector */
 38:     private $creating;
 39: 
 40: 
 41: 
 42:     /**
 43:      * Adds the specified service or service factory to the container.
 44:      * @param  string
 45:      * @param  mixed   object, class name or callback
 46:      * @param  mixed   array of tags or string typeHint
 47:      * @return NDIContainer|NServiceBuilder  provides a fluent interface
 48:      */
 49:     public function addService($name, $service, $tags = NULL)
 50:     {
 51:         $this->updating();
 52:         if (!is_string($name) || $name === '') {
 53:             throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
 54:         }
 55: 
 56:         if (isset($this->registry[$name]) || method_exists($this, "createService$name")) {
 57:             throw new InvalidStateException("Service '$name' has already been registered.");
 58:         }
 59: 
 60:         if (is_string($tags)) {
 61:             $tags = array(self::TAG_TYPEHINT => array($tags));
 62:         } elseif (is_array($tags)) {
 63:             foreach ($tags as $id => $attrs) {
 64:                 if (is_int($id) && is_string($attrs)) {
 65:                     $tags[$attrs] = array();
 66:                     unset($tags[$id]);
 67:                 } elseif (!is_array($attrs)) {
 68:                     $tags[$id] = (array) $attrs;
 69:                 }
 70:             }
 71:         }
 72: 
 73:         if (is_string($service) && strpos($service, ':') === FALSE&& $service[0] !== "\0") { // class name
 74:             if (!isset($tags[self::TAG_TYPEHINT][0])) {
 75:                 $tags[self::TAG_TYPEHINT][0] = $service;
 76:             }
 77:             $service = new NServiceBuilder($service);
 78:         }
 79: 
 80:         if ($service instanceof IServiceBuilder) {
 81:             $factory = array($service, 'createService');
 82: 
 83:         } elseif (is_object($service) && !$service instanceof Closure && !$service instanceof NCallback) {
 84:             $this->registry[$name] = $service;
 85:             $this->tags[$name] = $tags;
 86:             return $this;
 87: 
 88:         } else {
 89:             $factory = $service;
 90:         }
 91: 
 92:         $this->factories[$name] = array(callback($factory));
 93:         $this->tags[$name] = $tags;
 94:         $this->registry[$name] = & $this->factories[$name][1]; // forces cloning using reference
 95:         return $service;
 96:     }
 97: 
 98: 
 99: 
100:     /**
101:      * Removes the specified service type from the container.
102:      * @return void
103:      */
104:     public function removeService($name)
105:     {
106:         $this->updating();
107:         unset($this->registry[$name], $this->factories[$name]);
108:     }
109: 
110: 
111: 
112:     /**
113:      * Gets the service object by name.
114:      * @param  string
115:      * @return object
116:      */
117:     public function getService($name)
118:     {
119:         if (isset($this->registry[$name])) {
120:             return $this->registry[$name];
121: 
122:         } elseif (isset($this->creating[$name])) {
123:             throw new InvalidStateException("Circular reference detected for services: "
124:                 . implode(', ', array_keys($this->creating)) . ".");
125:         }
126: 
127:         if (isset($this->factories[$name])) {
128:             list($factory) = $this->factories[$name];
129:             if (!$factory->isCallable()) {
130:                 throw new InvalidStateException("Unable to create service '$name', factory '$factory' is not callable.");
131:             }
132: 
133:             $this->creating[$name] = TRUE;
134:             try {
135:                 $service = $factory->invoke($this);
136:             } catch (Exception $e) {}
137: 
138:         } elseif (method_exists($this, $factory = 'createService' . ucfirst($name))) { // static method
139:             $this->creating[$name] = TRUE;
140:             try {
141:                 $service = $this->$factory();
142:             } catch (Exception $e) {}
143: 
144:         } else {
145:             throw new NMissingServiceException("Service '$name' not found.");
146:         }
147: 
148:         unset($this->creating[$name]);
149: 
150:         if (isset($e)) {
151:             throw $e;
152: 
153:         } elseif (!is_object($service)) {
154:             throw new UnexpectedValueException("Unable to create service '$name', value returned by factory '$factory' is not object.");
155: 
156:         } elseif (isset($this->tags[$name][self::TAG_TYPEHINT][0]) && !$service instanceof $this->tags[$name][self::TAG_TYPEHINT][0]) {
157:             throw new UnexpectedValueException("Unable to create service '$name', value returned by factory '$factory' is not '{$this->tags[$name][self::TAG_TYPEHINT][0]}' type.");
158:         }
159: 
160:         unset($this->factories[$name]);
161:         return $this->registry[$name] = $service;
162:     }
163: 
164: 
165: 
166:     /**
167:      * Gets the service object of the specified type.
168:      * @param  string
169:      * @return object
170:      */
171:     public function getServiceByType($type)
172:     {
173:         foreach ($this->registry as $name => $service) {
174:             if (isset($this->tags[$name][self::TAG_TYPEHINT][0]) ? !strcasecmp($this->tags[$name][self::TAG_TYPEHINT][0], $type) : $service instanceof $type) {
175:                 $found[] = $name;
176:             }
177:         }
178:         if (!isset($found)) {
179:             throw new NMissingServiceException("Service matching '$type' type not found.");
180: 
181:         } elseif (count($found) > 1) {
182:             throw new NAmbiguousServiceException("Found more than one service ('" . implode("', '", $found) . "') matching '$type' type.");
183:         }
184:         return $this->getService($found[0]);
185:     }
186: 
187: 
188: 
189:     /**
190:      * Gets the service objects of the specified tag.
191:      * @param  string
192:      * @return array of [service name => tag attributes]
193:      */
194:     public function getServiceNamesByTag($tag)
195:     {
196:         $found = array();
197:         foreach ($this->registry as $name => $service) {
198:             if (isset($this->tags[$name][$tag])) {
199:                 $found[$name] = $this->tags[$name][$tag];
200:             }
201:         }
202:         return $found;
203:     }
204: 
205: 
206: 
207:     /**
208:      * Does the service exist?
209:      * @param  string service name
210:      * @return bool
211:      */
212:     public function hasService($name)
213:     {
214:         return isset($this->registry[$name])
215:             || isset($this->factories[$name])
216:             || method_exists($this, "createService$name");
217:     }
218: 
219: 
220: 
221:     /**
222:      * Checks the service type.
223:      * @param  string
224:      * @param  string
225:      * @return bool
226:      */
227:     public function checkServiceType($name, $type)
228:     {
229:         return isset($this->tags[$name][self::TAG_TYPEHINT][0])
230:             ? !strcasecmp($this->tags[$name][self::TAG_TYPEHINT][0], $type)
231:             : (isset($this->registry[$name]) && $this->registry[$name] instanceof $type);
232:     }
233: 
234: 
235: 
236:     /********************* shortcuts ****************d*g**/
237: 
238: 
239: 
240:     /**
241:      * Expands %placeholders% in string.
242:      * @param  mixed
243:      * @return mixed
244:      */
245:     public function expand($s)
246:     {
247:         return is_string($s) ? NStrings::expand($s, $this->params) : $s;
248:     }
249: 
250: 
251: 
252:     /**
253:      * Gets the service object, shortcut for getService().
254:      * @param  string
255:      * @return object
256:      */
257:     public function &__get($name)
258:     {
259:         if (!isset($this->registry[$name])) {
260:             $this->getService($name);
261:         }
262:         return $this->registry[$name];
263:     }
264: 
265: 
266: 
267:     /**
268:      * Adds the service object.
269:      * @param  string
270:      * @param  object
271:      * @return void
272:      */
273:     public function __set($name, $service)
274:     {
275:         $this->updating();
276:         if (!is_string($name) || $name === '') {
277:             throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
278: 
279:         } elseif (isset($this->registry[$name]) || method_exists($this, "createService$name")) {
280:             throw new InvalidStateException("Service '$name' has already been registered.");
281: 
282:         } elseif (!is_object($service)) {
283:             throw new InvalidArgumentException("Service must be a object, " . gettype($service) . " given.");
284:         }
285:         $this->registry[$name] = $service;
286:     }
287: 
288: 
289: 
290:     /**
291:      * Does the service exist?
292:      * @param  string
293:      * @return bool
294:      */
295:     public function __isset($name)
296:     {
297:         return $this->hasService($name);
298:     }
299: 
300: 
301: 
302:     /**
303:      * Removes the service, shortcut for removeService().
304:      * @return void
305:      */
306:     public function __unset($name)
307:     {
308:         $this->removeService($name);
309:     }
310: 
311: }
312: 
Nette Framework 2.0beta1 (for PHP 5.2) API API documentation generated by ApiGen 2.3.0