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\Reflection;
13: use Nette\Utils\Strings;
14: use Nette\Utils\Validators;
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: $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 $types)
175: {
176: foreach ($types as $type) {
177: if (class_exists($type) || interface_exists($type)) {
178: $type = Helpers::normalizeClass($type);
179: $this->excludedClasses += class_parents($type) + class_implements($type) + [$type => $type];
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:
215: public function getByType($type, $throw = false)
216: {
217: $type = Helpers::normalizeClass($type);
218:
219: if (
220: $this->currentService !== null
221: && is_a($this->definitions[$this->currentService]->getType(), $type, true)
222: ) {
223: return $this->currentService;
224: }
225:
226: $types = $this->getClassList();
227: if (empty($types[$type][true])) {
228: if ($throw) {
229: throw new MissingServiceException("Service of type '$type' not found.");
230: }
231: return;
232:
233: } elseif (count($types[$type][true]) === 1) {
234: return $types[$type][true][0];
235:
236: } else {
237: $list = $types[$type][true];
238: natsort($list);
239: $hint = count($list) === 2 && ($tmp = strpos($list[0], '.') xor strpos($list[1], '.'))
240: ? '. If you want to overwrite service ' . $list[$tmp ? 0 : 1] . ', give it proper name.'
241: : '';
242: throw new ServiceCreationException("Multiple services of type $type found: " . implode(', ', $list) . $hint);
243: }
244: }
245:
246:
247: 248: 249: 250: 251:
252: public function getDefinitionByType($type)
253: {
254: return $this->getDefinition($this->getByType($type, true));
255: }
256:
257:
258: 259: 260: 261: 262:
263: public function findByType($type)
264: {
265: $type = Helpers::normalizeClass($type);
266: $found = [];
267: $types = $this->getClassList();
268: if (!empty($types[$type])) {
269: foreach (array_merge(...array_values($types[$type])) as $name) {
270: $found[$name] = $this->definitions[$name];
271: }
272: }
273: return $found;
274: }
275:
276:
277: 278: 279: 280: 281:
282: public function findByTag($tag)
283: {
284: $found = [];
285: foreach ($this->definitions as $name => $def) {
286: if (($tmp = $def->getTag($tag)) !== null) {
287: $found[$name] = $tmp;
288: }
289: }
290: return $found;
291: }
292:
293:
294: 295: 296:
297: public function getClassList()
298: {
299: if ($this->classList !== false && $this->classListNeedsRefresh) {
300: $this->prepareClassList();
301: $this->classListNeedsRefresh = false;
302: }
303: return $this->classList ?: [];
304: }
305:
306:
307: 308: 309: 310: 311:
312: public function prepareClassList()
313: {
314: unset($this->definitions[self::THIS_CONTAINER]);
315: $this->addDefinition(self::THIS_CONTAINER)->setType(Container::class);
316:
317: $this->classList = false;
318:
319: foreach ($this->definitions as $name => $def) {
320:
321: if ($def->getImplement()) {
322: $this->resolveImplement($def, $name);
323: }
324:
325: if ($def->isDynamic()) {
326: if (!$def->getType()) {
327: throw new ServiceCreationException("Type is missing in definition of service '$name'.");
328: }
329: $def->setFactory(null);
330: continue;
331: }
332:
333:
334: if (!$def->getEntity()) {
335: if (!$def->getType()) {
336: throw new ServiceCreationException("Factory and type are missing in definition of service '$name'.");
337: }
338: $def->setFactory($def->getType(), ($factory = $def->getFactory()) ? $factory->arguments : []);
339: }
340:
341:
342: if (
343: $def->getAutowired() === true
344: && ($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->resolveServiceType($name);
354: }
355:
356:
357: $this->classList = $preferred = [];
358: foreach ($this->definitions as $name => $def) {
359: if ($type = $def->getImplement() ?: $def->getType()) {
360: $defAutowired = $def->getAutowired();
361: if (is_array($defAutowired)) {
362: foreach ($defAutowired as $k => $autowiredType) {
363: if ($autowiredType === self::THIS_SERVICE) {
364: $defAutowired[$k] = $type;
365: } elseif (!is_a($type, $autowiredType, true)) {
366: throw new ServiceCreationException("Incompatible class $autowiredType in autowiring definition of service '$name'.");
367: }
368: }
369: }
370:
371: foreach (class_parents($type) + class_implements($type) + [$type] as $parent) {
372: $autowired = $defAutowired && empty($this->excludedClasses[$parent]);
373: if ($autowired && is_array($defAutowired)) {
374: $autowired = false;
375: foreach ($defAutowired as $autowiredType) {
376: if (is_a($parent, $autowiredType, 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: $interface = Helpers::normalizeClass($interface);
402: $def->setImplement($interface);
403:
404: $rc = new ReflectionClass($interface);
405: $this->addDependency($rc);
406: $method = $rc->hasMethod('create')
407: ? $rc->getMethod('create')
408: : ($rc->hasMethod('get') ? $rc->getMethod('get') : null);
409:
410: if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) {
411: throw new ServiceCreationException("Interface $interface used in service '$name' must have just one non-static method create() or get().");
412: }
413: $def->setImplementMode($rc->hasMethod('create') ? $def::IMPLEMENT_MODE_CREATE : $def::IMPLEMENT_MODE_GET);
414: $methodName = Reflection::toString($method) . '()';
415:
416: if (!$def->getType() && !$def->getEntity()) {
417: $returnType = Helpers::getReturnType($method);
418: if (!$returnType) {
419: throw new ServiceCreationException("Method $methodName used in service '$name' has not return type hint or annotation @return.");
420: } elseif (!class_exists($returnType)) {
421: throw new ServiceCreationException("Check a type hint or annotation @return of the $methodName method used in service '$name', class '$returnType' cannot be found.");
422: }
423: $def->setType($returnType);
424: }
425:
426: if ($rc->hasMethod('get')) {
427: if ($method->getParameters()) {
428: throw new ServiceCreationException("Method $methodName used in service '$name' must have no arguments.");
429: } elseif ($def->getSetup()) {
430: throw new ServiceCreationException("Service accessor '$name' must have no setup.");
431: }
432: if (!$def->getEntity()) {
433: $def->setFactory('@\\' . ltrim($def->getType(), '\\'));
434: } elseif (!$this->getServiceName($def->getFactory()->getEntity())) {
435: throw new ServiceCreationException("Invalid factory in service '$name' definition.");
436: }
437: }
438:
439: if (!$def->parameters) {
440: $ctorParams = [];
441: if (!$def->getEntity()) {
442: $def->setFactory($def->getType(), $def->getFactory() ? $def->getFactory()->arguments : []);
443: }
444: if (
445: ($class = $this->resolveEntityType($def->getFactory(), [$name => 1]))
446: && ($ctor = (new ReflectionClass($class))->getConstructor())
447: ) {
448: foreach ($ctor->getParameters() as $param) {
449: $ctorParams[$param->getName()] = $param;
450: }
451: }
452:
453: foreach ($method->getParameters() as $param) {
454: $hint = Reflection::getParameterType($param);
455: if (isset($ctorParams[$param->getName()])) {
456: $arg = $ctorParams[$param->getName()];
457: $argHint = Reflection::getParameterType($arg);
458: if ($hint !== $argHint && !is_a($hint, $argHint, true)) {
459: throw new ServiceCreationException("Type hint for \${$param->getName()} in $methodName doesn't match type hint in $class constructor.");
460: }
461: $def->getFactory()->arguments[$arg->getPosition()] = self::literal('$' . $arg->getName());
462: } elseif (!$def->getSetup()) {
463: $hint = Nette\Utils\ObjectMixin::getSuggestion(array_keys($ctorParams), $param->getName());
464: throw new ServiceCreationException("Unused parameter \${$param->getName()} when implementing method $methodName" . ($hint ? ", did you mean \${$hint}?" : '.'));
465: }
466: $nullable = $hint && $param->allowsNull() && (!$param->isDefaultValueAvailable() || $param->getDefaultValue() !== null);
467: $paramDef = ($nullable ? '?' : '') . $hint . ' ' . $param->getName();
468: if ($param->isDefaultValueAvailable()) {
469: $def->parameters[$paramDef] = Reflection::getParameterDefaultValue($param);
470: } else {
471: $def->parameters[] = $paramDef;
472: }
473: }
474: }
475: }
476:
477:
478:
479: private function resolveServiceType($name, $recursive = [])
480: {
481: if (isset($recursive[$name])) {
482: throw new ServiceCreationException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($recursive))));
483: }
484: $recursive[$name] = true;
485:
486: $def = $this->definitions[$name];
487: $factoryClass = $def->getFactory() ? $this->resolveEntityType($def->getFactory()->getEntity(), $recursive) : null;
488: if ($type = $def->getType() ?: $factoryClass) {
489: if (!class_exists($type) && !interface_exists($type)) {
490: throw new ServiceCreationException("Class or interface '$type' used in service '$name' not found.");
491: }
492: $type = Helpers::normalizeClass($type);
493: $def->setType($type);
494: if (count($recursive) === 1) {
495: $this->addDependency(new ReflectionClass($factoryClass ?: $type));
496: }
497:
498: } elseif ($def->getAutowired()) {
499: throw new ServiceCreationException("Unknown type of service '$name', declare return type of factory method (for PHP 5 use annotation @return)");
500: }
501: return $type;
502: }
503:
504:
505:
506: private function resolveEntityType($entity, $recursive = [])
507: {
508: $entity = $this->normalizeEntity($entity instanceof Statement ? $entity->getEntity() : $entity);
509: $serviceName = current(array_slice(array_keys($recursive), -1));
510:
511: if (is_array($entity)) {
512: if (($service = $this->getServiceName($entity[0])) || $entity[0] instanceof Statement) {
513: $entity[0] = $this->resolveEntityType($entity[0], $recursive);
514: if (!$entity[0]) {
515: return;
516: } elseif (isset($this->definitions[$service]) && $this->definitions[$service]->getImplement()) {
517: return $entity[1] === 'create' ? $this->resolveServiceType($service, $recursive) : null;
518: }
519: }
520:
521: try {
522: $reflection = Nette\Utils\Callback::toReflection($entity[0] === '' ? $entity[1] : $entity);
523: $refClass = $reflection instanceof \ReflectionMethod ? $reflection->getDeclaringClass() : null;
524: } catch (\ReflectionException $e) {
525: }
526:
527: if (isset($e) || ($refClass && (!$reflection->isPublic()
528: || ($refClass->isTrait() && !$reflection->isStatic())
529: ))) {
530: throw new ServiceCreationException(sprintf("Method %s() used in service '%s' is not callable.", Nette\Utils\Callback::toString($entity), $serviceName));
531: }
532: $this->addDependency($reflection);
533:
534: $type = Helpers::getReturnType($reflection);
535: if ($type && !class_exists($type) && !interface_exists($type)) {
536: 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));
537: }
538: return $type;
539:
540: } elseif ($service = $this->getServiceName($entity)) {
541: if (Strings::contains($service, '\\')) {
542: return $service;
543: }
544: return $this->definitions[$service]->getImplement()
545: ?: $this->definitions[$service]->getType()
546: ?: $this->resolveServiceType($service, $recursive);
547:
548: } elseif (is_string($entity)) {
549: if (!class_exists($entity)) {
550: throw new ServiceCreationException("Class $entity used in service '$serviceName' not found.");
551: }
552: return $entity;
553: }
554: }
555:
556:
557: 558: 559:
560: public function complete()
561: {
562: $this->prepareClassList();
563:
564: foreach ($this->definitions as $name => $def) {
565: if ($def->isDynamic()) {
566: continue;
567: }
568:
569: $this->currentService = null;
570: $entity = $def->getFactory()->getEntity();
571: $serviceRef = $this->getServiceName($entity);
572: $factory = $serviceRef && !$def->getFactory()->arguments && !$def->getSetup() && $def->getImplementMode() !== $def::IMPLEMENT_MODE_CREATE
573: ? new Statement(['@' . self::THIS_CONTAINER, 'getService'], [$serviceRef])
574: : $def->getFactory();
575:
576: try {
577: $def->setFactory($this->completeStatement($factory));
578: $this->classListNeedsRefresh = false;
579:
580: $this->currentService = $name;
581: $setups = $def->getSetup();
582: foreach ($setups as &$setup) {
583: if (is_string($setup->getEntity()) && strpbrk($setup->getEntity(), ':@?\\') === false) {
584: $setup = new Statement(['@' . $name, $setup->getEntity()], $setup->arguments);
585: }
586: $setup = $this->completeStatement($setup);
587: }
588: $def->setSetup($setups);
589:
590: } catch (\Exception $e) {
591: $message = "Service '$name' (type of {$def->getType()}): " . $e->getMessage();
592: throw $e instanceof ServiceCreationException
593: ? $e->setMessage($message)
594: : new ServiceCreationException($message, 0, $e);
595:
596: } finally {
597: $this->currentService = null;
598: }
599: }
600: }
601:
602:
603: 604: 605:
606: public function completeStatement(Statement $statement)
607: {
608: $entity = $this->normalizeEntity($statement->getEntity());
609: $arguments = $statement->arguments;
610:
611: if (is_string($entity) && Strings::contains($entity, '?')) {
612:
613: } elseif ($service = $this->getServiceName($entity)) {
614: $params = [];
615: foreach ($this->definitions[$service]->parameters as $k => $v) {
616: $params[] = preg_replace('#\w+\z#', '\$$0', (is_int($k) ? $v : $k)) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v));
617: }
618: $rm = new \ReflectionFunction(eval('return function(' . implode(', ', $params) . ') {};'));
619: $arguments = Helpers::autowireArguments($rm, $arguments, $this);
620: $entity = '@' . $service;
621:
622: } elseif ($entity === 'not') {
623:
624: } elseif (is_string($entity)) {
625: if (!class_exists($entity)) {
626: throw new ServiceCreationException("Class $entity not found.");
627: } elseif ((new ReflectionClass($entity))->isAbstract()) {
628: throw new ServiceCreationException("Class $entity is abstract.");
629: } elseif (($rm = (new ReflectionClass($entity))->getConstructor()) !== null && !$rm->isPublic()) {
630: $visibility = $rm->isProtected() ? 'protected' : 'private';
631: throw new ServiceCreationException("Class $entity has $visibility constructor.");
632: } elseif ($constructor = (new ReflectionClass($entity))->getConstructor()) {
633: $this->addDependency($constructor);
634: $arguments = Helpers::autowireArguments($constructor, $arguments, $this);
635: } elseif ($arguments) {
636: throw new ServiceCreationException("Unable to pass arguments, class $entity has no constructor.");
637: }
638:
639: } elseif (!Nette\Utils\Arrays::isList($entity) || count($entity) !== 2) {
640: throw new ServiceCreationException(sprintf('Expected class, method or property, %s given.', PhpHelpers::dump($entity)));
641:
642: } elseif (!preg_match('#^\$?(\\\\?' . PhpHelpers::PHP_IDENT . ')+(\[\])?\z#', $entity[1])) {
643: throw new ServiceCreationException("Expected function, method or property name, '$entity[1]' given.");
644:
645: } elseif ($entity[0] === '') {
646: if (!Nette\Utils\Arrays::isList($arguments)) {
647: throw new ServiceCreationException("Unable to pass specified arguments to $entity[0].");
648: } elseif (!function_exists($entity[1])) {
649: throw new ServiceCreationException("Function $entity[1] doesn't exist.");
650: }
651:
652: $rf = new \ReflectionFunction($entity[1]);
653: $this->addDependency($rf);
654: $arguments = Helpers::autowireArguments($rf, $arguments, $this);
655:
656: } else {
657: if ($entity[0] instanceof Statement) {
658: $entity[0] = $this->completeStatement($entity[0]);
659: } elseif ($service = $this->getServiceName($entity[0])) {
660: $entity[0] = '@' . $service;
661: }
662:
663: if ($entity[1][0] === '$') {
664: Validators::assert($arguments, 'list:0..1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'");
665: if (!$arguments && substr($entity[1], -2) === '[]') {
666: throw new ServiceCreationException("Missing argument for $entity[1].");
667: }
668: } elseif (
669: $type = empty($service) || $entity[1] === 'create'
670: ? $this->resolveEntityType($entity[0])
671: : $this->definitions[$service]->getType()
672: ) {
673: $arguments = $this->autowireArguments($type, $entity[1], $arguments);
674: }
675: }
676:
677: try {
678: array_walk_recursive($arguments, function (&$val) {
679: if ($val instanceof Statement) {
680: $val = $this->completeStatement($val);
681:
682: } elseif ($val === $this) {
683: trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED);
684: $val = self::literal('$this');
685:
686: } elseif ($val instanceof ServiceDefinition) {
687: $val = '@' . current(array_keys($this->getDefinitions(), $val, true));
688:
689: } elseif (is_string($val) && strlen($val) > 1 && $val[0] === '@' && $val[1] !== '@') {
690: $pair = explode('::', $val, 2);
691: $name = $this->getServiceName($pair[0]);
692: if (!isset($pair[1])) {
693: $val = '@' . $name;
694: } elseif (preg_match('#^[A-Z][A-Z0-9_]*\z#', $pair[1], $m)) {
695: $val = self::literal($this->getDefinition($name)->getType() . '::' . $pair[1]);
696: } else {
697: $val = new Statement(['@' . $name, '$' . $pair[1]]);
698: }
699: }
700: });
701:
702: } catch (ServiceCreationException $e) {
703: if ((is_string($entity) || is_array($entity)) && !strpos($e->getMessage(), ' (used in')) {
704: $desc = is_string($entity)
705: ? $entity . '::__construct'
706: : (is_string($entity[0]) ? ($entity[0] . '::') : 'method ') . $entity[1];
707: $e->setMessage($e->getMessage() . " (used in $desc)");
708: }
709: throw $e;
710: }
711:
712: return new Statement($entity, $arguments);
713: }
714:
715:
716: 717: 718: 719: 720: 721:
722: public function addDependency($dep)
723: {
724: $this->dependencies[] = $dep;
725: return $this;
726: }
727:
728:
729: 730: 731: 732:
733: public function getDependencies()
734: {
735: return $this->dependencies;
736: }
737:
738:
739: 740: 741: 742: 743:
744: public function expand($value)
745: {
746: return Helpers::expand($value, $this->parameters);
747: }
748:
749:
750: 751: 752:
753: public static function literal($code, array $args = null)
754: {
755: return new Nette\PhpGenerator\PhpLiteral($args === null ? $code : PhpHelpers::formatArgs($code, $args));
756: }
757:
758:
759: 760: 761: 762:
763: public function normalizeEntity($entity)
764: {
765: if (is_string($entity) && Strings::contains($entity, '::') && !Strings::contains($entity, '?')) {
766: $entity = explode('::', $entity);
767: }
768:
769: if (is_array($entity) && $entity[0] instanceof ServiceDefinition) {
770: $entity[0] = '@' . current(array_keys($this->definitions, $entity[0], true));
771:
772: } elseif ($entity instanceof ServiceDefinition) {
773: $entity = '@' . current(array_keys($this->definitions, $entity, true));
774:
775: } elseif (is_array($entity) && $entity[0] === $this) {
776: trigger_error("Replace object ContainerBuilder in Statement entity with '@container'.", E_USER_DEPRECATED);
777: $entity[0] = '@' . self::THIS_CONTAINER;
778: }
779: return $entity;
780: }
781:
782:
783: 784: 785: 786: 787:
788: public function getServiceName($arg)
789: {
790: if (!is_string($arg) || !preg_match('#^@[\w\\\\.][^:]*\z#', $arg)) {
791: return false;
792: }
793: $service = substr($arg, 1);
794: if ($service === self::THIS_SERVICE) {
795: $service = $this->currentService;
796: }
797: if (Strings::contains($service, '\\')) {
798: if ($this->classList === false) {
799: return $service;
800: }
801: $res = $this->getByType($service);
802: if (!$res) {
803: throw new ServiceCreationException("Reference to missing service of type $service.");
804: }
805: return $res;
806: }
807: $service = isset($this->aliases[$service]) ? $this->aliases[$service] : $service;
808: if (!isset($this->definitions[$service])) {
809: throw new ServiceCreationException("Reference to missing service '$service'.");
810: }
811: return $service;
812: }
813:
814:
815: 816: 817: 818: 819:
820: public function autowireArguments($class, $method, array $arguments)
821: {
822: $rc = new ReflectionClass($class);
823: if (!$rc->hasMethod($method)) {
824: if (!Nette\Utils\Arrays::isList($arguments)) {
825: throw new ServiceCreationException("Unable to pass specified arguments to $class::$method().");
826: }
827: return $arguments;
828: }
829:
830: $rm = $rc->getMethod($method);
831: if (!$rm->isPublic()) {
832: throw new ServiceCreationException("$class::$method() is not callable.");
833: }
834: $this->addDependency($rm);
835: return Helpers::autowireArguments($rm, $arguments, $this);
836: }
837:
838:
839:
840: public function generateClasses($className = 'Container', $parentName = null)
841: {
842: trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
843: return (new PhpGenerator($this))->generate($className);
844: }
845:
846:
847:
848: public function formatStatement(Statement $statement)
849: {
850: trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
851: return (new PhpGenerator($this))->formatStatement($statement);
852: }
853:
854:
855:
856: public function formatPhp($statement, $args)
857: {
858: array_walk_recursive($args, function (&$val) {
859: if ($val instanceof Statement) {
860: $val = $this->completeStatement($val);
861:
862: } elseif ($val === $this) {
863: trigger_error("Replace object ContainerBuilder in Statement arguments with '@container'.", E_USER_DEPRECATED);
864: $val = self::literal('$this');
865:
866: } elseif ($val instanceof ServiceDefinition) {
867: $val = '@' . current(array_keys($this->getDefinitions(), $val, true));
868: }
869: });
870: return (new PhpGenerator($this))->formatPhp($statement, $args);
871: }
872: }
873: