Packages

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

Classes

  • NDIContainer
  • NDIContainerBuilder
  • NDIHelpers
  • NDIServiceDefinition
  • NDIStatement

Interfaces

  • IDIContainer

Exceptions

  • NMissingServiceException
  • NServiceCreationException
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 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 TAGS = 'tags';
 24: 
 25:     /** @var array  user parameters */
 26:     /*private*/public $parameters = array();
 27: 
 28:     /** @deprecated */
 29:     public $params = array();
 30: 
 31:     /** @var array */
 32:     public $classes = array();
 33: 
 34:     /** @var array  storage for shared objects */
 35:     private $registry = array();
 36: 
 37:     /** @var array  storage for service factories */
 38:     private $factories = array();
 39: 
 40:     /** @var array */
 41:     public $meta = array();
 42: 
 43:     /** @var array circular reference detector */
 44:     private $creating;
 45: 
 46: 
 47:     public function __construct(array $params = array())
 48:     {
 49:         $this->parameters = $params + $this->parameters;
 50:         $this->params = &$this->parameters;
 51:     }
 52: 
 53: 
 54:     /**
 55:      * @return array
 56:      */
 57:     public function getParameters()
 58:     {
 59:         return $this->parameters;
 60:     }
 61: 
 62: 
 63:     /**
 64:      * Adds the service or service factory to the container.
 65:      * @param  string
 66:      * @param  mixed   object, class name or callable
 67:      * @param  array   service meta information
 68:      * @return self
 69:      */
 70:     public function addService($name, $service, array $meta = NULL)
 71:     {
 72:         $this->updating();
 73:         if (!is_string($name) || !$name) {
 74:             throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
 75:         }
 76: 
 77:         if (isset($this->registry[$name])) {
 78:             throw new InvalidStateException("Service '$name' has already been registered.");
 79:         }
 80: 
 81:         if (is_object($service) && !$service instanceof Closure && !$service instanceof NCallback) {
 82:             $this->registry[$name] = $service;
 83:             $this->meta[$name] = $meta;
 84:             return $this;
 85: 
 86:         } elseif (!is_string($service) || strpos($service, ':') !== FALSE|| $service[0] === "\0") { // callable
 87:             $service = new NCallback($service);
 88:         }
 89: 
 90:         $this->factories[$name] = array($service);
 91:         $this->registry[$name] = & $this->factories[$name][1]; // forces cloning using reference
 92:         $this->meta[$name] = $meta;
 93:         return $this;
 94:     }
 95: 
 96: 
 97:     /**
 98:      * Removes the service from the container.
 99:      * @param  string
100:      * @return void
101:      */
102:     public function removeService($name)
103:     {
104:         $this->updating();
105:         unset($this->registry[$name], $this->factories[$name], $this->meta[$name]);
106:     }
107: 
108: 
109:     /**
110:      * Gets the service object by name.
111:      * @param  string
112:      * @return object
113:      */
114:     public function getService($name)
115:     {
116:         if (isset($this->registry[$name])) {
117:             return $this->registry[$name];
118: 
119:         } elseif (isset($this->creating[$name])) {
120:             throw new InvalidStateException("Circular reference detected for services: "
121:                 . implode(', ', array_keys($this->creating)) . ".");
122:         }
123: 
124:         if (isset($this->factories[$name])) {
125:             list($factory) = $this->factories[$name];
126:             if (is_string($factory)) {
127:                 if (!class_exists($factory)) {
128:                     throw new InvalidStateException("Cannot instantiate service, class '$factory' not found.");
129:                 }
130:                 try {
131:                     $this->creating[$name] = TRUE;
132:                     $service = new $factory;
133:                 } catch (Exception $e) {}
134: 
135:             } elseif (!$factory->isCallable()) {
136:                 throw new InvalidStateException("Unable to create service '$name', factory '$factory' is not callable.");
137: 
138:             } else {
139:                 $this->creating[$name] = TRUE;
140:                 try {
141:                     $service = $factory->invoke($this);
142:                 } catch (Exception $e) {}
143:             }
144: 
145:         } elseif (method_exists($this, $factory = NDIContainer::getMethodName($name)) && $this->getReflection()->getMethod($factory)->getName() === $factory) {
146:             $this->creating[$name] = TRUE;
147:             try {
148:                 $service = $this->$factory();
149:             } catch (Exception $e) {}
150: 
151:         } else {
152:             throw new NMissingServiceException("Service '$name' not found.");
153:         }
154: 
155:         unset($this->creating[$name]);
156: 
157:         if (isset($e)) {
158:             throw $e;
159: 
160:         } elseif (!is_object($service)) {
161:             throw new UnexpectedValueException("Unable to create service '$name', value returned by factory '$factory' is not object.");
162:         }
163: 
164:         return $this->registry[$name] = $service;
165:     }
166: 
167: 
168:     /**
169:      * Does the service exist?
170:      * @param  string service name
171:      * @return bool
172:      */
173:     public function hasService($name)
174:     {
175:         return isset($this->registry[$name])
176:             || isset($this->factories[$name])
177:             || method_exists($this, $method = NDIContainer::getMethodName($name)) && $this->getReflection()->getMethod($method)->getName() === $method;
178:     }
179: 
180: 
181:     /**
182:      * Is the service created?
183:      * @param  string service name
184:      * @return bool
185:      */
186:     public function isCreated($name)
187:     {
188:         if (!$this->hasService($name)) {
189:             throw new NMissingServiceException("Service '$name' not found.");
190:         }
191:         return isset($this->registry[$name]);
192:     }
193: 
194: 
195:     /**
196:      * Resolves service by type.
197:      * @param  string  class or interface
198:      * @param  bool    throw exception if service doesn't exist?
199:      * @return object  service or NULL
200:      * @throws NMissingServiceException
201:      */
202:     public function getByType($class, $need = TRUE)
203:     {
204:         $lower = ltrim(strtolower($class), '\\');
205:         if (!isset($this->classes[$lower])) {
206:             if ($need) {
207:                 throw new NMissingServiceException("Service of type $class not found.");
208:             }
209:         } elseif ($this->classes[$lower] === FALSE) {
210:             throw new NMissingServiceException("Multiple services of type $class found.");
211:         } else {
212:             return $this->getService($this->classes[$lower]);
213:         }
214:     }
215: 
216: 
217:     /**
218:      * Gets the service names of the specified tag.
219:      * @param  string
220:      * @return array of [service name => tag attributes]
221:      */
222:     public function findByTag($tag)
223:     {
224:         $found = array();
225:         foreach ($this->meta as $name => $meta) {
226:             if (isset($meta[self::TAGS][$tag])) {
227:                 $found[$name] = $meta[self::TAGS][$tag];
228:             }
229:         }
230:         return $found;
231:     }
232: 
233: 
234:     /********************* autowiring ****************d*g**/
235: 
236: 
237:     /**
238:      * Creates new instance using autowiring.
239:      * @param  string  class
240:      * @param  array   arguments
241:      * @return object
242:      * @throws InvalidArgumentException
243:      */
244:     public function createInstance($class, array $args = array())
245:     {
246:         $rc = NClassReflection::from($class);
247:         if (!$rc->isInstantiable()) {
248:             throw new NServiceCreationException("Class $class is not instantiable.");
249: 
250:         } elseif ($constructor = $rc->getConstructor()) {
251:             return $rc->newInstanceArgs(NDIHelpers::autowireArguments($constructor, $args, $this));
252: 
253:         } elseif ($args) {
254:             throw new NServiceCreationException("Unable to pass arguments, class $class has no constructor.");
255:         }
256:         return new $class;
257:     }
258: 
259: 
260:     /**
261:      * Calls method using autowiring.
262:      * @param  mixed   class, object, function, callable
263:      * @param  array   arguments
264:      * @return mixed
265:      */
266:     public function callMethod($function, array $args = array())
267:     {
268:         $callback = new NCallback($function);
269:         return $callback->invokeArgs(NDIHelpers::autowireArguments($callback->toReflection(), $args, $this));
270:     }
271: 
272: 
273:     /********************* shortcuts ****************d*g**/
274: 
275: 
276:     /**
277:      * Expands %placeholders%.
278:      * @param  mixed
279:      * @return mixed
280:      */
281:     public function expand($s)
282:     {
283:         return NDIHelpers::expand($s, $this->parameters);
284:     }
285: 
286: 
287:     /**
288:      * Gets the service object, shortcut for getService().
289:      * @param  string
290:      * @return object
291:      */
292:     public function &__get($name)
293:     {
294:         if (!isset($this->registry[$name])) {
295:             $this->getService($name);
296:         }
297:         return $this->registry[$name];
298:     }
299: 
300: 
301:     /**
302:      * Adds the service object.
303:      * @param  string
304:      * @param  object
305:      * @return void
306:      */
307:     public function __set($name, $service)
308:     {
309:         $this->updating();
310:         if (!is_string($name) || $name === '') {
311:             throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
312: 
313:         } elseif (isset($this->registry[$name])) {
314:             throw new InvalidStateException("Service '$name' has already been registered.");
315: 
316:         } elseif (!is_object($service)) {
317:             throw new InvalidArgumentException("Service must be a object, " . gettype($service) . " given.");
318:         }
319:         $this->registry[$name] = $service;
320:     }
321: 
322: 
323:     /**
324:      * Does the service exist?
325:      * @param  string
326:      * @return bool
327:      */
328:     public function __isset($name)
329:     {
330:         return $this->hasService($name);
331:     }
332: 
333: 
334:     /**
335:      * Removes the service, shortcut for removeService().
336:      * @return void
337:      */
338:     public function __unset($name)
339:     {
340:         $this->removeService($name);
341:     }
342: 
343: 
344:     public static function getMethodName($name, $isService = TRUE)
345:     {
346:         $uname = ucfirst($name);
347:         return ($isService ? 'createService' : 'create') . ((string) $name === $uname ? '__' : '') . str_replace('.', '__', $uname);
348:     }
349: 
350: }
351: 
Nette Framework 2.0.11 (for PHP 5.2, prefixed) API API documentation generated by ApiGen 2.8.0