15110261a225273f54fb17c25ffc7629c09fe9db
[yaffs-website] / vendor / symfony / dependency-injection / Compiler / ResolveInstanceofConditionalsPass.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\ChildDefinition;
15 use Symfony\Component\DependencyInjection\ContainerBuilder;
16 use Symfony\Component\DependencyInjection\Definition;
17 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
19
20 /**
21  * Applies instanceof conditionals to definitions.
22  *
23  * @author Nicolas Grekas <p@tchwork.com>
24  */
25 class ResolveInstanceofConditionalsPass implements CompilerPassInterface
26 {
27     /**
28      * {@inheritdoc}
29      */
30     public function process(ContainerBuilder $container)
31     {
32         foreach ($container->getAutoconfiguredInstanceof() as $interface => $definition) {
33             if ($definition->getArguments()) {
34                 throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines arguments but these are not supported and should be removed.', $interface));
35             }
36             if ($definition->getMethodCalls()) {
37                 throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines method calls but these are not supported and should be removed.', $interface));
38             }
39         }
40
41         foreach ($container->getDefinitions() as $id => $definition) {
42             if ($definition instanceof ChildDefinition) {
43                 // don't apply "instanceof" to children: it will be applied to their parent
44                 continue;
45             }
46             $container->setDefinition($id, $this->processDefinition($container, $id, $definition));
47         }
48     }
49
50     private function processDefinition(ContainerBuilder $container, $id, Definition $definition)
51     {
52         $instanceofConditionals = $definition->getInstanceofConditionals();
53         $autoconfiguredInstanceof = $definition->isAutoconfigured() ? $container->getAutoconfiguredInstanceof() : array();
54         if (!$instanceofConditionals && !$autoconfiguredInstanceof) {
55             return $definition;
56         }
57
58         if (!$class = $container->getParameterBag()->resolveValue($definition->getClass())) {
59             return $definition;
60         }
61
62         $conditionals = $this->mergeConditionals($autoconfiguredInstanceof, $instanceofConditionals, $container);
63
64         $definition->setInstanceofConditionals(array());
65         $parent = $shared = null;
66         $instanceofTags = array();
67
68         foreach ($conditionals as $interface => $instanceofDefs) {
69             if ($interface !== $class && (!$container->getReflectionClass($class, false))) {
70                 continue;
71             }
72
73             if ($interface !== $class && !is_subclass_of($class, $interface)) {
74                 continue;
75             }
76
77             foreach ($instanceofDefs as $key => $instanceofDef) {
78                 /** @var ChildDefinition $instanceofDef */
79                 $instanceofDef = clone $instanceofDef;
80                 $instanceofDef->setAbstract(true)->setParent($parent ?: 'abstract.instanceof.'.$id);
81                 $parent = 'instanceof.'.$interface.'.'.$key.'.'.$id;
82                 $container->setDefinition($parent, $instanceofDef);
83                 $instanceofTags[] = $instanceofDef->getTags();
84                 $instanceofDef->setTags(array());
85
86                 if (isset($instanceofDef->getChanges()['shared'])) {
87                     $shared = $instanceofDef->isShared();
88                 }
89             }
90         }
91
92         if ($parent) {
93             $bindings = $definition->getBindings();
94             $abstract = $container->setDefinition('abstract.instanceof.'.$id, $definition);
95
96             // cast Definition to ChildDefinition
97             $definition->setBindings(array());
98             $definition = serialize($definition);
99             $definition = substr_replace($definition, '53', 2, 2);
100             $definition = substr_replace($definition, 'Child', 44, 0);
101             $definition = unserialize($definition);
102             $definition->setParent($parent);
103
104             if (null !== $shared && !isset($definition->getChanges()['shared'])) {
105                 $definition->setShared($shared);
106             }
107
108             $i = count($instanceofTags);
109             while (0 <= --$i) {
110                 foreach ($instanceofTags[$i] as $k => $v) {
111                     foreach ($v as $v) {
112                         if ($definition->hasTag($k) && in_array($v, $definition->getTag($k))) {
113                             continue;
114                         }
115                         $definition->addTag($k, $v);
116                     }
117                 }
118             }
119
120             // reset fields with "merge" behavior
121             $abstract
122                 ->setBindings($bindings)
123                 ->setArguments(array())
124                 ->setMethodCalls(array())
125                 ->setDecoratedService(null)
126                 ->setTags(array())
127                 ->setAbstract(true);
128         }
129
130         return $definition;
131     }
132
133     private function mergeConditionals(array $autoconfiguredInstanceof, array $instanceofConditionals, ContainerBuilder $container)
134     {
135         // make each value an array of ChildDefinition
136         $conditionals = array_map(function ($childDef) { return array($childDef); }, $autoconfiguredInstanceof);
137
138         foreach ($instanceofConditionals as $interface => $instanceofDef) {
139             // make sure the interface/class exists (but don't validate automaticInstanceofConditionals)
140             if (!$container->getReflectionClass($interface)) {
141                 throw new RuntimeException(sprintf('"%s" is set as an "instanceof" conditional, but it does not exist.', $interface));
142             }
143
144             if (!isset($autoconfiguredInstanceof[$interface])) {
145                 $conditionals[$interface] = array();
146             }
147
148             $conditionals[$interface][] = $instanceofDef;
149         }
150
151         return $conditionals;
152     }
153 }