API Reference

The following make up the primary API of Stratigility.

Middleware

Zend\Stratigility\MiddlewarePipe is the primary application interface, and has been discussed previously. Its API is:

namespace Zend\Stratigility;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class MiddlewarePipe implements MiddlewareInterface, RequestHandlerInterface
{
    public function pipe(MiddlewareInterface $middleware);

    public function handle(ServerRequestInterface $request) : ResponseInterface;

    public function process(
        ServerRequestInterface $request,
        DelegateInterface $delegate
    ) : ResponseInterface;
}

Middleware is executed in the order in which it is piped to the MiddlewarePipe instance.

The MiddlewarePipe is itself middleware, and can be executed in stacks that expect PSR-15 middleware signatures. It is also a request handler, allowing you to use it in paradigms where a request handler is required; when executed in this way, it will process itself in order to generate a response.

Middleware should either return a response, or the result of RequestHandlerInterface::handle() (which should eventually evaluate to a response instance).

Internally, MiddlewarePipe creates an instance of Zend\Stratigility\Next to use as a RequestHandlerInterface implementation to pass to each middleware; Next receives the queue of middleware from the MiddlewarePipe instance and processes each one, calling them with the current request and itself, advancing its internal pointer until all middleware are executed, or a response is returned.

Next

Zend\Stratigility\Next is primarily an implementation detail, and exists to allow delegating to middleware aggregated in the MiddlewarePipe. It is implemented as an PSR-15 RequestHandlerInterface.

Since your middleware needs to return a response, the instance receives the $handler argument passed to MiddlewarePipe::process() as a fallback request handler; if the last middleware in the queue calls on its handler, Next will execute the fallback request handler to generate a response to return.

Providing an altered request:

function ($request, RequestHandlerInterface $handler) use ($bodyParser)
{
    $bodyParams = $bodyParser($request);

    // Delegate will receive the new request instance:
    return $handler->handle(
        $request->withBodyParams($bodyParams)
    );
}

Providing an altered request and operating on the returned response:

function ($request, RequestHandlerInterface $handler) use ($bodyParser)
{
    $bodyParams = $bodyParser($request);

    // Provide a new request instance to the handler:
    $response = return $handler->handle(
        $request->withBodyParams($bodyParams)
    );

    // Return a response with an additional header:
    return $response->withHeader('X-Completed', 'true');
}

Returning a response to complete the request

If your middleware does not need to delegate to another layer, it's time to return a response.

We recommend creating a new response, or providing your middleware with a response prototype; this will ensure that the response is specific for your context.

$prototype = new Response();

function ($request, RequestHandlerInterface $handler) use ($prototype)
{
    $response = $prototype->withAddedHeader('Cache-Control', [
        'public',
        'max-age=18600',
        's-maxage=18600',
    ]);
}

Delegation

If your middleware is not capable of returning a response, or a particular path in the middleware cannot return a response, return the result of executing the handler.

return $handler->handle($request);

Middleware should always return a response, and, if it cannot, return the result of delegating to the request handler.

Raising an error condition

If your middleware cannot complete — perhaps a database error occurred, a service was unreachable, etc. — how can you report the error?

Raise an exception!

function ($request, RequestHandlerInterface $handler) use ($service)
{
    $result = $service->fetchSomething();
    if (! $result->isSuccess()) {
        throw new RuntimeException('Error fetching something');
    }

    /* ... otherwise, complete the request ... */
}

Use the ErrorHandler middleware to handle exceptions thrown by your middleware and report the error condition to your users.

Middleware

Stratigility provides several concrete middleware implementations.

PathMiddlewareDecorator

If you wish to segregate middleware by path prefix and/or conditionally execute middleware based on a path prefix, decorate your middleware using Zend\Stratigility\Middleware\PathMiddlewareDecorator.

Middleware decorated by PathMiddlewareDecorator will only execute if the request URI matches the path prefix provided during instantiation.

// Only process $middleware if the URI path prefix matches '/foo':
$pipeline->pipe(new PathMiddlewareDecorator('/foo', $middleware));

