Completed
Push — master ( 9ea3ac...f613c4 )
by Kamil
01:25
created

SymfonyExtension::loadDriverKernel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FriendsOfBehat\SymfonyExtension\ServiceContainer;
6
7
use Behat\Behat\Context\ServiceContainer\ContextExtension;
8
use Behat\Mink\Session;
9
use Behat\MinkExtension\ServiceContainer\MinkExtension;
10
use Behat\Testwork\Environment\ServiceContainer\EnvironmentExtension;
11
use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension;
12
use Behat\Testwork\ServiceContainer\Extension;
13
use Behat\Testwork\ServiceContainer\ExtensionManager;
14
use FriendsOfBehat\SymfonyExtension\Context\Environment\Handler\ContextServiceEnvironmentHandler;
15
use FriendsOfBehat\SymfonyExtension\Driver\Factory\SymfonyDriverFactory;
16
use FriendsOfBehat\SymfonyExtension\Listener\KernelRebooter;
17
use FriendsOfBehat\SymfonyExtension\Mink\MinkParameters;
18
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
19
use Symfony\Component\DependencyInjection\ContainerBuilder;
20
use Symfony\Component\DependencyInjection\Definition;
21
use Symfony\Component\DependencyInjection\Parameter;
22
use Symfony\Component\DependencyInjection\Reference;
23
24
final class SymfonyExtension implements Extension
25
{
26
    /**
27
     * Kernel used inside Behat contexts or to create services injected to them.
28
     * Container is rebuilt before every scenario.
29
     */
30
    public const KERNEL_ID = 'fob_symfony.kernel';
31
32
    /**
33
     * Kernel used by Symfony driver to isolate web container from contexts' container.
34
     * Container is rebuilt before every request.
35
     */
36
    private const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel';
37
38
    /** @var bool */
39
    private $minkExtensionFound = false;
40
41
    public function getConfigKey(): string
42
    {
43
        return 'fob_symfony';
44
    }
45
46
    public function initialize(ExtensionManager $extensionManager): void
47
    {
48
        $this->registerMinkDriver($extensionManager);
49
    }
50
51
    public function configure(ArrayNodeDefinition $builder): void
52
    {
53
        $builder
54
            ->children()
55
                ->arrayNode('kernel')
56
                    ->addDefaultsIfNotSet()
57
                    ->children()
58
                        ->scalarNode('path')->defaultNull()->end()
59
                        ->scalarNode('class')->isRequired()->end()
60
                        ->scalarNode('env')->defaultValue('test')->cannotBeEmpty()->end()
61
                        ->booleanNode('debug')->defaultTrue()->end()
62
                    ->end()
63
                ->end()
64
            ->end()
65
        ;
66
    }
67
68
    public function load(ContainerBuilder $container, array $config): void
69
    {
70
        $this->loadKernel($container, $config['kernel']);
71
        $this->loadDriverKernel($container);
72
73
        $this->loadKernelRebooter($container);
74
75
        $this->loadEnvironmentHandler($container);
76
77
        if ($this->minkExtensionFound) {
78
            $this->loadMinkDefaultSession($container);
79
            $this->loadMinkParameters($container);
80
        }
81
    }
82
83
    public function process(ContainerBuilder $container): void
84
    {
85
    }
86
87
    private function registerMinkDriver(ExtensionManager $extensionManager): void
88
    {
89
        /** @var MinkExtension|null $minkExtension */
90
        $minkExtension = $extensionManager->getExtension('mink');
91
        if (null === $minkExtension) {
92
            return;
93
        }
94
95
        $minkExtension->registerDriverFactory(new SymfonyDriverFactory('symfony', new Reference(self::DRIVER_KERNEL_ID)));
96
97
        $this->minkExtensionFound = true;
98
    }
99
100
    private function loadKernel(ContainerBuilder $container, array $config): void
101
    {
102
        $definition = new Definition($config['class'], [
103
            $config['env'],
104
            (bool) $config['debug'],
105
        ]);
106
        $definition->addMethodCall('boot');
107
        $definition->setPublic(true);
108
109
        if (null !== $config['path']) {
110
            $definition->setFile($config['path']);
111
        }
112
113
        $container->setDefinition(self::KERNEL_ID, $definition);
114
    }
115
116
    private function loadDriverKernel(ContainerBuilder $container): void
117
    {
118
        $container->setDefinition(self::DRIVER_KERNEL_ID, $container->findDefinition(self::KERNEL_ID));
119
    }
120
121
    private function loadKernelRebooter(ContainerBuilder $container): void
122
    {
123
        $definition = new Definition(KernelRebooter::class, [new Reference(self::KERNEL_ID), $container]);
124
        $definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG);
125
126
        $container->setDefinition(self::KERNEL_ID . '.rebooter', $definition);
127
    }
128
129
    private function loadEnvironmentHandler(ContainerBuilder $container): void
130
    {
131
        $definition = new Definition(ContextServiceEnvironmentHandler::class, [
132
            new Reference(self::KERNEL_ID),
133
        ]);
134
        $definition->addTag(EnvironmentExtension::HANDLER_TAG, ['priority' => 128]);
135
136
        foreach ($container->findTaggedServiceIds(ContextExtension::INITIALIZER_TAG) as $serviceId => $tags) {
137
            $definition->addMethodCall('registerContextInitializer', [$container->getDefinition($serviceId)]);
138
        }
139
140
        $container->setDefinition('fob_symfony.environment_handler.context_service', $definition);
141
    }
142
143
    private function loadMinkDefaultSession(ContainerBuilder $container): void
144
    {
145
        $minkDefaultSessionDefinition = new Definition(Session::class);
146
        $minkDefaultSessionDefinition->setPublic(true);
147
        $minkDefaultSessionDefinition->setFactory([new Reference('mink'), 'getSession']);
148
149
        $container->setDefinition('fob_symfony.mink.default_session', $minkDefaultSessionDefinition);
150
    }
151
152
    private function loadMinkParameters(ContainerBuilder $container): void
153
    {
154
        $minkParametersDefinition = new Definition(MinkParameters::class, [new Parameter('mink.parameters')]);
155
        $minkParametersDefinition->setPublic(true);
156
157
        $container->setDefinition('fob_symfony.mink.parameters', $minkParametersDefinition);
158
    }
159
}
160