Completed
Push — master ( 3ef0d0...50fc50 )
by Kamil
07:01
created

SymfonyExtension::getKernelFile()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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