When the path prefix matches, the PathMiddlewareDecorator will strip the path prefix from the request passed to the decorated middleware. For example, if you executed $pipeline->pipe('/api', $api), and this was matched via a URI with the path /api/users/foo, the $api middleware will receive a request with the path /users/foo. This allows middleware segregated by path to be re-used without changes to its own internal routing.

CallableMiddlewareDecorator

Zend\Stratigility\Middleware\CallableMiddlewareDecorator provides the ability to decorate PHP callables that have the same signature as or a compatible signature to PSR-15's MiddlewareInterface. This allows for one-off middleware creation when creating your pipeline:

$pipeline->pipe(new CallableMiddlewareDecorator(function ($req, $handler) {
    // do some work
    $response = $handler->handle($req);
    // do some work
    return $response;
});

DoublePassMiddlewareDecorator

Zend\Stratigility\Middleware\DoublePassMiddlewareDecorator provides the ability to decorate "double-pass", callable middleware (so-called because you pass the request and response to the delegate) within a class implementing the PSR-15 MiddlewareInterface. This allows you to adapt existing middleware with the double-pass interface to work with Stratigility.

$pipeline->pipe(new DoublePassMiddlewareDecorator(function ($req, $res, $next) {
    // do some work
    $response = $next($req, $res);
    // do some work
    return $response;
});

$next is a callable that decorates Stratigility's Next instance; it ignores the response argument.

The constructor takes an optional second argument, a response prototype. This will be used to pass to the middleware when it is executed. If no instance is provided, a zend-diactoros response instance is auto-wired. If you want to use an alternate PSR-7 ResponseInterface implementation, pass it when creating the decorator instance:

$pipeline->pipe(new DoublePassMiddlewareDecorator(
    $doublePassMiddleware,
    $response
));

RequestHandlerMiddleware

Zend\Stratigility\Middleware\RequestHandlerMiddleware allows you to decorate a PSR-15 RequestHandlerInterface for use as either a request handler or middleware. When either its handle() or process() method are called, it will proxy to the composed request handler's handle() method and return the response it produces.

This can be useful for piping a final handler to a pipeline.

// Where $handler is a RequestHandlerInterface:
$pipeline->pipe(new RequestHandlerMiddleware($handler));

ErrorHandler and NotFoundHandler

These two middleware allow you to provide handle PHP errors and exceptions, and 404 conditions, respectively. You may read more about them in the error handling chapter.

OriginalMessages

This callable middleware can be used as the outermost layer of middleware in order to set the original request and URI instances as request attributes for inner layers.

Utility Functions

Stratigility provides the following utility functions.

host

function Zend\Stratigility\host(
  string $host,
  Psr\Http\Server\MiddlewareInterface $middleware
) : Zend\Stratigility\Middleware\HostMiddlewareDecorator

host() provides a convenient way to perform host name segregation when piping your middleware.

$pipeline->pipe(host('example.com', $middleware));

path

function Zend\Stratigility\path(
    string $pathPrefix,
    Psr\Http\Server\MiddlewareInterface $middleware
) : Zend\Stratigility\Middleware\PathMiddlewareDecorator

path() provides a convenient way to perform path segregation when piping your middleware.

$pipeline->pipe(path('/foo', $middleware));

middleware

function Zend\Stratigility\middleware(
    callable $middleware
) : Zend\Stratigility\Middleware\CallableMiddlewareDecorator

middleware() provides a convenient way to decorate callable middleware that implements the PSR-15 middleware signature when piping it to your application.

$pipeline->pipe(middleware(function ($request, $handler) {
  // ...
});

doublePassMiddleware

function Zend\Stratigility\doublePassMiddleware(
    callable $middleware,
    Psr\Http\Message\ResponseInterface $responsePrototype = null
) : Zend\Stratigility\Middleware\DoublePassMiddlewareDecorator

doublePassMiddleware() provides a convenient way to decorate middleware that implements the double pass middleware signature when piping it to your application.

$pipeline->pipe(doublePassMiddleware(function ($request, $response, $next) {
  // ...
});

If you are not using zend-diactoros as a PSR-7 implementation, you will need to pass a response prototype as well:

$pipeline->pipe(doublePassMiddleware(function ($request, $response, $next) {
  // ...
}, $response);

Found a mistake or want to contribute to the documentation? Edit this page on GitHub!