Completed
Pull Request — master (#127)
by
unknown
01:55
created

SymfonyExtension::loadEnv()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 0
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\KernelOrchestrator;
17
use FriendsOfBehat\SymfonyExtension\Mink\Mink;
18
use FriendsOfBehat\SymfonyExtension\Mink\MinkParameters;
19
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
20
use Symfony\Component\DependencyInjection\Alias;
21
use Symfony\Component\DependencyInjection\ContainerBuilder;
22
use Symfony\Component\DependencyInjection\Definition;
23
use Symfony\Component\DependencyInjection\Parameter;
24
use Symfony\Component\DependencyInjection\Reference;
25
use Symfony\Component\Dotenv\Dotenv;
26
use Symfony\Component\Dotenv\Exception\PathException;
27
28
final class SymfonyExtension implements Extension
29
{
30
    /**
31
     * Kernel used inside Behat contexts or to create services injected to them.
32
     * Container is rebuilt before every scenario.
33
     */
34
    public const KERNEL_ID = 'fob_symfony.kernel';
35
36
    /**
37
     * Kernel used by Symfony driver to isolate web container from contexts' container.
38
     * Container is rebuilt before every request.
39
     */
40
    public const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel';
41
42
    /** @var bool */
43
    private $minkExtensionFound = false;
44
45
    public function getConfigKey(): string
46
    {
47
        return 'fob_symfony';
48
    }
49
50
    public function initialize(ExtensionManager $extensionManager): void
51
    {
52
        $this->registerMinkDriver($extensionManager);
53
    }
54
55
    public function configure(ArrayNodeDefinition $builder): void
56
    {
57
        $builder
58
            ->addDefaultsIfNotSet()
59
            ->children()
60
                ->scalarNode('bootstrap')->defaultNull()->end()
61
                ->arrayNode('kernel')
62
                    ->addDefaultsIfNotSet()
63
                    ->children()
64
                        ->scalarNode('path')->defaultNull()->end()
65
                        ->scalarNode('class')->defaultNull()->end()
66
                        ->scalarNode('environment')->defaultNull()->end()
67
                        ->booleanNode('debug')->defaultNull()->end()
68
                    ->end()
69
                ->end()
70
            ->end()
71
        ;
72
    }
73
74
    public function load(ContainerBuilder $container, array $config): void
75
    {
76
        $this->fallbackToTestEnvironment();
77
78
        $this->loadBootstrap($this->autodiscoverBootstrap($config['bootstrap']));
79
80
        if (empty($config['bootstrap'])) {
81
            $this->loadEnv();
82
        }
83
84
        $this->loadKernel($container, $this->autodiscoverKernelConfiguration($config['kernel']));
85
        $this->loadDriverKernel($container);
86
87
        $this->loadKernelRebooter($container);
88
89
        $this->loadEnvironmentHandler($container);
90
91
        if ($this->minkExtensionFound) {
92
            $this->loadMink($container);
93
            $this->loadMinkDefaultSession($container);
94
            $this->loadMinkParameters($container);
95
        }
96
    }
97
98
    public function process(ContainerBuilder $container): void
99
    {
100
        $this->processEnvironmentHandler($container);
101
102
        if ($this->minkExtensionFound) {
103
            $container->getDefinition(MinkExtension::MINK_ID)->setClass(Mink::class);
104
        }
105
    }
106
107
    private function registerMinkDriver(ExtensionManager $extensionManager): void
108
    {
109
        /** @var MinkExtension|null $minkExtension */
110
        $minkExtension = $extensionManager->getExtension('mink');
111
        if (null === $minkExtension) {
112
            return;
113
        }
114
115
        $minkExtension->registerDriverFactory(new SymfonyDriverFactory('symfony', new Reference(self::DRIVER_KERNEL_ID)));
116
117
        $this->minkExtensionFound = true;
118
    }
119
120
    private function loadKernel(ContainerBuilder $container, array $config): void
121
    {
122
        $definition = new Definition($config['class'], [
123
            $config['environment'] ?? $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? 'test',
124
            (bool) ($config['debug'] ?? $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? true),
125
        ]);
126
        $definition->addMethodCall('boot');
127
        $definition->setPublic(true);
128
129
        if ($config['path'] !== null) {
130
            $definition->setFile($config['path']);
131
        }
132
133
        $container->setDefinition(self::KERNEL_ID, $definition);
134
    }
135
136
    private function loadDriverKernel(ContainerBuilder $container): void
137
    {
138
        $container->setDefinition(self::DRIVER_KERNEL_ID, $container->findDefinition(self::KERNEL_ID));
139
    }
140
141
    private function loadKernelRebooter(ContainerBuilder $container): void
142
    {
143
        $definition = new Definition(KernelOrchestrator::class, [new Reference(self::KERNEL_ID), $container]);
144
        $definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG);
145
146
        $container->setDefinition('fob_symfony.kernel_orchestrator', $definition);
147
    }
148
149
    private function loadEnvironmentHandler(ContainerBuilder $container): void
150
    {
151
        $definition = new Definition(ContextServiceEnvironmentHandler::class, [
152
            new Reference(self::KERNEL_ID),
153
            new Reference('environment.handler.context'),
154
        ]);
155
        $definition->addTag(EnvironmentExtension::HANDLER_TAG, ['priority' => 128]);
156
157
        $container->setDefinition('fob_symfony.environment_handler.context_service', $definition);
158
    }
159
160
    private function loadMink(ContainerBuilder $container): void
161
    {
162
        $container->setAlias('fob_symfony.mink', (new Alias('mink'))->setPublic(true));
163
    }
164
165
    private function loadMinkDefaultSession(ContainerBuilder $container): void
166
    {
167
        $minkDefaultSessionDefinition = new Definition(Session::class);
168
        $minkDefaultSessionDefinition->setPublic(true);
169
        $minkDefaultSessionDefinition->setFactory([new Reference('mink'), 'getSession']);
170
171
        $container->setDefinition('fob_symfony.mink.default_session', $minkDefaultSessionDefinition);
172
    }
173
174
    private function loadMinkParameters(ContainerBuilder $container): void
175
    {
176
        $minkParametersDefinition = new Definition(MinkParameters::class, [new Parameter('mink.parameters')]);
177
        $minkParametersDefinition->setPublic(true);
178
179
        $container->setDefinition('fob_symfony.mink.parameters', $minkParametersDefinition);
180
    }
181
182
    private function loadBootstrap(?string $bootstrap): void
183
    {
184
        if ($bootstrap === null) {
185
            return;
186
        }
187
188
        require_once $bootstrap;
189
    }
190
191
    private function loadEnv()
192
    {
193
        $env = $config['environment'] ?? $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? 'test';
194
195
        try {
196
            (new Dotenv())->bootEnv(basename(dirname(__DIR__)) . '/../.env', $env);
197
        } catch (PathException $exception) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\Dotenv\Exception\PathException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
198
            return;
199
        }
200
    }
