Middleware
Create PSR-15 compliant middleware to process requests and responses
What is Middleware?
Middleware provides a convenient mechanism for filtering HTTP requests entering your application. Larafony uses PSR-15 middleware, making it compatible with any PSR-15 compliant middleware.
Creating Middleware
Implement the MiddlewareInterface from PSR-15:
<?php
declare(strict_types=1);
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class LogRequestMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Before request
$start = microtime(true);
// Process request
$response = $handler->handle($request);
// After request
$duration = microtime(true) - $start;
error_log("Request to {$request->getUri()} took {$duration}s");
return $response;
}
}
Attaching Middleware to Routes
Use the #[Middleware] attribute to attach middleware to specific routes:
<?php
namespace App\Controllers;
use App\Middleware\AuthMiddleware;
use Larafony\Framework\Routing\Advanced\Attributes\{Route, Middleware};
use Larafony\Framework\Web\Controller;
use Psr\Http\Message\ResponseInterface;
class AdminController extends Controller
{
#[Route('/admin/dashboard', 'GET')]
#[Middleware(AuthMiddleware::class)]
public function dashboard(): ResponseInterface
{
// Only accessible if AuthMiddleware passes
return $this->render('admin.dashboard');
}
}
Authentication Middleware Example
Here's a complete authentication middleware:
<?php
declare(strict_types=1);
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Larafony\Framework\Http\Response\RedirectResponse;
class AuthMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Check if user is authenticated
$session = $request->getAttribute('session');
if (!$session || !$session->has('user_id')) {
// Not authenticated - redirect to login
return new RedirectResponse('/login');
}
// Authenticated - continue
return $handler->handle($request);
}
}
CORS Middleware Example
Add CORS headers to API responses:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class CorsMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Handle preflight requests
if ($request->getMethod() === 'OPTIONS') {
return new Response(200, [
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization',
]);
}
// Process request
$response = $handler->handle($request);
// Add CORS headers
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}
}
Request Transformation
Middleware can modify the request before it reaches the controller:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class AddUserToRequestMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$session = $request->getAttribute('session');
if ($session && $session->has('user_id')) {
// Load user from database
$user = User::query()->find($session->get('user_id'));
// Add user to request attributes
$request = $request->withAttribute('user', $user);
}
return $handler->handle($request);
}
}
Access the user in your controller:
#[Route('/profile', 'GET')]
#[Middleware(AddUserToRequestMiddleware::class)]
public function profile(ServerRequestInterface $request): ResponseInterface
{
$user = $request->getAttribute('user');
return $this->render('profile', ['user' => $user]);
}
Multiple Middleware
Stack multiple middleware on a single route:
#[Route('/admin/users', 'GET')]
#[Middleware(AuthMiddleware::class)]
#[Middleware(AdminMiddleware::class)]
#[Middleware(LogRequestMiddleware::class)]
public function index(): ResponseInterface
{
// Protected by three middleware layers
return $this->render('admin.users');
}
JSON API Middleware
Ensure all responses are JSON:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class JsonResponseMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$response = $handler->handle($request);
// Ensure Content-Type is application/json
if (!$response->hasHeader('Content-Type')) {
$response = $response->withHeader('Content-Type', 'application/json');
}
return $response;
}
}
Global Middleware
Register middleware globally in bootstrap/app.php:
$app->withMiddleware([
LogRequestMiddleware::class,
CorsMiddleware::class,
]);