|
| 1 | +# Dispatching PSR-7 Middleware |
| 2 | + |
| 3 | +[PSR-7](http://www.php-fig.org/psr/psr-7/) defines interfaces for HTTP messages, |
| 4 | +and is now being adopted by many frameworks; Zend Framework itself offers a |
| 5 | +parallel microframework targeting PSR-7 with [Expressive](https://zendframework.github.io/zend-expressive). |
| 6 | +What if you want to dispatch PSR-7 middleware from zend-mvc? |
| 7 | + |
| 8 | +zend-mvc currently uses [zend-http](https://github.com/zendframework/zend-http) |
| 9 | +for its HTTP transport layer, and the objects it defines are not compatible with |
| 10 | +PSR-7, meaning the basic MVC layer does not and cannot make use of PSR-7 |
| 11 | +currently. |
| 12 | + |
| 13 | +However, starting with version 2.7.0, zend-mvc offers |
| 14 | +`Zend\Mvc\MiddlewareListener`. This [dispatch](mvc-event.md#mvceventevent_dispatch-dispatch) |
| 15 | +listener listens prior to the default `DispatchListener`, and executes if the |
| 16 | +route matches contain a "middleware" parameter, and the service that resolves to |
| 17 | +is callable. When those conditions are met, it uses the [PSR-7 bridge](https://github.com/zendframework/zend-psr7bridge) |
| 18 | +to convert the zend-http request and response objects into PSR-7 instances, and |
| 19 | +then invokes the middleware. |
| 20 | + |
| 21 | +## Mapping routes to middleware |
| 22 | + |
| 23 | +The first step is to map a route to PSR-7 middleware. This looks like any other |
| 24 | +[routing](routing.md) configuration, with one small change: instead of providing |
| 25 | +a "controller" in the routing defaults, you provide "middleware": |
| 26 | + |
| 27 | +```php |
| 28 | +// Via configuration: |
| 29 | +return [ |
| 30 | + 'router' => |
| 31 | + 'routes' => [ |
| 32 | + 'home' => [ |
| 33 | + 'type' => 'literal', |
| 34 | + 'options' => [ |
| 35 | + 'route' => '/', |
| 36 | + 'defaults' => [ |
| 37 | + 'middleware' => 'Application\Middleware\IndexMiddleware', |
| 38 | + ], |
| 39 | + ], |
| 40 | + ], |
| 41 | + ], |
| 42 | + ], |
| 43 | +]; |
| 44 | + |
| 45 | +// Manually: |
| 46 | +$route = Literal::factory([ |
| 47 | + 'route' => '/', |
| 48 | + 'defaults' => [ |
| 49 | + 'middleware' => 'Application\Middleware\IndexMiddleware', |
| 50 | + ], |
| 51 | +]); |
| 52 | +``` |
| 53 | + |
| 54 | +Middleware may be provided as PHP callables, or as service names. |
| 55 | + |
| 56 | +> ### No action required |
| 57 | +> |
| 58 | +> Unlike action controllers, middleware typically is single purpose, and, as |
| 59 | +> such, does require a default `action` parameter. |
| 60 | +
|
| 61 | +## Middleware services |
| 62 | + |
| 63 | +In a normal zend-mvc dispatch cycle, controllers are pulled from a dedicated |
| 64 | +`ControllerManager`. Middleware, however, are pulled from the application |
| 65 | +service manager. |
| 66 | + |
| 67 | +Middleware retrieved *must* be PHP callables. The `MiddlewareListener` will |
| 68 | +create an error response if non-callable middleware is indicated. |
| 69 | + |
| 70 | +## Writing middleware |
| 71 | + |
| 72 | +When dispatching middleware, the `MiddlewareListener` calls it with two |
| 73 | +arguments, the PSR-7 request and response, respectively. As such, your |
| 74 | +middleware signature should look like the following: |
| 75 | + |
| 76 | +```php |
| 77 | +namespace Application\Middleware; |
| 78 | + |
| 79 | +use Psr\Http\Message\ResponseInterface; |
| 80 | +use Psr\Http\Message\ServerRequestInterface; |
| 81 | + |
| 82 | +class IndexMiddleware |
| 83 | +{ |
| 84 | + public function __invoke(ServerRequestInterface $request, ResponseInterface $response) |
| 85 | + { |
| 86 | + // do some work |
| 87 | + } |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +From there, you can pull information from the composed request, and manipulate |
| 92 | +the response. |
| 93 | + |
| 94 | +> ### Routing parameters |
| 95 | +> |
| 96 | +> At the time of the 2.7.0 release, route match parameters are not yet injected |
| 97 | +> into the PSR-7 `ServerRequest` instance, and are thus not available as request |
| 98 | +> attributes.. |
| 99 | +
|
| 100 | +## Middleware return values |
| 101 | + |
| 102 | +Ideally, your middleware should return a PSR-7 response. When it does, it is |
| 103 | +converted back to a zend-http response and returned by the `MiddlewareListener`, |
| 104 | +causing the application to short-circuit and return the response immediately. |
| 105 | + |
| 106 | +You can, however, return arbitrary values. If you do, the result is pushed into |
| 107 | +the `MvcEvent` as the event result, allowing later dispatch listeners to |
| 108 | +manipulate the results. |
0 commit comments