diff --git a/core/core.services.yml b/core/core.services.yml index 5583040c115..1d9b2d248dc 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -393,12 +393,7 @@ services: class: Drupal\Core\Controller\TitleResolver arguments: ['@controller_resolver', '@string_translation'] http_kernel: - class: Symfony\Component\HttpKernel\HttpKernel - factory_method: resolve - factory_service: http_kernel_factory - arguments: ['@http_kernel.basic'] - http_kernel_factory: - class: Stack\Builder + class: Stack\StackedHttpKernel http_kernel.basic: class: Symfony\Component\HttpKernel\HttpKernel arguments: ['@event_dispatcher', '@controller_resolver', '@request_stack'] diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php index bf8efc0745b..845867ac81b 100644 --- a/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php @@ -9,6 +9,7 @@ namespace Drupal\Core\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; /** * Provides a compiler pass for stacked HTTP kernels. @@ -21,25 +22,44 @@ class StackedKernelPass implements CompilerPassInterface { * {@inheritdoc} */ public function process(ContainerBuilder $container) { - if (!$container->hasDefinition('http_kernel_factory')) { + + if (!$container->hasDefinition('http_kernel')) { return; } - $http_kernel_factory = $container->getDefinition('http_kernel_factory'); - $middleware_priorities = array(); - $middleware_arguments = array(); - foreach ($container->findTaggedServiceIds('http_middleware') as $id => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $middleware_priorities[$id] = $priority; - $definition = $container->getDefinition($id); - $middleware_arguments[$id] = $definition->getArguments(); - array_unshift($middleware_arguments[$id], $definition->getClass()); - } - array_multisort($middleware_priorities, SORT_DESC, $middleware_arguments, SORT_DESC); + $stacked_kernel = $container->getDefinition('http_kernel'); - foreach ($middleware_arguments as $id => $push_arguments) { - $http_kernel_factory->addMethodCall('push', $push_arguments); + // Return now if this is not a stacked kernel. + if ($stacked_kernel->getClass() !== 'Stack\StackedHttpKernel') { + return; } + + $middlewares = []; + $priorities = []; + + foreach ($container->findTaggedServiceIds('http_middleware') as $id => $attributes) { + $priorities[$id] = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $middlewares[$id] = $container->getDefinition($id); + } + + array_multisort($priorities, SORT_ASC, $middlewares); + + $decorated_id = 'http_kernel.basic'; + $middlewares_param = [new Reference($decorated_id)]; + foreach ($middlewares as $id => $decorator) { + // Prepend a reference to the middlewares container parameter. + array_unshift($middlewares_param, new Reference($id)); + + // Prepend the inner kernel as first constructor argument. + $arguments = $decorator->getArguments(); + array_unshift($arguments, new Reference($decorated_id)); + $decorator->setArguments($arguments); + + $decorated_id = $id; + } + + $arguments = [$middlewares_param[0], $middlewares_param]; + $stacked_kernel->setArguments($arguments); } } diff --git a/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/StackedKernelPassTest.php b/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/StackedKernelPassTest.php new file mode 100644 index 00000000000..5bd60012810 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/StackedKernelPassTest.php @@ -0,0 +1,117 @@ +stackedKernelPass = new StackedKernelPass(); + $this->containerBuilder = new ContainerBuilder(); + } + + /** + * @covers ::process + */ + public function testProcessWithStackedKernel() { + $stacked_kernel = new Definition('Stack\StackedHttpKernel'); + + $this->containerBuilder->setDefinition('http_kernel', $stacked_kernel); + $this->containerBuilder->setDefinition('http_kernel.basic', $this->createMiddlewareServiceDefinition(FALSE, 0)); + + $this->containerBuilder->setDefinition('http_kernel.three', $this->createMiddlewareServiceDefinition()); + $this->containerBuilder->setDefinition('http_kernel.one', $this->createMiddlewareServiceDefinition(TRUE, 10)); + $this->containerBuilder->setDefinition('http_kernel.two', $this->createMiddlewareServiceDefinition(TRUE, 5)); + + $this->stackedKernelPass->process($this->containerBuilder); + + $stacked_kernel_args = $this->containerBuilder->getDefinition('http_kernel')->getArguments(); + + // Check the stacked kernel args. + $this->assertSame((string) $stacked_kernel_args[0], 'http_kernel.one'); + $this->assertCount(4, $stacked_kernel_args[1]); + $this->assertSame((string) $stacked_kernel_args[1][0], 'http_kernel.one'); + $this->assertSame((string) $stacked_kernel_args[1][1], 'http_kernel.two'); + $this->assertSame((string) $stacked_kernel_args[1][2], 'http_kernel.three'); + $this->assertSame((string) $stacked_kernel_args[1][3], 'http_kernel.basic'); + + // Check the modified definitions. + $definition = $this->containerBuilder->getDefinition('http_kernel.one'); + $args = $definition->getArguments(); + $this->assertSame('http_kernel.two', (string) $args[0]); + $this->assertSame('test', $args[1]); + + $definition = $this->containerBuilder->getDefinition('http_kernel.two'); + $args = $definition->getArguments(); + $this->assertSame('http_kernel.three', (string) $args[0]); + $this->assertSame('test', $args[1]); + + $definition = $this->containerBuilder->getDefinition('http_kernel.three'); + $args = $definition->getArguments(); + $this->assertSame('http_kernel.basic', (string) $args[0]); + $this->assertSame('test', $args[1]); + } + + /** + * @covers ::process + */ + public function testProcessWithHttpKernel() { + $kernel = new Definition('Symfony\Component\HttpKernel\HttpKernelInterface'); + $this->containerBuilder->setDefinition('http_kernel', $kernel); + $this->stackedKernelPass->process($this->containerBuilder); + + $unprocessed_kernel = $this->containerBuilder->getDefinition('http_kernel'); + + $this->assertSame($kernel, $unprocessed_kernel); + $this->assertSame($kernel->getArguments(), $unprocessed_kernel->getArguments()); + } + + /** + * Creates a middleware definition. + * + * @param bool $tag + * Whether ot not to set the http_middleware tag. + * @param int $priority + * The priority to be used for the tag. + * + * @return \Symfony\Component\DependencyInjection\Definition + */ + protected function createMiddlewareServiceDefinition($tag = TRUE, $priority = 0) { + $definition = new Definition('Symfony\Component\HttpKernel\HttpKernelInterface', ['test']); + + if ($tag) { + $definition->addTag('http_middleware', ['priority' => $priority]); + } + + return $definition; + } + +}