Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. ResolveInstanceofConditionalsPass.php

class ResolveInstanceofConditionalsPass

Applies instanceof conditionals to definitions.

@author Nicolas Grekas <p@tchwork.com>

Hierarchy

  • class \Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass implements \Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface

Expanded class hierarchy of ResolveInstanceofConditionalsPass

File

vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php, line 25

Namespace

Symfony\Component\DependencyInjection\Compiler
View source
class ResolveInstanceofConditionalsPass implements CompilerPassInterface {
    public function process(ContainerBuilder $container) : void {
        foreach ($container->getAutoconfiguredInstanceof() as $interface => $definition) {
            if ($definition->getArguments()) {
                throw new InvalidArgumentException(\sprintf('Autoconfigured instanceof for type "%s" defines arguments but these are not supported and should be removed.', $interface));
            }
        }
        $tagsToKeep = [];
        if ($container->hasParameter('container.behavior_describing_tags')) {
            $tagsToKeep = $container->getParameter('container.behavior_describing_tags');
        }
        foreach ($container->getDefinitions() as $id => $definition) {
            $container->setDefinition($id, $this->processDefinition($container, $id, $definition, $tagsToKeep));
        }
        if ($container->hasParameter('container.behavior_describing_tags')) {
            $container->getParameterBag()
                ->remove('container.behavior_describing_tags');
        }
    }
    private function processDefinition(ContainerBuilder $container, string $id, Definition $definition, array $tagsToKeep) : Definition {
        $instanceofConditionals = $definition->getInstanceofConditionals();
        $autoconfiguredInstanceof = $definition->isAutoconfigured() ? $container->getAutoconfiguredInstanceof() : [];
        if (!$instanceofConditionals && !$autoconfiguredInstanceof) {
            return $definition;
        }
        if (!($class = $container->getParameterBag()
            ->resolveValue($definition->getClass()))) {
            return $definition;
        }
        $conditionals = $this->mergeConditionals($autoconfiguredInstanceof, $instanceofConditionals, $container);
        $definition->setInstanceofConditionals([]);
        $shared = null;
        $instanceofTags = [];
        $instanceofCalls = [];
        $instanceofBindings = [];
        $reflectionClass = null;
        $parent = $definition instanceof ChildDefinition ? $definition->getParent() : null;
        foreach ($conditionals as $interface => $instanceofDefs) {
            if ($interface !== $class && !($reflectionClass ??= $container->getReflectionClass($class, false) ?: false)) {
                continue;
            }
            if ($interface !== $class && !is_subclass_of($class, $interface)) {
                continue;
            }
            foreach ($instanceofDefs as $key => $instanceofDef) {
                
                /** @var ChildDefinition $instanceofDef */
                $instanceofDef = clone $instanceofDef;
                $instanceofDef->setAbstract(true)
                    ->setParent($parent ?: '.abstract.instanceof.' . $id);
                $parent = '.instanceof.' . $interface . '.' . $key . '.' . $id;
                $container->setDefinition($parent, $instanceofDef);
                $instanceofTags[] = [
                    $interface,
                    $instanceofDef->getTags(),
                ];
                $instanceofBindings = $instanceofDef->getBindings() + $instanceofBindings;
                foreach ($instanceofDef->getMethodCalls() as $methodCall) {
                    $instanceofCalls[] = $methodCall;
                }
                $instanceofDef->setTags([]);
                $instanceofDef->setMethodCalls([]);
                $instanceofDef->setBindings([]);
                if (isset($instanceofDef->getChanges()['shared'])) {
                    $shared = $instanceofDef->isShared();
                }
            }
        }
        if ($parent) {
            $bindings = $definition->getBindings();
            $abstract = $container->setDefinition('.abstract.instanceof.' . $id, $definition);
            $definition->setBindings([]);
            $definition = serialize($definition);
            if (Definition::class === $abstract::class) {
                // cast Definition to ChildDefinition
                $definition = substr_replace($definition, '53', 2, 2);
                $definition = substr_replace($definition, 'Child', 44, 0);
            }
            
            /** @var ChildDefinition $definition */
            $definition = unserialize($definition);
            $definition->setParent($parent);
            if (null !== $shared && !isset($definition->getChanges()['shared'])) {
                $definition->setShared($shared);
            }
            // Don't add tags to service decorators
            $i = \count($instanceofTags);
            while (0 <= --$i) {
                [
                    $interface,
                    $tags,
                ] = $instanceofTags[$i];
                foreach ($tags as $k => $v) {
                    if (null === $definition->getDecoratedService() || $interface === $definition->getClass() || \in_array($k, $tagsToKeep, true)) {
                        foreach ($v as $v) {
                            if ($definition->hasTag($k) && \in_array($v, $definition->getTag($k), true)) {
                                continue;
                            }
                            $definition->addTag($k, $v);
                        }
                    }
                }
            }
            $definition->setMethodCalls(array_merge($instanceofCalls, $definition->getMethodCalls()));
            $definition->setBindings($bindings + $instanceofBindings);
            // reset fields with "merge" behavior
            $abstract->setBindings([])
                ->setArguments([])
                ->setMethodCalls([])
                ->setDecoratedService(null)
                ->setTags([])
                ->setAbstract(true);
        }
        return $definition;
    }
    private function mergeConditionals(array $autoconfiguredInstanceof, array $instanceofConditionals, ContainerBuilder $container) : array {
        // make each value an array of ChildDefinition
        $conditionals = array_map(fn($childDef) => [
            $childDef,
        ], $autoconfiguredInstanceof);
        foreach ($instanceofConditionals as $interface => $instanceofDef) {
            // make sure the interface/class exists (but don't validate automaticInstanceofConditionals)
            if (!$container->getReflectionClass($interface)) {
                throw new RuntimeException(\sprintf('"%s" is set as an "instanceof" conditional, but it does not exist.', $interface));
            }
            if (!isset($autoconfiguredInstanceof[$interface])) {
                $conditionals[$interface] = [];
            }
            $conditionals[$interface][] = $instanceofDef;
        }
        return $conditionals;
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
ResolveInstanceofConditionalsPass::mergeConditionals private function
ResolveInstanceofConditionalsPass::process public function You can modify the container here before it is dumped to PHP code. Overrides CompilerPassInterface::process
ResolveInstanceofConditionalsPass::processDefinition private function
RSS feed
Powered by Drupal