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
- Part 1: HttpKernel in Drupal
- Part 2: EventDispatcher in Drupal
- Part 3: Routing in Drupal)
- 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.
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.
Add new comment