Namespaces

  • 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

  • Container
  • ContainerBuilder
  • ServiceDefinition
  • Statement

Interfaces

  • IContainer

Exceptions

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