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