Middleware acts as a bridge between the request and response cycle. By implementing your own middleware, you can encapsulate functionality that can be reused across different parts of your application. This tutorial will cover how to create a simple middleware system from scratch, including how to register and execute middleware.

Step 1: Define the Middleware Interface

First, we need to define an interface that all middleware classes will implement. This ensures that each middleware class has a consistent structure.

<?php
namespace Middleware;

interface MiddlewareInterface
{
    public function handle($request, callable $next);
}

Step 2: Create a Base Middleware Class

Next, we will create a base middleware class that implements the MiddlewareInterface. This class will contain a method to pass the request to the next middleware in the pipeline.

<?php
namespace Middleware;

abstract class BaseMiddleware implements MiddlewareInterface
{
    public function handle($request, callable $next)
    {
        // Pass the request to the next middleware
        return $next($request);
    }
}

Step 3: Implement Concrete Middleware Classes

Now, let's create a couple of concrete middleware classes that extend BaseMiddleware. For this example, we will create an AuthenticationMiddleware and a LoggingMiddleware.

Authentication Middleware

This middleware will check if a user is authenticated before allowing access to certain routes.

<?php
namespace Middleware;

class AuthenticationMiddleware extends BaseMiddleware
{
    public function handle($request, callable $next)
    {
        if (!$this->isAuthenticated($request)) {
            return "Unauthorized access!";
        }

        return parent::handle($request, $next);
    }

    private function isAuthenticated($request)
    {
        // Logic to check if the user is authenticated
        return isset($request['user']);
    }
}

Logging Middleware

This middleware will log the request details for debugging purposes.

<?php
namespace Middleware;

class LoggingMiddleware extends BaseMiddleware
{
    public function handle($request, callable $next)
    {
        $this->logRequest($request);
        return parent::handle($request, $next);
    }

    private function logRequest($request)
    {
        // Logic to log request details
        file_put_contents('request.log', json_encode($request) . PHP_EOL, FILE_APPEND);
    }
}

Step 4: Create the Middleware Manager

Next, we will create a MiddlewareManager class that will manage the middleware pipeline. This class will allow us to register middleware and execute them in order.

<?php
namespace Middleware;

class MiddlewareManager
{
    private $middleware = [];

    public function register(MiddlewareInterface $middleware)
    {
        $this->middleware[] = $middleware;
    }

    public function handle($request)
    {
        $next = function($request) {
            return "Response from the application!";
        };

        foreach (array_reverse($this->middleware) as $middleware) {
            $next = function($request) use ($middleware, $next) {
                return $middleware->handle($request, $next);
            };
        }

        return $next($request);
    }
}

Step 5: Using the Middleware System

Finally, we will put everything together and see how to use the middleware system in a simple application.

<?php
require 'Middleware/MiddlewareInterface.php';
require 'Middleware/BaseMiddleware.php';
require 'Middleware/AuthenticationMiddleware.php';
require 'Middleware/LoggingMiddleware.php';
require 'Middleware/MiddlewareManager.php';

use Middleware\MiddlewareManager;
use Middleware\AuthenticationMiddleware;
use Middleware\LoggingMiddleware;

$request = ['user' => 'John Doe']; // Simulated request

$middlewareManager = new MiddlewareManager();
$middlewareManager->register(new LoggingMiddleware());
$middlewareManager->register(new AuthenticationMiddleware());

$response = $middlewareManager->handle($request);
echo $response; // Output: Response from the application!

Middleware Execution Flow

The execution flow of the middleware is as follows:

StepMiddlewareAction
1LoggingMiddlewareLogs the request details
2AuthenticationMiddlewareChecks if the user is authenticated
3Application ResponseReturns the final response

Conclusion

By implementing a custom middleware system, you can effectively manage cross-cutting concerns in your PHP applications. This design pattern promotes code reusability and separation of concerns, making your application more maintainable and scalable.


Learn more with useful resources