201
202
    private function fallbackToTestEnvironment(): void
203
    {
204
        // If there's no defined server / environment variable with an environment, default to test
205
        if (($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) === null) {
206
            putenv('APP_ENV=' . $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = 'test');
207
        }
208
    }
209
210
    private function processEnvironmentHandler(ContainerBuilder $container): void
211
    {
212
        $definition = $container->findDefinition('fob_symfony.environment_handler.context_service');
213
        foreach ($container->findTaggedServiceIds(ContextExtension::INITIALIZER_TAG) as $serviceId => $tags) {
214
            $definition->addMethodCall('registerContextInitializer', [new Reference($serviceId)]);
215
        }
216
    }
217
218
    private function autodiscoverKernelConfiguration(array $config): array
219
    {
220
        if ($config['class'] !== null) {
221
            return $config;
222
        }
223
224
        $autodiscovered = 0;
225
226
        if (class_exists('\App\Kernel')) {
227
            $config['class'] = '\App\Kernel';
228
229
            ++$autodiscovered;
230
        }
231
232
        if (file_exists('app/AppKernel.php')) {
233
            $config['class'] = '\AppKernel';
234
            $config['path'] = 'app/AppKernel.php';
235
236
            ++$autodiscovered;
237
        }
238
239
        if ($autodiscovered !== 1) {
240
            throw new \RuntimeException(
241
                'Could not autodiscover the application kernel. ' .
242
                'Please define it manually with "FriendsOfBehat\SymfonyExtension.kernel" configuration option.'
243
            );
244
        }
245
246
        return $config;
247
    }
248
249
    /**
250
     * @param string|bool|null $bootstrap
251
     */
252
    private function autodiscoverBootstrap($bootstrap): ?string
253
    {
254
        if (is_string($bootstrap)) {
255
            return $bootstrap;
256
        }
257
258
        if ($bootstrap === false) {
259
            return null;
260
        }
261
262
        $autodiscovered = 0;
263
264
        if (file_exists('config/bootstrap.php')) {
265
            $bootstrap = 'config/bootstrap.php';
266
267
            ++$autodiscovered;
268
        }
269
270
        if (file_exists('app/autoload.php')) {
271
            $bootstrap = 'app/autoload.php';
272
273
            ++$autodiscovered;
274
        }
275
276
        if ($autodiscovered === 2) {
277
            throw new \RuntimeException(
278
                'Could not autodiscover the bootstrap file. ' .
279
                'Please define it manually with "FriendsOfBehat\SymfonyExtension.bootstrap" configuration option. ' .
280
                'Setting that option to "false" disables autodiscovering.'
281
            );
282
        }
283
284
        return is_string($bootstrap) ? $bootstrap : null;
285
    }
286
}
287