class StackedKernelPass

Provides a compiler pass for stacked HTTP kernels.

Builds the HTTP kernel by collecting all services tagged 'http_middleware' and assembling them into a StackedHttpKernel. The middleware with the highest priority ends up as the outermost while the lowest priority middleware wraps the actual HTTP kernel defined by the http_kernel.basic service.

A HTTP middleware may act on a request before and/or after it is delegated to the next inner layer. The inner layer is injected into the middleware in the first constructor argument. The following type hints are supported for the argument: Either Symfony\Component\HttpKernel\HttpKernelInterface or \Closure or an union of both to retain backward compatibility. If the middleware type hint contains a \Closure, the inner layer is injected as a service closure.

In general middlewares should not have heavy dependencies. This is especially important for high-priority services which need to run before the internal page cache.

An example of a high priority middleware.


http_middleware.reverse_proxy:
  class: Drupal\Core\StackMiddleware\ReverseProxyMiddleware
  arguments: ['@settings']
  tags:
    - { name: http_middleware, priority: 300 }

Hierarchy

  • class \Drupal\Core\DependencyInjection\Compiler\StackedKernelPass implements \Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface uses \Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait extends \Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass

Expanded class hierarchy of StackedKernelPass

See also

\Drupal\Core\StackMiddleware\StackedHttpKernel

2 files declare their use of StackedKernelPass
CoreServiceProvider.php in core/lib/Drupal/Core/CoreServiceProvider.php
StackedKernelPassTest.php in core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/StackedKernelPassTest.php

File

core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php, line 46

Namespace

Drupal\Core\DependencyInjection\Compiler
View source
class StackedKernelPass extends AbstractRecursivePass implements CompilerPassInterface {
  use PriorityTaggedServiceTrait;
  
  /**
   * {@inheritdoc}
   */
  public function process(ContainerBuilder $container) : void {
    if (!$container->hasDefinition('http_kernel')) {
      return;
    }
    $stacked_kernel = $container->getDefinition('http_kernel');
    // Return now if this is not a stacked kernel.
    if ($stacked_kernel->getClass() !== StackedHttpKernel::class) {
      return;
    }
    $decorated_id = 'http_kernel.basic';
    $middlewares_param = [
      new Reference($decorated_id),
    ];
    foreach (array_reverse($this->findAndSortTaggedServices('http_middleware', $container)) as $ref) {
      // Prepend a reference to the middlewares container parameter.
      array_unshift($middlewares_param, $ref);
      // Setup an alias on the outer middleware pointing to the inner one.
      $decorator_id = (string) $ref;
      $container->setAlias($decorator_id . '.http_middleware_inner', $decorated_id);
      $decorated_id = $decorator_id;
    }
    $arguments = [
      new Reference($decorated_id),
      new IteratorArgument($middlewares_param),
    ];
    $stacked_kernel->setArguments($arguments);
    parent::process($container);
  }
  
  /**
   * {@inheritdoc}
   */
  protected function processValue(mixed $value, bool $isRoot = FALSE) : mixed {
    $value = parent::processValue($value, $isRoot);
    if (!$value instanceof Definition || !$value->hasTag('http_middleware')) {
      return $value;
    }
    $constructor = $this->getConstructor($value, TRUE);
    $params = $constructor->getParameters();
    $innerType = $params[0]->getType();
    $innerParamTypes = $innerType instanceof \ReflectionUnionType || $innerType instanceof \ReflectionIntersectionType ? $innerType->getTypes() : [
      $innerType,
    ];
    $paramTypeNames = array_map(fn($param) => (string) $param, $innerParamTypes);
    $inner = new Reference($this->currentId . '.http_middleware_inner');
    if (in_array(\Closure::class, $paramTypeNames, TRUE)) {
      $inner = new ServiceClosureArgument($inner);
    }
    $arguments = $value->getArguments();
    array_unshift($arguments, $inner);
    $value->setArguments($arguments);
    return $value;
  }

}

Members

Title Sort descending Modifiers Object type Summary
StackedKernelPass::process public function
StackedKernelPass::processValue protected function

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.