1beaaf0c53ce094ed8727649b53a01b840e07e8a
[yaffs-website] / vendor / symfony / dependency-injection / Compiler / InlineServiceDefinitionsPass.php
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         $container->setDefinitions($this->inlineArguments($container, $container->getDefinitions(), true));
52     }
53
54     /**
55      * Processes inline arguments.
56      *
57      * @param ContainerBuilder $container The ContainerBuilder
58      * @param array            $arguments An array of arguments
59      * @param bool             $isRoot    If we are processing the root definitions or not
60      *
61      * @return array
62      */
63     private function inlineArguments(ContainerBuilder $container, array $arguments, $isRoot = false)
64     {
65         foreach ($arguments as $k => $argument) {
66             if ($isRoot) {
67                 $this->currentId = $k;
68             }
69             if (is_array($argument)) {
70                 $arguments[$k] = $this->inlineArguments($container, $argument);
71             } elseif ($argument instanceof Reference) {
72                 if (!$container->hasDefinition($id = (string) $argument)) {
73                     continue;
74                 }
75
76                 if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) {
77                     $this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));
78
79                     if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false)) {
80                         $arguments[$k] = $definition;
81                     } else {
82                         $arguments[$k] = clone $definition;
83                     }
84                 }
85             } elseif ($argument instanceof Definition) {
86                 $argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
87                 $argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
88                 $argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
89
90                 $configurator = $this->inlineArguments($container, array($argument->getConfigurator()));
91                 $argument->setConfigurator($configurator[0]);
92
93                 $factory = $this->inlineArguments($container, array($argument->getFactory()));
94                 $argument->setFactory($factory[0]);
95             }
96         }
97
98         return $arguments;
99     }
100
101     /**
102      * Checks if the definition is inlineable.
103      *
104      * @param ContainerBuilder $container
105      * @param string           $id
106      * @param Definition       $definition
107      *
108      * @return bool If the definition is inlineable
109      */
110     private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
111     {
112         if (!$definition->isShared() || ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
113             return true;
114         }
115
116         if ($definition->isPublic() || $definition->isLazy()) {
117             return false;
118         }
119
120         if (!$this->graph->hasNode($id)) {
121             return true;
122         }
123
124         if ($this->currentId == $id) {
125             return false;
126         }
127
128         $ids = array();
129         foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
130             $ids[] = $edge->getSourceNode()->getId();
131         }
132
133         if (count(array_unique($ids)) > 1) {
134             return false;
135         }
136
137         if (count($ids) > 1 && is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) {
138             return false;
139         }
140
141         if (count($ids) > 1 && $definition->getFactoryService(false)) {
142             return false;
143         }
144
145         return $container->getDefinition(reset($ids))->getScope(false) === $definition->getScope(false);
146     }
147 }