StackedKernelPass.php

Same filename and directory in other branches
  1. 11.x core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php
  2. 10 core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php
  3. 9 core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php
  4. 8.9.x core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php

Namespace

Drupal\Core\DependencyInjection\Compiler

File

core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php

View source
<?php

namespace Drupal\Core\DependencyInjection\Compiler;

use Drupal\Core\StackMiddleware\StackedHttpKernel;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

/**
 * 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.
 * @code
 * http_middleware.reverse_proxy:
 *   class: Drupal\Core\StackMiddleware\ReverseProxyMiddleware
 *   arguments: ['@settings']
 *   tags:
 *     - { name: http_middleware, priority: 300 }
 * @endcode
 *
 * @see \Drupal\Core\StackMiddleware\StackedHttpKernel
 */
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;
  }

}

Classes

Title Deprecated Summary
StackedKernelPass Provides a compiler pass for stacked HTTP kernels.

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