diff --git a/CHANGELOG.md b/CHANGELOG.md index 049c5df5..af60b4b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 2.0.2 - TBD +## 2.0.2 - 2017-03-13 ### Added @@ -18,7 +18,12 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed -- Nothing. +- [#467](https://github.com/zendframework/zend-expressive/pull/467) fixes an + issue when passing invokable, duck-typed, interop middleware to the + application without registering it with the container. Prior to the patch, it + was incorrectly being decorated by + `Zend\Stratigility\Middleware\CallableMiddlewareWrapper` instead of + `Zend\Stratigility\Middleware\CallableInteropMiddlewareWrapper`. ## 2.0.1 - 2017-03-09 diff --git a/src/MarshalMiddlewareTrait.php b/src/MarshalMiddlewareTrait.php index 85b816b9..1b7ba9f1 100644 --- a/src/MarshalMiddlewareTrait.php +++ b/src/MarshalMiddlewareTrait.php @@ -148,6 +148,10 @@ private function marshalInvokableMiddleware($middleware, ResponseInterface $resp return $instance; } + if ($this->isCallableInteropMiddleware($instance)) { + return new CallableInteropMiddlewareWrapper($instance); + } + if (! is_callable($instance)) { throw new Exception\InvalidMiddlewareException(sprintf( 'Middleware of class "%s" is invalid; neither invokable nor %s', diff --git a/test/Application/MarshalMiddlewareTraitTest.php b/test/Application/MarshalMiddlewareTraitTest.php index 1049f7d5..bdc6febe 100644 --- a/test/Application/MarshalMiddlewareTraitTest.php +++ b/test/Application/MarshalMiddlewareTraitTest.php @@ -256,7 +256,7 @@ public function testPreparingInvokableInteropMiddlewareReturnsDecoratedInteropMi $middleware = $this->prepareMiddleware($base); - $this->assertInstanceOf(CallableMiddlewareWrapper::class, $middleware); + $this->assertInstanceOf(CallableInteropMiddlewareWrapper::class, $middleware); $this->assertAttributeInstanceOf(TestAsset\CallableInteropMiddleware::class, 'middleware', $middleware); } diff --git a/test/IntegrationTest.php b/test/IntegrationTest.php index 5f72f6ff..89e44d18 100644 --- a/test/IntegrationTest.php +++ b/test/IntegrationTest.php @@ -8,8 +8,12 @@ namespace ZendTest\Expressive; use Fig\Http\Message\StatusCodeInterface as StatusCode; +use Interop\Http\ServerMiddleware\DelegateInterface; +use Interop\Http\ServerMiddleware\MiddlewareInterface; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; use Zend\Diactoros\Response\EmitterInterface; @@ -76,4 +80,37 @@ public function testInjectedFinalHandlerCanEmitA404WhenNoMiddlewareMatches() $this->assertInstanceOf(ResponseInterface::class, $this->response); $this->assertEquals(StatusCode::STATUS_NOT_FOUND, $this->response->getStatusCode()); } + + public function testCallableClassInteropMiddlewareNotRegisteredWithContainerCanBeComposedSuccessfully() + { + $response = new Response(); + $routedMiddleware = $this->prophesize(MiddlewareInterface::class); + $routedMiddleware + ->process( + Argument::type(ServerRequestInterface::class), + Argument::type(DelegateInterface::class) + ) + ->willReturn($response); + + $container = $this->prophesize(ContainerInterface::class); + $container->has('RoutedMiddleware')->willReturn(true); + $container->get('RoutedMiddleware')->will([$routedMiddleware, 'reveal']); + $container->has(TestAsset\CallableInteropMiddleware::class)->willReturn(false); + + $delegate = new NotFoundDelegate($response); + $app = new Application(new FastRouteRouter(), $container->reveal(), $delegate, $this->getEmitter()); + + $app->pipe(TestAsset\CallableInteropMiddleware::class); + $app->get('/', 'RoutedMiddleware'); + + $request = new ServerRequest([], [], 'https://example.com/foo', 'GET'); + $app->run($request, new Response()); + + $this->assertInstanceOf(ResponseInterface::class, $this->response); + $this->assertTrue($this->response->hasHeader('X-Callable-Interop-Middleware')); + $this->assertEquals( + TestAsset\CallableInteropMiddleware::class, + $this->response->getHeaderLine('X-Callable-Interop-Middleware') + ); + } } diff --git a/test/TestAsset/CallableInteropMiddleware.php b/test/TestAsset/CallableInteropMiddleware.php new file mode 100644 index 00000000..0fd5c824 --- /dev/null +++ b/test/TestAsset/CallableInteropMiddleware.php @@ -0,0 +1,20 @@ +process($request); + return $response->withHeader('X-Callable-Interop-Middleware', __CLASS__); + } +}