diff --git a/.travis.yml b/.travis.yml index 97a0e47..652d855 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ cache: env: global: - - COMPOSER_ARGS="--no-interaction" + - COMPOSER_ARGS="--no-interaction --no-scripts" - COVERAGE_DEPS="php-coveralls/php-coveralls" matrix: @@ -19,7 +19,7 @@ matrix: - php: 5.6 env: - DEPS=locked - - LEGACY_DEPS="phpunit/phpunit" + - LEGACY_DEPS="phpunit/phpunit symfony/console symfony/finder" - php: 5.6 env: - DEPS=latest @@ -29,7 +29,7 @@ matrix: - php: 7 env: - DEPS=locked - - LEGACY_DEPS="phpunit/phpunit" + - LEGACY_DEPS="phpunit/phpunit symfony/console symfony/finder" - php: 7 env: - DEPS=latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fa29ec..5405781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,27 @@ All notable changes to this project will be documented in this file, in reverse `Zend\Expressive\Router\Middleware\RouteMiddleware`. These are the same as the versions shipped in 2.3.0, but under a new namespace. +- [#55](https://github.com/zendframework/zend-expressive-router/pull/55) adds + `Zend\Expressive\Router\Middleware\ImplicitHeadMiddleware`. It is imported + from zend-expressive, and implements the same functionality. + +- [#55](https://github.com/zendframework/zend-expressive-router/pull/55) adds + `Zend\Expressive\Router\Middleware\ImplicitOptionsMiddleware`. It is imported + from zend-expressive, and implements the same functionality. + +- [#57](https://github.com/zendframework/zend-expressive-router/pull/57) adds + the following factories for use with PSR-11 containers: + + - Zend\Expressive\Router\Middleware\DispatchMiddlewareFactory` + - Zend\Expressive\Router\Middleware\ImplicitHeadMiddlewareFactory` + - Zend\Expressive\Router\Middleware\ImplicitOptionsMiddlewareFactory` + - Zend\Expressive\Router\Middleware\RouteMiddlewareFactory` + +- [#57](https://github.com/zendframework/zend-expressive-router/pull/57) adds + `Zend\Expressive\Router\ConfigProvider`, mapping the above factories to their + respective middleware, and exposing it to zend-component-installer via the + package definition. + ### Changed - Nothing. diff --git a/composer.json b/composer.json index 76a0f40..097cb2d 100644 --- a/composer.json +++ b/composer.json @@ -22,6 +22,7 @@ "require": { "php": "^5.6 || ^7.0", "fig/http-message-util": "^1.1.2", + "psr/container": "^1.0", "psr/http-message": "^1.0.1", "webimpress/http-middleware-compatibility": "^0.1.1" }, @@ -53,6 +54,9 @@ "dev-master": "2.3.x-dev", "dev-develop": "2.4.x-dev", "dev-release-3.0.0": "3.0.x-dev" + }, + "zf": { + "config-provider": "Zend\\Expressive\\Router\\ConfigProvider" } }, "scripts": { diff --git a/composer.lock b/composer.lock index 66ae809..1acf0ff 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": "8b1727e2eb706c98f91f01f0958476c2", + "content-hash": "4d198aeec8690d52327f269190bfa9e8", "packages": [ { "name": "fig/http-message-util", @@ -58,16 +58,16 @@ }, { "name": "http-interop/http-middleware", - "version": "0.4.1", + "version": "0.5.0", "source": { "type": "git", "url": "https://github.com/http-interop/http-middleware.git", - "reference": "9a801fe60e70d5d608b61d56b2dcde29516c81b9" + "reference": "b49e1f9f6c584e704317b563302e566b8ce11858" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/http-interop/http-middleware/zipball/9a801fe60e70d5d608b61d56b2dcde29516c81b9", - "reference": "9a801fe60e70d5d608b61d56b2dcde29516c81b9", + "url": "https://api.github.com/repos/http-interop/http-middleware/zipball/b49e1f9f6c584e704317b563302e566b8ce11858", + "reference": "b49e1f9f6c584e704317b563302e566b8ce11858", "shasum": "" }, "require": { @@ -82,7 +82,7 @@ }, "autoload": { "psr-4": { - "Interop\\Http\\ServerMiddleware\\": "src/" + "Interop\\Http\\Server\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -97,17 +97,65 @@ ], "description": "Common interface for HTTP server-side middleware", "keywords": [ - "factory", "http", "middleware", "psr", - "psr-17", + "psr-15", "psr-7", "request", "response" ], "abandoned": "http-interop/http-server-middleware", - "time": "2017-01-14T15:23:42+00:00" + "time": "2017-09-18T15:27:03+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" }, { "name": "psr/http-message", @@ -159,28 +207,80 @@ ], "time": "2016-08-06T14:39:51+00:00" }, + { + "name": "webimpress/composer-extra-dependency", + "version": "0.2.2", + "source": { + "type": "git", + "url": "https://github.com/webimpress/composer-extra-dependency.git", + "reference": "31fa56391d30f03b1180c87610cbe22254780ad9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webimpress/composer-extra-dependency/zipball/31fa56391d30f03b1180c87610cbe22254780ad9", + "reference": "31fa56391d30f03b1180c87610cbe22254780ad9", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1", + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "composer/composer": "^1.5.2", + "mikey179/vfsstream": "^1.6.5", + "phpunit/phpunit": "^5.7.22 || ^6.4.1", + "zendframework/zend-coding-standard": "~1.0.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Webimpress\\ComposerExtraDependency\\Plugin" + }, + "autoload": { + "psr-4": { + "Webimpress\\ComposerExtraDependency\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "description": "Composer plugin to require extra dependencies", + "homepage": "https://github.com/webimpress/composer-extra-dependency", + "keywords": [ + "composer", + "dependency", + "webimpress" + ], + "time": "2017-10-17T17:15:14+00:00" + }, { "name": "webimpress/http-middleware-compatibility", - "version": "0.1.1", + "version": "0.1.4", "source": { "type": "git", "url": "https://github.com/webimpress/http-middleware-compatibility.git", - "reference": "793d21864a0417bbe01437c33f902cac49c1788c" + "reference": "8ed1c2c7523dce0035b98bc4f3a73ca9cd1d3717" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webimpress/http-middleware-compatibility/zipball/793d21864a0417bbe01437c33f902cac49c1788c", - "reference": "793d21864a0417bbe01437c33f902cac49c1788c", + "url": "https://api.github.com/repos/webimpress/http-middleware-compatibility/zipball/8ed1c2c7523dce0035b98bc4f3a73ca9cd1d3717", + "reference": "8ed1c2c7523dce0035b98bc4f3a73ca9cd1d3717", "shasum": "" }, "require": { "http-interop/http-middleware": "^0.1.1 || ^0.2 || ^0.3 || ^0.4.1 || ^0.5", - "php": "^5.6 || ^7.0" + "php": "^5.6 || ^7.0", + "webimpress/composer-extra-dependency": "^0.2.2" }, "require-dev": { - "phpunit/phpunit": "^5.7.22 || ^6.3.1" + "phpunit/phpunit": "^5.7.23 || ^6.4.3" }, "type": "library", + "extra": { + "dependency": [ + "http-interop/http-middleware" + ] + }, "autoload": { "files": [ "autoload/http-middleware.php" @@ -198,7 +298,7 @@ "webimpress" ], "abandoned": "psr/http-server-middleware", - "time": "2017-10-05T15:55:30+00:00" + "time": "2017-10-17T17:31:10+00:00" } ], "packages-dev": [ @@ -258,25 +358,26 @@ }, { "name": "malukenho/docheader", - "version": "0.1.5", + "version": "0.1.7", "source": { "type": "git", "url": "https://github.com/malukenho/docheader.git", - "reference": "f35ada934d1de3f5ba09970a6541009a41347658" + "reference": "3eb59f0621125c0dc40775f1bcc3206c37993703" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/malukenho/docheader/zipball/f35ada934d1de3f5ba09970a6541009a41347658", - "reference": "f35ada934d1de3f5ba09970a6541009a41347658", + "url": "https://api.github.com/repos/malukenho/docheader/zipball/3eb59f0621125c0dc40775f1bcc3206c37993703", + "reference": "3eb59f0621125c0dc40775f1bcc3206c37993703", "shasum": "" }, "require": { "php": "~5.5|^7.0", - "symfony/console": "~2.0|^3.0", - "symfony/finder": "~2.0|^3.0" + "symfony/console": "~2.0 || ^3.0 || ^4.0", + "symfony/finder": "~2.0 || ^3.0 || ^4.0" }, "require-dev": { - "phpunit/phpunit": "^4.7" + "phpunit/phpunit": "^4.7", + "squizlabs/php_codesniffer": "^2.8" }, "bin": [ "bin/docheader" @@ -304,7 +405,7 @@ "code standard", "license" ], - "time": "2016-11-17T16:46:05+00:00" + "time": "2017-12-18T09:16:11+00:00" }, { "name": "myclabs/deep-copy", @@ -509,29 +610,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.1.1", + "version": "4.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2" + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2d3d238c433cf69caeb4842e97a3223a116f94b2", - "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/reflection-common": "^1.0.0", "phpdocumentor/type-resolver": "^0.4.0", "webmozart/assert": "^1.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": [ @@ -550,7 +657,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-08-30T18:51:59+00:00" + "time": "2017-11-30T07:14:17+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -601,16 +708,16 @@ }, { "name": "phpspec/prophecy", - "version": "v1.7.2", + "version": "1.7.5", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", - "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", + "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", "shasum": "" }, "require": { @@ -622,7 +729,7 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8 || ^5.6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" }, "type": "library", "extra": { @@ -660,20 +767,20 @@ "spy", "stub" ], - "time": "2017-09-04T11:05:03+00:00" + "time": "2018-02-19T10:16:54+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.2.2", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b" + "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8ed1902a57849e117b5651fc1a5c48110946c06b", - "reference": "8ed1902a57849e117b5651fc1a5c48110946c06b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1", + "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1", "shasum": "" }, "require": { @@ -682,14 +789,13 @@ "php": "^7.0", "phpunit/php-file-iterator": "^1.4.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^1.4.11 || ^2.0", + "phpunit/php-token-stream": "^2.0.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^3.0", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "ext-xdebug": "^2.5", "phpunit/phpunit": "^6.0" }, "suggest": { @@ -698,7 +804,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.2.x-dev" + "dev-master": "5.3.x-dev" } }, "autoload": { @@ -713,7 +819,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -724,20 +830,20 @@ "testing", "xunit" ], - "time": "2017-08-03T12:40:43+00:00" + "time": "2017-12-06T09:29:45+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.2", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", "shasum": "" }, "require": { @@ -771,7 +877,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2017-11-27T13:52:08+00:00" }, { "name": "phpunit/php-text-template", @@ -865,16 +971,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0" + "reference": "791198a2c6254db10131eecfe8c06670700904db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9a02332089ac48e704c70f6cefed30c224e3c0b0", - "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", "shasum": "" }, "require": { @@ -910,20 +1016,20 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20T05:47:52+00:00" + "time": "2017-11-27T05:48:46+00:00" }, { "name": "phpunit/phpunit", - "version": "6.4.3", + "version": "6.5.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13" + "reference": "6bd77b57707c236833d2b57b968e403df060c9d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/06b28548fd2b4a20c3cd6e247dc86331a7d4db13", - "reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6bd77b57707c236833d2b57b968e403df060c9d9", + "reference": "6bd77b57707c236833d2b57b968e403df060c9d9", "shasum": "" }, "require": { @@ -937,12 +1043,12 @@ "phar-io/version": "^1.0", "php": "^7.0", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.2.2", - "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-code-coverage": "^5.3", + "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^4.0.3", - "sebastian/comparator": "^2.0.2", + "phpunit/phpunit-mock-objects": "^5.0.5", + "sebastian/comparator": "^2.1", "sebastian/diff": "^2.0", "sebastian/environment": "^3.1", "sebastian/exporter": "^3.1", @@ -968,7 +1074,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.4.x-dev" + "dev-master": "6.5.x-dev" } }, "autoload": { @@ -994,33 +1100,33 @@ "testing", "xunit" ], - "time": "2017-10-16T13:18:59+00:00" + "time": "2018-02-26T07:01:09+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "4.0.4", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "2f789b59ab89669015ad984afa350c4ec577ade0" + "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0", - "reference": "2f789b59ab89669015ad984afa350c4ec577ade0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf", + "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.5", "php": "^7.0", "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.0" + "sebastian/exporter": "^3.1" }, "conflict": { "phpunit/phpunit": "<6.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^6.5" }, "suggest": { "ext-soap": "*" @@ -1028,7 +1134,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "5.0.x-dev" } }, "autoload": { @@ -1043,7 +1149,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1053,54 +1159,7 @@ "mock", "xunit" ], - "time": "2017-08-03T14:08:16+00:00" - }, - { - "name": "psr/log", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2018-01-06T05:45:45+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1149,21 +1208,21 @@ }, { "name": "sebastian/comparator", - "version": "2.1.0", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "1174d9018191e93cb9d719edec01257fc05f8158" + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1174d9018191e93cb9d719edec01257fc05f8158", - "reference": "1174d9018191e93cb9d719edec01257fc05f8158", + "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": { @@ -1209,7 +1268,7 @@ "compare", "equality" ], - "time": "2017-11-03T07:16:52+00:00" + "time": "2018-02-01T13:46:46+00:00" }, { "name": "sebastian/diff", @@ -1663,16 +1722,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "2.8.1", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d" + "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d", - "reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62", + "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62", "shasum": "" }, "require": { @@ -1737,43 +1796,48 @@ "phpcs", "standards" ], - "time": "2017-03-01T22:17:45+00:00" + "time": "2017-05-22T02:43:20+00:00" }, { "name": "symfony/console", - "version": "v3.2.4", + "version": "v4.0.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0e5e6899f82230fcb1153bcaf0e106ffaa44b870" + "reference": "555c8dbe0ae9e561740451eabdbed2cc554b6a51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0e5e6899f82230fcb1153bcaf0e106ffaa44b870", - "reference": "0e5e6899f82230fcb1153bcaf0e106ffaa44b870", + "url": "https://api.github.com/repos/symfony/console/zipball/555c8dbe0ae9e561740451eabdbed2cc554b6a51", + "reference": "555c8dbe0ae9e561740451eabdbed2cc554b6a51", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/debug": "~2.8|~3.0", + "php": "^7.1.3", "symfony/polyfill-mbstring": "~1.0" }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" + }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/filesystem": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/lock": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0" }, "suggest": { "psr/log": "For using the console logger", "symfony/event-dispatcher": "", - "symfony/filesystem": "", + "symfony/lock": "", "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1800,86 +1864,29 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-02-16T14:07:22+00:00" - }, - { - "name": "symfony/debug", - "version": "v3.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "9b98854cb45bc59d100b7d4cc4cf9e05f21026b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/9b98854cb45bc59d100b7d4cc4cf9e05f21026b9", - "reference": "9b98854cb45bc59d100b7d4cc4cf9e05f21026b9", - "shasum": "" - }, - "require": { - "php": ">=5.5.9", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" - }, - "require-dev": { - "symfony/class-loader": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Debug Component", - "homepage": "https://symfony.com", - "time": "2017-02-16T16:34:18+00:00" + "time": "2018-02-26T15:55:47+00:00" }, { "name": "symfony/finder", - "version": "v3.2.4", + "version": "v4.0.6", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8c71141cae8e2957946b403cc71a67213c0380d6" + "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8c71141cae8e2957946b403cc71a67213c0380d6", - "reference": "8c71141cae8e2957946b403cc71a67213c0380d6", + "url": "https://api.github.com/repos/symfony/finder/zipball/44a796d2ecc2a16a5fc8f2956a34ee617934d55f", + "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1906,20 +1913,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-01-02T20:32:22+00:00" + "time": "2018-03-05T18:28:26+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.3.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", - "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", "shasum": "" }, "require": { @@ -1931,7 +1938,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -1965,7 +1972,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2018-01-30T19:27:44+00:00" }, { "name": "theseer/tokenizer", @@ -2009,16 +2016,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": { @@ -2055,7 +2062,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2018-01-29T19:49:41+00:00" }, { "name": "zendframework/zend-coding-standard", diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php new file mode 100644 index 0000000..7896e5e --- /dev/null +++ b/src/ConfigProvider.php @@ -0,0 +1,38 @@ + $this->getDependencies(), + ]; + } + + /** + * @return array + */ + public function getDependencies() + { + // @codingStandardsIgnoreStart + return [ + 'factories' => [ + Middleware\DispatchMiddleware::class => Middleware\DispatchMiddlewareFactory::class, + Middleware\ImplicitHeadMiddleware::class => Middleware\ImplicitHeadMiddlewareFactory::class, + Middleware\ImplicitOptionsMiddleware::class => Middleware\ImplicitOptionsMiddlewareFactory::class, + Middleware\RouteMiddleware::class => Middleware\RouteMiddlewareFactory::class, + ] + ]; + // @codingStandardsIgnoreEnd + } +} diff --git a/src/Exception/MissingDependencyException.php b/src/Exception/MissingDependencyException.php new file mode 100644 index 0000000..7f026e1 --- /dev/null +++ b/src/Exception/MissingDependencyException.php @@ -0,0 +1,31 @@ +response = $response; + $this->streamFactory = $streamFactory; + } + + /** + * Handle an implicit HEAD request. + * + * If the route allows GET requests, dispatches as a GET request and + * resets the response body to be empty; otherwise, creates a new empty + * response. + * + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) + { + if ($request->getMethod() !== RequestMethod::METHOD_HEAD) { + return $handler->{HANDLER_METHOD}($request); + } + + $result = $request->getAttribute(RouteResult::class); + if (! $result) { + return $handler->{HANDLER_METHOD}($request); + } + + $route = $result->getMatchedRoute(); + if (! $route || ! $route->implicitHead()) { + return $handler->{HANDLER_METHOD}($request); + } + + if (! $route->allowsMethod(RequestMethod::METHOD_GET)) { + return $this->response; + } + + $response = $handler->{HANDLER_METHOD}( + $request + ->withMethod(RequestMethod::METHOD_GET) + ->withAttribute(self::FORWARDED_HTTP_METHOD_ATTRIBUTE, RequestMethod::METHOD_HEAD) + ); + + $streamFactory = $this->streamFactory; + /** @var StreamInterface $body */ + $body = $streamFactory(); + return $this->response->withBody($body); + } +} diff --git a/src/Middleware/ImplicitHeadMiddlewareFactory.php b/src/Middleware/ImplicitHeadMiddlewareFactory.php new file mode 100644 index 0000000..0316404 --- /dev/null +++ b/src/Middleware/ImplicitHeadMiddlewareFactory.php @@ -0,0 +1,61 @@ +has(ResponseInterface::class)) { + throw MissingDependencyException::dependencyForService( + ResponseInterface::class, + ImplicitHeadMiddleware::class + ); + } + + if (! $container->has(StreamInterface::class)) { + throw MissingDependencyException::dependencyForService( + StreamInterface::class, + ImplicitHeadMiddleware::class + ); + } + + // If the response service resolves to a callable factory, call it to + // resolve to an instance. + $response = $container->get(ResponseInterface::class); + if (! $response instanceof ResponseInterface && is_callable($response)) { + $response = $response(); + } + + return new ImplicitHeadMiddleware( + $response, + $container->get(StreamInterface::class) + ); + } +} diff --git a/src/Middleware/ImplicitOptionsMiddleware.php b/src/Middleware/ImplicitOptionsMiddleware.php new file mode 100644 index 0000000..b8d3b3b --- /dev/null +++ b/src/Middleware/ImplicitOptionsMiddleware.php @@ -0,0 +1,79 @@ +response = $response; + } + + /** + * Handle an implicit OPTIONS request. + * + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) + { + if ($request->getMethod() !== RequestMethod::METHOD_OPTIONS) { + return $handler->{HANDLER_METHOD}($request); + } + + $result = $request->getAttribute(RouteResult::class); + if (! $result) { + return $handler->{HANDLER_METHOD}($request); + } + + $route = $result->getMatchedRoute(); + if (! $route || ! $route->implicitOptions()) { + return $handler->{HANDLER_METHOD}($request); + } + + $methods = implode(',', $route->getAllowedMethods()); + + return $this->response->withHeader('Allow', $methods); + } +} diff --git a/src/Middleware/ImplicitOptionsMiddlewareFactory.php b/src/Middleware/ImplicitOptionsMiddlewareFactory.php new file mode 100644 index 0000000..dbc99ef --- /dev/null +++ b/src/Middleware/ImplicitOptionsMiddlewareFactory.php @@ -0,0 +1,48 @@ +has(ResponseInterface::class)) { + throw MissingDependencyException::dependencyForService( + ResponseInterface::class, + ImplicitOptionsMiddleware::class + ); + } + + // If the response service resolves to a callable factory, call it to + // resolve to an instance. + $response = $container->get(ResponseInterface::class); + if (! $response instanceof ResponseInterface && is_callable($response)) { + $response = $response(); + } + + return new ImplicitOptionsMiddleware($response); + } +} diff --git a/src/Middleware/MethodNotAllowedMiddleware.php b/src/Middleware/MethodNotAllowedMiddleware.php new file mode 100644 index 0000000..ad917c2 --- /dev/null +++ b/src/Middleware/MethodNotAllowedMiddleware.php @@ -0,0 +1,56 @@ +response = $response; + } + + /** + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) + { + $routeResult = $request->getAttribute(RouteResult::class); + if (! $routeResult || ! $routeResult->isMethodFailure()) { + return $handler->{HANDLER_METHOD}($request); + } + + return $this->response + ->withStatus(StatusCode::STATUS_METHOD_NOT_ALLOWED) + ->withHeader('Allow', implode(',', $routeResult->getAllowedMethods())); + } +} diff --git a/src/Middleware/RouteMiddlewareFactory.php b/src/Middleware/RouteMiddlewareFactory.php new file mode 100644 index 0000000..fcaeaed --- /dev/null +++ b/src/Middleware/RouteMiddlewareFactory.php @@ -0,0 +1,58 @@ +has(RouterInterface::class)) { + throw MissingDependencyException::dependencyForService( + RouterInterface::class, + RouteMiddleware::class + ); + } + + if (! $container->has(ResponseInterface::class)) { + throw MissingDependencyException::dependencyForService( + ResponseInterface::class, + ImplicitHeadMiddleware::class + ); + } + + // If the response service resolves to a callable factory, call it to + // resolve to an instance. + $response = $container->get(ResponseInterface::class); + if (! $response instanceof ResponseInterface && is_callable($response)) { + $response = $response(); + } + + return new RouteMiddleware($container->get(RouterInterface::class), $response); + } +} diff --git a/test/ConfigProviderTest.php b/test/ConfigProviderTest.php new file mode 100644 index 0000000..af46499 --- /dev/null +++ b/test/ConfigProviderTest.php @@ -0,0 +1,28 @@ +assertTrue(isset($config['dependencies']['factories'])); + $factories = $config['dependencies']['factories']; + $this->assertArrayHasKey(Middleware\DispatchMiddleware::class, $factories); + $this->assertArrayHasKey(Middleware\ImplicitHeadMiddleware::class, $factories); + $this->assertArrayHasKey(Middleware\ImplicitOptionsMiddleware::class, $factories); + $this->assertArrayHasKey(Middleware\RouteMiddleware::class, $factories); + } +} diff --git a/test/Middleware/DispatchMiddlewareFactoryTest.php b/test/Middleware/DispatchMiddlewareFactoryTest.php new file mode 100644 index 0000000..31ba8a4 --- /dev/null +++ b/test/Middleware/DispatchMiddlewareFactoryTest.php @@ -0,0 +1,24 @@ +prophesize(ContainerInterface::class)->reveal(); + $factory = new DispatchMiddlewareFactory(); + $middleware = $factory($container); + $this->assertInstanceOf(DispatchMiddleware::class, $middleware); + } +} diff --git a/test/Middleware/ImplicitHeadMiddlewareFactoryTest.php b/test/Middleware/ImplicitHeadMiddlewareFactoryTest.php new file mode 100644 index 0000000..eeadb99 --- /dev/null +++ b/test/Middleware/ImplicitHeadMiddlewareFactoryTest.php @@ -0,0 +1,89 @@ +container = $this->prophesize(ContainerInterface::class); + $this->factory = new ImplicitHeadMiddlewareFactory(); + } + + public function testFactoryRaisesExceptionIfResponseFactoryServiceIsMissing() + { + $this->container->has(ResponseInterface::class)->willReturn(false); + $this->container->has(StreamInterface::class)->shouldNotBeCalled(); + + $this->expectException(MissingDependencyException::class); + $this->factory->__invoke($this->container->reveal()); + } + + public function testFactoryRaisesExceptionIfStreamFactoryServiceIsMissing() + { + $this->container->has(ResponseInterface::class)->willReturn(true); + $this->container->has(StreamInterface::class)->willReturn(false); + + $this->expectException(MissingDependencyException::class); + $this->factory->__invoke($this->container->reveal()); + } + + public function testFactoryProducesImplicitHeadMiddlewareWhenAllDependenciesPresent() + { + $response = $this->prophesize(ResponseInterface::class)->reveal(); + $responseFactory = function () use ($response) { + return $response; + }; + $this->container->has(ResponseInterface::class)->willReturn(true); + $this->container->get(ResponseInterface::class)->willReturn($responseFactory); + + $streamFactory = function () { + }; + $this->container->has(StreamInterface::class)->willReturn(true); + $this->container->get(StreamInterface::class)->willReturn($streamFactory); + + $middleware = $this->factory->__invoke($this->container->reveal()); + + $this->assertInstanceOf(ImplicitHeadMiddleware::class, $middleware); + $this->assertAttributeSame($response, 'response', $middleware); + $this->assertAttributeSame($streamFactory, 'streamFactory', $middleware); + } + + public function testFactoryProducesImplicitHeadMiddlewareWhenResponseInstanceReturnedFromContainer() + { + $response = $this->prophesize(ResponseInterface::class)->reveal(); + $this->container->has(ResponseInterface::class)->willReturn(true); + $this->container->get(ResponseInterface::class)->willReturn($response); + + $streamFactory = function () { + }; + $this->container->has(StreamInterface::class)->willReturn(true); + $this->container->get(StreamInterface::class)->willReturn($streamFactory); + + $middleware = $this->factory->__invoke($this->container->reveal()); + + $this->assertInstanceOf(ImplicitHeadMiddleware::class, $middleware); + $this->assertAttributeSame($response, 'response', $middleware); + $this->assertAttributeSame($streamFactory, 'streamFactory', $middleware); + } +} diff --git a/test/Middleware/ImplicitHeadMiddlewareTest.php b/test/Middleware/ImplicitHeadMiddlewareTest.php new file mode 100644 index 0000000..cceb960 --- /dev/null +++ b/test/Middleware/ImplicitHeadMiddlewareTest.php @@ -0,0 +1,170 @@ +response = $this->prophesize(ResponseInterface::class); + + $this->stream = $this->prophesize(StreamInterface::class); + $streamFactory = function () { + return $this->stream->reveal(); + }; + + $this->middleware = new ImplicitHeadMiddleware($this->response->reveal(), $streamFactory); + } + + public function testReturnsResultOfHandlerOnNonHeadRequests() + { + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_GET); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}($request->reveal())->will([$this->response, 'reveal']); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($this->response->reveal(), $result); + } + + public function testReturnsResultOfHandlerWhenNoRouteResultPresentInRequest() + { + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_HEAD); + $request->getAttribute(RouteResult::class)->willReturn(null); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}($request->reveal())->will([$this->response, 'reveal']); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($this->response->reveal(), $result); + } + + public function testReturnsResultOfHandlerWhenRouteResultDoesNotContainAMatchedRoute() + { + $result = $this->prophesize(RouteResult::class); + $result->getMatchedRoute()->willReturn(null); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_HEAD); + $request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}($request->reveal())->will([$this->response, 'reveal']); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($this->response->reveal(), $result); + } + + public function testReturnsResultOfHandlerWhenRouteResultContainsAMatchedRouteWithExplicitHeadSupport() + { + $route = $this->prophesize(Route::class); + $route->implicitHead()->willReturn(false); + + $result = $this->prophesize(RouteResult::class); + $result->getMatchedRoute()->will([$route, 'reveal']); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_HEAD); + $request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}($request->reveal())->will([$this->response, 'reveal']); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($this->response->reveal(), $result); + } + + public function testReturnsCannedResponseWhenRouteDoesNotExplicitlySupportHeadAndDoesNotSupportGet() + { + $route = $this->prophesize(Route::class); + $route->implicitHead()->willReturn(true); + $route->allowsMethod(RequestMethod::METHOD_GET)->willReturn(false); + + $result = $this->prophesize(RouteResult::class); + $result->getMatchedRoute()->will([$route, 'reveal']); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_HEAD); + $request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + $request->withMethod(RequestMethod::METHOD_GET)->will([$request, 'reveal']); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}(Argument::any())->shouldNotBeCalled(); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($this->response->reveal(), $result); + } + + public function testInvokesHandlerWhenRouteImplicitlySupportsHeadAndSupportsGet() + { + $result = $this->prophesize(RouteResult::class); + $result->getMatchedRoute()->willReturn(false); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_HEAD); + $request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + $request->withMethod(RequestMethod::METHOD_GET)->will([$request, 'reveal']); + $request + ->withAttribute( + ImplicitHeadMiddleware::FORWARDED_HTTP_METHOD_ATTRIBUTE, + RequestMethod::METHOD_HEAD + ) + ->will([$request, 'reveal']); + + $response = $this->prophesize(ResponseInterface::class); + $response->withBody($this->stream->reveal())->will([$response, 'reveal']); + + $route = $this->prophesize(Route::class); + + $result = $this->prophesize(RouteResult::class); + $result->isFailure()->willReturn(false); + $result->getMatchedRoute()->will([$route, 'reveal']); + + $request->withAttribute(RouteResult::class, $result->reveal())->will([$request, 'reveal']); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler + ->{HANDLER_METHOD}(Argument::that([$request, 'reveal'])) + ->will([$response, 'reveal']); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($response->reveal(), $result); + } +} diff --git a/test/Middleware/ImplicitOptionsMiddlewareFactoryTest.php b/test/Middleware/ImplicitOptionsMiddlewareFactoryTest.php new file mode 100644 index 0000000..9fafc92 --- /dev/null +++ b/test/Middleware/ImplicitOptionsMiddlewareFactoryTest.php @@ -0,0 +1,67 @@ +container = $this->prophesize(ContainerInterface::class); + $this->factory = new ImplicitOptionsMiddlewareFactory(); + } + + public function testFactoryRaisesExceptionIfResponseFactoryServiceIsMissing() + { + $this->container->has(ResponseInterface::class)->willReturn(false); + + $this->expectException(MissingDependencyException::class); + $this->factory->__invoke($this->container->reveal()); + } + + public function testFactoryProducesImplicitOptionsMiddlewareWhenAllDependenciesPresent() + { + $response = $this->prophesize(ResponseInterface::class)->reveal(); + $responseFactory = function () use ($response) { + return $response; + }; + + $this->container->has(ResponseInterface::class)->willReturn(true); + $this->container->get(ResponseInterface::class)->willReturn($responseFactory); + + $middleware = $this->factory->__invoke($this->container->reveal()); + + $this->assertInstanceOf(ImplicitOptionsMiddleware::class, $middleware); + $this->assertAttributeSame($response, 'response', $middleware); + } + + public function testFactoryProducesImplicitOptionsMiddlewareWhenCResponseInstanceReturnedFromContainer() + { + $response = $this->prophesize(ResponseInterface::class)->reveal(); + $this->container->has(ResponseInterface::class)->willReturn(true); + $this->container->get(ResponseInterface::class)->willReturn($response); + + $middleware = $this->factory->__invoke($this->container->reveal()); + + $this->assertInstanceOf(ImplicitOptionsMiddleware::class, $middleware); + $this->assertAttributeSame($response, 'response', $middleware); + } +} diff --git a/test/Middleware/ImplicitOptionsMiddlewareTest.php b/test/Middleware/ImplicitOptionsMiddlewareTest.php new file mode 100644 index 0000000..e0fb0ef --- /dev/null +++ b/test/Middleware/ImplicitOptionsMiddlewareTest.php @@ -0,0 +1,133 @@ +response = $this->prophesize(ResponseInterface::class); + $this->middleware = new ImplicitOptionsMiddleware($this->response->reveal()); + } + + public function testNonOptionsRequestInvokesHandler() + { + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_GET); + $request->getAttribute(RouteResult::class, false)->shouldNotBeCalled(); + + $response = $this->prophesize(ResponseInterface::class)->reveal(); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}($request->reveal())->willReturn($response); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + $this->assertSame($response, $result); + } + + public function testMissingRouteResultInvokesHandler() + { + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_OPTIONS); + $request->getAttribute(RouteResult::class)->willReturn(null); + + $response = $this->prophesize(ResponseInterface::class)->reveal(); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}($request->reveal())->willReturn($response); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + $this->assertSame($response, $result); + } + + public function testReturnsHandlerResultIfNoRoutePresentInRouteResult() + { + $result = $this->prophesize(RouteResult::class); + $result->getMatchedRoute()->willReturn(null); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_OPTIONS); + $request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + + $response = $this->prophesize(ResponseInterface::class)->reveal(); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}(Argument::that([$request, 'reveal']))->willReturn($response); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($response, $result); + } + + public function testReturnsHandlerResultIfRoutePresentInRouteResultSupportsExplicitOptions() + { + $route = $this->prophesize(Route::class); + $route->implicitOptions()->willReturn(false); + + $result = $this->prophesize(RouteResult::class); + $result->getMatchedRoute()->will([$route, 'reveal']); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_OPTIONS); + $request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + + $response = $this->prophesize(ResponseInterface::class)->reveal(); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}(Argument::that([$request, 'reveal']))->willReturn($response); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + + $this->assertSame($response, $result); + } + + public function testInjectsAllowHeaderInResponseProvidedToConstructorDuringOptionsRequest() + { + $allowedMethods = [RequestMethod::METHOD_GET, RequestMethod::METHOD_POST]; + + $route = $this->prophesize(Route::class); + $route->implicitOptions()->willReturn(true); + $route->getAllowedMethods()->willReturn($allowedMethods); + + $result = $this->prophesize(RouteResult::class); + $result->getMatchedRoute()->will([$route, 'reveal']); + + $request = $this->prophesize(ServerRequestInterface::class); + $request->getMethod()->willReturn(RequestMethod::METHOD_OPTIONS); + $request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + + $handler = $this->prophesize(RequestHandlerInterface::class); + $handler->{HANDLER_METHOD}($request->reveal())->shouldNotBeCalled(); + + $this->response + ->withHeader('Allow', implode(',', $allowedMethods)) + ->will([$this->response, 'reveal']); + + $result = $this->middleware->process($request->reveal(), $handler->reveal()); + $this->assertSame($this->response->reveal(), $result); + } +} diff --git a/test/Middleware/MethodNotAllowedMiddlewareTest.php b/test/Middleware/MethodNotAllowedMiddlewareTest.php new file mode 100644 index 0000000..6ca45e4 --- /dev/null +++ b/test/Middleware/MethodNotAllowedMiddlewareTest.php @@ -0,0 +1,93 @@ +handler = $this->prophesize(RequestHandlerInterface::class); + $this->request = $this->prophesize(ServerRequestInterface::class); + $this->response = $this->prophesize(ResponseInterface::class); + + $this->middleware = new MethodNotAllowedMiddleware($this->response->reveal()); + } + + public function testDelegatesToHandlerIfNoRouteResultPresentInRequest() + { + $this->request->getAttribute(RouteResult::class)->willReturn(null); + $this->handler->{HANDLER_METHOD}(Argument::that([$this->request, 'reveal']))->will([$this->response, 'reveal']); + + $this->response->withStatus(Argument::any())->shouldNotBeCalled(); + $this->response->withHeader('Allow', Argument::any())->shouldNotBeCalled(); + + $this->assertSame( + $this->response->reveal(), + $this->middleware->process($this->request->reveal(), $this->handler->reveal()) + ); + } + + public function testDelegatesToHandlerIfRouteResultNotAMethodFailure() + { + $result = $this->prophesize(RouteResult::class); + $result->isMethodFailure()->willReturn(false); + + $this->request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + $this->handler->{HANDLER_METHOD}(Argument::that([$this->request, 'reveal']))->will([$this->response, 'reveal']); + + $this->response->withStatus(Argument::any())->shouldNotBeCalled(); + $this->response->withHeader('Allow', Argument::any())->shouldNotBeCalled(); + + $this->assertSame( + $this->response->reveal(), + $this->middleware->process($this->request->reveal(), $this->handler->reveal()) + ); + } + + public function testReturns405ResponseWithAllowHeaderIfResultDueToMethodFailure() + { + $result = $this->prophesize(RouteResult::class); + $result->isMethodFailure()->willReturn(true); + $result->getAllowedMethods()->willReturn(['GET', 'POST']); + + $this->request->getAttribute(RouteResult::class)->will([$result, 'reveal']); + $this->handler->{HANDLER_METHOD}(Argument::that([$this->request, 'reveal']))->shouldNotBeCalled(); + + $this->response->withStatus(StatusCode::STATUS_METHOD_NOT_ALLOWED)->will([$this->response, 'reveal']); + $this->response->withHeader('Allow', 'GET,POST')->will([$this->response, 'reveal']); + + $this->assertSame( + $this->response->reveal(), + $this->middleware->process($this->request->reveal(), $this->handler->reveal()) + ); + } +} diff --git a/test/Middleware/RouteMiddlewareFactoryTest.php b/test/Middleware/RouteMiddlewareFactoryTest.php new file mode 100644 index 0000000..987c157 --- /dev/null +++ b/test/Middleware/RouteMiddlewareFactoryTest.php @@ -0,0 +1,83 @@ +container = $this->prophesize(ContainerInterface::class); + $this->factory = new RouteMiddlewareFactory(); + } + + public function testFactoryRaisesExceptionIfRouterServiceIsMissing() + { + $this->container->has(RouterInterface::class)->willReturn(false); + $this->container->has(ResponseInterface::class)->shouldNotBeCalled(); + + $this->expectException(MissingDependencyException::class); + $this->factory->__invoke($this->container->reveal()); + } + + public function testFactoryRaisesExceptionIfResponseServiceIsMissing() + { + $this->container->has(RouterInterface::class)->willReturn(true); + $this->container->has(ResponseInterface::class)->willReturn(false); + + $this->expectException(MissingDependencyException::class); + $this->factory->__invoke($this->container->reveal()); + } + + public function testFactoryProducesRouteMiddlewareWhenAllDependenciesPresent() + { + $router = $this->prophesize(RouterInterface::class)->reveal(); + $this->container->has(RouterInterface::class)->willReturn(true); + $this->container->get(RouterInterface::class)->willReturn($router); + + $response = $this->prophesize(ResponseInterface::class)->reveal(); + $responseFactory = function () use ($response) { + return $response; + }; + $this->container->has(ResponseInterface::class)->willReturn(true); + $this->container->get(ResponseInterface::class)->willReturn($responseFactory); + + $middleware = $this->factory->__invoke($this->container->reveal()); + + $this->assertInstanceOf(RouteMiddleware::class, $middleware); + } + + public function testFactoryProducesRouteMiddlewareWhenResponseInstanceReturnedFromContainer() + { + $router = $this->prophesize(RouterInterface::class)->reveal(); + $this->container->has(RouterInterface::class)->willReturn(true); + $this->container->get(RouterInterface::class)->willReturn($router); + + $response = $this->prophesize(ResponseInterface::class)->reveal(); + $this->container->has(ResponseInterface::class)->willReturn(true); + $this->container->get(ResponseInterface::class)->willReturn($response); + + $middleware = $this->factory->__invoke($this->container->reveal()); + + $this->assertInstanceOf(RouteMiddleware::class, $middleware); + } +}