Skip to main content

Application Middleware

Overview

DomainFlow Core’s middleware system lets you define callables that process a “payload” in sequence before reaching a final callback. It’s a flexible mechanism for tackling cross-cutting concerns—like authentication, logging, or caching—without tightly coupling them to the rest of your application logic.


Key Concepts

  • Middleware Stack: A list of callable functions that each have the opportunity to act on a payload.
  • Pipeline: The process of executing each middleware in series, passing the transformed (or unmodified) payload along until it reaches a final callback.
  • Short-Circuit: A middleware can bypass subsequent handlers by returning early or throwing an exception, depending on your use case.

Method Descriptions

getRegisteredMiddleware()

Signature

public function getRegisteredMiddleware(): array

Purpose
Returns an array of all middleware callables that have been registered. You can use this for debugging or to dynamically inspect which middleware you’ve added.

ParameterTypeRequired?Description
NoneN/AN/AN/A

Usage Example

$stack = $app->getRegisteredMiddleware();

containsMiddleware($middleware)

Signature

public function containsMiddleware(callable $middleware): bool

Purpose
Checks whether a specific middleware callable is already registered.

ParameterTypeRequired?Description
$middlewarecallableYesThe middleware callable to look for.

Usage Example

if (!$app->containsMiddleware($authMiddleware)) {
$app->useMiddleware($authMiddleware);
}

useMiddleware($middleware)

Signature

public function useMiddleware(callable $middleware): void

Purpose
Adds a middleware callable to the end of the stack. This middleware is a function with the following expected signature:

function ($payload, callable $next) {
// Perform actions on $payload
// Call $next($payload) to pass control forward
}
ParameterTypeRequired?Description
$middlewarecallableYesA function accepting a payload and a $next callback.

Usage Example

$app->useMiddleware(function ($payload, $next) {
// e.g. Log something before proceeding
return $next($payload);
});

pipeline($payload, $final)

Signature

public function pipeline(mixed $payload, callable $final): mixed

Purpose
Executes the middleware stack with an initial $payload and a final callable $final that runs last, after all middleware have been applied. Returns whatever the final callback (or the last middleware) produces.

ParameterTypeRequired?Description
$payloadmixedYesThe data passed through the middleware stack.
$finalcallableYesA callback that runs after the last middleware.

Usage Example

$result = $app->pipeline($request, function ($payload) {
// Final processing step, e.g. sending a response
return 'Done';
});
  • If any middleware throws an exception, the pipeline halts and an internal error event is fired.

Comparative Descriptions

  • useMiddleware() vs. on() (Event System)
  • useMiddleware() chains callables that modify a single payload in order.
  • on() (from the event system) notifies multiple listeners concurrently for an event, rather than sequentially processing a single piece of data.
  • pipeline() vs. Traditional Function Calls
  • Rather than calling functions manually in a certain order, pipeline() automatically composes them. Each middleware decides whether to pass control to the next or stop the sequence.

Practical Examples

// Register some middleware
$app->useMiddleware(function ($payload, $next) {
// Example: simple logging
error_log("Middleware #1 start");
$result = $next($payload);
error_log("Middleware #1 end");
return $result;
});

$app->useMiddleware(function ($payload, $next) {
// Example: check a condition
if (!isset($payload['user'])) {
// Possibly short-circuit with an error or custom response
return 'No user found.';
}
return $next($payload);
});

// Execute the pipeline with a final callback
$response = $app->pipeline(['user' => 'Alice'], function ($payload) {
// Final logic
return "Hello, " . $payload['user'];
});

echo $response; // "Hello, Alice"

Extensibility

  • Stack Order: The order you call useMiddleware() defines the execution sequence. You can reorder them if needed.
  • Conditional Middleware: Check environment or user roles before adding certain middleware (e.g., debugging middleware only in development).
  • Framework Modules: Large applications often have separate modules that each contribute their own set of middleware to the stack, enabling a more pluggable design.

With middleware, DomainFlow Core simplifies how you handle cross-cutting application logic—whether it’s for security, performance, or auditing—without tangling it into every part of your codebase.