ContextServiceExtension::load()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the ContextServiceExtension package.
7
 *
8
 * (c) Kamil Kokot <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace FriendsOfBehat\ContextServiceExtension\ServiceContainer;
15
16
use Behat\Behat\Context\ServiceContainer\ContextExtension;
17
use Behat\Testwork\Environment\ServiceContainer\EnvironmentExtension;
18
use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension;
19
use Behat\Testwork\ServiceContainer\Extension;
20
use Behat\Testwork\ServiceContainer\ExtensionManager;
21
use FriendsOfBehat\ContextServiceExtension\Context\ContextRegistry;
22
use FriendsOfBehat\ContextServiceExtension\Context\Environment\Handler\ContextServiceEnvironmentHandler;
23
use FriendsOfBehat\ContextServiceExtension\Listener\ScenarioContainerResetter;
24
use FriendsOfBehat\ContextServiceExtension\ServiceContainer\Scenario\ContainerFactory;
25
use FriendsOfBehat\ContextServiceExtension\ServiceContainer\Scenario\ContextRegistryPass;
26
use FriendsOfBehat\CrossContainerExtension\CrossContainerProcessor;
27
use FriendsOfBehat\CrossContainerExtension\ServiceContainer\CrossContainerExtension;
28
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
29
use Symfony\Component\DependencyInjection\ContainerBuilder;
30
use Symfony\Component\DependencyInjection\Definition;
31
use Symfony\Component\DependencyInjection\Reference;
32
33
/**
34
 * @internal
35
 */
36
final class ContextServiceExtension implements Extension
37
{
38
    /**
39
     * @var CrossContainerProcessor|null
40
     */
41
    private $crossContainerProcessor;
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function getConfigKey(): string
47
    {
48
        return 'fob_context_service';
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function initialize(ExtensionManager $extensionManager): void
55
    {
56
        /** @var CrossContainerExtension|null $crossContainerExtension */
57
        $crossContainerExtension = $extensionManager->getExtension('fob_cross_container');
58
        if ($crossContainerExtension !== null) {
59
            $this->crossContainerProcessor = $crossContainerExtension->getCrossContainerProcessor();
60
        }
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function configure(ArrayNodeDefinition $builder): void
67
    {
68
        $builder
69
            ->children()
70
                ->arrayNode('imports')
71
                    ->performNoDeepMerging()
72
                    ->prototype('scalar')->end()
73
                ->end()
74
            ->end()
75
        ;
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function load(ContainerBuilder $container, array $config): void
82
    {
83
        $this->loadContextRegistry($container);
84
        $this->loadScenarioServiceContainer($container, $config);
85
        $this->loadEnvironmentHandler($container);
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91
    public function process(ContainerBuilder $container): void
92
    {
93
        /** @var ContainerBuilder $scenarioContainer */
94
        $scenarioContainer = $container->get('fob_context_service.service_container.scenario');
95
96
        if ($this->crossContainerProcessor !== null) {
97
            $this->crossContainerProcessor->process($scenarioContainer);
98
        }
99
100
        // This feature was introduced only in symfony/dependency-injection v3.3
101
        // So we are adding the feature for modern containers and leaving as-is for older ones
102
        if (method_exists($scenarioContainer, 'registerForAutoconfiguration')) {
103
            $scenarioContainer
104
                ->registerForAutoconfiguration(\Behat\Behat\Context\Context::class)
105
                ->addTag(ContextRegistryPass::CONTEXT_SERVICE_TAG)
106
            ;
107
        }
108
109
        $scenarioContainer->addCompilerPass(new ContextRegistryPass($container->getDefinition('fob_context_service.context_registry')));
110
        $scenarioContainer->compile();
111
    }
112
113
    /**
114
     * @param ContainerBuilder $container
115
     */
116
    private function loadContextRegistry(ContainerBuilder $container): void
117
    {
118
        $container->setDefinition('fob_context_service.context_registry', (new Definition(ContextRegistry::class))->setPublic(false));
119
    }
120
121
    /**
122
     * @param ContainerBuilder $container
123
     * @param array $config
124
     */
125
    private function loadScenarioServiceContainer(ContainerBuilder $container, array $config): void
126
    {
127
        $container->set(
128
            'fob_context_service.service_container.scenario',
129
            (new ContainerFactory())->createContainer($container->getParameter('paths.base'), $config['imports'])
130
        );
131
132
        $definition = new Definition(ScenarioContainerResetter::class, [
133
            new Reference('fob_context_service.service_container.scenario'),
134
        ]);
135
        $definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG);
136
        $container->setDefinition('fob_context_service.service_container.scenario.resetter', $definition);
137
    }
138
139
    /**
140
     * @param ContainerBuilder $container
141
     */
142
    private function loadEnvironmentHandler(ContainerBuilder $container): void
143
    {
144
        $definition = new Definition(ContextServiceEnvironmentHandler::class, [
145
            new Reference('fob_context_service.service_container.scenario'),
146
            new Reference('fob_context_service.context_registry'),
147
        ]);
148
        $definition->addTag(EnvironmentExtension::HANDLER_TAG, ['priority' => 128]);
149
150
        foreach ($container->findTaggedServiceIds(ContextExtension::INITIALIZER_TAG) as $serviceId => $tags) {
151
            $definition->addMethodCall('registerContextInitializer', [$container->getDefinition($serviceId)]);
152
        }
153
154
        $container->setDefinition('fob_context_service.environment_handler.context_service', $definition);
155
    }
156
}
157