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
  • PHP

Classes

  • Container
  • ContainerBuilder
  • Helpers
  • ServiceDefinition
  • Statement

Interfaces

  • IContainer

Exceptions

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