Lesson 3
Setting Up Middlewares in Symfony
Setting Up Middlewares in Symfony

Greetings! In this session, we will explore how to configure middlewares in Symfony to incorporate enterprise-level features into your application.

Middlewares provide a mechanism to intercept the request-response cycle of your application, allowing you to run specific code before a request is processed or after a response is generated. This approach is especially useful for tasks such as logging, authentication, and performance monitoring.

By the conclusion of this lesson, you will be equipped to create and configure a TimerMiddleware that measures the time it takes to process a request and includes this information in the response headers.

Crafting the TimerMiddleware Class

To start, we'll create the TimerMiddleware class. This class will be tasked with tracking the duration from the initiation of a request to the delivery of the response.

Here's the basic structure of the TimerMiddleware class:

php
1<?php 2 3namespace App\Middleware; 4 5use Symfony\Component\HttpKernel\Event\RequestEvent; 6use Symfony\Component\HttpKernel\Event\ResponseEvent; 7 8class TimerMiddleware 9{ 10 public function onKernelRequest(RequestEvent $event): void 11 { 12 $request = $event->getRequest(); 13 $start = microtime(true); 14 $request->attributes->set('start_time', $start); 15 } 16 17 public function onKernelResponse(ResponseEvent $event): void 18 { 19 $request = $event->getRequest(); 20 $start = $request->attributes->get('start_time'); 21 $duration = microtime(true) - $start; 22 $response = $event->getResponse(); 23 $response->headers->set('X-Duration', $duration); 24 } 25}

This class captures the start time when a request arrives (onKernelRequest) and calculates the duration when responding (onKernelResponse). The measured duration is added to the response headers.

Handling Requests

Now, let's delve into the onKernelRequest method, where we start tracking time as soon as a request comes in:

php
1public function onKernelRequest(RequestEvent $event): void 2{ 3 $request = $event->getRequest(); 4 $start = microtime(true); 5 $request->attributes->set('start_time', $start); 6}

Here, we capture the current time and store it as an attribute in the request. This attribute will be used later to calculate how long the request takes to process.

Handling Responses

Next, let's look at the onKernelResponse method, where we calculate and add the request duration to the response headers:

php
1public function onKernelResponse(ResponseEvent $event): void 2{ 3 $request = $event->getRequest(); 4 $start = $request->attributes->get('start_time'); 5 $duration = microtime(true) - $start; 6 $response = $event->getResponse(); 7 $response->headers->set('X-Duration', $duration); 8}

Here, we retrieve the start time from the request, calculate the duration by subtracting the start time from the current time, and then add this duration to the response headers.

Configuring services.yaml

To integrate the TimerMiddleware, we need to configure it in the config/services.yaml file, which manages Symfony's service container settings.

YAML
1services: 2 # default configuration for services in this file 3 _defaults: 4 autowire: true # Automatically inject dependencies in your services. 5 autoconfigure: true # Automatically register your services as commands, event subscribers, etc. 6 7 # makes classes in src/ available to be used as services 8 App\: 9 resource: '../src/' 10 exclude: 11 - '../src/DependencyInjection/' 12 - '../src/Entity/' 13 - '../src/Kernel.php' 14 15 # Register the TimerMiddleware service 16 App\Middleware\TimerMiddleware: 17 tags: 18 - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest } 19 - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }

In this configuration, we enable autowiring and autoconfiguration for services in the src/ directory. We specifically register the TimerMiddleware and tag it to listen for kernel.request and kernel.response events. This ensures that our middleware is triggered at the beginning of request handling and at the end of response handling.

Testing the Middleware

To verify the TimerMiddleware, you can send a request to your Symfony application and inspect the response headers to ensure the X-Duration header is present and contains the request processing duration.

An example of response headers with the TimerMiddleware functioning correctly might look like this:

Plain text
1HTTP/1.1 200 OK 2Host: localhost:3000 3Connection: close 4X-Powered-By: PHP/8.1.29 5Cache-Control: no-cache, private 6Date: Sat, 21 Sep 2024 22:50:03 GMT 7Content-Type: application/json 8X-Duration: 0.034611940383911 9X-Robots-Tag: noindex

Notice the X-Duration header in the response. This header shows the total time taken to process the request, confirming that the TimerMiddleware is operating as intended.

Recap and Next Steps

In this lesson, you have successfully implemented and configured a TimerMiddleware to measure the time taken to handle a request in your Symfony application.

Key Points Covered:

  1. Understanding Middlewares: Their role and advantages.
  2. Creating the TimerMiddleware Class: Implementing request and response handlers.
  3. Implementing Request and Response Handlers: Tracking and setting the request duration.
  4. Configuring Middleware in services.yaml: Registering the middleware correctly.
  5. Testing the Middleware: Verifying its functionality through response headers.

With this foundational knowledge, you can now implement a variety of middlewares in your Symfony application to manage tasks such as logging, authentication, and performance monitoring. Move on to the practice exercises to solidify these concepts and apply what you have learned.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.