From e5e27a1afd73124d7a63d1616a801af09f17642c Mon Sep 17 00:00:00 2001 From: webimpress Date: Thu, 22 Feb 2018 18:19:42 +0000 Subject: [PATCH 1/5] Use response facttories in ErrorHandler and NotFoundHandler --- composer.json | 2 +- composer.lock | 52 ++++++++++++++++++++++++- src/Middleware/ErrorHandler.php | 17 ++++---- src/Middleware/NotFoundHandler.php | 18 +++++---- test/Middleware/ErrorHandlerTest.php | 14 ++++++- test/Middleware/NotFoundHandlerTest.php | 6 ++- 6 files changed, 89 insertions(+), 20 deletions(-) diff --git a/composer.json b/composer.json index 791624c..e4d502f 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ }, "require": { "php": "^7.1", - "psr/http-message": "^1.0", + "fig/http-message-util": "^1.1.2", "psr/http-server-middleware": "^1.0", "zendframework/zend-escaper": "^2.3" }, diff --git a/composer.lock b/composer.lock index b816500..da31d45 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,58 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "c8add8be84844b01406c95b4715c929a", + "content-hash": "ed87a4f3b618587a1560f36ff9bb3829", "packages": [ + { + "name": "fig/http-message-util", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "20b2c280cb6914b7b83089720df44e490f4b42f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/20b2c280cb6914b7b83089720df44e490f4b42f0", + "reference": "20b2c280cb6914b7b83089720df44e490f4b42f0", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2017-02-09T16:10:21+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", diff --git a/src/Middleware/ErrorHandler.php b/src/Middleware/ErrorHandler.php index bd14ac2..1f0b221 100644 --- a/src/Middleware/ErrorHandler.php +++ b/src/Middleware/ErrorHandler.php @@ -75,19 +75,22 @@ final class ErrorHandler implements MiddlewareInterface private $responseGenerator; /** - * @var ResponseInterface + * @var callable */ - private $responsePrototype; + private $responseFactory; /** - * @param ResponseInterface $responsePrototype Empty/prototype response to - * update and return when returning an error response. + * @param callable $responseFactory A factory capable of returning an + * empty ResponseInterface instance to update and return when returning + * an error response. * @param null|callable $responseGenerator Callback that will generate the final * error response; if none is provided, ErrorResponseGenerator is used. */ - public function __construct(ResponseInterface $responsePrototype, callable $responseGenerator = null) + public function __construct(callable $responseFactory, callable $responseGenerator = null) { - $this->responsePrototype = $responsePrototype; + $this->responseFactory = function () use ($responseFactory) { + return $responseFactory(); + }; $this->responseGenerator = $responseGenerator ?: new ErrorResponseGenerator(); } @@ -155,7 +158,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface private function handleThrowable(Throwable $e, ServerRequestInterface $request) : ResponseInterface { $generator = $this->responseGenerator; - $response = $generator($e, $request, $this->responsePrototype); + $response = $generator($e, $request, ($this->responseFactory)()); $this->triggerListeners($e, $request, $response); return $response; } diff --git a/src/Middleware/NotFoundHandler.php b/src/Middleware/NotFoundHandler.php index 53c892e..916e725 100644 --- a/src/Middleware/NotFoundHandler.php +++ b/src/Middleware/NotFoundHandler.php @@ -8,6 +8,7 @@ namespace Zend\Stratigility\Middleware; +use Fig\Http\Message\StatusCodeInterface as StatusCode; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; @@ -16,17 +17,18 @@ class NotFoundHandler implements MiddlewareInterface { /** - * @var ResponseInterface + * @var callable */ - private $responsePrototype; + private $responseFactory; /** - * @param ResponseInterface $responsePrototype Empty/prototype response to - * update and return when returning an 404 response. + * @param callable $responseFactory A factory capable of returning an + * empty ResponseInterface instance to update and return when returning + * an 404 response. */ - public function __construct(ResponseInterface $responsePrototype) + public function __construct(callable $responseFactory) { - $this->responsePrototype = $responsePrototype; + $this->responseFactory = $responseFactory; } /** @@ -34,8 +36,8 @@ public function __construct(ResponseInterface $responsePrototype) */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface { - $response = $this->responsePrototype - ->withStatus(404); + $response = ($this->responseFactory)() + ->withStatus(StatusCode::STATUS_NOT_FOUND); $response->getBody()->write(sprintf( 'Cannot %s %s', $request->getMethod(), diff --git a/test/Middleware/ErrorHandlerTest.php b/test/Middleware/ErrorHandlerTest.php index b2733f5..ba10f30 100644 --- a/test/Middleware/ErrorHandlerTest.php +++ b/test/Middleware/ErrorHandlerTest.php @@ -10,6 +10,7 @@ use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Prophecy\Prophecy\ObjectProphecy; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; @@ -21,9 +22,18 @@ class ErrorHandlerTest extends TestCase { + /** @var ResponseInterface|ObjectProphecy */ + private $response; + + /** @var callable */ + private $responseFactory; + public function setUp() { $this->response = $this->prophesize(ResponseInterface::class); + $this->responseFactory = function () { + return $this->response->reveal(); + }; $this->request = $this->prophesize(ServerRequestInterface::class); $this->body = $this->prophesize(StreamInterface::class); $this->handler = $this->prophesize(RequestHandlerInterface::class); @@ -38,7 +48,7 @@ public function tearDown() public function createMiddleware($isDevelopmentMode = false) { $generator = new ErrorResponseGenerator($isDevelopmentMode); - return new ErrorHandler($this->response->reveal(), $generator); + return new ErrorHandler($this->responseFactory, $generator); } public function testReturnsResponseFromHandlerWhenNoProblemsOccur() @@ -203,7 +213,7 @@ public function testCanProvideAlternateErrorResponseGenerator() $this->response->getBody()->will([$this->body, 'reveal']); $this->body->write('The client messed up')->shouldBeCalled(); - $middleware = new ErrorHandler($this->response->reveal(), $generator); + $middleware = new ErrorHandler($this->responseFactory, $generator); $result = $middleware->process($this->request->reveal(), $this->handler->reveal()); $this->assertSame($this->response->reveal(), $result); diff --git a/test/Middleware/NotFoundHandlerTest.php b/test/Middleware/NotFoundHandlerTest.php index cd4c286..d1f5b87 100644 --- a/test/Middleware/NotFoundHandlerTest.php +++ b/test/Middleware/NotFoundHandlerTest.php @@ -30,7 +30,11 @@ public function testReturnsResponseWith404StatusAndErrorMessageInBody() $request->getMethod()->willReturn('POST'); $request->getUri()->willReturn('https://example.com/foo'); - $middleware = new NotFoundHandler($response->reveal()); + $responseFactory = function () use ($response) { + return $response->reveal(); + }; + + $middleware = new NotFoundHandler($responseFactory); $this->assertSame( $response->reveal(), From d670b89fdd564798dbf5235fe32e83d5d322a79c Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Thu, 22 Feb 2018 13:44:28 -0600 Subject: [PATCH 2/5] Reverts (most) changes to composer.json Reinstates the `psr/http-message` requirement, as this is a direct dependency. Modifies the `fig/http-message-util` requirement to be `^1.1`, as that is the release that adds the `StatusCodeInterface`; we don't use any specifics from the later releases to make pinning to a later version necessary. --- composer.json | 3 +- composer.lock | 80 +++++++++++++++++++++++++-------------------------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/composer.json b/composer.json index e4d502f..c0c95b2 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ }, "require": { "php": "^7.1", - "fig/http-message-util": "^1.1.2", + "fig/http-message-util": "^1.1", + "psr/http-message": "^1.0", "psr/http-server-middleware": "^1.0", "zendframework/zend-escaper": "^2.3" }, diff --git a/composer.lock b/composer.lock index da31d45..81fafc7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "ed87a4f3b618587a1560f36ff9bb3829", + "content-hash": "ade7df0f0b1cbce17814977372076a6c", "packages": [ { "name": "fig/http-message-util", @@ -566,16 +566,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.2.0", + "version": "4.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "66465776cfc249844bde6d117abff1d22e06c2da" + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/66465776cfc249844bde6d117abff1d22e06c2da", - "reference": "66465776cfc249844bde6d117abff1d22e06c2da", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", "shasum": "" }, "require": { @@ -613,7 +613,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-27T17:38:31+00:00" + "time": "2017-11-30T07:14:17+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -664,16 +664,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.3", + "version": "1.7.5", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf" + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", - "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", "shasum": "" }, "require": { @@ -685,7 +685,7 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" }, "type": "library", "extra": { @@ -723,7 +723,7 @@ "spy", "stub" ], - "time": "2017-11-24T13:59:53+00:00" + "time": "2018-02-19T10:16:54+00:00" }, { "name": "phpunit/php-code-coverage", @@ -976,16 +976,16 @@ }, { "name": "phpunit/phpunit", - "version": "6.5.5", + "version": "6.5.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "83d27937a310f2984fd575686138597147bdc7df" + "reference": "3330ef26ade05359d006041316ed0fa9e8e3cefe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/83d27937a310f2984fd575686138597147bdc7df", - "reference": "83d27937a310f2984fd575686138597147bdc7df", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3330ef26ade05359d006041316ed0fa9e8e3cefe", + "reference": "3330ef26ade05359d006041316ed0fa9e8e3cefe", "shasum": "" }, "require": { @@ -1056,7 +1056,7 @@ "testing", "xunit" ], - "time": "2017-12-17T06:31:19+00:00" + "time": "2018-02-01T05:57:37+00:00" }, { "name": "phpunit/phpunit-mock-objects", @@ -1164,21 +1164,21 @@ }, { "name": "sebastian/comparator", - "version": "2.1.2", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "11c07feade1d65453e06df3b3b90171d6d982087" + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/11c07feade1d65453e06df3b3b90171d6d982087", - "reference": "11c07feade1d65453e06df3b3b90171d6d982087", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", "shasum": "" }, "require": { "php": "^7.0", - "sebastian/diff": "^2.0", + "sebastian/diff": "^2.0 || ^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { @@ -1224,7 +1224,7 @@ "compare", "equality" ], - "time": "2018-01-12T06:34:42+00:00" + "time": "2018-02-01T13:46:46+00:00" }, { "name": "sebastian/diff", @@ -1756,16 +1756,16 @@ }, { "name": "symfony/console", - "version": "v4.0.3", + "version": "v4.0.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "fe0e69d7162cba0885791cf7eea5f0d7bc0f897e" + "reference": "36d5b41e7d4e1ccf0370f6babe966c08ef0a1488" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/fe0e69d7162cba0885791cf7eea5f0d7bc0f897e", - "reference": "fe0e69d7162cba0885791cf7eea5f0d7bc0f897e", + "url": "https://api.github.com/repos/symfony/console/zipball/36d5b41e7d4e1ccf0370f6babe966c08ef0a1488", + "reference": "36d5b41e7d4e1ccf0370f6babe966c08ef0a1488", "shasum": "" }, "require": { @@ -1820,11 +1820,11 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-01-03T07:38:00+00:00" + "time": "2018-01-29T09:06:29+00:00" }, { "name": "symfony/finder", - "version": "v4.0.3", + "version": "v4.0.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -1873,16 +1873,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", - "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", "shasum": "" }, "require": { @@ -1894,7 +1894,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -1928,7 +1928,7 @@ "portable", "shim" ], - "time": "2017-10-11T12:05:26+00:00" + "time": "2018-01-30T19:27:44+00:00" }, { "name": "theseer/tokenizer", @@ -1972,16 +1972,16 @@ }, { "name": "webmozart/assert", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", "shasum": "" }, "require": { @@ -2018,7 +2018,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2018-01-29T19:49:41+00:00" }, { "name": "zendframework/zend-coding-standard", From ab157506af87e04e4085594142f30ce5ba3ff36b Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Thu, 22 Feb 2018 13:48:27 -0600 Subject: [PATCH 3/5] Ensure return type safety of response factories Updates the `$responseFactory` property of the `ErrorHandler` to add a return type hint, ensuring return type safety of the composed callable. Wraps the `$responseFactory` property of the `NotFoundHandler` in a callable, to ensure return type safety of the composed callable. --- src/Middleware/ErrorHandler.php | 2 +- src/Middleware/NotFoundHandler.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Middleware/ErrorHandler.php b/src/Middleware/ErrorHandler.php index 1f0b221..035340a 100644 --- a/src/Middleware/ErrorHandler.php +++ b/src/Middleware/ErrorHandler.php @@ -88,7 +88,7 @@ final class ErrorHandler implements MiddlewareInterface */ public function __construct(callable $responseFactory, callable $responseGenerator = null) { - $this->responseFactory = function () use ($responseFactory) { + $this->responseFactory = function () use ($responseFactory) : ResponseInterface { return $responseFactory(); }; $this->responseGenerator = $responseGenerator ?: new ErrorResponseGenerator(); diff --git a/src/Middleware/NotFoundHandler.php b/src/Middleware/NotFoundHandler.php index 916e725..fd0e05e 100644 --- a/src/Middleware/NotFoundHandler.php +++ b/src/Middleware/NotFoundHandler.php @@ -28,7 +28,9 @@ class NotFoundHandler implements MiddlewareInterface */ public function __construct(callable $responseFactory) { - $this->responseFactory = $responseFactory; + $this->responseFactory = function () use ($responseFactory) : ResponseInterface { + return $responseFactory(); + }; } /** From 3f5be7feb3de3cda8da10f47fee9af08f7a57417 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Thu, 22 Feb 2018 14:01:20 -0600 Subject: [PATCH 4/5] Adds section to migration document on constructor changes --- docs/book/v3/migration.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/book/v3/migration.md b/docs/book/v3/migration.md index d513529..2e6b6ae 100644 --- a/docs/book/v3/migration.md +++ b/docs/book/v3/migration.md @@ -89,6 +89,15 @@ internal logic. `Psr\Http\Server\RequestHandlerInterface`, and provides a return typehint of `Psr\Http\Message\ResponseInterface`. +- `ErrorHandler::__construct()` and `NotFoundHandler::__construct()`: the first + parameter of each constructor now expects a PHP `callable` capable of + returning a PSR-7 `ResponseInterface` instance (instead of typehinting + directly against `ResponseInterface`). This paves the way for usage with the + upcoming PSR-17 (HTTP Message Factories) specification, and simplifies re-use + of a dependency injection container service (as otherwise you would need to + specify a discrete service per class that expects a response prototype, due to + mutability of the response body). + ### Class additions - `Zend\Stratigility\MiddlewarePipeInterface` extends From df4c8a00c879a4f3ff750d54b56e21d166954e17 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Thu, 22 Feb 2018 14:03:33 -0600 Subject: [PATCH 5/5] Adds CHANGELOG entry for #153 --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76b00dd..ffba2b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,34 @@ Versions prior to 1.0 were originally released as `phly/conduit`; please visit its [CHANGELOG](https://github.com/phly/conduit/blob/master/CHANGELOG.md) for details. +## 3.0.0alpha4 - TBD + +### Added + +- Nothing. + +### Changed + +- [#153](https://github.com/zendframework/zend-stratigility/pull/153) modifies + the first argument of the `Zend\Expressive\Middleware\ErrorHandler` and + `NotFoundHandler` classes. Previously, they each expected a + `Psr\Http\Message\ResponseInterface` instance; they now both expect a PHP + callable capable of producing such an instance. This change was done to + simplify re-use of a service for producing unique response instances within + dependency injection containers. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 3.0.0alpha3 - 2018-02-05 ### Added