|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\DependencyInjection\Compiler; |
|
13 |
|
14 use Symfony\Component\DependencyInjection\ContainerInterface; |
|
15 use Symfony\Component\DependencyInjection\Definition; |
|
16 use Symfony\Component\DependencyInjection\Reference; |
|
17 use Symfony\Component\DependencyInjection\ContainerBuilder; |
|
18 |
|
19 /** |
|
20 * Inline service definitions where this is possible. |
|
21 * |
|
22 * @author Johannes M. Schmitt <schmittjoh@gmail.com> |
|
23 */ |
|
24 class InlineServiceDefinitionsPass implements RepeatablePassInterface |
|
25 { |
|
26 private $repeatedPass; |
|
27 private $graph; |
|
28 private $compiler; |
|
29 private $formatter; |
|
30 private $currentId; |
|
31 |
|
32 /** |
|
33 * {@inheritDoc} |
|
34 */ |
|
35 public function setRepeatedPass(RepeatedPass $repeatedPass) |
|
36 { |
|
37 $this->repeatedPass = $repeatedPass; |
|
38 } |
|
39 |
|
40 /** |
|
41 * Processes the ContainerBuilder for inline service definitions. |
|
42 * |
|
43 * @param ContainerBuilder $container |
|
44 */ |
|
45 public function process(ContainerBuilder $container) |
|
46 { |
|
47 $this->compiler = $container->getCompiler(); |
|
48 $this->formatter = $this->compiler->getLoggingFormatter(); |
|
49 $this->graph = $this->compiler->getServiceReferenceGraph(); |
|
50 |
|
51 foreach ($container->getDefinitions() as $id => $definition) { |
|
52 $this->currentId = $id; |
|
53 |
|
54 $definition->setArguments( |
|
55 $this->inlineArguments($container, $definition->getArguments()) |
|
56 ); |
|
57 |
|
58 $definition->setMethodCalls( |
|
59 $this->inlineArguments($container, $definition->getMethodCalls()) |
|
60 ); |
|
61 |
|
62 $definition->setProperties( |
|
63 $this->inlineArguments($container, $definition->getProperties()) |
|
64 ); |
|
65 } |
|
66 } |
|
67 |
|
68 /** |
|
69 * Processes inline arguments. |
|
70 * |
|
71 * @param ContainerBuilder $container The ContainerBuilder |
|
72 * @param array $arguments An array of arguments |
|
73 */ |
|
74 private function inlineArguments(ContainerBuilder $container, array $arguments) |
|
75 { |
|
76 foreach ($arguments as $k => $argument) { |
|
77 if (is_array($argument)) { |
|
78 $arguments[$k] = $this->inlineArguments($container, $argument); |
|
79 } else if ($argument instanceof Reference) { |
|
80 if (!$container->hasDefinition($id = (string) $argument)) { |
|
81 continue; |
|
82 } |
|
83 |
|
84 if ($this->isInlinableDefinition($container, $id, $definition = $container->getDefinition($id))) { |
|
85 $this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId)); |
|
86 |
|
87 if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) { |
|
88 $arguments[$k] = $definition; |
|
89 } else { |
|
90 $arguments[$k] = clone $definition; |
|
91 } |
|
92 } |
|
93 } else if ($argument instanceof Definition) { |
|
94 $argument->setArguments($this->inlineArguments($container, $argument->getArguments())); |
|
95 $argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls())); |
|
96 $argument->setProperties($this->inlineArguments($container, $argument->getProperties())); |
|
97 } |
|
98 } |
|
99 |
|
100 return $arguments; |
|
101 } |
|
102 |
|
103 /** |
|
104 * Checks if the definition is inlineable. |
|
105 * |
|
106 * @param ContainerBuilder $container |
|
107 * @param string $id |
|
108 * @param Definition $definition |
|
109 * @return Boolean If the definition is inlineable |
|
110 */ |
|
111 private function isInlinableDefinition(ContainerBuilder $container, $id, Definition $definition) |
|
112 { |
|
113 if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) { |
|
114 return true; |
|
115 } |
|
116 |
|
117 if ($definition->isPublic()) { |
|
118 return false; |
|
119 } |
|
120 |
|
121 if (!$this->graph->hasNode($id)) { |
|
122 return true; |
|
123 } |
|
124 |
|
125 $ids = array(); |
|
126 foreach ($this->graph->getNode($id)->getInEdges() as $edge) { |
|
127 $ids[] = $edge->getSourceNode()->getId(); |
|
128 } |
|
129 |
|
130 if (count(array_unique($ids)) > 1) { |
|
131 return false; |
|
132 } |
|
133 |
|
134 return $container->getDefinition(reset($ids))->getScope() === $definition->getScope(); |
|
135 } |
|
136 } |