|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony framework. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * This source file is subject to the MIT license that is bundled |
|
9 * with this source code in the file LICENSE. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\DependencyInjection\Compiler; |
|
13 |
|
14 use Symfony\Component\DependencyInjection\Definition; |
|
15 use Symfony\Component\DependencyInjection\DefinitionDecorator; |
|
16 use Symfony\Component\DependencyInjection\ContainerBuilder; |
|
17 |
|
18 /** |
|
19 * This replaces all DefinitionDecorator instances with their equivalent fully |
|
20 * merged Definition instance. |
|
21 * |
|
22 * @author Johannes M. Schmitt <schmittjoh@gmail.com> |
|
23 */ |
|
24 class ResolveDefinitionTemplatesPass implements CompilerPassInterface |
|
25 { |
|
26 private $container; |
|
27 private $compiler; |
|
28 private $formatter; |
|
29 |
|
30 /** |
|
31 * Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances. |
|
32 * |
|
33 * @param ContainerBuilder $container |
|
34 */ |
|
35 public function process(ContainerBuilder $container) |
|
36 { |
|
37 $this->container = $container; |
|
38 $this->compiler = $container->getCompiler(); |
|
39 $this->formatter = $this->compiler->getLoggingFormatter(); |
|
40 |
|
41 foreach (array_keys($container->getDefinitions()) as $id) { |
|
42 // yes, we are specifically fetching the definition from the |
|
43 // container to ensure we are not operating on stale data |
|
44 $definition = $container->getDefinition($id); |
|
45 if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) { |
|
46 continue; |
|
47 } |
|
48 |
|
49 $this->resolveDefinition($id, $definition); |
|
50 } |
|
51 } |
|
52 |
|
53 /** |
|
54 * Resolves the definition |
|
55 * |
|
56 * @param string $id The definition identifier |
|
57 * @param DefinitionDecorator $definition |
|
58 * @return Definition |
|
59 */ |
|
60 private function resolveDefinition($id, DefinitionDecorator $definition) |
|
61 { |
|
62 if (!$this->container->hasDefinition($parent = $definition->getParent())) { |
|
63 throw new \RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id)); |
|
64 } |
|
65 |
|
66 $parentDef = $this->container->getDefinition($parent); |
|
67 if ($parentDef instanceof DefinitionDecorator) { |
|
68 $parentDef = $this->resolveDefinition($parent, $parentDef); |
|
69 } |
|
70 |
|
71 $this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent)); |
|
72 $def = new Definition(); |
|
73 |
|
74 // merge in parent definition |
|
75 // purposely ignored attributes: scope, abstract, tags |
|
76 $def->setClass($parentDef->getClass()); |
|
77 $def->setArguments($parentDef->getArguments()); |
|
78 $def->setMethodCalls($parentDef->getMethodCalls()); |
|
79 $def->setProperties($parentDef->getProperties()); |
|
80 $def->setFactoryClass($parentDef->getFactoryClass()); |
|
81 $def->setFactoryMethod($parentDef->getFactoryMethod()); |
|
82 $def->setFactoryService($parentDef->getFactoryService()); |
|
83 $def->setConfigurator($parentDef->getConfigurator()); |
|
84 $def->setFile($parentDef->getFile()); |
|
85 $def->setPublic($parentDef->isPublic()); |
|
86 |
|
87 // overwrite with values specified in the decorator |
|
88 $changes = $definition->getChanges(); |
|
89 if (isset($changes['class'])) { |
|
90 $def->setClass($definition->getClass()); |
|
91 } |
|
92 if (isset($changes['factory_class'])) { |
|
93 $def->setFactoryClass($definition->getFactoryClass()); |
|
94 } |
|
95 if (isset($changes['factory_method'])) { |
|
96 $def->setFactoryMethod($definition->getFactoryMethod()); |
|
97 } |
|
98 if (isset($changes['factory_service'])) { |
|
99 $def->setFactoryService($definition->getFactoryService()); |
|
100 } |
|
101 if (isset($changes['configurator'])) { |
|
102 $def->setConfigurator($definition->getConfigurator()); |
|
103 } |
|
104 if (isset($changes['file'])) { |
|
105 $def->setFile($definition->getFile()); |
|
106 } |
|
107 if (isset($changes['public'])) { |
|
108 $def->setPublic($definition->isPublic()); |
|
109 } |
|
110 |
|
111 // merge arguments |
|
112 foreach ($definition->getArguments() as $k => $v) { |
|
113 if (is_numeric($k)) { |
|
114 $def->addArgument($v); |
|
115 continue; |
|
116 } |
|
117 |
|
118 if (0 !== strpos($k, 'index_')) { |
|
119 throw new \RuntimeException(sprintf('Invalid argument key "%s" found.', $k)); |
|
120 } |
|
121 |
|
122 $index = (integer) substr($k, strlen('index_')); |
|
123 $def->replaceArgument($index, $v); |
|
124 } |
|
125 |
|
126 // merge properties |
|
127 foreach ($definition->getProperties() as $k => $v) { |
|
128 $def->setProperty($k, $v); |
|
129 } |
|
130 |
|
131 // append method calls |
|
132 if (count($calls = $definition->getMethodCalls()) > 0) { |
|
133 $def->setMethodCalls(array_merge($def->getMethodCalls(), $calls)); |
|
134 } |
|
135 |
|
136 // these attributes are always taken from the child |
|
137 $def->setAbstract($definition->isAbstract()); |
|
138 $def->setScope($definition->getScope()); |
|
139 $def->setTags($definition->getTags()); |
|
140 |
|
141 // set new definition on container |
|
142 $this->container->setDefinition($id, $def); |
|
143 |
|
144 return $def; |
|
145 } |
|
146 } |