A Relay middleware callable must have the following signature:
A Relay middleware callable must return an implementation of Psr\Http\Message\ResponseInterface.
This signature makes Relay appropriate for both server-related and client-related use cases. That is, it can receive an incoming ServerRequestInterface and generate an outgoing ResponseInterface (acting as a server), or it can build an outgoing RequestInterface and return the resulting ResponseInterface (acting as a client).
N.b.: Psr\Http\Message\ServerRequestInterface extends RequestInterface, so typehinting to RequestInterface covers both use cases.
$queue array of middleware callables:
Use the RelayBuilder to create a Relay with the
$queue, and invoke the Relay with a request and response.
That will execute each of the middlewares in first-in-first-out order.
Your middleware logic should follow this pattern:
Receive the request and response objects from the previous middleware as parameters, along with the next middleware as a callable.
Optionally modify the received request and response as desired.
Optionally invoke the next middleware with the request and response, receiving a new response in return.
Optionally modify the returned response as desired.
Return the response to the previous middleware.
Here is a skeleton example; your own middleware may or may not perform the various optional processes:
N.b.: You MUST return the response from your middleware logic.
Remember that the request and response are immutable. Implicit in that is the fact that changes to the request are always transmitted to the
$next middleware but never to the previous one.
Note also that this logic chain means the request and response are subjected to two passes through each middleware:
first on the way “in” through each middleware via the
then on the way “out” from each middleware via the
returnto the previous middleware.
For example, if the middleware queue looks like this:
… the request and response path through the middlewares will look like this:
Foo is 1st on the way in Bar is 2nd on the way in Baz is 3rd on the way in, and 1st on the way out Bar is 2nd on the way out Foo is 3rd on the way out
You can use this dual-pass logic in clever and perhaps unintuitive ways. For example, middleware placed at the very start may do nothing with the request and call
$next right away, but it is the middleware with the “real” last opportunity to modify the response.
You may wish to use
$queue entries other than anonymous functions or already-instantiated objects. If so, you can pass a
$resolver callable to the Relay that will convert the
$queue entry to a callable. Thus, using a
$resolver allows you to pass in your own factory mechanism for
For example, this
$resolver will naively convert
$queue string entries to new class instances:
You can then add
$queue entries as class names, and the Relay will use the
$resolver to create the objects in turn.
As long as the classes listed in the
__invoke(Request $request, Response $response, callable $next), then the Relay will work correctly.
Sometimes using an array for the
$queue will not be suitable. You may wish to use an object to build the middleware queue instead.
In these cases, you can use the RelayBuilder to create the Relay queue from any object that extends ArrayObject or that implements Relay\GetArrayCopyInterface. The RelayBuilder will then get an array copy of that queue object for the Relay.
For example, first instantiate a RelayBuilder with an optional
… then instantiate a Relay where
$queue is an array, an ArrayObject, or a Relay\GetArrayCopyInterface implementation:
You can then use the
$relay as described above.
In Relay 1.1, the RelayBuilder will also accept any Traversable implementation, and convert it to an array using
iterator_to_array(). For backwards compatibility with Relay 1.0,
iterator_to_array() is only called on a Traversable that is not an ArrayObject and that does not implement Relay\GetArrayCopyInterface.
If you wish, you can reuse the same Relay object multiple times. The same middleware queue will be used each time you invoke that Relay. For example, if you are making multiple client requests:
If you are certain that you will never reuse the Relay instance, you can instantiate a single-use Runner to avoid some minor overhead.