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
|
|
|
$this->loadKernel($container, $this->autodiscoverKernelConfiguration($config['kernel'])); |
81
|
|
|
$this->loadDriverKernel($container); |
82
|
|
|
|
83
|
|
|
$this->loadKernelRebooter($container); |
84
|
|
|
|
85
|
|
|
$this->loadEnvironmentHandler($container); |
86
|
|
|
|
87
|
|
|
if ($this->minkExtensionFound) { |
88
|
|
|
$this->loadMink($container); |
89
|
|
|
$this->loadMinkDefaultSession($container); |
90
|
|
|
$this->loadMinkParameters($container); |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
public function process(ContainerBuilder $container): void |
95
|
|
|
{ |
96
|
|
|
$this->processEnvironmentHandler($container); |
97
|
|
|
|
98
|
|
|
if ($this->minkExtensionFound) { |
99
|
|
|
$container->getDefinition(MinkExtension::MINK_ID)->setClass(Mink::class); |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
private function registerMinkDriver(ExtensionManager $extensionManager): void |
104
|
|
|
{ |
105
|
|
|
/** @var MinkExtension|null $minkExtension */ |
106
|
|
|
$minkExtension = $extensionManager->getExtension('mink'); |
107
|
|
|
if (null === $minkExtension) { |
108
|
|
|
return; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
$minkExtension->registerDriverFactory(new SymfonyDriverFactory('symfony', new Reference(self::DRIVER_KERNEL_ID))); |
112
|
|
|
|
113
|
|
|
$this->minkExtensionFound = true; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
private function loadKernel(ContainerBuilder $container, array $config): void |
117
|
|
|
{ |
118
|
|
|
$definition = new Definition($config['class'], [ |
119
|
|
|
$config['environment'] ?? $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? 'test', |
120
|
|
|
(bool) ($config['debug'] ?? $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? true), |
121
|
|
|
]); |
122
|
|
|
$definition->addMethodCall('boot'); |
123
|
|
|
$definition->setPublic(true); |
124
|
|
|
|
125
|
|
|
if ($config['path'] !== null) { |
126
|
|
|
$definition->setFile($config['path']); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
$container->setDefinition(self::KERNEL_ID, $definition); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
private function loadDriverKernel(ContainerBuilder $container): void |
133
|
|
|
{ |
134
|
|
|
$container->setDefinition(self::DRIVER_KERNEL_ID, $container->findDefinition(self::KERNEL_ID)); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
private function loadKernelRebooter(ContainerBuilder $container): void |
138
|
|
|
{ |
139
|
|
|
$definition = new Definition(KernelOrchestrator::class, [new Reference(self::KERNEL_ID), $container]); |
140
|
|
|
$definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG); |
141
|
|
|
|
142
|
|
|
$container->setDefinition('fob_symfony.kernel_orchestrator', $definition); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
private function loadEnvironmentHandler(ContainerBuilder $container): void |
146
|
|
|
{ |
147
|
|
|
$definition = new Definition(ContextServiceEnvironmentHandler::class, [ |
148
|
|
|
new Reference(self::KERNEL_ID), |
149
|
|
|
new Reference('environment.handler.context'), |
150
|
|
|
]); |
151
|
|
|
$definition->addTag(EnvironmentExtension::HANDLER_TAG, ['priority' => 128]); |
152
|
|
|
|
153
|
|
|
$container->setDefinition('fob_symfony.environment_handler.context_service', $definition); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
private function loadMink(ContainerBuilder $container): void |
157
|
|
|
{ |
158
|
|
|
$container->setAlias('fob_symfony.mink', (new Alias('mink'))->setPublic(true)); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
private function loadMinkDefaultSession(ContainerBuilder $container): void |
162
|
|
|
{ |
163
|
|
|
$minkDefaultSessionDefinition = new Definition(Session::class); |
164
|
|
|
$minkDefaultSessionDefinition->setPublic(true); |
165
|
|
|
$minkDefaultSessionDefinition->setFactory([new Reference('mink'), 'getSession']); |
166
|
|
|
|
167
|
|
|
$container->setDefinition('fob_symfony.mink.default_session', $minkDefaultSessionDefinition); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
private function loadMinkParameters(ContainerBuilder $container): void |
171
|
|
|
{ |
172
|
|
|
$minkParametersDefinition = new Definition(MinkParameters::class, [new Parameter('mink.parameters')]); |
173
|
|
|
$minkParametersDefinition->setPublic(true); |
174
|
|
|
|
175
|
|
|
$container->setDefinition('fob_symfony.mink.parameters', $minkParametersDefinition); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
private function loadBootstrap(?string $bootstrap): void |
179
|
|
|
{ |
180
|
|
|
if ($bootstrap === null) { |
181
|
|
|
$this->loadEnv(); |
182
|
|
|
|
183
|
|
|
return; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
require_once $bootstrap; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
private function loadEnv() |
190
|
|
|
{ |
191
|
|
|
$env = $config['environment'] ?? $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? 'test'; |
192
|
|
|
try { |
193
|
|
|
(new Dotenv())->bootEnv(basename(dirname(__DIR__)).'/../.env', $env); |
194
|
|
|
} |
195
|
|
|
catch (PathException $exception) { |
|
|
|
|
196
|
|
|
return null; |
197
|
|
|
} |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
private function fallbackToTestEnvironment(): void |
201
|
|
|
{ |
202
|
|
|
// If there's no defined server / environment variable with an environment, default to test |
203
|
|
|
if (($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) === null) { |
204
|
|
|
putenv('APP_ENV=' . $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = 'test'); |
205
|
|
|
} |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
private function processEnvironmentHandler(ContainerBuilder $container): void |
209
|
|
|
{ |
210
|
|
|
$definition = $container->findDefinition('fob_symfony.environment_handler.context_service'); |
211
|
|
|
foreach ($container->findTaggedServiceIds(ContextExtension::INITIALIZER_TAG) as $serviceId => $tags) { |
212
|
|
|
$definition->addMethodCall('registerContextInitializer', [new Reference($serviceId)]); |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
private function autodiscoverKernelConfiguration(array $config): array |
217
|
|
|
{ |
218
|
|
|
if ($config['class'] !== null) { |
219
|
|
|
return $config; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
$autodiscovered = 0; |
223
|
|
|
|
224
|
|
|
if (class_exists('\App\Kernel')) { |
225
|
|
|
$config['class'] = '\App\Kernel'; |
226
|
|
|
|
227
|
|
|
++$autodiscovered; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
if (file_exists('app/AppKernel.php')) { |
231
|
|
|
$config['class'] = '\AppKernel'; |
232
|
|
|
$config['path'] = 'app/AppKernel.php'; |
233
|
|
|
|
234
|
|
|
++$autodiscovered; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
if ($autodiscovered !== 1) { |
238
|
|
|
throw new \RuntimeException( |
239
|
|
|
'Could not autodiscover the application kernel. ' . |
240
|
|
|
'Please define it manually with "FriendsOfBehat\SymfonyExtension.kernel" configuration option.' |
241
|
|
|
); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
return $config; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* @param string|bool|null $bootstrap |
249
|
|
|
*/ |
250
|
|
|
private function autodiscoverBootstrap($bootstrap): ?string |
251
|
|
|
{ |
252
|
|
|
if (is_string($bootstrap)) { |
253
|
|
|
return $bootstrap; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
if ($bootstrap === false) { |
257
|
|
|
return null; |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
$autodiscovered = 0; |
261
|
|
|
|
262
|
|
|
if (file_exists('config/bootstrap.php')) { |
263
|
|
|
$bootstrap = 'config/bootstrap.php'; |
264
|
|
|
|
265
|
|
|
++$autodiscovered; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
if (file_exists('app/autoload.php')) { |
269
|
|
|
$bootstrap = 'app/autoload.php'; |
270
|
|
|
|
271
|
|
|
++$autodiscovered; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
if ($autodiscovered === 2) { |
275
|
|
|
throw new \RuntimeException( |
276
|
|
|
'Could not autodiscover the bootstrap file. ' . |
277
|
|
|
'Please define it manually with "FriendsOfBehat\SymfonyExtension.bootstrap" configuration option. ' . |
278
|
|
|
'Setting that option to "false" disables autodiscovering.' |
279
|
|
|
); |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
return is_string($bootstrap) ? $bootstrap : null; |
283
|
|
|
} |
284
|
|
|
} |
285
|
|
|
|
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.