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

Classes

Interfaces

Exceptions

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