Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • Compiler
  • CompilerExtension
  • Container
  • ContainerBuilder
  • ContainerLoader
  • DependencyChecker
  • Helpers
  • PhpGenerator
  • PhpReflection
  • ServiceDefinition
  • Statement

Exceptions

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