1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\DI;
9:
10: use Nette;
11: use Nette\PhpGenerator\Helpers as PhpHelpers;
12: use Nette\Utils\Strings;
13: use Nette\Utils\Validators;
14: use Nette\Utils\Reflection;
15: use ReflectionClass;
16:
17:
18: 19: 20:
21: class ContainerBuilder
22: {
23: use Nette\SmartObject;
24:
25: const THIS_SERVICE = 'self',
26: THIS_CONTAINER = 'container';
27:
28:
29: public $parameters = [];
30:
31:
32: private $definitions = [];
33:
34:
35: private $aliases = [];
36:
37:
38: private $classList = [];
39:
40:
41: private $classListNeedsRefresh = TRUE;
42:
43:
44: private $excludedClasses = [];
45:
46:
47: private $dependencies = [];
48:
49:
50: private $currentService;
51:
52:
53: 54: 55: 56: 57:
58: public function addDefinition($name, ServiceDefinition $definition = NULL)
59: {
60: $this->classListNeedsRefresh = TRUE;
61: if (!is_string($name) || !$name) {
62: throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name)));
63: }
64: $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
65: if (isset($this->definitions[$name])) {
66: throw new Nette\InvalidStateException("Service '$name' has already been added.");
67: }
68: if (!$definition) {
69: $definition = new ServiceDefinition;
70: }
71: $definition->setNotifier(function () {
72: $this->classListNeedsRefresh = TRUE;
73: });
74: return $this->definitions[$name] = $definition;
75: }
76:
77:
78: 79: 80: 81: 82:
83: public function removeDefinition($name)
84: {
85: $this->classListNeedsRefresh = TRUE;
86: $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
87: unset($this->definitions[$name]);
88: }
89:
90:
91: 92: 93: 94: 95:
96: public function getDefinition($name)
97: {
98: $service = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
99: if (!isset($this->definitions[$service])) {
100: throw new MissingServiceException("Service '$name' not found.");
101: }
102: return $this->definitions[$service];
103: }
104:
105:
106: 107: 108: 109:
110: public function getDefinitions()
111: {
112: return $this->definitions;
113: }
114:
115:
116: 117: 118: 119: 120:
121: public function hasDefinition($name)
122: {
123: $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
124: return isset($this->definitions[$name]);
125: }
126:
127:
128: 129: 130: 131:
132: public function addAlias($alias, $service)
133: {
134: if (!is_string($alias) || !$alias) {
135: throw new Nette\InvalidArgumentException(sprintf('Alias name must be a non-empty string, %s given.', gettype($alias)));
136:
137: } elseif (!is_string($service) || !$service) {
138: throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($service)));
139:
140: } elseif (isset($this->aliases[$alias])) {
141: throw new Nette\InvalidStateException("Alias '$alias' has already been added.");
142:
143: } elseif (isset($this->definitions[$alias])) {
144: throw new Nette\InvalidStateException("Service '$alias' has already been added.");
145:
146: }
147: $this->aliases[$alias] = $service;
148: }
149:
150:
151: 152: 153: 154:
155: public function removeAlias($alias)
156: {
157: unset($this->aliases[$alias]);
158: }
159:
160:
161: 162: 163: 164:
165: public function getAliases()
166: {
167: return $this->aliases;
168: }
169:
170:
171: 172: 173: 174:
175: public function addExcludedClasses(array $classes)
176: {
177: foreach ($classes as $class) {
178: if (class_exists($class) || interface_exists($class)) {
179: self::checkCase($class);
180: $this->excludedClasses += class_parents($class) + class_implements($class) + [$class => $class];
181: }
182: }
183: return $this;
184: }
185:
186:
187: 188: 189:
190: public function setClassName($name)
191: {
192: trigger_error(__METHOD__ . ' has been deprecated', E_USER_DEPRECATED);
193: return $this;
194: }
195:
196:
197: 198: 199:
200: public function getClassName()
201: {
202: trigger_error(__METHOD__ . ' has been deprecated', E_USER_DEPRECATED);
203: }
204:
205:
206:
207:
208:
209: 210: 211: 212: 213: 214:
215: public function getByType($class)
216: {
217: $class = ltrim($class, '\\');
218:
219: if ($this->currentService !== NULL
220: && is_a($this->definitions[$this->currentService]->getClass(), $class, TRUE)
221: ) {
222: return $this->currentService;
223: }
224:
225: $classes = $this->getClassList();
226: if (empty($classes[$class][TRUE])) {
227: self::checkCase($class);
228: return;
229:
230: } elseif (count($classes[$class][TRUE]) === 1) {
231: return $classes[$class][TRUE][0];
232:
233: } else {
234: $list = $classes[$class][TRUE];
235: $hint = count($list) === 2 && ($tmp = strpos($list[0], '.') xor strpos($list[1], '.'))
236: ? '. If you want to overwrite service ' . $list[$tmp ? 0 : 1] . ', give it proper name.'
237: : '';
238: throw new ServiceCreationException("Multiple services of type $class found: " . implode(', ', $list) . $hint);
239: }
240: }
241:
242:
243: 244: 245: 246: 247:
248: public function getDefinitionByType($class)
249: {
250: $definitionName = $this->getByType($class);
251: if (!$definitionName) {
252: throw new MissingServiceException("Service of type '$class' not found.");
253: }
254:
255: return $this->getDefinition($definitionName);
256: }
257:
258:
259: 260: 261: 262: 263:
264: public function findByType($class)
265: {
266: $class = ltrim($class, '\\');
267: self::checkCase($class);
268: $found = [];
269: $classes = $this->getClassList();
270: if (!empty($classes[$class])) {
271: foreach (array_merge(...array_values($classes[$class])) as $name) {
272: $found[$name] = $this->definitions[$name];
273: }
274: }
275: return $found;
276: }
277:
278:
279: 280: 281: 282: 283:
284: public function findByTag($tag)
285: {
286: $found = [];
287: foreach ($this->definitions as $name => $def) {
288: if (($tmp = $def->getTag($tag)) !== NULL) {
289: $found[$name] = $tmp;
290: }
291: }
292: return $found;
293: }
294:
295:
296: 297: 298:
299: public function getClassList()
300: {
301: if ($this->classList !== FALSE && $this->classListNeedsRefresh) {
302: $this->prepareClassList();
303: $this->classListNeedsRefresh = FALSE;
304: }
305: return $this->classList ?: [];
306: }
307:
308:
309: 310: 311: 312: 313:
314: public function prepareClassList()
315: {
316: unset($this->definitions[self::THIS_CONTAINER]);
317: $this->addDefinition(self::THIS_CONTAINER)->setClass(Container::class);
318:
319: $this->classList = FALSE;
320:
321: foreach ($this->definitions as $name => $def) {
322:
323: if ($def->getImplement()) {
324: $this->resolveImplement($def, $name);
325: }
326:
327: if ($def->isDynamic()) {
328: if (!$def->getClass()) {
329: throw new ServiceCreationException("Class is missing in definition of service '$name'.");
330: }
331: $def->setFactory(NULL);
332: continue;
333: }
334:
335:
336: if (!$def->getEntity()) {
337: if (!$def->getClass()) {
338: throw new ServiceCreationException("Class and factory are missing in definition of service '$name'.");
339: }
340: $def->setFactory($def->getClass(), ($factory = $def->getFactory()) ? $factory->arguments : []);
341: }
342:
343:
344: if (($alias = $this->getServiceName($def->getFactory()->getEntity())) &&
345: (!$def->getImplement() || (!Strings::contains($alias, '\\') && $this->definitions[$alias]->getImplement()))
346: ) {
347: $def->setAutowired(FALSE);
348: }
349: }
350:
351:
352: foreach ($this->definitions as $name => $def) {
353: $this->resolveServiceClass($name);
354: }
355:
356:
357: $this->classList = $preferred = [];
358: foreach ($this->definitions as $name => $def) {
359: if ($class = $def->getImplement() ?: $def->getClass()) {
360: $defAutowired = $def->getAutowired();
361: if (is_array($defAutowired)) {
362: foreach ($defAutowired as $k => $aclass) {
363: if ($aclass === self::THIS_SERVICE) {
364: $defAutowired[$k] = $class;
365: } elseif (!is_a($class, $aclass, TRUE)) {
366: throw new ServiceCreationException("Incompatible class $aclass in autowiring definition of service '$name'.");
367: }
368: }
369: }
370:
371: foreach (class_parents($class) + class_implements($class) + [$class] as $parent) {
372: $autowired = $defAutowired && empty($this->excludedClasses[$parent]);
373: if ($autowired && is_array($defAutowired)) {
374: $autowired = FALSE;
375: foreach ($defAutowired as $aclass) {
376: if (is_a($parent, $aclass, TRUE)) {
377: if (empty($preferred[$parent]) && isset($this->classList[$parent][TRUE])) {
378: $this->classList[$parent][FALSE] = array_merge(...$this->classList[$parent]);
379: $this->classList[$parent][TRUE] = [];
380: }
381: $preferred[$parent] = $autowired = TRUE;
382: break;
383: }
384: }
385: } elseif (isset($preferred[$parent])) {
386: $autowired = FALSE;
387: }
388: $this->classList[$parent][$autowired][] = (string) $name;
389: }
390: }
391: }
392: }
393:
394:
395: private function resolveImplement(ServiceDefinition $def, $name)
396: {
397: $interface = $def->getImplement();
398: if (!interface_exists($interface)) {
399: throw new ServiceCreationException("Interface $interface used in service '$name' not found.");
400: }
401: self::checkCase($interface);
402: $rc = new ReflectionClass($interface);
403: $this->addDependency($rc);
404: $method = $rc->hasMethod('create')
405: ? $rc->getMethod('create')
406: : ($rc->hasMethod('get') ? $rc->getMethod('get') : NULL);
407:
408: if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) {
409: throw new ServiceCreationException("Interface $interface used in service '$name' must have just one non-static method create() or get().");
410: }
411: $def->setImplementMode($rc->hasMethod('create') ? $def::IMPLEMENT_MODE_CREATE : $def::IMPLEMENT_MODE_GET);
412: $methodName = Reflection::toString($method) . '()';
413:
414: if (!$def->getClass() && !$def->getEntity()) {
415: $returnType = Helpers::getReturnType($method);
416: if (!$returnType) {
417: throw new ServiceCreationException("Method $methodName used in service '$name' has not return type hint or annotation @return.");
418: } elseif (!class_exists($returnType)) {
419: throw new ServiceCreationException("Check a type hint or annotation @return of the $methodName method used in service '$name', class '$returnType' cannot be found.");
420: }
421: $def->setClass($returnType);
422: }
423:
424: if ($rc->hasMethod('get')) {
425: if ($method->getParameters()) {
426: throw new ServiceCreationException("Method $methodName used in service '$name' must have no arguments.");
427: }
428: if (!$def->getEntity()) {
429: $def->setFactory('@\\' . ltrim($def->getClass(), '\\'));
430: } elseif (!$this->getServiceName($def->getFactory()->getEntity())) {
431: throw new ServiceCreationException("Invalid factory in service '$name' definition.");
432: }
433: }
434:
435: if (!$def->parameters) {
436: $ctorParams = [];
437: if (!$def->getEntity()) {
438: $def->setFactory($def->getClass(), $def->getFactory() ? $def->getFactory()->arguments : []);
439: }
440: if (($class = $this->resolveEntityClass($def->getFactory(), [$name => 1]))
441: && ($ctor = (new ReflectionClass($class))->getConstructor())
442: ) {
443: foreach ($ctor->getParameters() as $param) {
444: $ctorParams[$param->getName()] = $param;
445: }
446: }
447:
448: foreach ($method->getParameters() as $param) {
449: $hint = Reflection::getParameterType($param);
450: if (isset($ctorParams[$param->getName()])) {
451: $arg = $ctorParams[$param->getName()];
452: if ($hint !== Reflection::getParameterType($arg)) {
453: throw new ServiceCreationException("Type hint for \${$param->getName()} in $methodName doesn't match type hint in $class constructor.");
454: }
455: $def->getFactory()->arguments[$arg->getPosition()] = self::literal('$' . $arg->getName());
456: } elseif (!$def->getSetup()) {
457: $hint = Nette\Utils\ObjectMixin::getSuggestion(array_keys($ctorParams), $param->getName());
458: throw new ServiceCreationException("Unused parameter \${$param->getName()} when implementing method $methodName" . ($hint ? ", did you mean \${$hint}?" : '.'));
459: }
460: $nullable = $hint && $param->allowsNull() && (!$param->isDefaultValueAvailable() || $param->getDefaultValue() !== NULL);
461: $paramDef = ($nullable ? '?' : '') . $hint . ' ' . $param->getName();
462: if ($param->isDefaultValueAvailable()) {
463: $def->parameters[$paramDef] = Reflection::getParameterDefaultValue($param);
464: } else {
465: $def->parameters[] = $paramDef;
466: }
467: }
468: }
469: }
470:
471:
472:
473: private function resolveServiceClass($name, $recursive = [])
474: {
475: if (isset($recursive[$name])) {
476: throw new ServiceCreationException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($recursive))));
477: }
478: $recursive[$name] = TRUE;
479:
480: $def = $this->definitions[$name];
481: $factoryClass = $def->getFactory() ? $this->resolveEntityClass($def->getFactory()->getEntity(), $recursive) : NULL;
482: if ($class = $def->getClass() ?: $factoryClass) {
483: if (!class_exists($class) && !interface_exists($class)) {
484: throw new ServiceCreationException("Class or interface '$class' used in service '$name' not found.");
485: }
486: self::checkCase($class);
487: $def->setClass($class);
488: if (count($recursive) === 1) {
489: $this->addDependency(new ReflectionClass($factoryClass ?: $class));
490: }
491:
492: } elseif ($def->getAutowired()) {
493: throw new ServiceCreationException("Unknown type of service '$name', declare return type of factory method (for PHP 5 use annotation @return)");
494: }
495: return $class;
496: }
497:
498:
499:
500: private function resolveEntityClass($entity, $recursive = [])
501: {
502: $entity = $this->normalizeEntity($entity instanceof Statement ? $entity->getEntity() : $entity);
503: $serviceName = current(array_slice(array_keys($recursive), -1));
504:
505: if (is_array($entity)) {
506: if (($service = $this->getServiceName($entity[0])) || $entity[0] instanceof Statement) {
507: $entity[0] = $this->resolveEntityClass($entity[0], $recursive);
508: if (!$entity[0]) {
509: return;
510: } elseif (isset($this->definitions[$service]) && $this->definitions[$service]->getImplement()) {
511: return $entity[1] === 'create' ? $this->resolveServiceClass($service, $recursive) : NULL;
512: }
513: }
514:
515: try {
516: $reflection = Nette\Utils\Callback::toReflection($entity[0] === '' ? $entity[1] : $entity);
517: $refClass = $reflection instanceof \ReflectionMethod ? $reflection->getDeclaringClass() : NULL;
518: } catch (\ReflectionException $e) {
519: }
520:
521: if (isset($e) || ($refClass && (!$reflection->isPublic()
522: || ($refClass->isTrait() && !$reflection->isStatic())
523: ))) {
524: throw new ServiceCreationException(sprintf("Method %s() used in service '%s' is not callable.", Nette\Utils\Callback::toString($entity), $serviceName));
525: }
526: $this->addDependency($reflection);
527:
528: $type = Helpers::getReturnType($reflection);
529: if ($type && !class_exists($type) && !interface_exists($type)) {
530: throw new ServiceCreationException(sprintf("Class or interface '%s' not found. Is return type of %s() used in service '%s' correct?", $type, Nette\Utils\Callback::toString($entity), $serviceName));
531: }
532: return $type;
533:
534: } elseif ($service = $this->getServiceName($entity)) {
535: if (Strings::contains($service, '\\')) {
536: return ltrim($service, '\\');
537: }
538: return $this->definitions[$service]->getImplement()
539: ?: $this->definitions[$service]->getClass()
540: ?: $this->resolveServiceClass($service, $recursive);
541:
542: } elseif (is_string($entity)) {
543: if (!class_exists($entity)) {
544: throw new ServiceCreationException("Class $entity used in service '$serviceName' not found.");
545: }
546: return ltrim($entity, '\\');
547: }
548: }
549:
550:
551: 552: 553:
554: public function complete()
555: {
556: $this->prepareClassList();
557:
558: foreach ($this->definitions as $name => $def) {
559: if ($def->isDynamic()) {
560: continue;
561: }
562:
563: $this->currentService = NULL;
564: $entity = $def->getFactory()->getEntity();
565: $serviceRef = $this->getServiceName($entity);
566: $factory = $serviceRef && !$def->getFactory()->arguments && !$def->getSetup() && $def->getImplementMode() !== $def::IMPLEMENT_MODE_CREATE
567: ? new Statement(['@' . self::THIS_CONTAINER, 'getService'], [$serviceRef])
568: : $def->getFactory();
569:
570: try {
571: $def->setFactory($this->completeStatement($factory));
572: $this->classListNeedsRefresh = FALSE;
573:
574: $this->currentService = $name;
575: $setups = $def->getSetup();
576: foreach ($setups as &$setup) {
577: if (is_string($setup->getEntity()) && strpbrk($setup->getEntity(), ':@?\\') === FALSE) {
578: $setup = new Statement(['@' . $name, $setup->getEntity()], $setup->arguments);
579: }
580: $setup = $this->completeStatement($setup);
581: }
582: $def->setSetup($setups);
583:
584: } catch (\Exception $e) {
585: throw new ServiceCreationException("Service '$name': " . $e->getMessage(), 0, $e);
586:
587: } finally {
588: $this->currentService = NULL;
589: }
590: }
591: }
592:
593:
594: 595: 596:
597: public function completeStatement(Statement $statement)
598: {
599: $entity = $this->normalizeEntity($statement->getEntity());
600: $arguments = $statement->arguments;
601:
602: if (is_string($entity) && Strings::contains($entity, '?')) {
603:
604: } elseif ($service = $this->getServiceName($entity)) {
605: $params = [];
606: foreach ($this->definitions[$service]->parameters as $k => $v) {
607: $params[] = preg_replace('#\w+\z#', '\$$0', (is_int($k) ? $v : $k)) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v));
608: }
609: $rm = new \ReflectionFunction(create_function(implode(', ', $params), ''));
610: $arguments = Helpers::autowireArguments($rm, $arguments, $this);
611: $entity = '@' . $service;
612:
613: } elseif ($entity === 'not') {
614:
615: } elseif (is_string($entity)) {
616: if (!class_exists($entity)) {
617: throw new ServiceCreationException("Class $entity not found.");
618: } elseif ((new ReflectionClass($entity))->isAbstract()) {
619: throw new ServiceCreationException("Class $entity is abstract.");
620: } elseif (($rm = (new ReflectionClass($entity))->getConstructor()) !== NULL && !$rm->isPublic()) {
621: $visibility = $rm->isProtected() ? 'protected' : 'private';
622: throw new ServiceCreationException("Class $entity has $visibility constructor.");
623: } elseif ($constructor = (new ReflectionClass($entity))->getConstructor()) {
624: $this->addDependency($constructor);
625: $arguments = Helpers::autowireArguments($constructor, $arguments, $this);
626: } elseif ($arguments) {
627: throw new ServiceCreationException("Unable to pass arguments, class $entity has no constructor.");
628: }
629:
630: } elseif (!Nette\Utils\Arrays::isList($entity) || count($entity) !== 2) {
631: throw new ServiceCreationException(sprintf('Expected class, method or property, %s given.', PhpHelpers::dump($entity)));
632:
633: } elseif (!preg_match('#^\$?' . PhpHelpers::PHP_IDENT . '(\[\])?\z#', $entity[1])) {
634: throw new ServiceCreationException("Expected function, method or property name, '$entity[1]' given.");
635:
636: } elseif ($entity[0] === '') {
637: if (!Nette\Utils\Arrays::isList($arguments)) {
638: throw new ServiceCreationException("Unable to pass specified arguments to $entity[0].");
639: } elseif (!function_exists($entity[1])) {
640: throw new ServiceCreationException("Function $entity[1] doesn't exist.");
641: }
642:
643: $rf = new \ReflectionFunction($entity[1]);
644: $this->addDependency($rf);
645: $arguments = Helpers::autowireArguments($rf, $arguments, $this);
646:
647: } else {
648: if ($entity[0] instanceof Statement) {
649: $entity[0] = $this->completeStatement($entity[0]);
650: } elseif ($service = $this->getServiceName($entity[0])) {
651: $entity[0] = '@' . $service;
652: }
653:
654: if ($entity[1][0] === '$') {
655: Validators::assert($arguments, 'list:0..1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'");
656: if (!$arguments && substr($entity[1], -2) === '[]') {
657: throw new ServiceCreationException("Missing argument for $entity[1].");
658: }
659: } elseif ($class = empty($service) || $entity[1] === 'create'
660: ? $this->resolveEntityClass($entity[0])
661: : $this->definitions[$service]->getClass()
662: ) {
663: $arguments = $this->autowireArguments($class, $entity[1], $arguments);
664: }
665: }
666:
667: array_walk_recursive($arguments, function (&$val) {
668: if ($val instanceof Statement) {
669: $val = $this->completeStatement($val);
670:
671: } elseif ($val === $this) {
672: trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED);
673: $val = self::literal('$this');
674:
675: } elseif ($val instanceof ServiceDefinition) {
676: $val = '@' . current(array_keys($this->getDefinitions(), $val, TRUE));
677:
678: } elseif (is_string($val) && strlen($val) > 1 && $val[0] === '@' && $val[1] !== '@') {
679: $pair = explode('::', $val, 2);
680: $name = $this->getServiceName($pair[0]);
681: if (!isset($pair[1])) {
682: $val = '@' . $name;
683: } elseif (preg_match('#^[A-Z][A-Z0-9_]*\z#', $pair[1], $m)) {
684: $val = self::literal($this->getDefinition($name)->getClass() . '::' . $pair[1]);
685: } else {
686: $val = new Statement(['@' . $name, '$' . $pair[1]]);
687: }
688: }
689: });
690:
691: return new Statement($entity, $arguments);
692: }
693:
694:
695: private function checkCase($class)
696: {
697: if ((class_exists($class) || interface_exists($class)) && $class !== ($name = (new ReflectionClass($class))->getName())) {
698: throw new ServiceCreationException("Case mismatch on class name '$class', correct name is '$name'.");
699: }
700: }
701:
702:
703: 704: 705: 706: 707: 708:
709: public function addDependency($dep)
710: {
711: $this->dependencies[] = $dep;
712: return $this;
713: }
714:
715:
716: 717: 718: 719:
720: public function getDependencies()
721: {
722: return $this->dependencies;
723: }
724:
725:
726: 727: 728: 729: 730:
731: public function expand($value)
732: {
733: return Helpers::expand($value, $this->parameters);
734: }
735:
736:
737: 738: 739:
740: public static function literal($code, array $args = NULL)
741: {
742: return new Nette\PhpGenerator\PhpLiteral($args === NULL ? $code : PhpHelpers::formatArgs($code, $args));
743: }
744:
745:
746:
747: public function normalizeEntity($entity)
748: {
749: if (is_string($entity) && Strings::contains($entity, '::') && !Strings::contains($entity, '?')) {
750: $entity = explode('::', $entity);
751: }
752:
753: if (is_array($entity) && $entity[0] instanceof ServiceDefinition) {
754: $entity[0] = '@' . current(array_keys($this->definitions, $entity[0], TRUE));
755:
756: } elseif ($entity instanceof ServiceDefinition) {
757: $entity = '@' . current(array_keys($this->definitions, $entity, TRUE));
758:
759: } elseif (is_array($entity) && $entity[0] === $this) {
760: trigger_error("Replace object ContainerBuilder in Statement entity with '@container'.", E_USER_DEPRECATED);
761: $entity[0] = '@' . self::THIS_CONTAINER;
762: }
763: return $entity;
764: }
765:
766:
767: 768: 769: 770: 771:
772: public function getServiceName($arg)
773: {
774: if (!is_string($arg) || !preg_match('#^@[\w\\\\.][^:]*\z#', $arg)) {
775: return FALSE;
776: }
777: $service = substr($arg, 1);
778: if ($service === self::THIS_SERVICE) {
779: $service = $this->currentService;
780: }
781: if (Strings::contains($service, '\\')) {
782: if ($this->classList === FALSE) {
783: return $service;
784: }
785: $res = $this->getByType($service);
786: if (!$res) {
787: throw new ServiceCreationException("Reference to missing service of type $service.");
788: }
789: return $res;
790: }
791: $service = isset($this->aliases[$service]) ? $this->aliases[$service] : $service;
792: if (!isset($this->definitions[$service])) {
793: throw new ServiceCreationException("Reference to missing service '$service'.");
794: }
795: return $service;
796: }
797:
798:
799: 800: 801: 802: 803:
804: public function autowireArguments($class, $method, array $arguments)
805: {
806: $rc = new ReflectionClass($class);
807: if (!$rc->hasMethod($method)) {
808: if (!Nette\Utils\Arrays::isList($arguments)) {
809: throw new ServiceCreationException("Unable to pass specified arguments to $class::$method().");
810: }
811: return $arguments;
812: }
813:
814: $rm = $rc->getMethod($method);
815: if (!$rm->isPublic()) {
816: throw new ServiceCreationException("$class::$method() is not callable.");
817: }
818: $this->addDependency($rm);
819: return Helpers::autowireArguments($rm, $arguments, $this);
820: }
821:
822:
823:
824: public function generateClasses($className = 'Container', $parentName = NULL)
825: {
826: trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
827: return (new PhpGenerator($this))->generate($className);
828: }
829:
830:
831:
832: public function formatStatement(Statement $statement)
833: {
834: trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
835: return (new PhpGenerator($this))->formatStatement($statement);
836: }
837:
838:
839:
840: public function formatPhp($statement, $args)
841: {
842: array_walk_recursive($args, function (&$val) {
843: if ($val instanceof Statement) {
844: $val = $this->completeStatement($val);
845:
846: } elseif ($val === $this) {
847: trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED);
848: $val = self::literal('$this');
849:
850: } elseif ($val instanceof ServiceDefinition) {
851: $val = '@' . current(array_keys($this->getDefinitions(), $val, TRUE));
852: }
853: });
854: return (new PhpGenerator($this))->formatPhp($statement, $args);
855: }
856:
857: }
858: