Part 1: HttpKernel in Drupal (Spotlight on Symfony in Drupal)

For over a decade, Drupal has been using Symfony Components. In 2015, with the release of Drupal 8, these components became a part of Drupal's core software. It's possible to build complex Drupal sites without worrying about what these components do. But learning about the system we're using will make us better developers of Drupal sites and other PHP applications.

In this first part of a 4-part series, we'll explore how Symfony helps Drupal with its HttpKernel component. We'll look at the component itself and how Drupal uses it to coordinate the request/response cycle.

Spotlight on Symfony in Drupal

  1. Part 1: HttpKernel in Drupal
  2. Part 2: EventDispatcher in Drupal
  3. Part 3: Routing in Drupal)
  4. Part 4: Utility Components in Drupal

Symfony's HttpKernel component in Drupal

One key Symfony component in Drupal is the HttpKernel Component. Its first job is to take the incoming HTTP request from the server, and turn it into a PHP Request object. This format allows other code to interact with the request without worrying about parsing HTTP. Then, the kernel coordinates the steps to create an HTML response for the browser to display.

To do this, it parses the request and notifies events that convert the Request object into a Response.

Drupal's StackedHttpKernel class

Drupal decorates the HttpKernel in its StackedHttpKernel (/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php). As you read the code, notice that the StackedHttpKernel class has 2 main functions: handle and terminate.

  • handle deals with incoming requests.
  • terminate sends the final response to the user.

Here's the truncated class:

    /**
    ...
    */
    class StackedHttpKernel implements HttpKernelInterface, TerminableInterface {
    // ...
    /**
       * Constructs a stacked HTTP kernel.
       *
       * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel
       *   The decorated kernel.
       * @param array $middlewares
       *   An array of previous middleware services.
       */
      public function __construct(HttpKernelInterface $kernel, array $middlewares) {
        $this->kernel = $kernel;
        $this->middlewares = $middlewares;
      }
    
      /**
       * {@inheritdoc}
       */
      public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUEST, $catch = TRUE): Response {
        return $this->kernel->handle($request, $type, $catch);
      }
    
      /**
       * {@inheritdoc}
       */
      public function terminate(Request $request, Response $response) {
        $previous = NULL;
        foreach ($this->middlewares as $kernel) {
          // If the previous kernel was terminable we can assume this middleware
          // has already been called.
          if (!$previous instanceof TerminableInterface && $kernel instanceof TerminableInterface) {
            $kernel->terminate($request, $response);
          }
          $previous = $kernel;
        }
      }
    }

Symfony's HttpKernel class

Let's examine the handle method in the HttpKernel class.

You can find the code for this in vendor/symfony/http-kernel/HttpKernel.php in your Drupal setup. Here's the truncated class:

    /**
    ...
    */
    class HttpKernel implements HttpKernelInterface, TerminableInterface
    // ...
    
        public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response
        {
          // ...
          $this->requestStack->push($request);
            $response = null;
            try {
                return $response = $this->handleRaw($request, $type);
            }
    
          // ...
        private function handleRaw(Request $request, int $type = self::MAIN_REQUEST): Response
        {
            // request
            $event = new RequestEvent($this, $request, $type);
            $this->dispatcher->dispatch($event, KernelEvents::REQUEST);
    
    
            if ($event->hasResponse()) {
              return $this->filterResponse($event->getResponse(), $request, $type);
            }
    
            // ...
        }

It uses something called requestStack to organize the request into a request stack object. Another Symfony component, HttpFoundation creates it. The requestStack method pushes the current request onto that stack. Then the handleRaw method creates a RequestEvent object, and dispatches it to the EventDispatcher, giving certain events an opportunity to respond to the request. If an event responds to the request, it sends its response, triggering the terminate method.

Learn more

Dig into the details in our tutorial, How Drupal Turns a Request into a Response, part of our course, Routes and Controllers in Drupal.

Infographic shows the request to response workflow that the HttpKernel coordinates.

Next up

Stay tuned for the next post in our Spotlight on Symfony in Drupal series, where we'll look at the EventDispatcher component and its role in handling requests.

Related Topics

Add new comment

Filtered HTML

  • Web page addresses and email addresses turn into links automatically.
  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <code class> <ul type> <ol start type> <li> <dl> <dt> <dd><h3 id> <p>
  • Lines and paragraphs break automatically.

About us

Drupalize.Me is the best resource for learning Drupal online. We have an extensive library covering multiple versions of Drupal and we are the most accurate and up-to-date Drupal resource. Learn more