Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Diagnostics
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
      • Diagnostics
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • PhpGenerator
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
  • NetteModule
  • none

Classes

  • Compiler
  • CompilerExtension
  • Container
  • ContainerBuilder
  • ServiceDefinition
  • Statement

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 (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\DI;
  9: 
 10: use Nette;
 11: use Nette\Utils\Validators;
 12: use Nette\Utils\Strings;
 13: use Nette\Reflection;
 14: use Nette\PhpGenerator\Helpers as PhpHelpers;
 15: 
 16: 
 17: /**
 18:  * Basic container builder.
 19:  *
 20:  * @author     David Grudl
 21:  * @property-read ServiceDefinition[] $definitions
 22:  * @property-read array $dependencies
 23:  */
 24: class ContainerBuilder extends Nette\Object
 25: {
 26:     const THIS_SERVICE = 'self',
 27:         THIS_CONTAINER = 'container';
 28: 
 29:     /** @var array */
 30:     public $parameters = array();
 31: 
 32:     /** @var ServiceDefinition[] */
 33:     private $definitions = array();
 34: 
 35:     /** @var array for auto-wiring */
 36:     private $classes;
 37: 
 38:     /** @var array of file names */
 39:     private $dependencies = array();
 40: 
 41:     /** @var Nette\PhpGenerator\ClassType[] */
 42:     private $generatedClasses = array();
 43: 
 44:     /** @var string */
 45:     /*private in 5.4*/public $currentService;
 46: 
 47: 
 48:     /**
 49:      * Adds new service definition.
 50:      * @param  string
 51:      * @return ServiceDefinition
 52:      */
 53:     public function addDefinition($name, ServiceDefinition $definition = NULL)
 54:     {
 55:         if (!is_string($name) || !$name) { // builder is not ready for falsy names such as '0'
 56:             throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name)));
 57: 
 58:         } elseif (isset($this->definitions[$name])) {
 59:             throw new Nette\InvalidStateException("Service '$name' has already been added.");
 60:         }
 61:         return $this->definitions[$name] = $definition ?: new ServiceDefinition;
 62:     }
 63: 
 64: 
 65:     /**
 66:      * Removes the specified service definition.
 67:      * @param  string
 68:      * @return void
 69:      */
 70:     public function removeDefinition($name)
 71:     {
 72:         unset($this->definitions[$name]);
 73:     }
 74: 
 75: 
 76:     /**
 77:      * Gets the service definition.
 78:      * @param  string
 79:      * @return ServiceDefinition
 80:      */
 81:     public function getDefinition($name)
 82:     {
 83:         if (!isset($this->definitions[$name])) {
 84:             throw new MissingServiceException("Service '$name' not found.");
 85:         }
 86:         return $this->definitions[$name];
 87:     }
 88: 
 89: 
 90:     /**
 91:      * Gets all service definitions.
 92:      * @return array
 93:      */
 94:     public function getDefinitions()
 95:     {
 96:         return $this->definitions;
 97:     }
 98: 
 99: 
