annotate vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php @ 19:fa3358dc1485 tip

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