Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 47fcb19

Browse files
committed
Document middleware listener
1 parent 3a8a322 commit 47fcb19

File tree

6 files changed

+130
-7
lines changed

6 files changed

+130
-7
lines changed

doc/book/intro.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ Once you've done this, there are two additional actions you can take. The first
244244
the application. In the default implementation, this does the following:
245245

246246
- Attaches the default route listener (`Zend\Mvc\RouteListener`).
247+
- Attaches the middleware dispatch listener (`Zend\Mvc\MiddlewareListener`)
248+
(v2.7.0 and up).
247249
- Attaches the default dispatch listener (`Zend\Mvc\DispatchListener`).
248250
- Attaches the `ViewManager` listener (`Zend\Mvc\View\ViewManager`).
249251
- Creates the `MvcEvent`, and injects it with the application, request, and

doc/book/middleware.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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.

doc/book/migration.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
## Upgrading to 2.7
44

5+
### Middleware
6+
7+
zend-mvc now registers `Zend\Mvc\MiddlewareListener` as a dispatch listener at
8+
a priority higher than `Zend\Mvc\DispatchListener`, allowing dispatch of
9+
[PSR-7](http://www.php-fig.org/psr/psr-7/) middleware. Read the
10+
[middleware chapter](middleware.md) for details on how to use this new feature.
11+
512
### Application
613

714
The constructor signature of `Zend\Mvc\Application` has changed. Previously, it

doc/book/mvc-event.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,13 @@ Class | Priority | Method Called
138138

139139
#### All contexts
140140

141-
The following listeners are attached for all contexts:
141+
The following listeners are attached for all contexts (sorted from higher
142+
priority to lower priority):
142143

143144
Class | Priority | Method Called | Triggers | Description
144145
------------------------------|---------:|---------------|----------|------------
145-
`Zend\Mvc\DispatchListener` | 1 | `onDispatch` | `MvcEvent::EVENT_DISPATCH_ERROR` (if an exception is raised during dispatch processes) | Try to load the matched controller from the service manager (and throws various exceptions if it does not).
146+
`Zend\Mvc\MiddlewareListener` | 1 | `onDispatch` | `MvcEvent::EVENT_DISPATCH_ERROR` (if an exception is raised during dispatch processes) | Load and dispatch the matched PSR-7 middleware from the service manager (and throws various exceptions if it does not).
147+
`Zend\Mvc\DispatchListener` | 1 | `onDispatch` | `MvcEvent::EVENT_DISPATCH_ERROR` (if an exception is raised during dispatch processes) | Load and dispatch the matched controller from the service manager (and throws various exceptions if it does not).
146148
`Zend\Mvc\AbstractController` | 1 | `onDispatch` | none | The `onDispatch` method of the `AbstractController` is an abstract method. In `AbstractActionController`, for instance, it calls the action method.
147149

148150
### Triggered By
@@ -192,11 +194,12 @@ Class | Priority | Method Called | Description
192194

193195
### Triggered By
194196

195-
Class | In Method
196-
----------------------------|----------
197-
`Zend\Mvc\DispatchListener` | `onDispatch`
198-
`Zend\Mvc\DispatchListener` | `marshallControllerNotFoundEvent`
199-
`Zend\Mvc\DispatchListener` | `marshallBadControllerEvent`
197+
Class | In Method
198+
------------------------------|----------
199+
`Zend\Mvc\MiddlewareListener` | `onDispatch`
200+
`Zend\Mvc\DispatchListener` | `onDispatch`
201+
`Zend\Mvc\DispatchListener` | `marshallControllerNotFoundEvent`
202+
`Zend\Mvc\DispatchListener` | `marshallBadControllerEvent`
200203

201204
## `MvcEvent::EVENT_RENDER` ("render")
202205

doc/book/services.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ services configured out of the box.
7777
### Invokable services
7878

7979
- `DispatchListener`, mapping to `Zend\Mvc\DispatchListener`.
80+
- `Zend\Mvc\MiddlewareListener`.
8081
- `RouteListener`, mapping to `Zend\Mvc\RouteListener`.
8182
- `SendResponseListener`, mapping to `Zend\Mvc\SendResponseListener`.
8283
- `SharedEventManager`, mapping to `Zend\EventManager\SharedEventManager`.
@@ -314,6 +315,7 @@ services configured out of the box.
314315
- `Configuration`, mapping to the `Config` service.
315316
- `Console`, mapping to the `ConsoleAdapter` service.
316317
- `Di`, mapping to the `DependencyInjector` service.
318+
- `MiddlewareListener`, mapping to the `Zend\Mvc\MiddlewareListener` service.
317319
- `Zend\Di\LocatorInterface`, mapping to the `DependencyInjector` service.
318320
- `Zend\EventManager\EventManagerInterface`, mapping to the `EventManager`
319321
service. This is mainly to ensure that when falling through to DI, classes

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pages:
1212
- 'Available Controllers': controllers.md
1313
- 'Controller Plugins': plugins.md
1414
- Examples: examples.md
15+
- 'Dispatching PSR-7 Middleware': middleware.md
1516
- 'Migration Guide': migration.md
1617
site_name: zend-mvc
1718
site_description: 'zend-mvc: MVC application provider'

0 commit comments

Comments
 (0)