diff --git a/composer.json b/composer.json index b0b1d58..588ee4a 100644 --- a/composer.json +++ b/composer.json @@ -11,26 +11,32 @@ ], "require": { "php": "^7.1", - "behat/behat": "^3.4", + "symfony/dotenv": "^3.4|^4.1", "symfony/http-kernel": "^3.4|^4.1", - "symfony/dotenv": "^3.4|^4.1" + "symfony/proxy-manager-bridge": "^3.4|^4.1" }, "require-dev": { "behat/mink": "^1.7", "behat/mink-browserkit-driver": "^1.3", "behat/mink-extension": "^2.2", - "friends-of-behat/cross-container-extension": "^1.0", "friends-of-behat/test-context": "^1.0", "phpstan/phpstan-shim": "^0.10", "sylius-labs/coding-standard": "^3.0", "symfony/framework-bundle": "^3.4|^4.1" }, "suggest": { - "behat/mink-browserkit-driver": "^1.3", - "friends-of-behat/cross-container-extension": "^1.0" + "behat/mink-browserkit-driver": "^1.3" }, "autoload": { "psr-4": { "FriendsOfBehat\\SymfonyExtension\\": "src/" } + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } } } diff --git a/features/not_crashing_behat.feature b/features/not_crashing_behat.feature index a2e0f7b..e1728ff 100644 --- a/features/not_crashing_behat.feature +++ b/features/not_crashing_behat.feature @@ -39,7 +39,6 @@ Feature: Not crashing Behat extensions: FriendsOfBehat\SymfonyExtension: kernel: - bootstrap: app/autoload.php path: app/MyKernel.php class: MyKernel env: test @@ -108,7 +107,6 @@ Feature: Not crashing Behat kernel: path: src/MyKernel.php class: MyKernel - bootstrap: ~ """ And a file "../config/.env_in_memory" containing: """ @@ -139,7 +137,6 @@ Feature: Not crashing Behat FriendsOfBehat\SymfonyExtension: env_file: .env_in_memory kernel: - bootstrap: ~ path: src/MyKernel.php class: MyKernel env: dev @@ -165,33 +162,3 @@ Feature: Not crashing Behat And a feature file with passing scenario When I run Behat Then it should pass - - Scenario: Not crashing Behat with CrossContainerExtension - Given a Behat configuration containing: - """ - default: - extensions: - FriendsOfBehat\SymfonyExtension: ~ - FriendsOfBehat\CrossContainerExtension: ~ - """ - And a file "app/autoload.php" containing: - """ - registerBehatContainer($container); + $this->provideMinkIntegration($container); + + $container + ->registerForAutoconfiguration(Context::class) + ->addTag('fob.context') + ; + } + + public function process(ContainerBuilder $container): void + { + foreach ($container->findTaggedServiceIds('fob.context') as $serviceId => $attributes) { + $container->findDefinition($serviceId)->setPublic(true); + } + } + + private function registerBehatContainer(ContainerBuilder $container): void + { + $behatServiceContainerDefinition = new Definition(ContainerInterface::class); + $behatServiceContainerDefinition->setPublic(true); + $behatServiceContainerDefinition->setSynthetic(true); + + $container->setDefinition('behat.service_container', $behatServiceContainerDefinition); + } + + private function provideMinkIntegration(ContainerBuilder $container): void + { + $minkDefinition = new Definition(Mink::class, ['mink']); + $minkDefinition->setPublic(true); + $minkDefinition->setFactory([new Reference('behat.service_container'), 'get']); + + $container->setDefinition('behat.mink', $minkDefinition); + + $minkDefaultSessionDefinition = new Definition(Session::class); + $minkDefaultSessionDefinition->setPublic(true); + $minkDefaultSessionDefinition->setLazy(true); + $minkDefaultSessionDefinition->setFactory([new Reference('behat.mink'), 'getSession']); + + $container->setDefinition('behat.mink.default_session', $minkDefaultSessionDefinition); + $container->setAlias(Session::class, 'behat.mink.default_session'); + } +} diff --git a/src/Bundle/FriendsOfBehatSymfonyExtensionBundle.php b/src/Bundle/FriendsOfBehatSymfonyExtensionBundle.php new file mode 100644 index 0000000..2694538 --- /dev/null +++ b/src/Bundle/FriendsOfBehatSymfonyExtensionBundle.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FriendsOfBehat\SymfonyExtension\Context\Environment; + +use Behat\Behat\Context\Environment\ContextEnvironment; +use FriendsOfBehat\SymfonyExtension\Context\Environment\Handler\ContextServiceEnvironmentHandler; + +/** + * @see ContextServiceEnvironmentHandler + */ +interface ContextServiceEnvironment extends ContextEnvironment +{ +} diff --git a/src/Context/Environment/Handler/ContextServiceEnvironmentHandler.php b/src/Context/Environment/Handler/ContextServiceEnvironmentHandler.php new file mode 100644 index 0000000..438db23 --- /dev/null +++ b/src/Context/Environment/Handler/ContextServiceEnvironmentHandler.php @@ -0,0 +1,160 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FriendsOfBehat\SymfonyExtension\Context\Environment\Handler; + +use Behat\Behat\Context\Context; +use Behat\Behat\Context\Initializer\ContextInitializer; +use Behat\Testwork\Environment\Environment; +use Behat\Testwork\Environment\Exception\EnvironmentIsolationException; +use Behat\Testwork\Environment\Handler\EnvironmentHandler; +use Behat\Testwork\Suite\Exception\SuiteConfigurationException; +use Behat\Testwork\Suite\Suite; +use FriendsOfBehat\SymfonyExtension\Context\Environment\InitialisedContextServiceEnvironment; +use FriendsOfBehat\SymfonyExtension\Context\Environment\UninitialisedContextServiceEnvironment; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpKernel\KernelInterface; + +final class ContextServiceEnvironmentHandler implements EnvironmentHandler +{ + /** @var KernelInterface */ + private $symfonyKernel; + + /** @var ContextInitializer[] */ + private $contextInitializers = []; + + public function __construct(KernelInterface $symfonyKernel) + { + $this->symfonyKernel = $symfonyKernel; + } + + public function supportsSuite(Suite $suite): bool + { + return $suite->hasSetting('contexts'); + } + + public function buildEnvironment(Suite $suite): Environment + { + $environment = new UninitialisedContextServiceEnvironment($suite); + foreach ($this->getSuiteContextsServices($suite) as $contextId) { + $environment->registerContextService($contextId, $this->getContextClass($contextId)); + } + + return $environment; + } + + public function supportsEnvironmentAndSubject(Environment $environment, $testSubject = null): bool + { + return $environment instanceof UninitialisedContextServiceEnvironment; + } + + /** + * @throws EnvironmentIsolationException + */ + public function isolateEnvironment(Environment $uninitializedEnvironment, $testSubject = null): Environment + { + /** @var UninitialisedContextServiceEnvironment $uninitializedEnvironment */ + $this->assertEnvironmentCanBeIsolated($uninitializedEnvironment, $testSubject); + + $environment = new InitialisedContextServiceEnvironment($uninitializedEnvironment->getSuite()); + foreach ($uninitializedEnvironment->getContextServices() as $contextId) { + /** @var Context $context */ + $context = $this->getContext($contextId); + $this->initializeInstance($context); + $environment->registerContext($context); + } + + return $environment; + } + + public function registerContextInitializer(ContextInitializer $initializer): void + { + $this->contextInitializers[] = $initializer; + } + + /** + * @return string[] + * + * @throws SuiteConfigurationException If "contexts" setting is not an array + */ + private function getSuiteContextsServices(Suite $suite): array + { + $contextsServices = $suite->getSetting('contexts'); + + if (!is_array($contextsServices)) { + throw new SuiteConfigurationException(sprintf( + '"contexts" setting of the "%s" suite is expected to be an array, %s given.', + $suite->getName(), + gettype($contextsServices) + ), $suite->getName()); + } + + return $contextsServices; + } + + /** + * @throws EnvironmentIsolationException + */ + private function assertEnvironmentCanBeIsolated(Environment $uninitializedEnvironment, $testSubject): void + { + if (!$this->supportsEnvironmentAndSubject($uninitializedEnvironment, $testSubject)) { + throw new EnvironmentIsolationException(sprintf( + '"%s" does not support isolation of "%s" environment.', + static::class, + get_class($uninitializedEnvironment) + ), $uninitializedEnvironment); + } + } + + private function initializeInstance(Context $context): void + { + foreach ($this->contextInitializers as $initializer) { + $initializer->initializeContext($context); + } + } + + private function getContextClass(string $contextId): string + { + if ($this->getContainer()->has($contextId)) { + return get_class($this->getContainer()->get($contextId)); + } + + $class = '\\' . ltrim($contextId, '\\'); + + if (class_exists($class)) { + return $class; + } + + throw new \Exception('wtf?'); + } + + private function getContext(string $contextId): Context + { + if ($this->getContainer()->has($contextId)) { + return $this->getContainer()->get($contextId); + } + + $class = '\\' . ltrim($contextId, '\\'); + + if (class_exists($class)) { + return new $class(); + } + + throw new \Exception('wtf?'); + } + + private function getContainer(): ContainerInterface + { + return $this->symfonyKernel->getContainer(); + } +} diff --git a/src/Context/Environment/InitialisedContextServiceEnvironment.php b/src/Context/Environment/InitialisedContextServiceEnvironment.php new file mode 100644 index 0000000..d8c1904 --- /dev/null +++ b/src/Context/Environment/InitialisedContextServiceEnvironment.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FriendsOfBehat\SymfonyExtension\Context\Environment; + +use Behat\Behat\Context\Context; +use Behat\Behat\Context\Exception\ContextNotFoundException; +use Behat\Testwork\Call\Callee; +use Behat\Testwork\Suite\Suite; +use FriendsOfBehat\SymfonyExtension\Context\Environment\Handler\ContextServiceEnvironmentHandler; + +/** + * @see ContextServiceEnvironmentHandler + */ +final class InitialisedContextServiceEnvironment implements ContextServiceEnvironment +{ + /** @var Suite */ + private $suite; + + /** @var Context[] */ + private $contexts = []; + + public function __construct(Suite $suite) + { + $this->suite = $suite; + } + + public function registerContext(Context $context): void + { + $this->contexts[get_class($context)] = $context; + } + + public function getSuite(): Suite + { + return $this->suite; + } + + public function bindCallee(Callee $callee): callable + { + $callable = $callee->getCallable(); + + if ($callee->isAnInstanceMethod()) { + return [$this->getContext($callable[0]), $callable[1]]; + } + + return $callable; + } + + public function hasContexts(): bool + { + return count($this->contexts) > 0; + } + + public function getContextClasses(): array + { + return array_keys($this->contexts); + } + + public function hasContextClass($class): bool + { + return isset($this->contexts[$class]); + } + + /** + * @throws ContextNotFoundException + */ + private function getContext(string $class): Context + { + if (!isset($this->contexts[$class])) { + throw new ContextNotFoundException(sprintf( + '`%s` context is not found in the suite environment. Have you registered it?', + $class + ), $class); + } + + return $this->contexts[$class]; + } +} diff --git a/src/Context/Environment/UninitialisedContextServiceEnvironment.php b/src/Context/Environment/UninitialisedContextServiceEnvironment.php new file mode 100644 index 0000000..bbd6211 --- /dev/null +++ b/src/Context/Environment/UninitialisedContextServiceEnvironment.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FriendsOfBehat\SymfonyExtension\Context\Environment; + +use Behat\Testwork\Environment\StaticEnvironment; +use FriendsOfBehat\SymfonyExtension\Context\Environment\Handler\ContextServiceEnvironmentHandler; + +/** + * @see ContextServiceEnvironmentHandler + */ +final class UninitialisedContextServiceEnvironment extends StaticEnvironment implements ContextServiceEnvironment +{ + /** @var string[] */ + private $contextServices = []; + + public function registerContextService(string $serviceId, string $serviceClass): void + { + $this->contextServices[$serviceId] = $serviceClass; + } + + public function getContextServices(): array + { + return array_keys($this->contextServices); + } + + public function hasContexts(): bool + { + return count($this->contextServices) > 0; + } + + public function getContextClasses(): array + { + return array_values($this->contextServices); + } + + public function hasContextClass($class): bool + { + return in_array($class, $this->contextServices, true); + } +} diff --git a/src/Driver/Factory/SymfonyDriverFactory.php b/src/Driver/Factory/SymfonyDriverFactory.php index 409add4..8c8f37b 100644 --- a/src/Driver/Factory/SymfonyDriverFactory.php +++ b/src/Driver/Factory/SymfonyDriverFactory.php @@ -12,52 +12,32 @@ use Symfony\Component\DependencyInjection\Reference; final class SymfonyDriverFactory implements DriverFactory { - /** - * @var string - */ + /** @var string */ private $name; - /** - * @var Reference - */ + /** @var Reference */ private $kernel; - /** - * @param string $name - * @param Reference $kernel - */ public function __construct(string $name, Reference $kernel) { $this->name = $name; $this->kernel = $kernel; } - /** - * {@inheritdoc} - */ public function getDriverName(): string { return $this->name; } - /** - * {@inheritdoc} - */ public function supportsJavascript(): bool { return false; } - /** - * {@inheritdoc} - */ public function configure(ArrayNodeDefinition $builder): void { } - /** - * {@inheritdoc} - */ public function buildDriver(array $config): Definition { return new Definition(SymfonyDriver::class, [ diff --git a/src/Driver/SymfonyDriver.php b/src/Driver/SymfonyDriver.php index de0267b..97387a5 100644 --- a/src/Driver/SymfonyDriver.php +++ b/src/Driver/SymfonyDriver.php @@ -10,10 +10,6 @@ use Symfony\Component\HttpKernel\KernelInterface; final class SymfonyDriver extends BrowserKitDriver { - /** - * @param KernelInterface $kernel - * @param string $baseUrl - */ public function __construct(KernelInterface $kernel, string $baseUrl) { $testClient = $kernel->getContainer()->get('test.client'); diff --git a/src/Listener/KernelRebooter.php b/src/Listener/KernelRebooter.php index 4cc7036..69f105a 100644 --- a/src/Listener/KernelRebooter.php +++ b/src/Listener/KernelRebooter.php @@ -6,38 +6,44 @@ namespace FriendsOfBehat\SymfonyExtension\Listener; use Behat\Behat\EventDispatcher\Event\ExampleTested; use Behat\Behat\EventDispatcher\Event\ScenarioTested; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\KernelInterface; final class KernelRebooter implements EventSubscriberInterface { - /** - * @var KernelInterface - */ - private $kernel; + /** @var KernelInterface */ + private $symfonyKernel; - /** - * @param KernelInterface $kernel - */ - public function __construct(KernelInterface $kernel) + /** @var ContainerInterface */ + private $behatContainer; + + public function __construct(KernelInterface $symfonyKernel, ContainerInterface $behatContainer) { - $this->kernel = $kernel; + $this->symfonyKernel = $symfonyKernel; + $this->behatContainer = $behatContainer; } - /** - * {@inheritdoc} - */ public static function getSubscribedEvents(): array { return [ - ScenarioTested::AFTER => ['rebootKernel', -15], - ExampleTested::AFTER => ['rebootKernel', -15], + ScenarioTested::AFTER => ['rebootSymfonyKernel', -15], + ExampleTested::AFTER => ['rebootSymfonyKernel', -15], + ScenarioTested::BEFORE => ['transferBehatContainer', 15], + ExampleTested::BEFORE => ['transferBehatContainer', 15], ]; } - public function rebootKernel(): void + public function transferBehatContainer(): void { - $this->kernel->shutdown(); - $this->kernel->boot(); + $symfonyContainer = $this->symfonyKernel->getContainer(); + + $symfonyContainer->set('behat.service_container', $this->behatContainer); + } + + public function rebootSymfonyKernel(): void + { + $this->symfonyKernel->shutdown(); + $this->symfonyKernel->boot(); } } diff --git a/src/ServiceContainer/SymfonyExtension.php b/src/ServiceContainer/SymfonyExtension.php index bda7c3d..1df810f 100644 --- a/src/ServiceContainer/SymfonyExtension.php +++ b/src/ServiceContainer/SymfonyExtension.php @@ -4,22 +4,20 @@ declare(strict_types=1); namespace FriendsOfBehat\SymfonyExtension\ServiceContainer; +use Behat\Behat\Context\ServiceContainer\ContextExtension; use Behat\MinkExtension\ServiceContainer\MinkExtension; +use Behat\Testwork\Environment\ServiceContainer\EnvironmentExtension; use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension; use Behat\Testwork\ServiceContainer\Extension; use Behat\Testwork\ServiceContainer\ExtensionManager; -use FriendsOfBehat\CrossContainerExtension\CrossContainerProcessor; -use FriendsOfBehat\CrossContainerExtension\KernelBasedContainerAccessor; -use FriendsOfBehat\CrossContainerExtension\ServiceContainer\CrossContainerExtension; +use FriendsOfBehat\SymfonyExtension\Context\Environment\Handler\ContextServiceEnvironmentHandler; use FriendsOfBehat\SymfonyExtension\Driver\Factory\SymfonyDriverFactory; use FriendsOfBehat\SymfonyExtension\Listener\KernelRebooter; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; -use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Dotenv\Dotenv; -use Symfony\Component\HttpKernel\KernelInterface; final class SymfonyExtension implements Extension { @@ -27,41 +25,13 @@ final class SymfonyExtension implements Extension * Kernel used inside Behat contexts or to create services injected to them. * Container is built before every scenario. */ - const KERNEL_ID = 'sylius_symfony_extension.kernel'; + public const KERNEL_ID = 'sylius_symfony_extension.kernel'; /** - * The current container used in scenario contexts. - * To be used as a factory for current injected application services. - */ - const KERNEL_CONTAINER_ID = 'sylius_symfony_extension.kernel.container'; - - /** - * Kernel used by Symfony2 driver to isolate web container from contexts' container. + * Kernel used by Symfony driver to isolate web container from contexts' container. * Container is built before every request. */ - const DRIVER_KERNEL_ID = 'sylius_symfony_extension.driver_kernel'; - - /** - * Kernel that should be used by extensions only. - * Container is built only once at the first use. - */ - const SHARED_KERNEL_ID = 'sylius_symfony_extension.shared_kernel'; - - /** - * The only container built by shared kernel. - * To be used as a factory for shared injected application services. - */ - const SHARED_KERNEL_CONTAINER_ID = 'sylius_symfony_extension.shared_kernel.container'; - - /** - * Default symfony environment used to run your suites. - */ - private const DEFAULT_ENV = 'test'; - - /** - * Enable or disable the debug mode - */ - private const DEFAULT_DEBUG_MODE = true; + private const DRIVER_KERNEL_ID = 'sylius_symfony_extension.driver_kernel'; /** * Default Symfony configuration @@ -69,53 +39,22 @@ final class SymfonyExtension implements Extension private const SYMFONY_DEFAULTS = [ 'env_file' => null, 'kernel' => [ - 'bootstrap' => 'app/autoload.php', - 'path' => 'app/AppKernel.php', 'class' => 'AppKernel', - 'env' => self::DEFAULT_ENV, - 'debug' => self::DEFAULT_DEBUG_MODE, + 'env' => 'test', + 'debug' => true, ], ]; - /** - * Default Symfony 4 configuration - */ - private const SYMFONY_4_DEFAULTS = [ - 'env_file' => '.env', - 'kernel' => [ - 'bootstrap' => null, - 'path' => 'src/Kernel.php', - 'class' => 'App\Kernel', - 'env' => self::DEFAULT_ENV, - 'debug' => self::DEFAULT_DEBUG_MODE, - ], - ]; - - /** - * @var CrossContainerProcessor|null - */ - private $crossContainerProcessor; - - /** - * {@inheritdoc} - */ public function getConfigKey(): string { return 'fob_symfony'; } - /** - * {@inheritdoc} - */ public function initialize(ExtensionManager $extensionManager): void { $this->registerSymfonyDriverFactory($extensionManager); - $this->initializeCrossContainerProcessor($extensionManager); } - /** - * {@inheritdoc} - */ public function configure(ArrayNodeDefinition $builder): void { $builder @@ -124,8 +63,6 @@ final class SymfonyExtension implements Extension ->arrayNode('kernel') ->addDefaultsIfNotSet() ->children() - ->scalarNode('bootstrap')->defaultFalse()->end() - ->scalarNode('path')->end() ->scalarNode('class')->end() ->scalarNode('env')->end() ->booleanNode('debug')->end() @@ -135,28 +72,18 @@ final class SymfonyExtension implements Extension ; } - /** - * {@inheritdoc} - */ public function load(ContainerBuilder $container, array $config): void { $config = $this->autoconfigure($container, $config); $this->loadKernel($container, $config['kernel']); - $this->loadKernelContainer($container); - $this->loadDriverKernel($container); - $this->loadSharedKernel($container); - $this->loadSharedKernelContainer($container); + $this->loadEnvironmentHandler($container); $this->loadKernelRebooter($container); - $this->declareSymfonyContainers($container); } - /** - * {@inheritdoc} - */ public function process(ContainerBuilder $container): void { } @@ -165,13 +92,6 @@ final class SymfonyExtension implements Extension { $defaults = self::SYMFONY_DEFAULTS; - $symfonyFourKernelPath = sprintf('%s/%s', $container->getParameter('paths.base'), self::SYMFONY_4_DEFAULTS['kernel']['path']); - if ($userConfig['kernel']['bootstrap'] === null || file_exists($symfonyFourKernelPath)) { - $defaults = self::SYMFONY_4_DEFAULTS; - } - - $userConfig['kernel']['bootstrap'] = $userConfig['kernel']['bootstrap'] === false ? null : $userConfig['kernel']['bootstrap']; - $config = array_replace_recursive($defaults, $userConfig); if (null !== $config['env_file']) { @@ -200,30 +120,12 @@ final class SymfonyExtension implements Extension { $definition = new Definition($config['class'], [ $config['env'], - $config['debug'], + (bool) $config['debug'], ]); $definition->addMethodCall('boot'); $definition->setPublic(true); - $file = $this->getKernelFile($container->getParameter('paths.base'), $config['path']); - if (null !== $file) { - $definition->setFile($file); - } - $container->setDefinition(self::KERNEL_ID, $definition); - - $this->requireKernelBootstrapFile($container->getParameter('paths.base'), $config['bootstrap']); - } - - private function loadKernelContainer(ContainerBuilder $container): void - { - $containerDefinition = new Definition(Container::class); - $containerDefinition->setFactory([ - new Reference(self::KERNEL_ID), - 'getContainer', - ]); - - $container->setDefinition(self::KERNEL_CONTAINER_ID, $containerDefinition); } private function loadDriverKernel(ContainerBuilder $container): void @@ -231,71 +133,26 @@ final class SymfonyExtension implements Extension $container->setDefinition(self::DRIVER_KERNEL_ID, $container->findDefinition(self::KERNEL_ID)); } - private function loadSharedKernel(ContainerBuilder $container): void - { - $container->setDefinition(self::SHARED_KERNEL_ID, $container->findDefinition(self::KERNEL_ID)); - } - - private function loadSharedKernelContainer(ContainerBuilder $container): void - { - $containerDefinition = new Definition(Container::class); - $containerDefinition->setFactory([ - new Reference(self::SHARED_KERNEL_ID), - 'getContainer', - ]); - - $container->setDefinition(self::SHARED_KERNEL_CONTAINER_ID, $containerDefinition); - } - - /** - * @throws \Exception - */ private function loadKernelRebooter(ContainerBuilder $container): void { - $definition = new Definition(KernelRebooter::class, [new Reference(self::KERNEL_ID)]); + $definition = new Definition(KernelRebooter::class, [new Reference(self::KERNEL_ID), $container]); $definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG); $container->setDefinition(self::KERNEL_ID . '.rebooter', $definition); } - /** - * @throws \Exception - */ - private function declareSymfonyContainers(ContainerBuilder $container): void + private function loadEnvironmentHandler(ContainerBuilder $container): void { - if (null === $this->crossContainerProcessor) { - return; + $definition = new Definition(ContextServiceEnvironmentHandler::class, [ + new Reference(self::KERNEL_ID), + ]); + $definition->addTag(EnvironmentExtension::HANDLER_TAG, ['priority' => 128]); + + foreach ($container->findTaggedServiceIds(ContextExtension::INITIALIZER_TAG) as $serviceId => $tags) { + $definition->addMethodCall('registerContextInitializer', [$container->getDefinition($serviceId)]); } - $containerAccessors = [ - 'symfony' => self::KERNEL_ID, - 'symfony_driver' => self::DRIVER_KERNEL_ID, - 'symfony_shared' => self::SHARED_KERNEL_ID, - ]; - - foreach ($containerAccessors as $containerName => $kernelIdentifier) { - $kernel = $container->get($kernelIdentifier); - - if (!$kernel instanceof KernelInterface) { - throw new \RuntimeException(sprintf( - 'Expected service "%s" to be an instance of "%s", got "%s" instead.', - $kernelIdentifier, - KernelInterface::class, - \is_object($kernel) ? \get_class($kernel) : \gettype($kernel) - )); - } - - $this->crossContainerProcessor->addContainerAccessor($containerName, new KernelBasedContainerAccessor($kernel)); - } - } - - private function initializeCrossContainerProcessor(ExtensionManager $extensionManager): void - { - /** @var CrossContainerExtension $extension */ - $extension = $extensionManager->getExtension('fob_cross_container'); - if (null !== $extension) { - $this->crossContainerProcessor = $extension->getCrossContainerProcessor(); - } + $container->setDefinition('fob_symfony.environment_handler.context_service', $definition); } private function registerSymfonyDriverFactory(ExtensionManager $extensionManager): void @@ -306,50 +163,6 @@ final class SymfonyExtension implements Extension return; } - $minkExtension->registerDriverFactory(new SymfonyDriverFactory( - 'symfony', - new Reference(self::DRIVER_KERNEL_ID) - )); - } - - private function getKernelFile(string $basePath, string $kernelPath): ?string - { - $possibleFiles = [ - sprintf('%s/%s', $basePath, $kernelPath), - $kernelPath, - ]; - - foreach ($possibleFiles as $possibleFile) { - if (file_exists($possibleFile)) { - return $possibleFile; - } - } - - return null; - } - - /** - * @throws \DomainException - */ - private function requireKernelBootstrapFile(string $basePath, ?string $bootstrapPath): void - { - if (null === $bootstrapPath) { - return; - } - - $possiblePaths = [ - sprintf('%s/%s', $basePath, $bootstrapPath), - $bootstrapPath, - ]; - - foreach ($possiblePaths as $possiblePath) { - if (file_exists($possiblePath)) { - require_once $possiblePath; - - return; - } - } - - throw new \DomainException('Could not load bootstrap file.'); + $minkExtension->registerDriverFactory(new SymfonyDriverFactory('symfony', new Reference(self::DRIVER_KERNEL_ID))); } }