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