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

Commit

Permalink
Merge branch 'feature/217' into develop
Browse files Browse the repository at this point in the history
Close #217
Fixes #196
  • Loading branch information
weierophinney committed May 1, 2017
2 parents 00bdd8c + 665dfbe commit 9935a57
Show file tree
Hide file tree
Showing 10 changed files with 522 additions and 24 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ All notable changes to this project will be documented in this file, in reverse

### Added

- Nothing.
- [#217](https://github.com/zendframework/zend-mvc/pull/217) adds support for
middleware _pipelines_ when using the `MiddlewareListener`. You can now
specify an _array` of middleware for the `middleware` attached to a route, and
it will be marshaled into a `Zend\Stratigility\MiddlewarePipe` instance, using
the same rules as if you specified a single middleware.

### Deprecated

Expand Down
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"phpunit/phpunit": "^6.0.7 || ^5.7.14",
"zendframework/zend-coding-standard": "~1.0.0",
"zendframework/zend-json": "^2.6.1 || ^3.0",
"zendframework/zend-psr7bridge": "^0.2"
"zendframework/zend-psr7bridge": "^0.2",
"zendframework/zend-stratigility": "^2.0.1"
},
"suggest": {
"zendframework/zend-json": "(^2.6.1 || ^3.0) To auto-deserialize JSON body content in AbstractRestfulController extensions, when json_decode is unavailable",
Expand All @@ -40,7 +41,8 @@
"zendframework/zend-mvc-plugin-prg": "To provide Post/Redirect/Get functionality within controllers",
"zendframework/zend-paginator": "^2.7 To provide pagination functionality via PaginatorPluginManager",
"zendframework/zend-psr7bridge": "(^0.2) To consume PSR-7 middleware within the MVC workflow",
"zendframework/zend-servicemanager-di": "zend-servicemanager-di provides utilities for integrating zend-di and zend-servicemanager in your zend-mvc application"
"zendframework/zend-servicemanager-di": "zend-servicemanager-di provides utilities for integrating zend-di and zend-servicemanager in your zend-mvc application",
"zendframework/zend-stratigility": "zend-stratigility is required to use middleware pipes in the MiddlewareListener"
},
"config": {
"sort-packages": true
Expand Down
108 changes: 107 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 55 additions & 7 deletions doc/book/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ $route = Literal::factory([

Middleware may be provided as PHP callables, or as service names.

**As of 3.1.0** you may also specify an `array` of middleware, and middleware
may be [http-interop/http-middleware](https://github.com/http-interop/http-middleware)
compatible. Each item in the array must be a PHP callable, service name, or
http-middleware instance. These will then be piped into a
`Zend\Stratigility\MiddlewarePipe` instance in the order in which they are
present in the array.

> ### No action required
>
> Unlike action controllers, middleware typically is single purpose, and, as
Expand All @@ -69,8 +76,8 @@ create an error response if non-callable middleware is indicated.

## Writing middleware

When dispatching middleware, the `MiddlewareListener` calls it with two
arguments, the PSR-7 request and response, respectively. As such, your
Prior to 3.1.0, when dispatching middleware, the `MiddlewareListener` calls it
with two arguments, the PSR-7 request and response, respectively. As such, your
middleware signature should look like the following:

```php
Expand All @@ -88,14 +95,55 @@ class IndexMiddleware
}
```

From there, you can pull information from the composed request, and manipulate
the response.
Starting in 3.1.0, the `MiddlewareListener` always adds middleware to a
`Zend\Stratigility\MiddlewarePipe` instance, and invokes it as
[http-interop/http-middleware](https://github.com/http-interop/http-middleware),
passing it a PSR-7 `ServerRequestInterface` and an http-interop
`DelegateInterface`.

As such, ideally your middleware should implement the `MiddlewareInterface` from
[http-interop/http-middleware](https://github.com/http-interop/http-middleware):

```php
namespace Application\Middleware;

use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;

class IndexMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, DelegateInterface $delegate)
{
// do some work
}
}
```

Alternately, you may still write `callable` middleware using the following
signature:

```php
function (ServerREquestInterface $request, ResponseInterface $response, callable $next)
{
// do some work
}
```

In the above case, the `DelegateInterface` is decorated as a callable.

In all versions, within your middleware, you can pull information from the
composed request, and return a response.

> ### Routing parameters
>
> At the time of the 2.7.0 release, route match parameters are not yet injected
> into the PSR-7 `ServerRequest` instance, and are thus not available as request
> attributes..
> At the time of the 2.7.0 release, route match parameters were not yet injected
> into the PSR-7 `ServerRequest` instance, and thus not available as request
> attributes.
>
> With the 3.0 release, they are pushed into the PSR-7 `ServerRequest` as
> attributes, and may thus be fetched using
> `$request->getAttribute($attributeName)`.
## Middleware return values

Expand Down
44 changes: 44 additions & 0 deletions src/Exception/InvalidMiddlewareException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Zend\Mvc\Exception;

final class InvalidMiddlewareException extends RuntimeException
{
/**
* @var string
*/
private $middlewareName;

/**
* @param string $middlewareName
* @return self
*/
public static function fromMiddlewareName($middlewareName)
{
$middlewareName = (string)$middlewareName;
$instance = new self(sprintf('Cannot dispatch middleware %s', $middlewareName));
$instance->middlewareName = $middlewareName;
return $instance;
}

public static function fromNull()
{
$instance = new self('Middleware name cannot be null');
return $instance;
}

/**
* @return string
*/
public function toMiddlewareName()
{
return null !== $this->middlewareName ? $this->middlewareName : '';
}
}
21 changes: 21 additions & 0 deletions src/Exception/ReachedFinalHandlerException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Zend\Mvc\Exception;

class ReachedFinalHandlerException extends RuntimeException
{
/**
* @return self
*/
public static function create()
{
return new self('Reached the final handler for middleware pipe - check the pipe configuration');
}
}
Loading

0 comments on commit 9935a57

Please sign in to comment.