100:     /**
101:      * Does the service definition exist?
102:      * @param  string
103:      * @return bool
104:      */
105:     public function hasDefinition($name)
106:     {
107:         return isset($this->definitions[$name]);
108:     }
109: 
110: 
111:     /********************* class resolving ****************d*g**/
112: 
113: 
114:     /**
115:      * Resolves service name by type.
116:      * @param  string  class or interface
117:      * @return string  service name or NULL
118:      * @throws ServiceCreationException
119:      */
120:     public function getByType($class)
121:     {
122:         if ($this->currentService !== NULL && Reflection\ClassType::from($this->definitions[$this->currentService]->class)->is($class)) {
123:             return $this->currentService;
124:         }
125: 
126:         $lower = ltrim(strtolower($class), '\\');
127:         if (!isset($this->classes[$lower])) {
128:             return;
129: 
130:         } elseif (count($this->classes[$lower]) === 1) {
131:             return $this->classes[$lower][0];
132: 
133:         } else {
134:             throw new ServiceCreationException("Multiple services of type $class found: " . implode(', ', $this->classes[$lower]));
135:         }
136:     }
137: 
138: 
139:     /**
140:      * Gets the service objects of the specified tag.
141:      * @param  string
142:      * @return array of [service name => tag attributes]
143:      */
144:     public function findByTag($tag)
145:     {
146:         $found = array();
147:         foreach ($this->definitions as $name => $def) {
148:             if (isset($def->tags[$tag])) {
149:                 $found[$name] = $def->tags[$tag];
150:             }
151:         }
152:         return $found;
153:     }
154: 
155: 
156:     /**
157:      * Creates a list of arguments using autowiring.
158:      * @return array
159:      */
160:     public function autowireArguments($class, $method, array $arguments)
161:     {
162:         $rc = Reflection\ClassType::from($class);
163:         if (!$rc->hasMethod($method)) {
164:             if (!Nette\Utils\Arrays::isList($arguments)) {
165:                 throw new ServiceCreationException("Unable to pass specified arguments to $class::$method().");
166:             }
167:             return $arguments;
168:         }
169: 
170:         $rm = $rc->getMethod($method);
171:         if (!$rm->isPublic()) {
172:             throw new ServiceCreationException("$rm is not callable.");
173:         }
174:         $this->addDependency($rm->getFileName());
175:         return Helpers::autowireArguments($rm, $arguments, $this);
176:     }
177: 
178: 
179:     /**
180:      * Generates $dependencies, $classes and normalizes class names.
181:      * @return array
182:      * @internal
183:      */
184:     public function prepareClassList()
185:     {
186:         $this->classes = FALSE;
187: 
188:         // prepare generated factories
189:         foreach ($this->definitions as $name => $def) {
190:             if (!$def->implement) {
191:                 continue;
192:             }
193: 
194:             if (!interface_exists($def->implement)) {
195:                 throw new ServiceCreationException("Interface $def->implement used in service '$name' not found.");
196:             }
197:             $rc = Reflection\ClassType::from($def->implement);
198:             $method = $rc->hasMethod('create') ? $rc->getMethod('create') : ($rc->hasMethod('get') ? $rc->getMethod('get') : NULL);
199:             if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) {
200:                 throw new ServiceCreationException("Interface $def->implement used in service '$name' must have just one non-static method create() or get().");
201:             }
202:             $def->implement = $rc->getName();
203:             $def->implementType = $rc->hasMethod('create') ? 'create' : 'get';
204: 
205:             if (!$def->class && empty($def->factory->entity)) {
206:                 $returnType = $method->getAnnotation('return');
207:                 if (!$returnType) {
208:                     throw new ServiceCreationException("Method $method used in service '$name' has no @return annotation.");
209:                 }
210: 
211:                 $returnType = Reflection\AnnotationsParser::expandClassName(preg_replace('#[|\s].*#', '', $returnType), $rc);
212:                 if (!class_exists($returnType)) {
213:                     throw new ServiceCreationException("Please check a @return annotation of the $method method used in service '$name'. Class '$returnType' cannot be found.");
214:                 }
215:                 $def->setClass($returnType);
216:             }
217: 
218:             if ($method->getName() === 'get') {
219:                 if ($method->getParameters()) {
220:                     throw new ServiceCreationException("Method $method used in service '$name' must have no arguments.");
221:                 }
222:                 if (empty($def->factory->entity)) {
223:                     $def->setFactory('@\\' . ltrim($def->class, '\\'));
224:                 } elseif (!$this->getServiceName($def->factory->entity)) {
225:                     throw new ServiceCreationException("Invalid factory in service '$name' definition.");
226:                 }
227:             }
228: 
229:             if (!$def->parameters) {
230:                 foreach ($method->getParameters() as $param) {
231:                     $paramDef = ($param->isArray() ? 'array' : $param->getClassName()) . ' ' . $param->getName();
232:                     if ($param->isOptional()) {
233:                         $def->parameters[$paramDef] = $param->getDefaultValue();
234:                     } else {
235:                         $def->parameters[] = $paramDef;
236:                     }
237:                 }
238:             }
239:         }
240: 
241:         // complete class-factory pairs
242:         foreach ($this->definitions as $name => $def) {
243:             if (!$def->factory || !$def->factory->entity) {
244:                 if (!$def->class) {
245:                     throw new ServiceCreationException("Class and factory are missing in service '$name' definition.");
246:                 }
247:                 if ($def->factory) {
248:                     $def->factory->entity = $def->class;
249:                 } else {
250:                     $def->factory = new Statement($def->class);
251:                 }
252:             }
253:         }
254: 
255:         // check if services are instantiable
256:         foreach ($this->definitions as $name => $def) {
257:             $factory = $def->factory->entity = $this->normalizeEntity($def->factory->entity);
258: 
259:             if (is_string($factory) && preg_match('#^[\w\\\\]+\z#', $factory) && $factory !== self::THIS_SERVICE) {
260:                 if (!class_exists($factory) || !Reflection\ClassType::from($factory)->isInstantiable()) {
261:                     throw new ServiceCreationException("Class $factory used in service '$name' not found or is not instantiable.");
262:                 }
263:             }
264:         }
265: 
266:         // complete classes
267:         foreach ($this->definitions as $name => $def) {
268:             $this->resolveClass($name);
269: 
270:             if (!$def->class) {
271:                 continue;
272:             } elseif (!class_exists($def->class) && !interface_exists($def->class)) {
273:                 throw new ServiceCreationException("Class or interface $def->class used in service '$name' not found.");
274:             } else {
275:                 $def->class = Reflection\ClassType::from($def->class)->getName();
276:             }
277:         }
278: 
279:         //  build auto-wiring list
280:         $this->classes = array();
281:         foreach ($this->definitions as $name => $def) {
282:             $class = $def->implement ?: $def->class;
283:             if ($def->autowired && $class) {
284:                 foreach (class_parents($class) + class_implements($class) + array($class) as $parent) {
285:                     $this->classes[strtolower($parent)][] = (string) $name;
286:                 }
287:             }
288:         }
289: 
290:         foreach ($this->classes as $class => $foo) {
291:             $this->addDependency(Reflection\ClassType::from($class)->getFileName());
292:         }
293:     }
294: 
295: 
296:     private function resolveClass($name, $recursive = array())
297:     {
298:         if (isset($recursive[$name])) {
299:             throw new ServiceCreationException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($recursive))));
300:         }
301:         $recursive[$name] = TRUE;
302: 
303:         $def = $this->definitions[$name];
304:         $factory = $def->factory->entity;
305: 
306:         if ($def->class) {
307:             return $def->class;
308: 
309:         } elseif (is_array($factory)) { // method calling
310:             if ($service = $this->getServiceName($factory[0])) {
311:                 if (Strings::contains($service, '\\')) { // @\Class
312:                     $factory[0] = $service;
313:                 } else {
314:                     $factory[0] = $this->resolveClass($service, $recursive);
315:                     if (!$factory[0]) {
316:                         return;
317:                     }
318:                     if ($this->definitions[$service]->implement && $factory[1] === 'create') {
319:                         return $def->class = $factory[0];
320:                     }
321:                 }
322:             }
323:             try {
324:                 $reflection = Nette\Utils\Callback::toReflection($factory);
325:             } catch (\ReflectionException $e) {
326:             }
327:             if (isset($e) || !is_callable($factory)) {
328:                 throw new ServiceCreationException(sprintf("Factory '%s' used in service '%s' is not callable.", Nette\Utils\Callback::toString($factory), $name));
329:             }
330:             $def->class = preg_replace('#[|\s].*#', '', $reflection->getAnnotation('return'));
331:             if ($def->class && $reflection instanceof \ReflectionMethod) {
332:                 $def->class = Reflection\AnnotationsParser::expandClassName($tmp = $def->class, $reflection->getDeclaringClass());
333:                 if ($tmp !== $def->class && $tmp[0] !== '\\' && class_exists($tmp)) {
334:                     $def->class = $tmp;
335:                     trigger_error("You should use @return \\$tmp' in $reflection.", E_USER_WARNING);
336:                 }
337:             }
338: 
339:         } elseif ($service = $this->getServiceName($factory)) { // alias or factory
340:             if (!$def->implement) {
341:                 $def->autowired = FALSE;
342:             }
343:             if (Strings::contains($service, '\\')) { // @\Class
344:                 return $def->class = $service;
345:             }
346:             if ($this->definitions[$service]->implement) {
347:                 $def->autowired = FALSE;
348:             }
349:             return $def->class = $this->definitions[$service]->implement ?: $this->resolveClass($service, $recursive);
350: 
351:         } else {
352:             return $def->class = $factory; // class name
353:         }
354:     }
355: 
356: 
357:     /**
358:      * Adds a file to the list of dependencies.
359:      * @return self
360:      */
361:     public function addDependency($file)
362:     {
363:         $this->dependencies[$file] = TRUE;
364:         return $this;
365:     }
366: 
367: 
368:     /**
369:      * Returns the list of dependent files.
370:      * @return array
371:      */
372:     public function getDependencies()
373:     {
374:         unset($this->dependencies[FALSE]);
375:         return array_keys($this->dependencies);
376:     }
377: 
378: 
379:     /********************* code generator ****************d*g**/
380: 
381: 
382:     /**
383:      * Generates PHP classes. First class is the container.
384:      * @return Nette\PhpGenerator\ClassType[]
385:      */
386:     public function generateClasses($className = 'Container', $parentName = 'Nette\DI\Container')
387:     {
388:         unset($this->definitions[self::THIS_CONTAINER]);
389:         $this->addDefinition(self::THIS_CONTAINER)->setClass('Nette\DI\Container');
390: 
391:         $this->generatedClasses = array();
392:         $this->prepareClassList();
393: 
394:         $containerClass = $this->generatedClasses[] = new Nette\PhpGenerator\ClassType($className);
395:         $containerClass->setExtends($parentName);
396:         $containerClass->addMethod('__construct')
397:             ->addBody('parent::__construct(?);', array($this->parameters));
398: 
399:         $definitions = $this->definitions;
400:         ksort($definitions);
401: 
402:         $meta = $containerClass->addProperty('meta', array())
403:             ->setVisibility('protected')
404:             ->setValue(array(Container::TYPES => $this->classes));
405: 
406:         foreach ($definitions as $name => $def) {
407:             foreach ($def->tags as $tag => $value) {
408:                 $meta->value[Container::TAGS][$tag][$name] = $value;
409:             }
410:         }
411: 
412:         foreach ($definitions as $name => $def) {
413:             try {
414:                 $name = (string) $name;
415:                 $methodName = Container::getMethodName($name);
416:                 if (!PhpHelpers::isIdentifier($methodName)) {
417:                     throw new ServiceCreationException('Name contains invalid characters.');
418:                 }
419:                 $containerClass->addMethod($methodName)
420:                     ->addDocument('@return ' . ($def->implement ?: $def->class))
421:                     ->setBody($name === self::THIS_CONTAINER ? 'return $this;' : $this->generateService($name))
422:                     ->setParameters($def->implement ? array() : $this->convertParameters($def->parameters));
423:             } catch (\Exception $e) {
424:                 throw new ServiceCreationException("Service '$name': " . $e->getMessage(), NULL, $e);
425:             }
426:         }
427: 
428:         return $this->generatedClasses;
429:     }
430: 
431: 
432:     /**
433:      * Generates body of service method.
434:      * @return string
435:      */
436:     private function generateService($name)
437:     {
438:         $this->currentService = NULL;
439:         $def = $this->definitions[$name];
440: 
441:         $serviceRef = $this->getServiceName($def->factory->entity);
442:         $factory = $serviceRef && !$def->factory->arguments && !$def->setup && $def->implementType !== 'create'
443:             ? new Statement(array('@' . ContainerBuilder::THIS_CONTAINER, 'getService'), array($serviceRef))
444:             : $def->factory;
445: 
446:         $code = '$service = ' . $this->formatStatement($factory) . ";\n";
447:         $this->currentService = $name;
448: 
449:         if ($def->class && $def->class !== $def->factory->entity && !$serviceRef) {
450:             $code .= PhpHelpers::formatArgs("if (!\$service instanceof $def->class) {\n"
451:                 . "\tthrow new Nette\\UnexpectedValueException(?);\n}\n",
452:                 array("Unable to create service '$name', value returned by factory is not $def->class type.")
453:             );
454:         }
455: 
456:         $setups = (array) $def->setup;
457:         if ($def->inject && $def->class) {
458:             $injects = array();
459:             foreach (Helpers::getInjectProperties(Reflection\ClassType::from($def->class), $this) as $property => $type) {
460:                 $injects[] = new Statement('$' . $property, array('@\\' . ltrim($type, '\\')));
461:             }
462: 
463:             foreach (get_class_methods($def->class) as $method) {
464:                 if (substr($method, 0, 6) === 'inject') {
465:                     $injects[] = new Statement($method);
466:                 }
467:             }
468: 
469:             foreach ($injects as $inject) {
470:                 foreach ($setups as $key => $setup) {
471:                     if ($setup->entity === $inject->entity) {
472:                         $inject = $setup;
473:                         unset($setups[$key]);
474:                     }
475:                 }
476:                 array_unshift($setups, $inject);
477:             }
478:         }
479: 
480:         foreach ($setups as $setup) {
481:             if (is_string($setup->entity) && strpbrk($setup->entity, ':@?') === FALSE) { // auto-prepend @self
482:                 $setup->entity = array('@self', $setup->entity);
483:             }
484:             $code .= $this->formatStatement($setup) . ";\n";
485:         }
486:         $this->currentService = NULL;
487: 
488:         $code .= 'return $service;';
489: 
490:         if (!$def->implement) {
491:             return $code;
492:         }
493: 
494:         $factoryClass = $this->generatedClasses[] = new Nette\PhpGenerator\ClassType;
495:         $factoryClass->setName(str_replace(array('\\', '.'), '_', "{$this->generatedClasses[0]->name}_{$def->implement}Impl_{$name}"))
496:             ->addImplement($def->implement)
497:             ->setFinal(TRUE);
498: 
499:         $factoryClass->addProperty('container')
500:             ->setVisibility('private');
501: 
502:         $factoryClass->addMethod('__construct')
503:             ->addBody('$this->container = $container;')
504:             ->addParameter('container')
505:                 ->setTypeHint('Nette\DI\Container');
506: 
507:         $factoryClass->addMethod($def->implementType)
508:             ->setParameters($this->convertParameters($def->parameters))
509:             ->setBody(str_replace('$this', '$this->container', $code));
510: 
511:         return "return new {$factoryClass->name}(\$this);";
512:     }
513: 
514: 
515:     /**
516:      * Converts parameters from ServiceDefinition to PhpGenerator.
517:      * @return Nette\PhpGenerator\Parameter[]
518:      */
519:     private function convertParameters(array $parameters)
520:     {
521:         $res = array();
522:         foreach ($parameters as $k => $v) {
523:             $tmp = explode(' ', is_int($k) ? $v : $k);
524:             $param = $res[] = new Nette\PhpGenerator\Parameter;
525:             $param->setName(end($tmp));
526:             if (!is_int($k)) {
527:                 $param = $param->setOptional(TRUE)->setDefaultValue($v);
528:             }
529:             if (isset($tmp[1])) {
530:                 $param->setTypeHint($tmp[0]);
531:             }
532:         }
533:         return $res;
534:     }
535: 
536: 
537:     /**
538:      * Formats PHP code for class instantiating, function calling or property setting in PHP.
539:      * @return string
540:      * @internal
541:      */
542:     public function formatStatement(Statement $statement)
543:     {
544:         $entity = $this->normalizeEntity($statement->entity);
545:         $arguments = $statement->arguments;
546: 
547:         if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal
548:             return $this->formatPhp($entity, $arguments);
549: 
550:         } elseif ($service = $this->getServiceName($entity)) { // factory calling
551:             $params = array();
552:             foreach ($this->definitions[$service]->parameters as $k => $v) {
553:                 $params[] = preg_replace('#\w+\z#', '\$$0', (is_int($k) ? $v : $k)) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v));
554:             }
555:             $rm = new Reflection\GlobalFunction(create_function(implode(', ', $params), ''));
556:             $arguments = Helpers::autowireArguments($rm, $arguments, $this);
557:             return $this->formatPhp('$this->?(?*)', array(Container::getMethodName($service), $arguments));
558: 
559:         } elseif ($entity === 'not') { // operator
560:             return $this->formatPhp('!?', array($arguments[0]));
561: 
562:         } elseif (is_string($entity)) { // class name
563:             if ($constructor = Reflection\ClassType::from($entity)->getConstructor()) {
564:                 $this->addDependency($constructor->getFileName());
565:                 $arguments = Helpers::autowireArguments($constructor, $arguments, $this);
566:             } elseif ($arguments) {
567:                 throw new ServiceCreationException("Unable to pass arguments, class $entity has no constructor.");
568:             }
569:             return $this->formatPhp("new $entity" . ($arguments ? '(?*)' : ''), array($arguments));
570: 
571:         } elseif (!Nette\Utils\Arrays::isList($entity) || count($entity) !== 2) {
572:             throw new ServiceCreationException(sprintf('Expected class, method or property, %s given.', PhpHelpers::dump($entity)));
573: 
574:         } elseif ($entity[0] === '') { // globalFunc
575:             return $this->formatPhp("$entity[1](?*)", array($arguments));
576: 
577:         } elseif (Strings::contains($entity[1], '$')) { // property setter
578:             Validators::assert($arguments, 'list:1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'");
579:             if ($this->getServiceName($entity[0])) {
580:                 return $this->formatPhp('?->? = ?', array($entity[0], substr($entity[1], 1), $arguments[0]));
581:             } else {
582:                 return $this->formatPhp($entity[0] . '::$? = ?', array(substr($entity[1], 1), $arguments[0]));
583:             }
584: 
585:         } elseif ($service = $this->getServiceName($entity[0])) { // service method
586:             $class = $this->definitions[$service]->implement;
587:             if (!$class || !method_exists($class, $entity[1])) {
588:                 $class = $this->definitions[$service]->class;
589:             }
590:             if ($class) {
591:                 $arguments = $this->autowireArguments($class, $entity[1], $arguments);
592:             }
593:             return $this->formatPhp('?->?(?*)', array($entity[0], $entity[1], $arguments));
594: 
595:         } else { // static method
596:             $arguments = $this->autowireArguments($entity[0], $entity[1], $arguments);
597:             return $this->formatPhp("$entity[0]::$entity[1](?*)", array($arguments));
598:         }
599:     }
600: 
601: 
602:     /**
603:      * Formats PHP statement.
604:      * @return string
605:      * @internal
606:      */
607:     public function formatPhp($statement, $args)
608:     {
609:         $that = $this;
610:         array_walk_recursive($args, function (& $val) use ($that) {
611:             if ($val instanceof Statement) {
612:                 $val = ContainerBuilder::literal($that->formatStatement($val));
613: 
614:             } elseif ($val === $that) {
615:                 $val = ContainerBuilder::literal('$this');
616: 
617:             } elseif ($val instanceof ServiceDefinition) {
618:                 $val = '@' . current(array_keys($that->definitions, $val, TRUE));
619: 
620:             } elseif (is_string($val) && preg_match('#^[\w\\\\]*::[A-Z][A-Z0-9_]*\z#', $val, $m)) {
621:                 $val = ContainerBuilder::literal(ltrim($val, ':'));
622:             }
623: 
624:             if (is_string($val) && substr($val, 0, 1) === '@') {
625:                 $pair = explode('::', $val, 2);
626:                 $name = $that->getServiceName($pair[0]);
627:                 if (isset($pair[1]) && preg_match('#^[A-Z][A-Z0-9_]*\z#', $pair[1], $m)) {
628:                     $val = $that->definitions[$name]->class . '::' . $pair[1];
629:                 } else {
630:                     if ($name === ContainerBuilder::THIS_CONTAINER) {
631:                         $val = '$this';
632:                     } elseif ($name === $that->currentService) {
633:                         $val = '$service';
634:                     } else {
635:                         $val = $that->formatStatement(new Statement(array('@' . ContainerBuilder::THIS_CONTAINER, 'getService'), array($name)));
636:                     }
637:                     $val .= (isset($pair[1]) ? PhpHelpers::formatArgs('->?', array($pair[1])) : '');
638:                 }
639:                 $val = ContainerBuilder::literal($val);
640:             }
641:         });
642:         return PhpHelpers::formatArgs($statement, $args);
643:     }
644: 
645: 
646:     /**
647:      * Expands %placeholders% in strings.
648:      * @return mixed
649:      */
650:     public function expand($value)
651:     {
652:         return Helpers::expand($value, $this->parameters);
653:     }
654: 
655: 
656:     /**
657:      * @return Nette\PhpGenerator\PhpLiteral
658:      */
659:     public static function literal($phpCode)
660:     {
661:         return new Nette\PhpGenerator\PhpLiteral($phpCode);
662:     }
663: 
664: 
665:     /** @internal */
666:     public function normalizeEntity($entity)
667:     {
668:         if (is_string($entity) && Strings::contains($entity, '::') && !Strings::contains($entity, '?')) { // Class::method -> [Class, method]
669:             $entity = explode('::', $entity);
670:         }
671: 
672:         if (is_array($entity) && $entity[0] instanceof ServiceDefinition) { // [ServiceDefinition, ...] -> [@serviceName, ...]
673:             $entity[0] = '@' . current(array_keys($this->definitions, $entity[0], TRUE));
674: 
675:         } elseif ($entity instanceof ServiceDefinition) { // ServiceDefinition -> @serviceName
676:             $entity = '@' . current(array_keys($this->definitions, $entity, TRUE));
677: 
678:         } elseif (is_array($entity) && $entity[0] === $this) { // [$this, ...] -> [@container, ...]
679:             $entity[0] = '@' . ContainerBuilder::THIS_CONTAINER;
680:         }
681:         return $entity; // Class, @service, [Class, member], [@service, member], [, globalFunc]
682:     }
683: 
684: 
685:     /**
686:      * Converts @service or @\Class -> service name and checks its existence.
687:      * @return string  of FALSE, if argument is not service name
688:      * @internal
689:      */
690:     public function getServiceName($arg)
691:     {
692:         if (!is_string($arg) || !preg_match('#^@[\w\\\\.].*\z#', $arg)) {
693:             return FALSE;
694:         }
695:         $service = substr($arg, 1);
696:         if ($service === self::THIS_SERVICE) {
697:             $service = $this->currentService;
698:         }
699:         if (Strings::contains($service, '\\')) {
700:             if ($this->classes === FALSE) { // may be disabled by prepareClassList
701:                 return $service;
702:             }
703:             $res = $this->getByType($service);
704:             if (!$res) {
705:                 throw new ServiceCreationException("Reference to missing service of type $service.");
706:             }
707:             return $res;
708:         }
709:         if (!isset($this->definitions[$service])) {
710:             throw new ServiceCreationException("Reference to missing service '$service'.");
711:         }
712:         return $service;
713:     }
714: 
715: 
716:     /** @deprecated */
717:     function generateClass()
718:     {
719:         throw new Nette\DeprecatedException(__METHOD__ . '() is deprecated; use generateClasses()[0] instead.');
720:     }
721: 
722: }
723: 
Nette 2.1 API documentation generated by ApiGen 2.8.0