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