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

Commit bf741df

Browse files
committed
Merge pull request #217 from asgrim/modify-middleware-listener-to-use-stratigility-pipe
Modify middleware listener to use stratigility pipe
2 parents 00bdd8c + 4dbdb4b commit bf741df

8 files changed

+443
-13
lines changed

composer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"phpunit/phpunit": "^6.0.7 || ^5.7.14",
2828
"zendframework/zend-coding-standard": "~1.0.0",
2929
"zendframework/zend-json": "^2.6.1 || ^3.0",
30-
"zendframework/zend-psr7bridge": "^0.2"
30+
"zendframework/zend-psr7bridge": "^0.2",
31+
"zendframework/zend-stratigility": "^2.0.1"
3132
},
3233
"suggest": {
3334
"zendframework/zend-json": "(^2.6.1 || ^3.0) To auto-deserialize JSON body content in AbstractRestfulController extensions, when json_decode is unavailable",
@@ -40,7 +41,8 @@
4041
"zendframework/zend-mvc-plugin-prg": "To provide Post/Redirect/Get functionality within controllers",
4142
"zendframework/zend-paginator": "^2.7 To provide pagination functionality via PaginatorPluginManager",
4243
"zendframework/zend-psr7bridge": "(^0.2) To consume PSR-7 middleware within the MVC workflow",
43-
"zendframework/zend-servicemanager-di": "zend-servicemanager-di provides utilities for integrating zend-di and zend-servicemanager in your zend-mvc application"
44+
"zendframework/zend-servicemanager-di": "zend-servicemanager-di provides utilities for integrating zend-di and zend-servicemanager in your zend-mvc application",
45+
"zendframework/zend-stratigility": "zend-stratigility is required to use middleware pipes in the MiddlewareListener"
4446
},
4547
"config": {
4648
"sort-packages": true

composer.lock

Lines changed: 107 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @link http://github.com/zendframework/zf2 for the canonical source repository
6+
* @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license http://framework.zend.com/license/new-bsd New BSD License
8+
*/
9+
10+
namespace Zend\Mvc\Exception;
11+
12+
final class MiddlewareNotCallableException extends RuntimeException
13+
{
14+
/**
15+
* @var string
16+
*/
17+
private $middlewareName;
18+
19+
/**
20+
* @param string $middlewareName
21+
* @return self
22+
*/
23+
public static function fromMiddlewareName($middlewareName)
24+
{
25+
$middlewareName = (string)$middlewareName;
26+
$instance = new self(sprintf('Cannot dispatch middleware %s', $middlewareName));
27+
$instance->middlewareName = $middlewareName;
28+
return $instance;
29+
}
30+
31+
/**
32+
* @return string
33+
*/
34+
public function toMiddlewareName()
35+
{
36+
return null !== $this->middlewareName ? $this->middlewareName : '';
37+
}
38+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @link http://github.com/zendframework/zf2 for the canonical source repository
6+
* @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license http://framework.zend.com/license/new-bsd New BSD License
8+
*/
9+
10+
namespace Zend\Mvc\Exception;
11+
12+
class ReachedFinalHandlerException extends RuntimeException
13+
{
14+
/**
15+
* @return self
16+
*/
17+
public static function create()
18+
{
19+
return new self('Reached the final handler for middleware pipe - check the pipe configuration');
20+
}
21+
}

src/MiddlewareListener.php

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,19 @@
99

1010
namespace Zend\Mvc;
1111

12+
use Interop\Container\ContainerInterface;
13+
use Interop\Http\ServerMiddleware\MiddlewareInterface;
1214
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
15+
use Psr\Http\Message\ResponseInterface;
16+
use Psr\Http\Message\ServerRequestInterface as PsrServerRequestInterface;
1317
use Zend\EventManager\AbstractListenerAggregate;
1418
use Zend\EventManager\EventManagerInterface;
19+
use Zend\Mvc\Exception\MiddlewareNotCallableException;
20+
use Zend\Mvc\Exception\ReachedFinalHandlerException;
1521
use Zend\Psr7Bridge\Psr7ServerRequest as Psr7Request;
1622
use Zend\Psr7Bridge\Psr7Response;
1723
use Zend\Router\RouteMatch;
24+
use Zend\Stratigility\MiddlewarePipe;
1825

1926
class MiddlewareListener extends AbstractListenerAggregate
2027
{
@@ -47,15 +54,19 @@ public function onDispatch(MvcEvent $event)
4754
$application = $event->getApplication();
4855
$response = $application->getResponse();
4956
$serviceManager = $application->getServiceManager();
50-
$middlewareName = is_string($middleware) ? $middleware : get_class($middleware);
5157

52-
if (is_string($middleware) && $serviceManager->has($middleware)) {
53-
$middleware = $serviceManager->get($middleware);
54-
}
55-
if (! is_callable($middleware)) {
58+
$psr7ResponsePrototype = Psr7Response::fromZend($response);
59+
60+
try {
61+
$pipe = $this->createPipeFromSpec(
62+
$serviceManager,
63+
$psr7ResponsePrototype,
64+
is_array($middleware) ? $middleware : [$middleware]
65+
);
66+
} catch (MiddlewareNotCallableException $middlewareNotCallableException) {
5667
$return = $this->marshalMiddlewareNotCallable(
5768
$application::ERROR_MIDDLEWARE_CANNOT_DISPATCH,
58-
$middlewareName,
69+
$middlewareNotCallableException->toMiddlewareName(),
5970
$event,
6071
$application
6172
);
@@ -69,7 +80,13 @@ public function onDispatch(MvcEvent $event)
6980
foreach ($routeMatch->getParams() as $key => $value) {
7081
$psr7Request = $psr7Request->withAttribute($key, $value);
7182
}
72-
$return = $middleware($psr7Request, Psr7Response::fromZend($response));
83+
$return = $pipe(
84+
$psr7Request,
85+
$psr7ResponsePrototype,
86+
function (PsrServerRequestInterface $request, PsrResponseInterface $response) {
87+
throw ReachedFinalHandlerException::create();
88+
}
89+
);
7390
} catch (\Throwable $ex) {
7491
$caughtException = $ex;
7592
} catch (\Exception $ex) { // @TODO clean up once PHP 7 requirement is enforced
@@ -79,8 +96,6 @@ public function onDispatch(MvcEvent $event)
7996
if ($caughtException !== null) {
8097
$event->setName(MvcEvent::EVENT_DISPATCH_ERROR);
8198
$event->setError($application::ERROR_EXCEPTION);
82-
$event->setController($middlewareName);
83-
$event->setControllerClass(get_class($middleware));
8499
$event->setParam('exception', $caughtException);
85100

86101
$events = $application->getEventManager();
@@ -100,6 +115,42 @@ public function onDispatch(MvcEvent $event)
100115
return $response;
101116
}
102117

118+
/**
119+
* Create a middleware pipe from the array spec given.
120+
*
121+
* @param ContainerInterface $serviceLocator
122+
* @param ResponseInterface $responsePrototype
123+
* @param array $middlewaresToBePiped
124+
* @return MiddlewarePipe
125+
* @throws \InvalidArgumentException
126+
* @throws \Zend\Mvc\Exception\MiddlewareNotCallableException
127+
*/
128+
private function createPipeFromSpec(
129+
ContainerInterface $serviceLocator,
130+
ResponseInterface $responsePrototype,
131+
array $middlewaresToBePiped
132+
) {
133+
$pipe = new MiddlewarePipe();
134+
$pipe->setResponsePrototype($responsePrototype);
135+
foreach ($middlewaresToBePiped as $middlewareToBePiped) {
136+
if (null === $middlewareToBePiped) {
137+
throw new \InvalidArgumentException('Middleware name cannot be null');
138+
}
139+
140+
$middlewareName = is_string($middlewareToBePiped) ? $middlewareToBePiped : get_class($middlewareToBePiped);
141+
142+
if (is_string($middlewareToBePiped) && $serviceLocator->has($middlewareToBePiped)) {
143+
$middlewareToBePiped = $serviceLocator->get($middlewareToBePiped);
144+
}
145+
if (! $middlewareToBePiped instanceof MiddlewareInterface && ! is_callable($middlewareToBePiped)) {
146+
throw MiddlewareNotCallableException::fromMiddlewareName($middlewareName);
147+
}
148+
149+
$pipe->pipe($middlewareToBePiped);
150+
}
151+
return $pipe;
152+
}
153+
103154
/**
104155
* Marshal a middleware not callable exception event
105156
*
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @link http://github.com/zendframework/zf2 for the canonical source repository
6+
* @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license http://framework.zend.com/license/new-bsd New BSD License
8+
*/
9+
10+
namespace ZendTest\Mvc;
11+
12+
use PHPUnit\Framework\TestCase;
13+
use Zend\Mvc\Exception\MiddlewareNotCallableException;
14+
15+
final class MiddlewareNotCallableExceptionTest extends TestCase
16+
{
17+
public function testFromMiddlewareName()
18+
{
19+
$middlewareName = uniqid('middlewareName', true);
20+
$exception = MiddlewareNotCallableException::fromMiddlewareName($middlewareName);
21+
22+
$this->assertInstanceOf(MiddlewareNotCallableException::class, $exception);
23+
$this->assertSame('Cannot dispatch middleware ' . $middlewareName, $exception->getMessage());
24+
$this->assertSame($middlewareName, $exception->toMiddlewareName());
25+
}
26+
27+
public function testToMiddlewareNameWhenNotSet()
28+
{
29+
$exception = new MiddlewareNotCallableException();
30+
$this->assertSame('', $exception->toMiddlewareName());
31+
}
32+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* Zend Framework (http://framework.zend.com/)
4+
*
5+
* @link http://github.com/zendframework/zf2 for the canonical source repository
6+
* @copyright Copyright (c) 2005-2017 Zend Technologies USA Inc. (http://www.zend.com)
7+
* @license http://framework.zend.com/license/new-bsd New BSD License
8+
*/
9+
10+
namespace ZendTest\Mvc;
11+
12+
use PHPUnit\Framework\TestCase;
13+
use Zend\Mvc\Exception\ReachedFinalHandlerException;
14+
15+
final class ReachedFinalHandlerExceptionTest extends TestCase
16+
{
17+
public function testFromNothing()
18+
{
19+
$exception = ReachedFinalHandlerException::create();
20+
21+
$this->assertInstanceOf(ReachedFinalHandlerException::class, $exception);
22+
$this->assertSame(
23+
'Reached the final handler for middleware pipe - check the pipe configuration',
24+
$exception->getMessage()
25+
);
26+
}
27+
}

0 commit comments

Comments
 (0)