From fbd1c10ebe9cd678869edb336995c9ffdb01cd9a Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 8 Aug 2020 10:46:07 -0400 Subject: [PATCH 01/53] Upgrade PHPUnit to v9 --- composer.json | 8 +- composer.lock | 1274 +++++++++++++++++++++++++++++--------------- phpunit.xml.dist | 53 +- test/bootstrap.php | 6 - 4 files changed, 889 insertions(+), 452 deletions(-) delete mode 100644 test/bootstrap.php diff --git a/composer.json b/composer.json index d2e8e48..6430ef5 100644 --- a/composer.json +++ b/composer.json @@ -18,11 +18,17 @@ "psr/http-server-middleware": "~1.0" }, "require-dev": { - "phpunit/phpunit": "^8" + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9" }, "autoload": { "psr-4": { "WellRESTed\\": "src/" } + }, + "autoload-dev": { + "psr-4": { + "WellRESTed\\Test\\": "test/src/" + } } } diff --git a/composer.lock b/composer.lock index 0ee2347..5fb2477 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "29344ee99e0ff32d5d20fa62c0278512", + "content-hash": "ee44c87f0246b5c26e6e51fc4b0c6b4c", "packages": [ { "name": "psr/http-message", @@ -166,20 +166,20 @@ "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea", + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", @@ -218,24 +218,38 @@ "constructor", "instantiate" ], - "time": "2019-10-21T16:45:58+00:00" + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-05-29T17:27:14+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.9.5", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", - "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "replace": { "myclabs/deep-copy": "self.version" @@ -266,32 +280,91 @@ "object", "object graph" ], - "time": "2020-01-17T21:11:47+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2020-06-29T13:22:24+00:00" }, { - "name": "phar-io/manifest", - "version": "1.0.3", + "name": "nikic/php-parser", + "version": "v4.7.0", "source": { "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "21dce06dfbf0365c6a7cc8fdbdc995926c6a9300" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/21dce06dfbf0365c6a7cc8fdbdc995926c6a9300", + "reference": "21dce06dfbf0365c6a7cc8fdbdc995926c6a9300", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.7-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2020-07-25T13:18:53+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -321,24 +394,24 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2018-07-08T19:23:20+00:00" + "time": "2020-06-27T14:33:11+00:00" }, { "name": "phar-io/version", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + "reference": "c6bb6825def89e0a32220f88337f8ceaf1975fa0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "url": "https://api.github.com/repos/phar-io/version/zipball/c6bb6825def89e0a32220f88337f8ceaf1975fa0", + "reference": "c6bb6825def89e0a32220f88337f8ceaf1975fa0", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -368,32 +441,29 @@ } ], "description": "Library for handling version information and constraints", - "time": "2018-07-08T19:19:57+00:00" + "time": "2020-06-27T14:39:04+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "2.0.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~6" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-2.x": "2.x-dev" } }, "autoload": { @@ -420,45 +490,41 @@ "reflection", "static analysis" ], - "time": "2018-08-07T13:53:10+00:00" + "time": "2020-06-27T09:03:43+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.4", + "version": "5.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" + "reference": "3170448f5769fe19f456173d833734e0ff1b84df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/3170448f5769fe19f456173d833734e0ff1b84df", + "reference": "3170448f5769fe19f456173d833734e0ff1b84df", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpdocumentor/type-resolver": "0.4.*", - "phpunit/phpunit": "^6.4" + "mockery/mockery": "~1.3.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -469,38 +535,40 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-12-28T18:55:12+00:00" + "time": "2020-07-20T20:05:34+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.0.1", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651", + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651", "shasum": "" }, "require": { - "php": "^7.1", + "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" + "ext-tokenizer": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { @@ -519,37 +587,37 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" + "time": "2020-06-27T10:12:23+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.10.2", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" + "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b20034be5efcdab4fb60ca3a29cba2949aead160", + "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + "doctrine/instantiator": "^1.2", + "php": "^7.2", + "phpdocumentor/reflection-docblock": "^5.0", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5 || ^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + "phpspec/phpspec": "^6.0", + "phpunit/phpunit": "^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -582,44 +650,96 @@ "spy", "stub" ], - "time": "2020-01-20T15:57:02+00:00" + "time": "2020-07-08T12:44:21+00:00" }, { - "name": "phpunit/php-code-coverage", - "version": "7.0.10", + "name": "phpspec/prophecy-phpunit", + "version": "v2.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" + "url": "https://github.com/phpspec/prophecy-phpunit.git", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", - "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/2d7a9df55f257d2cba9b1d0c0963a54960657177", + "reference": "2d7a9df55f257d2cba9b1d0c0963a54960657177", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.2", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.1.1", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.2.2", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1.3" - }, - "require-dev": { - "phpunit/phpunit": "^8.2.2" - }, - "suggest": { - "ext-xdebug": "^2.7.2" + "php": "^7.3 || ^8", + "phpspec/prophecy": "^1.3", + "phpunit/phpunit": "^9.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\PhpUnit\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integrating the Prophecy mocking library in PHPUnit test cases", + "homepage": "http://phpspec.net", + "keywords": [ + "phpunit", + "prophecy" + ], + "time": "2020-07-09T08:33:42+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ee24e82baca11d7d6fb3513e127d6000f541cf90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ee24e82baca11d7d6fb3513e127d6000f541cf90", + "reference": "ee24e82baca11d7d6fb3513e127d6000f541cf90", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.7", + "php": "^7.3 || ^8.0", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.0-dev" } }, "autoload": { @@ -645,32 +765,38 @@ "testing", "xunit" ], - "time": "2019-11-20T13:55:58+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-08-07T04:12:30+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "2.0.2", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "050bedf145a257b1ff02746c31894800e5122946" + "reference": "25fefc5b19835ca653877fe081644a3f8c1d915e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", - "reference": "050bedf145a257b1ff02746c31894800e5122946", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/25fefc5b19835ca653877fe081644a3f8c1d915e", + "reference": "25fefc5b19835ca653877fe081644a3f8c1d915e", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -695,26 +821,99 @@ "filesystem", "iterator" ], - "time": "2018-09-13T20:33:42+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-11T05:18:21+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.1.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "7a85b66acc48cacffdf87dadd3694e7123674298" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/7a85b66acc48cacffdf87dadd3694e7123674298", + "reference": "7a85b66acc48cacffdf87dadd3694e7123674298", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-08-06T07:04:15+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/6ff9c8ea4d3212b88fcf74e25e516e2c51c99324", + "reference": "6ff9c8ea4d3212b88fcf74e25e516e2c51c99324", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -736,32 +935,38 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T11:55:37+00:00" }, { "name": "phpunit/php-timer", - "version": "2.1.2", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" + "reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/cc49734779cbb302bf51a44297dab8c4bbf941e7", + "reference": "cc49734779cbb302bf51a44297dab8c4bbf941e7", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -785,105 +990,64 @@ "keywords": [ "timer" ], - "time": "2019-06-07T04:22:29+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + "funding": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "url": "https://github.com/sebastianbergmann", + "type": "github" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2019-09-17T06:23:10+00:00" + "time": "2020-06-26T11:58:13+00:00" }, { "name": "phpunit/phpunit", - "version": "8.5.2", + "version": "9.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0" + "reference": "7e3942a29e7705cf109aa58c6e5d80997796d1dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0", - "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7e3942a29e7705cf109aa58c6e5d80997796d1dc", + "reference": "7e3942a29e7705cf109aa58c6e5d80997796d1dc", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.2.0", + "doctrine/instantiator": "^1.3.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.9.1", - "phar-io/manifest": "^1.0.3", - "phar-io/version": "^2.0.1", - "php": "^7.2", - "phpspec/prophecy": "^1.8.1", - "phpunit/php-code-coverage": "^7.0.7", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1.2", - "sebastian/comparator": "^3.0.2", - "sebastian/diff": "^3.0.2", - "sebastian/environment": "^4.2.2", - "sebastian/exporter": "^3.1.1", - "sebastian/global-state": "^3.0.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0.1", - "sebastian/type": "^1.1.3", - "sebastian/version": "^2.0.1" + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.1", + "phar-io/version": "^3.0.2", + "php": "^7.3 || ^8.0", + "phpspec/prophecy": "^1.11.1", + "phpunit/php-code-coverage": "^9.0", + "phpunit/php-file-iterator": "^3.0.4", + "phpunit/php-invoker": "^3.1", + "phpunit/php-text-template": "^2.0.2", + "phpunit/php-timer": "^5.0.1", + "sebastian/code-unit": "^1.0.5", + "sebastian/comparator": "^4.0.3", + "sebastian/diff": "^4.0.2", + "sebastian/environment": "^5.1.2", + "sebastian/exporter": "^4.0.2", + "sebastian/global-state": "^5.0", + "sebastian/object-enumerator": "^4.0.2", + "sebastian/resource-operations": "^3.0.2", + "sebastian/type": "^2.2.1", + "sebastian/version": "^3.0.1" }, "require-dev": { - "ext-pdo": "*" + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0.0" + "ext-xdebug": "*" }, "bin": [ "phpunit" @@ -891,12 +1055,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.5-dev" + "dev-master": "9.3-dev" } }, "autoload": { "classmap": [ "src/" + ], + "files": [ + "src/Framework/Assert/Functions.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -917,32 +1084,94 @@ "testing", "xunit" ], - "time": "2020-01-08T08:49:49+00:00" + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-08-08T05:12:01+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", + "name": "sebastian/code-unit", + "version": "1.0.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "c1e2df332c905079980b119c4db103117e5e5c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/c1e2df332c905079980b119c4db103117e5e5c90", + "reference": "c1e2df332c905079980b119c4db103117e5e5c90", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:50:45+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ee51f9bb0c6d8a43337055db3120829fa14da819" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ee51f9bb0c6d8a43337055db3120829fa14da819", + "reference": "ee51f9bb0c6d8a43337055db3120829fa14da819", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" } }, "autoload": { @@ -962,34 +1191,40 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:04:00+00:00" }, { "name": "sebastian/comparator", - "version": "3.0.2", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" + "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f", + "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f", "shasum": "" }, "require": { - "php": "^7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" + "php": "^7.3 || ^8.0", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1002,6 +1237,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1013,10 +1252,6 @@ { "name": "Bernhard Schussek", "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" } ], "description": "Provides the functionality to compare PHP values for equality", @@ -1026,33 +1261,39 @@ "compare", "equality" ], - "time": "2018-07-12T15:12:46+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:05:46+00:00" }, { - "name": "sebastian/diff", - "version": "3.0.2", + "name": "sebastian/complexity", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "33fcd6a26656c6546f70871244ecba4b4dced097" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/33fcd6a26656c6546f70871244ecba4b4dced097", + "reference": "33fcd6a26656c6546f70871244ecba4b4dced097", "shasum": "" }, "require": { - "php": "^7.1" + "nikic/php-parser": "^4.7", + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1066,12 +1307,65 @@ ], "authors": [ { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-25T14:01:34+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113", + "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], "description": "Diff implementation", @@ -1082,27 +1376,33 @@ "unidiff", "unified diff" ], - "time": "2019-02-04T06:01:07+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-30T04:46:02+00:00" }, { "name": "sebastian/environment", - "version": "4.2.3", + "version": "5.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" + "reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2", + "reference": "0a757cab9d5b7ef49a619f1143e6c9c1bc0fe9d2", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-posix": "*" @@ -1110,7 +1410,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1135,34 +1435,40 @@ "environment", "hhvm" ], - "time": "2019-11-20T08:46:58+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:07:24+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.2", + "version": "4.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" + "reference": "571d721db4aec847a0e59690b954af33ebf9f023" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/571d721db4aec847a0e59690b954af33ebf9f023", + "reference": "571d721db4aec847a0e59690b954af33ebf9f023", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" + "php": "^7.3 || ^8.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1202,30 +1508,36 @@ "export", "exporter" ], - "time": "2019-09-14T09:02:43+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:08:55+00:00" }, { "name": "sebastian/global-state", - "version": "3.0.0", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" + "reference": "22ae663c951bdc39da96603edc3239ed3a299097" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", - "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/22ae663c951bdc39da96603edc3239ed3a299097", + "reference": "22ae663c951bdc39da96603edc3239ed3a299097", "shasum": "" }, "require": { - "php": "^7.2", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": "^7.3 || ^8.0", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^8.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -1233,7 +1545,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1256,34 +1568,93 @@ "keywords": [ "global state" ], - "time": "2019-02-01T05:30:01+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-08-07T04:09:03+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "3.0.3", + "name": "sebastian/lines-of-code", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e02bf626f404b5daec382a7b8a6a4456e49017e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e02bf626f404b5daec382a7b8a6a4456e49017e5", + "reference": "e02bf626f404b5daec382a7b8a6a4456e49017e5", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "nikic/php-parser": "^4.6", + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-22T18:33:42+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/074fed2d0a6d08e1677dd8ce9d32aecb384917b8", + "reference": "074fed2d0a6d08e1677dd8ce9d32aecb384917b8", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, "autoload": { @@ -1303,122 +1674,33 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:11:32+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" + "reference": "127a46f6b057441b201253526f81d5406d6c7840" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/127a46f6b057441b201253526f81d5406d6c7840", + "reference": "127a46f6b057441b201253526f81d5406d6c7840", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "shasum": "" - }, - "require": { - "php": "^7.1" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { @@ -1441,34 +1723,150 @@ "email": "sebastian@phpunit.de" } ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2018-10-04T04:07:39+00:00" + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:12:55+00:00" }, { - "name": "sebastian/type", - "version": "1.1.3", + "name": "sebastian/recursion-context", + "version": "4.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", - "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/062231bf61d2b9448c4fa5a7643b5e1829c11d63", + "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63", "shasum": "" }, "require": { - "php": "^7.2" + "php": "^7.3 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:14:17+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0653718a5a629b065e91f774595267f8dc32e213" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0653718a5a629b065e91f774595267f8dc32e213", + "reference": "0653718a5a629b065e91f774595267f8dc32e213", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:16:22+00:00" + }, + { + "name": "sebastian/type", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "86991e2b33446cd96e648c18bcdb1e95afb2c05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/86991e2b33446cd96e648c18bcdb1e95afb2c05a", + "reference": "86991e2b33446cd96e648c18bcdb1e95afb2c05a", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" } }, "autoload": { @@ -1489,29 +1887,35 @@ ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", - "time": "2019-07-02T08:10:15+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-05T08:31:53+00:00" }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "626586115d0ed31cb71483be55beb759b5af5a3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/626586115d0ed31cb71483be55beb759b5af5a3c", + "reference": "626586115d0ed31cb71483be55beb759b5af5a3c", "shasum": "" }, "require": { - "php": ">=5.6" + "php": "^7.3 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1532,20 +1936,26 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-06-26T12:18:43+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.13.1", + "version": "v1.18.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", "shasum": "" }, "require": { @@ -1557,7 +1967,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -1590,27 +2004,41 @@ "polyfill", "portable" ], - "time": "2019-11-27T13:56:44+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.3", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + "reference": "75a63c33a8577608444246075ea0af0d052e452a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", + "reference": "75a63c33a8577608444246075ea0af0d052e452a", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -1630,28 +2058,35 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2020-07-12T23:59:07+00:00" }, { "name": "webmozart/assert", - "version": "1.6.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "vimeo/psalm": "<3.6.0" + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<3.9.1" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" @@ -1678,7 +2113,7 @@ "check", "validate" ], - "time": "2019-11-24T13:36:37+00:00" + "time": "2020-07-08T17:02:28+00:00" } ], "aliases": [], @@ -1689,5 +2124,6 @@ "platform": { "php": ">=7.0" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 6bd77e3..35a3533 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,28 +1,29 @@ - - - - ./test/tests/unit - - - ./test/tests/integration - - - - - ./src - - - - - + + + + ./src + + + + + + + + ./test/tests/unit + + + ./test/tests/integration + + + diff --git a/test/bootstrap.php b/test/bootstrap.php deleted file mode 100644 index d4132bc..0000000 --- a/test/bootstrap.php +++ /dev/null @@ -1,6 +0,0 @@ -addPsr4('WellRESTed\\Test\\', __DIR__ . '/src'); From 4485675c119fac74facb67cd4a98ba0d2974a4f6 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 8 Aug 2020 10:59:46 -0400 Subject: [PATCH 02/53] Use ProphecyTrait in tests with Prophecy mocks --- test/tests/unit/Routing/Route/PrefixRouteTest.php | 3 +++ test/tests/unit/Routing/Route/RegexRouteTest.php | 5 +++-- test/tests/unit/Routing/Route/RouteFactoryTest.php | 3 +++ test/tests/unit/Routing/Route/RouteTest.php | 3 +++ test/tests/unit/Routing/Route/StaticRouteTest.php | 3 +++ test/tests/unit/Routing/Route/TemplateRouteTest.php | 3 +++ test/tests/unit/Routing/RouterTest.php | 3 +++ test/tests/unit/ServerTest.php | 3 +++ test/tests/unit/Transmission/TransmitterTest.php | 3 +++ 9 files changed, 27 insertions(+), 2 deletions(-) diff --git a/test/tests/unit/Routing/Route/PrefixRouteTest.php b/test/tests/unit/Routing/Route/PrefixRouteTest.php index ef47262..dd884e2 100644 --- a/test/tests/unit/Routing/Route/PrefixRouteTest.php +++ b/test/tests/unit/Routing/Route/PrefixRouteTest.php @@ -2,6 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; +use Prophecy\PhpUnit\ProphecyTrait; use WellRESTed\Routing\Route\MethodMap; use WellRESTed\Routing\Route\PrefixRoute; use WellRESTed\Routing\Route\RouteInterface; @@ -9,6 +10,8 @@ use WellRESTed\Test\TestCase; class PrefixRouteTest extends TestCase { + use ProphecyTrait; + public function testTrimsAsteriskFromEndOfTarget() { $methodMap = $this->prophesize(MethodMap::class); diff --git a/test/tests/unit/Routing/Route/RegexRouteTest.php b/test/tests/unit/Routing/Route/RegexRouteTest.php index eede717..88410b2 100644 --- a/test/tests/unit/Routing/Route/RegexRouteTest.php +++ b/test/tests/unit/Routing/Route/RegexRouteTest.php @@ -2,8 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; -use PHPUnit\Framework\Error\Notice; -use PHPUnit\Framework\Error\Warning; +use Prophecy\PhpUnit\ProphecyTrait; use RuntimeException; use WellRESTed\Routing\Route\MethodMap; use WellRESTed\Routing\Route\RegexRoute; @@ -12,6 +11,8 @@ use WellRESTed\Test\TestCase; class RegexRouteTest extends TestCase { + use ProphecyTrait; + private $methodMap; public function setUp(): void diff --git a/test/tests/unit/Routing/Route/RouteFactoryTest.php b/test/tests/unit/Routing/Route/RouteFactoryTest.php index 1608eea..e7a18b2 100644 --- a/test/tests/unit/Routing/Route/RouteFactoryTest.php +++ b/test/tests/unit/Routing/Route/RouteFactoryTest.php @@ -2,6 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; +use Prophecy\PhpUnit\ProphecyTrait; use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Routing\Route\RouteFactory; use WellRESTed\Routing\Route\RouteInterface; @@ -9,6 +10,8 @@ use WellRESTed\Test\TestCase; class RouteFactoryTest extends TestCase { + use ProphecyTrait; + private $dispatcher; public function setUp(): void diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index 2e6d338..993e411 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -3,6 +3,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Server\RequestHandlerInterface; use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; @@ -12,6 +13,8 @@ use WellRESTed\Test\TestCase; class RouteTest extends TestCase { + use ProphecyTrait; + const TARGET = '/target'; private $methodMap; diff --git a/test/tests/unit/Routing/Route/StaticRouteTest.php b/test/tests/unit/Routing/Route/StaticRouteTest.php index 1ff3654..6ca6067 100644 --- a/test/tests/unit/Routing/Route/StaticRouteTest.php +++ b/test/tests/unit/Routing/Route/StaticRouteTest.php @@ -2,6 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; +use Prophecy\PhpUnit\ProphecyTrait; use WellRESTed\Routing\Route\MethodMap; use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\StaticRoute; @@ -9,6 +10,8 @@ use WellRESTed\Test\TestCase; class StaticRouteTest extends TestCase { + use ProphecyTrait; + public function testReturnsStaticType() { $methodMap = $this->prophesize(MethodMap::class); diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index 7f11ba9..c480db2 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -2,6 +2,7 @@ namespace WellRESTed\Test\Unit\Routing\Route; +use Prophecy\PhpUnit\ProphecyTrait; use WellRESTed\Routing\Route\MethodMap; use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\TemplateRoute; @@ -9,6 +10,8 @@ use WellRESTed\Test\TestCase; class TemplateRouteTest extends TestCase { + use ProphecyTrait; + private $methodMap; public function setUp(): void diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index a484f51..2587c51 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -3,6 +3,7 @@ namespace WellRESTed\Test\Unit\Routing; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; use WellRESTed\Dispatching\Dispatcher; use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; @@ -14,6 +15,8 @@ use WellRESTed\Test\TestCase; class RouterTest extends TestCase { + use ProphecyTrait; + private $factory; private $request; private $response; diff --git a/test/tests/unit/ServerTest.php b/test/tests/unit/ServerTest.php index 4e209c9..7dabfc2 100644 --- a/test/tests/unit/ServerTest.php +++ b/test/tests/unit/ServerTest.php @@ -3,6 +3,7 @@ namespace WellRESTed\Test\Unit; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; @@ -15,6 +16,8 @@ require_once __DIR__ . '/../../src/HeaderStack.php'; class ServerTest extends TestCase { + use ProphecyTrait; + private $transmitter; /** @var Server */ private $server; diff --git a/test/tests/unit/Transmission/TransmitterTest.php b/test/tests/unit/Transmission/TransmitterTest.php index 553b7ca..8f7ae47 100644 --- a/test/tests/unit/Transmission/TransmitterTest.php +++ b/test/tests/unit/Transmission/TransmitterTest.php @@ -3,6 +3,7 @@ namespace WellRESTed\Test\Unit\Transmission; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\StreamInterface; use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; @@ -14,6 +15,8 @@ require_once __DIR__ . "/../../../src/HeaderStack.php"; class TransmitterTest extends TestCase { + use ProphecyTrait; + private $request; private $response; private $body; From 2cf65def5c1060d213a2e2b8a0bc610b58e0a295 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 8 Aug 2020 11:31:47 -0400 Subject: [PATCH 03/53] Configure Psalm --- .gitattributes | 1 + composer.json | 3 +- composer.lock | 1462 ++++++++++++++++++++++++++++++++++++++++- docker/php/Dockerfile | 3 +- psalm.xml | 15 + 5 files changed, 1481 insertions(+), 3 deletions(-) create mode 100644 psalm.xml diff --git a/.gitattributes b/.gitattributes index c2412f7..aa941fb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,4 +8,5 @@ /docs export-ignore /test export-ignore /phpunit.xml.dist export-ignore +/psalm.xnk export-ignore /public export-ignore diff --git a/composer.json b/composer.json index 6430ef5..085901b 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ }, "require-dev": { "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9" + "phpunit/phpunit": "^9", + "vimeo/psalm": "^3.4" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 5fb2477..9daf443 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ee44c87f0246b5c26e6e51fc4b0c6b4c", + "content-hash": "591aa22398b48f0252eca221eea45e04", "packages": [ { "name": "psr/http-message", @@ -164,6 +164,290 @@ } ], "packages-dev": [ + { + "name": "amphp/amp", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "f220a51458bf4dd0dedebb171ac3457813c72bbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/f220a51458bf4dd0dedebb171ac3457813c72bbc", + "reference": "f220a51458bf4dd0dedebb171ac3457813c72bbc", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6.0.9 | ^7", + "psalm/phar": "^3.11@dev", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-07-14T21:47:18+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/f0c20cf598a958ba2aa8c6e5a71c697d652c7088", + "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.4", + "friendsofphp/php-cs-fixer": "^2.3", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6 || ^7 || ^8", + "psalm/phar": "^3.11.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "time": "2020-06-29T18:35:05+00:00" + }, + { + "name": "composer/semver", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3426bd5efa8a12d230824536c42a8a4ad30b7940", + "reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.19", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-05-26T18:22:04+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51", + "reference": "fa2aaf99e2087f013a14f7432c1cd2dd7d8f1f51", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-06-04T11:16:35+00:00" + }, { "name": "doctrine/instantiator", "version": "1.3.1", @@ -234,6 +518,94 @@ ], "time": "2020-05-29T17:27:14+00:00" }, + { + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40", + "shasum": "" + }, + "require": { + "netresearch/jsonmapper": "^1.0 || ^2.0", + "php": ">=7.0", + "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "time": "2020-03-11T15:21:41+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpstan/phpstan": "*", + "phpunit/phpunit": "^6.3", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "time": "2019-06-23T21:03:50+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.10.1", @@ -288,6 +660,52 @@ ], "time": "2020-06-29T13:22:24+00:00" }, + { + "name": "netresearch/jsonmapper", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0", + "squizlabs/php_codesniffer": "~3.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "time": "2020-04-16T18:48:43+00:00" + }, { "name": "nikic/php-parser", "version": "v4.7.0", @@ -340,6 +758,116 @@ ], "time": "2020-07-25T13:18:53+00:00" }, + { + "name": "ocramius/package-versions", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "94c9d42a466c57f91390cdd49c81313264f49d85" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/94c9d42a466c57f91390cdd49c81313264f49d85", + "reference": "94c9d42a466c57f91390cdd49c81313264f49d85", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7.4.0" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "doctrine/coding-standard": "^7.0.2", + "ext-zip": "^1.15.0", + "infection/infection": "^0.15.3", + "phpunit/phpunit": "^9.1.1", + "vimeo/psalm": "^3.9.3" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.99.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "funding": [ + { + "url": "https://github.com/Ocramius", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ocramius/package-versions", + "type": "tidelift" + } + ], + "time": "2020-06-22T14:15:44+00:00" + }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "time": "2019-03-29T20:06:56+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.1", @@ -1096,6 +1624,102 @@ ], "time": "2020-08-08T05:12:01+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/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.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": "2020-03-23T09:12:05+00:00" + }, { "name": "sebastian/code-unit", "version": "1.0.5", @@ -1944,6 +2568,99 @@ ], "time": "2020-06-26T12:18:43+00:00" }, + { + "name": "symfony/console", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "2226c68009627934b8cfc01260b4d287eab070df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/2226c68009627934b8cfc01260b4d287eab070df", + "reference": "2226c68009627934b8cfc01260b4d287eab070df", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", + "symfony/service-contracts": "^1.1|^2", + "symfony/string": "^5.1" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "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 Console Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-06T13:23:11+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.18.1", @@ -2020,6 +2737,559 @@ ], "time": "2020-07-14T12:35:20+00:00" }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b740103edbdcc39602239ee8860f0f45a8eb9aa5", + "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "shasum": "" + }, + "require": { + "php": ">=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "58c7475e5457c5492c26cc740cc0ad7464be9442" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/58c7475e5457c5492c26cc740cc0ad7464be9442", + "reference": "58c7475e5457c5492c26cc740cc0ad7464be9442", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-06T13:23:11+00:00" + }, + { + "name": "symfony/string", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "f629ba9b611c76224feb21fe2bcbf0b6f992300b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/f629ba9b611c76224feb21fe2bcbf0b6f992300b", + "reference": "f629ba9b611c76224feb21fe2bcbf0b6f992300b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony String component", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-08T08:27:49+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.0", @@ -2066,6 +3336,103 @@ ], "time": "2020-07-12T23:59:07+00:00" }, + { + "name": "vimeo/psalm", + "version": "3.12.2", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "7c7ebd068f8acaba211d4a2c707c4ba90874fa26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/7c7ebd068f8acaba211d4a2c707c4ba90874fa26", + "reference": "7c7ebd068f8acaba211d4a2c707c4ba90874fa26", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.1", + "amphp/byte-stream": "^1.5", + "composer/semver": "^1.4 || ^2.0 || ^3.0", + "composer/xdebug-handler": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.4", + "netresearch/jsonmapper": "^1.0 || ^2.0", + "nikic/php-parser": "^4.3", + "ocramius/package-versions": "^1.2", + "openlss/lib-array2xml": "^1.0", + "php": "^7.1.3|^8", + "sebastian/diff": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "webmozart/glob": "^4.1", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "amphp/amp": "^2.4.2", + "bamarni/composer-bin-plugin": "^1.2", + "brianium/paratest": "^4.0.0", + "ext-curl": "*", + "php-coveralls/php-coveralls": "^2.2", + "phpmyadmin/sql-parser": "5.1.0", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^7.5.16 || ^8.5 || ^9.0", + "psalm/plugin-phpunit": "^0.10", + "slevomat/coding-standard": "^5.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3" + }, + "suggest": { + "ext-igbinary": "^2.0.5" + }, + "bin": [ + "psalm", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor", + "psalter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psalm\\": "src/Psalm/" + }, + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "time": "2020-07-03T16:59:07+00:00" + }, { "name": "webmozart/assert", "version": "1.9.1", @@ -2114,6 +3481,99 @@ "validate" ], "time": "2020-07-08T17:02:28+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/glob.git", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0", + "webmozart/path-util": "^2.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1", + "symfony/filesystem": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "time": "2015-12-29T11:14:33+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "time": "2015-12-17T08:42:14+00:00" } ], "aliases": [], diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 1f4bfc1..2030c9c 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -32,8 +32,9 @@ COPY ./test /usr/local/src/wellrested/test COPY ./composer.* /usr/local/src/wellrested/ COPY ./phpunit.xml.dist /usr/local/src/wellrested/ -# Add symlink for phpunit for easier running +# Add symlinks for phpunit and psalm for easier running RUN ln -s /usr/local/src/wellrested/vendor/bin/phpunit /usr/local/bin/phpunit +RUN ln -s /usr/local/src/wellrested/vendor/bin/psalm /usr/local/bin/psalm WORKDIR /usr/local/src/wellrested diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..3e4e3d0 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + From 08ddb0aa2fa88eab90977bda0cebc2b107d7a936 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 8 Aug 2020 12:05:33 -0400 Subject: [PATCH 04/53] Fix issues detected by Psalm --- src/Dispatching/DispatchStack.php | 2 +- src/Message/Message.php | 2 +- src/Message/NullStream.php | 5 +++-- src/Message/Request.php | 2 +- src/Message/Stream.php | 8 +++++--- src/Routing/Router.php | 30 +++++++++++++++--------------- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/Dispatching/DispatchStack.php b/src/Dispatching/DispatchStack.php index 76cdc01..17ae0e2 100644 --- a/src/Dispatching/DispatchStack.php +++ b/src/Dispatching/DispatchStack.php @@ -26,7 +26,7 @@ class DispatchStack implements DispatchStackInterface * Push a new middleware onto the stack. * * @param mixed $middleware Middleware to dispatch in sequence - * @return self + * @return static */ public function add($middleware) { diff --git a/src/Message/Message.php b/src/Message/Message.php index 8d88645..0bdd913 100644 --- a/src/Message/Message.php +++ b/src/Message/Message.php @@ -101,7 +101,7 @@ abstract class Message implements MessageInterface * While header names are not case-sensitive, getHeaders() will preserve the * exact case in which headers were originally specified. * - * @return array Returns an associative array of the message's headers. + * @return string[][] Returns an associative array of the message's headers. */ public function getHeaders() { diff --git a/src/Message/NullStream.php b/src/Message/NullStream.php index bfbc3de..468ad36 100644 --- a/src/Message/NullStream.php +++ b/src/Message/NullStream.php @@ -51,9 +51,10 @@ class NullStream implements StreamInterface } /** - * Returns 0 + * Returns the current position of the file read/write pointer * - * @return int|bool Position of the file pointer or false on error. + * @return int Position of the file pointer + * @throws \RuntimeException on error. */ public function tell() { diff --git a/src/Message/Request.php b/src/Message/Request.php index 114c9f3..2a95ae6 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -212,7 +212,7 @@ class Request extends Message implements RequestInterface /** * @param string $method - * @return static + * @return string * @throws \InvalidArgumentException */ private function getValidatedMethod($method) diff --git a/src/Message/Stream.php b/src/Message/Stream.php index 54ba4e6..a37df74 100644 --- a/src/Message/Stream.php +++ b/src/Message/Stream.php @@ -67,7 +67,9 @@ class Stream implements StreamInterface */ public function close() { - fclose($this->resource); + $resource = $this->resource; + fclose($resource); + $this->resource = null; } /** @@ -79,9 +81,9 @@ class Stream implements StreamInterface */ public function detach() { - $stream = $this->resource; + $resource = $this->resource; $this->resource = null; - return $stream; + return $resource; } /** diff --git a/src/Routing/Router.php b/src/Routing/Router.php index d18d337..4ac8164 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -203,7 +203,7 @@ class Router } /** - * @param DispatcherInterface + * @param DispatcherInterface $dispatcher * @return RouteFactoryInterface */ protected function getRouteFactory($dispatcher) @@ -266,21 +266,21 @@ class Router } ); - if ($matches) { - if (count($matches) > 0) { - // If there are multiple matches, sort them to find the one with - // the longest string length. - $compareByLength = function ($a, $b) { - return strlen($b) - strlen($a); - }; - usort($matches, $compareByLength); - } - /** @var string $bestMatch */ - $bestMatch = $matches[0]; - $route = $this->prefixRoutes[$bestMatch]; - return $route; + if (!$matches) { + return null; } - return null; + + // If there are multiple matches, sort them to find the one with the + // longest string length. + if (count($matches) > 1) { + $compareByLength = function ($a, $b) { + return strlen($b) - strlen($a); + }; + usort($matches, $compareByLength); + } + + $bestMatch = $matches[0]; + return $this->prefixRoutes[$bestMatch]; } private function startsWith($haystack, $needle) From 29cfa34f1795d0f8809001f8681f2b5f0347097e Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 10:52:47 -0400 Subject: [PATCH 05/53] Set minimum PHP version to 7.2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 085901b..6f415d9 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "php": ">=7.0", + "php": ">=7.2", "psr/http-message": "~1.0", "psr/http-server-handler": "~1.0", "psr/http-server-middleware": "~1.0" From fe780e6b92595af1a7478d0291e8cae86ffe0862 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 10:54:26 -0400 Subject: [PATCH 06/53] Set Psalm error level to 3; fix possibly null reason phrase in Response --- psalm.xml | 2 +- src/Message/Response.php | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/psalm.xml b/psalm.xml index 3e4e3d0..30258a7 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,6 +1,6 @@ "Not Extended", 511 => "Network Authentication Required" ]; - if (isset($reasonPhraseLookup[$statusCode])) { - return $reasonPhraseLookup[$statusCode]; - } - return null; + return $reasonPhraseLookup[$statusCode] ?? ''; } } From a7b08ad8a3ff4f70b34a68085b9dc4283c325e3a Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 10:55:37 -0400 Subject: [PATCH 07/53] Stream detects read/write more accurately; fix issues after detach() --- src/Message/Stream.php | 91 ++++++++++++++++--- test/tests/unit/Message/StreamTest.php | 119 ++++++++++++++++++++++++- 2 files changed, 194 insertions(+), 16 deletions(-) diff --git a/src/Message/Stream.php b/src/Message/Stream.php index a37df74..4543e38 100644 --- a/src/Message/Stream.php +++ b/src/Message/Stream.php @@ -6,7 +6,10 @@ use Psr\Http\Message\StreamInterface; class Stream implements StreamInterface { - /** @var resource */ + private const READABLE_MODES = ['r', 'r+', 'w+', 'a+', 'x+', 'c+']; + private const WRITABLE_MODES = ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+']; + + /** @var resource|null */ private $resource; /** @@ -46,18 +49,16 @@ class Stream implements StreamInterface */ public function __toString() { - $string = ""; try { if ($this->isSeekable()) { - rewind($this->resource); + $this->rewind(); } - $string = $this->getContents(); - // @codeCoverageIgnoreStart + return $this->getContents(); } catch (\Exception $e) { - // @codeCoverageIgnoreEnd - // Silence exceptions in order to conform with PHP's string casting operations. + // Silence exceptions in order to conform with PHP's string casting + // operations. + return ''; } - return $string; } /** @@ -67,6 +68,10 @@ class Stream implements StreamInterface */ public function close() { + if ($this->resource === null) { + return; + } + $resource = $this->resource; fclose($resource); $this->resource = null; @@ -93,6 +98,10 @@ class Stream implements StreamInterface */ public function getSize() { + if ($this->resource === null) { + return null; + } + $statistics = fstat($this->resource); if ($statistics && $statistics["size"]) { return $statistics["size"]; @@ -108,6 +117,10 @@ class Stream implements StreamInterface */ public function tell() { + if ($this->resource === null) { + throw new \RuntimeException("Unable to retrieve current position of detached stream."); + } + $position = ftell($this->resource); if ($position === false) { throw new \RuntimeException("Unable to retrieve current position of file pointer."); @@ -122,6 +135,10 @@ class Stream implements StreamInterface */ public function eof() { + if ($this->resource === null) { + return true; + } + return feof($this->resource); } @@ -132,6 +149,10 @@ class Stream implements StreamInterface */ public function isSeekable() { + if ($this->resource === null) { + return false; + } + return $this->getMetadata("seekable") == 1; } @@ -149,6 +170,10 @@ class Stream implements StreamInterface */ public function seek($offset, $whence = SEEK_SET) { + if ($this->resource === null) { + throw new \RuntimeException("Unable to seek detached stream."); + } + $result = -1; if ($this->isSeekable()) { $result = fseek($this->resource, $offset, $whence); @@ -170,12 +195,16 @@ class Stream implements StreamInterface */ public function rewind() { + if ($this->resource === null) { + throw new \RuntimeException("Unable to seek detached stream."); + } + $result = false; if ($this->isSeekable()) { $result = rewind($this->resource); } if ($result === false) { - throw new \RuntimeException("Unable to seek to position."); + throw new \RuntimeException("Unable to rewind."); } } @@ -186,8 +215,12 @@ class Stream implements StreamInterface */ public function isWritable() { - $mode = $this->getMetadata("mode"); - return $mode[0] !== "r" || strpos($mode, "+") !== false; + if ($this->resource === null) { + return false; + } + + $mode = $this->getBasicMode(); + return in_array($mode, self::WRITABLE_MODES); } /** @@ -199,6 +232,10 @@ class Stream implements StreamInterface */ public function write($string) { + if ($this->resource === null) { + throw new \RuntimeException("Unable to write to detached stream."); + } + $result = false; if ($this->isWritable()) { $result = fwrite($this->resource, $string); @@ -216,8 +253,12 @@ class Stream implements StreamInterface */ public function isReadable() { - $mode = $this->getMetadata("mode"); - return strpos($mode, "r") !== false || strpos($mode, "+") !== false; + if ($this->resource === null) { + return false; + } + + $mode = $this->getBasicMode(); + return in_array($mode, self::READABLE_MODES); } /** @@ -232,6 +273,10 @@ class Stream implements StreamInterface */ public function read($length) { + if ($this->resource === null) { + throw new \RuntimeException("Unable to read to detached stream."); + } + $result = false; if ($this->isReadable()) { $result = fread($this->resource, $length); @@ -251,6 +296,10 @@ class Stream implements StreamInterface */ public function getContents() { + if ($this->resource === null) { + throw new \RuntimeException("Unable to read to detached stream."); + } + $result = false; if ($this->isReadable()) { $result = stream_get_contents($this->resource); @@ -268,13 +317,17 @@ class Stream implements StreamInterface * stream_get_meta_data() function. * * @link http://php.net/manual/en/function.stream-get-meta-data.php - * @param string $key Specific metadata to retrieve. + * @param string|null $key Specific metadata to retrieve. * @return array|mixed|null Returns an associative array if no key is * provided. Returns a specific key value if a key is provided and the * value is found, or null if the key is not found. */ public function getMetadata($key = null) { + if ($this->resource === null) { + return null; + } + $metadata = stream_get_meta_data($this->resource); if ($key === null) { return $metadata; @@ -282,4 +335,14 @@ class Stream implements StreamInterface return $metadata[$key]; } } + + /** + * @return string Mode for the resource reduced to only the characters + * r, w, a, x, c, and + needed to determine readable and writeable status. + */ + private function getBasicMode() + { + $mode = $this->getMetadata('mode') ?? ''; + return preg_replace('/[^rwaxc+]/', '', $mode); + } } diff --git a/test/tests/unit/Message/StreamTest.php b/test/tests/unit/Message/StreamTest.php index 714b981..b89db9f 100644 --- a/test/tests/unit/Message/StreamTest.php +++ b/test/tests/unit/Message/StreamTest.php @@ -13,14 +13,14 @@ class StreamTest extends TestCase private $resourceDevNull; private $content = "Hello, world!"; - public function setUp(): void + protected function setUp(): void { $this->resource = fopen("php://memory", "w+"); $this->resourceDevNull = fopen("/dev/null", "r"); fwrite($this->resource, $this->content); } - public function tearDown(): void + protected function tearDown(): void { if (is_resource($this->resource)) { fclose($this->resource); @@ -269,4 +269,119 @@ class StreamTest extends TestCase ["c+", true, true] ]; } + + // ------------------------------------------------------------------------- + // After Detach + + public function testAfterDetachToStringReturnsEmptyString(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertEquals('', (string) $stream); + } + + public function testAfterDetachCloseDoesNothing(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $stream->close(); + $this->assertTrue(true); + } + + public function testAfterDetachDetachReturnsNull(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertNull($stream->detach()); + } + + public function testAfterDetachGetSizeReturnsNull(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertNull($stream->getSize()); + } + + public function testAfterDetachTellThrowsRuntimeException(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->expectException(RuntimeException::class); + $stream->tell(); + } + + public function testAfterDetachEofReturnsTrue(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertTrue($stream->eof()); + } + + public function testAfterDetachIsSeekableReturnsFalse(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertFalse($stream->isSeekable()); + } + + public function testAfterDetachSeekThrowsRuntimeException(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->expectException(RuntimeException::class); + $stream->seek(0); + } + + public function testAfterDetachRewindThrowsRuntimeException(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->expectException(RuntimeException::class); + $stream->rewind(); + } + + public function testAfterDetachIsWritableReturnsFalse(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertFalse($stream->isWritable()); + } + + public function testAfterDetachWriteThrowsRuntimeException(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->expectException(RuntimeException::class); + $stream->write('bork'); + } + + public function testAfterDetachIsReadableReturnsFalse(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertFalse($stream->isReadable()); + } + + public function testAfterDetachReadThrowsRuntimeException(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->expectException(RuntimeException::class); + $stream->read(10); + } + + public function testAfterDetachGetContentsThrowsRuntimeException(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->expectException(RuntimeException::class); + $stream->getContents(); + } + + public function testAfterDetachGetMetadataReturnsNull(): void + { + $stream = new Stream($this->resource); + $stream->detach(); + $this->assertNull($stream->getMetadata()); + } } From e9fb474eb726288a126a84907d765ea6701b80f0 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 11:08:33 -0400 Subject: [PATCH 08/53] Fix minor issues found by Psalm --- src/Routing/Route/TemplateRoute.php | 9 ++++++++- src/Routing/Router.php | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Routing/Route/TemplateRoute.php b/src/Routing/Route/TemplateRoute.php index 3649633..8b71790 100644 --- a/src/Routing/Route/TemplateRoute.php +++ b/src/Routing/Route/TemplateRoute.php @@ -29,7 +29,7 @@ class TemplateRoute extends Route * Examines a request target to see if it is a match for the route. * * @param string $requestTarget - * @return boolean + * @return bool */ public function matchesRequestTarget($requestTarget) { @@ -49,9 +49,16 @@ class TemplateRoute extends Route return false; } + /** + * @param $requestTarget + * @return bool + */ private function matchesStartOfRequestTarget($requestTarget) { $firstVarPos = strpos($this->target, "{"); + if ($firstVarPos === false) { + return $requestTarget === $this->target; + } return (substr($requestTarget, 0, $firstVarPos) === substr($this->target, 0, $firstVarPos)); } diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 4ac8164..b836538 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -12,7 +12,7 @@ use WellRESTed\Routing\Route\RouteInterface; class Router { - /** @var string attribute name for matched path variables */ + /** @var string|null Attribute name for matched path variables */ private $pathVariablesAttributeName; /** @var DispatcherInterface */ private $dispatcher; @@ -42,7 +42,7 @@ class Router * stored with the name. The value will be an array containing all of the * path variables. * - * @param DispatcherInterface $dispatcher + * @param DispatcherInterface|null $dispatcher * Instance to use for dispatching middleware and handlers. * @param string|null $pathVariablesAttributeName * Attribute name for matched path variables. A null value sets From ecc077a1bef0a7a17b4c9ac833c5c659f362d8f5 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 11:45:41 -0400 Subject: [PATCH 09/53] Add type hints to Dispatch classes --- psalm.xml | 3 ++- src/Dispatching/DispatchStack.php | 19 ++++++++++++++++--- src/Dispatching/Dispatcher.php | 4 ++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/psalm.xml b/psalm.xml index 30258a7..030ec2f 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,7 +1,8 @@ stack) as $middleware) { - $chain = function ($request, $response) use ($dispatcher, $middleware, $chain) { - return $dispatcher->dispatch($middleware, $request, $response, $chain); + $chain = function ( + ServerRequestInterface $request, + ResponseInterface $response + ) use ($dispatcher, $middleware, $chain): ResponseInterface { + return $dispatcher->dispatch( + $middleware, + $request, + $response, + $chain + ); }; } diff --git a/src/Dispatching/Dispatcher.php b/src/Dispatching/Dispatcher.php index 5e6a76f..f420c4f 100644 --- a/src/Dispatching/Dispatcher.php +++ b/src/Dispatching/Dispatcher.php @@ -67,6 +67,10 @@ class Dispatcher implements DispatcherInterface } } + /** + * @param mixed[] $dispatchables + * @return DispatchStack + */ protected function getDispatchStack($dispatchables) { $stack = new DispatchStack($this); From bdc5ac40d9a7a286af99fe7d630c1f89f496d2bc Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 13:08:50 -0400 Subject: [PATCH 10/53] Add notes to .gitignore --- .gitignore | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 88bfaac..1d41a9c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,9 +18,5 @@ preview # PhpStorm workspace.xml -# Vagrant -.vagrant/ - -# Vagrant sandbox site files. -/htdocs/ -/autoload/ +# Local scratch files +notes \ No newline at end of file From 7ade042b4bb87fef9972bf352ab53017c0914290 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 13:10:14 -0400 Subject: [PATCH 11/53] Change Request constructor signature Various updates to Message classes --- psalm.xml | 12 +++++++ src/Message/Message.php | 38 +++++++++++++------- src/Message/NullStream.php | 2 ++ src/Message/Request.php | 30 ++++++++-------- src/Message/Response.php | 9 +++-- src/Message/ServerRequest.php | 46 ++++++++++++++----------- test/tests/unit/Message/RequestTest.php | 25 +++++++++----- 7 files changed, 101 insertions(+), 61 deletions(-) diff --git a/psalm.xml b/psalm.xml index 030ec2f..9b0f03a 100644 --- a/psalm.xml +++ b/psalm.xml @@ -13,4 +13,16 @@ + + + + + + + + + + + + diff --git a/src/Message/Message.php b/src/Message/Message.php index 0bdd913..b5e1a5e 100644 --- a/src/Message/Message.php +++ b/src/Message/Message.php @@ -28,11 +28,13 @@ abstract class Message implements MessageInterface * * @param array $headers Associative array with header field names as * (string) keys and lists of header field values (string[]) as values. - * @param StreamInterface $body A stream representation of the message + * @param StreamInterface|null $body A stream representation of the message * entity body */ - public function __construct(array $headers = null, StreamInterface $body = null) - { + public function __construct( + array $headers = [], + ?StreamInterface $body = null + ) { $this->headers = new HeaderCollection(); if ($headers) { foreach ($headers as $name => $values) { @@ -265,22 +267,32 @@ abstract class Message implements MessageInterface // ------------------------------------------------------------------------ - private function getValidatedHeaders($name, $value) + /** + * @param mixed $name + * @param mixed|mixed[] $values + * @return string[] + * @throws \InvalidArgumentException Name is not a string or value is not + * a string or array of strings + */ + private function getValidatedHeaders($name, $values) { - $is_allowed = function ($item) { - return is_string($item) || is_numeric($item); - }; - if (!is_string($name)) { throw new \InvalidArgumentException('Header name must be a string'); } - if ($is_allowed($value)) { - return [$value]; - } elseif (is_array($value) && count($value) === count(array_filter($value, $is_allowed))) { - return $value; - } else { + if (!is_array($values)) { + $values = [$values]; + } + + $isNotStringOrNumber = function ($item): bool { + return !(is_string($item) || is_numeric($item)); + }; + + $invalid = array_filter($values, $isNotStringOrNumber); + if ($invalid) { throw new \InvalidArgumentException('Header values must be a string or string[]'); } + + return array_map('strval', $values); } } diff --git a/src/Message/NullStream.php b/src/Message/NullStream.php index 468ad36..bf3a34d 100644 --- a/src/Message/NullStream.php +++ b/src/Message/NullStream.php @@ -91,6 +91,7 @@ class NullStream implements StreamInterface * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to * offset bytes SEEK_CUR: Set position to current location plus offset * SEEK_END: Set position to end-of-stream plus offset. + * @return void * @throws \RuntimeException on failure. */ public function seek($offset, $whence = SEEK_SET) @@ -103,6 +104,7 @@ class NullStream implements StreamInterface * * @see seek() * @link http://www.php.net/manual/en/function.fseek.php + * @return void * @throws \RuntimeException on failure. */ public function rewind() diff --git a/src/Message/Request.php b/src/Message/Request.php index 2a95ae6..412bc98 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -22,7 +22,7 @@ class Request extends Message implements RequestInterface { /** @var string */ protected $method; - /** @var string */ + /** @var string|null */ protected $requestTarget; /** @var UriInterface */ protected $uri; @@ -33,26 +33,24 @@ class Request extends Message implements RequestInterface * Create a new Request. * * @see \WellRESTed\Message\Message - * @param UriInterface $uri + * @param string|UriInterface $uri * @param string $method * @param array $headers - * @param StreamInterface $body + * @param StreamInterface|null $body */ public function __construct( - UriInterface $uri = null, - $method = "GET", - array $headers = null, - StreamInterface $body = null + string $method = 'GET', + $uri = '', + array $headers = [], + ?StreamInterface $body = null ) { parent::__construct($headers, $body); - - if ($uri !== null) { - $this->uri = $uri; - } else { - $this->uri = new Uri(); - } - $this->method = $method; + if (!($uri instanceof UriInterface)) { + $uri = new Uri($uri); + } + $this->uri = $uri; + $this->requestTarget = null; } public function __clone() @@ -83,7 +81,7 @@ class Request extends Message implements RequestInterface public function getRequestTarget() { // Use the explicitly set request target first. - if (isset($this->requestTarget)) { + if ($this->requestTarget !== null) { return $this->requestTarget; } @@ -211,7 +209,7 @@ class Request extends Message implements RequestInterface // ------------------------------------------------------------------------ /** - * @param string $method + * @param mixed $method * @return string * @throws \InvalidArgumentException */ diff --git a/src/Message/Response.php b/src/Message/Response.php index 7f5d586..aca9c0c 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -36,10 +36,13 @@ class Response extends Message implements ResponseInterface * @see \WellRESTed\Message\Message * @param int $statusCode * @param array $headers - * @param StreamInterface $body + * @param StreamInterface|null $body */ - public function __construct($statusCode = 500, array $headers = null, StreamInterface $body = null) - { + public function __construct( + int $statusCode = 500, + array $headers = [], + ?StreamInterface $body = null + ) { parent::__construct($headers, $body); $this->statusCode = $statusCode; $this->reasonPhrase = $this->getDefaultReasonPhraseForStatusCode($statusCode); diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index 49cc798..8e8e458 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -5,6 +5,7 @@ namespace WellRESTed\Message; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; +use Psr\Http\Message\UriInterface; /** * Representation of an incoming, server-side HTTP request. @@ -336,9 +337,13 @@ class ServerRequest extends Request implements ServerRequestInterface // ------------------------------------------------------------------------ - protected function readFromServerRequest(array $attributes = null) + /** + * @param array $attributes + * @return void + */ + protected function readFromServerRequest(array $attributes = []) { - $this->attributes = $attributes ?: []; + $this->attributes = $attributes; $this->serverParams = $_SERVER; $this->cookieParams = $_COOKIE; $this->readUploadedFiles($_FILES); @@ -367,7 +372,7 @@ class ServerRequest extends Request implements ServerRequestInterface } } - protected function readUploadedFiles($input) + protected function readUploadedFiles(array $input): void { $uploadedFiles = []; foreach ($input as $name => $value) { @@ -376,8 +381,11 @@ class ServerRequest extends Request implements ServerRequestInterface $this->uploadedFiles = $uploadedFiles; } - protected function addUploadedFilesToBranch(&$branch, $name, $value) - { + protected function addUploadedFilesToBranch( + array &$branch, + string $name, + array $value + ): void { // Check for each of the expected keys. if (isset($value["name"], $value["type"], $value["tmp_name"], $value["error"], $value["size"])) { // This is a file. It may be a single file, or a list of files. @@ -419,7 +427,7 @@ class ServerRequest extends Request implements ServerRequestInterface } } - protected function readUri() + protected function readUri(): UriInterface { $uri = ""; @@ -449,7 +457,7 @@ class ServerRequest extends Request implements ServerRequestInterface * @return static * @static */ - public static function getServerRequest(array $attributes = null) + public static function getServerRequest(array $attributes = []) { $request = new static(); $request->readFromServerRequest($attributes); @@ -480,28 +488,22 @@ class ServerRequest extends Request implements ServerRequestInterface protected function getServerRequestHeaders() { // http://www.php.net/manual/en/function.getallheaders.php#84262 - $headers = array(); + $headers = []; foreach ($_SERVER as $name => $value) { if (substr($name, 0, 5) === "HTTP_") { $name = $this->normalizeHeaderName(substr($name, 5)); - $headers[$name] = $value; - } elseif ($this->isContentHeader($name, $value)) { + $headers[$name] = trim($value); + } elseif ($this->isContentHeader($name) && !empty(trim($value))) { $name = $this->normalizeHeaderName($name); - $headers[$name] = $value; + $headers[$name] = trim($value); } } return $headers; } - /** - * @param $name - * @param $value - * @return bool - */ - private function isContentHeader($name, $value) + private function isContentHeader(string $name): bool { - return ($name === "CONTENT_LENGTH" || $name === "CONTENT_TYPE") - && trim($value); + return ($name === 'CONTENT_LENGTH' || $name === 'CONTENT_TYPE'); } /** @@ -540,7 +542,11 @@ class ServerRequest extends Request implements ServerRequestInterface return true; } - private function isValidUploadedFilesBranch($branch) + /** + * @param UploadedFileInterface|array $branch + * @return bool + */ + private function isValidUploadedFilesBranch($branch): bool { if (is_array($branch)) { // Branch. diff --git a/test/tests/unit/Message/RequestTest.php b/test/tests/unit/Message/RequestTest.php index 4d3223d..8b8cb9f 100644 --- a/test/tests/unit/Message/RequestTest.php +++ b/test/tests/unit/Message/RequestTest.php @@ -19,32 +19,39 @@ class RequestTest extends TestCase $this->assertNotNull($request); } + public function testCreatesInstanceWithMethod() + { + $method = 'POST'; + $request = new Request($method); + $this->assertSame($method, $request->getMethod()); + } + public function testCreatesInstanceWithUri() { $uri = new Uri(); - $request = new Request($uri); + $request = new Request('GET', $uri); $this->assertSame($uri, $request->getUri()); } - public function testCreatesInstanceWithMethod() + public function testCreatesInstanceWithStringUri() { - $method = "POST"; - $request = new Request(null, $method); - $this->assertSame($method, $request->getMethod()); + $uri = 'http://localhost:8080'; + $request = new Request('GET', $uri); + $this->assertSame($uri, (string) $request->getUri()); } public function testSetsHeadersOnConstruction() { - $request = new Request(null, null, [ - "X-foo" => ["bar","baz"] + $request = new Request('GET', '/', [ + 'X-foo' => ['bar', 'baz'] ]); - $this->assertEquals(["bar","baz"], $request->getHeader("X-foo")); + $this->assertEquals(['bar', 'baz'], $request->getHeader('X-foo')); } public function testSetsBodyOnConstruction() { $body = new NullStream(); - $request = new Request(null, null, [], $body); + $request = new Request('GET', '/', [], $body); $this->assertSame($body, $request->getBody()); } From c339512f012e714bb63f018eef51c122718551a5 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 13:29:05 -0400 Subject: [PATCH 12/53] Add type hints to Stream, UploadedFile, and Uri --- psalm.xml | 1 + src/Message/Stream.php | 2 + src/Message/UploadedFile.php | 16 +++++- src/Message/Uri.php | 60 ++++++++++---------- test/tests/unit/Message/UploadedFileTest.php | 7 ++- 5 files changed, 51 insertions(+), 35 deletions(-) diff --git a/psalm.xml b/psalm.xml index 9b0f03a..1f59fbb 100644 --- a/psalm.xml +++ b/psalm.xml @@ -17,6 +17,7 @@ + diff --git a/src/Message/Stream.php b/src/Message/Stream.php index 4543e38..7bcd6f9 100644 --- a/src/Message/Stream.php +++ b/src/Message/Stream.php @@ -166,6 +166,7 @@ class Stream implements StreamInterface * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to * offset bytes SEEK_CUR: Set position to current location plus offset * SEEK_END: Set position to end-of-stream plus offset. + * @return void * @throws \RuntimeException on failure. */ public function seek($offset, $whence = SEEK_SET) @@ -191,6 +192,7 @@ class Stream implements StreamInterface * * @see seek() * @link http://www.php.net/manual/en/function.fseek.php + * @return void * @throws \RuntimeException on failure. */ public function rewind() diff --git a/src/Message/UploadedFile.php b/src/Message/UploadedFile.php index d5cfc9b..aa8094e 100644 --- a/src/Message/UploadedFile.php +++ b/src/Message/UploadedFile.php @@ -10,12 +10,19 @@ use Psr\Http\Message\UploadedFileInterface; */ class UploadedFile implements UploadedFileInterface { + /** @var string */ private $clientFilename; + /** @var string */ private $clientMediaType; + /** @var int */ private $error; + /** @var bool */ private $moved = false; + /** @var int */ private $size; + /** @var StreamInterface */ private $stream; + /** @var string|null */ private $tmpName; /** @@ -57,10 +64,11 @@ class UploadedFile implements UploadedFileInterface $this->size = $size; if (file_exists($tmpName)) { + $this->stream = new Stream(fopen($tmpName, 'r')); $this->tmpName = $tmpName; - $this->stream = new Stream(fopen($tmpName, "r")); } else { $this->stream = new NullStream(); + $this->tmpName = null; } } @@ -82,8 +90,11 @@ class UploadedFile implements UploadedFileInterface */ public function getStream() { + if ($this->tmpName === null) { + throw new \RuntimeException("Unable to read uploaded file."); + } if ($this->moved) { - throw new \RuntimeException("File has already been moved"); + throw new \RuntimeException("File has already been moved."); } if (php_sapi_name() !== "cli" && !is_uploaded_file($this->tmpName)) { throw new \RuntimeException("File is not an uploaded file."); @@ -105,6 +116,7 @@ class UploadedFile implements UploadedFileInterface * @see http://php.net/is_uploaded_file * @see http://php.net/move_uploaded_file * @param string $path Path to which to move the uploaded file. + * @return void * @throws \InvalidArgumentException if the $path specified is invalid. * @throws \RuntimeException on any error during the move operation, or on * the second or subsequent call to the method. diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 6feaffb..78007b8 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -40,36 +40,36 @@ class Uri implements UriInterface /** * @param string $uri A string representation of a URI. */ - public function __construct($uri = "") + public function __construct(string $uri = '') { - if (is_string($uri) && $uri !== "") { - $parsed = parse_url($uri); - if ($parsed !== false) { - if (isset($parsed["scheme"])) { - $this->scheme = $parsed["scheme"]; - } - if (isset($parsed["host"])) { - $this->host = strtolower($parsed["host"]); - } - if (isset($parsed["port"])) { - $this->port = $parsed["port"]; - } - if (isset($parsed["user"])) { - $this->user = $parsed["user"]; - } - if (isset($parsed["pass"])) { - $this->password = $parsed["pass"]; - } - if (isset($parsed["path"])) { - $this->path = $parsed["path"]; - } - if (isset($parsed["query"])) { - $this->query = $parsed["query"]; - } - if (isset($parsed["fragment"])) { - $this->fragment = $parsed["fragment"]; - } - } + $parsed = parse_url($uri); + if (!$parsed) { + return; + } + + if (isset($parsed['scheme'])) { + $this->scheme = $parsed['scheme']; + } + if (isset($parsed['host'])) { + $this->host = strtolower($parsed['host']); + } + if (isset($parsed['port'])) { + $this->port = $parsed['port']; + } + if (isset($parsed['user'])) { + $this->user = $parsed['user']; + } + if (isset($parsed['pass'])) { + $this->password = $parsed['pass']; + } + if (isset($parsed['path'])) { + $this->path = $parsed['path']; + } + if (isset($parsed['query'])) { + $this->query = $parsed['query']; + } + if (isset($parsed['fragment'])) { + $this->fragment = $parsed['fragment']; } } @@ -538,7 +538,7 @@ class Uri implements UriInterface $reserved = ':/?#[]@!$&\'()*+,;='; $reserved = preg_quote($reserved); $pattern = '~(?:%(?![a-fA-F0-9]{2}))|(?:[^%a-zA-Z0-9\-\.\_\~' . $reserved . ']{1})~'; - $callback = function ($matches) { + $callback = function (array $matches): string { return urlencode($matches[0]); }; return preg_replace_callback($pattern, $callback, $subject); diff --git a/test/tests/unit/Message/UploadedFileTest.php b/test/tests/unit/Message/UploadedFileTest.php index 09b65f6..bab21ee 100644 --- a/test/tests/unit/Message/UploadedFileTest.php +++ b/test/tests/unit/Message/UploadedFileTest.php @@ -40,7 +40,7 @@ class UploadedFileTest extends TestCase public function testGetStreamReturnsStreamInterface() { - $file = new UploadedFile("", "", 0, "", 0); + $file = new UploadedFile("", "", 0, $this->tmpName, 0); $this->assertInstanceOf(StreamInterface::class, $file->getStream()); } @@ -53,10 +53,11 @@ class UploadedFileTest extends TestCase $this->assertEquals($content, (string) $stream); } - public function testGetStreamReturnsEmptyStreamForNoFile() + public function testGetStreamThrowsRuntimeExceptionForNoFile() { $file = new UploadedFile("", "", 0, "", 0); - $this->assertTrue($file->getStream()->eof()); + $this->expectException(RuntimeException::class); + $file->getStream(); } public function testGetStreamThrowsExceptionAfterMoveTo() From 967b6ac2a48a4d697103b071c349382c028de2a9 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 13:58:24 -0400 Subject: [PATCH 13/53] Add type hints for Routes --- src/Routing/Route/MethodMap.php | 17 ++++++---- src/Routing/Route/PrefixRoute.php | 8 ++--- src/Routing/Route/RegexRoute.php | 9 +++--- src/Routing/Route/Route.php | 9 ++---- src/Routing/Route/RouteInterface.php | 8 ++--- src/Routing/Route/StaticRoute.php | 6 ++-- src/Routing/Route/TemplateRoute.php | 32 +++++++++---------- test/tests/unit/Routing/Route/RouteTest.php | 3 +- .../unit/Routing/Route/TemplateRouteTest.php | 22 ++++++------- 9 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/Routing/Route/MethodMap.php b/src/Routing/Route/MethodMap.php index 11a2188..0e49959 100644 --- a/src/Routing/Route/MethodMap.php +++ b/src/Routing/Route/MethodMap.php @@ -8,7 +8,9 @@ use WellRESTed\Dispatching\DispatcherInterface; class MethodMap { + /** @var DispatcherInterface */ private $dispatcher; + /** @var array */ private $map; // ------------------------------------------------------------------------ @@ -39,7 +41,7 @@ class MethodMap * @param string $method * @param mixed $dispatchable */ - public function register($method, $dispatchable) + public function register($method, $dispatchable): void { $methods = explode(",", $method); $methods = array_map("trim", $methods); @@ -90,13 +92,16 @@ class MethodMap // ------------------------------------------------------------------------ - private function addAllowHeader(ResponseInterface $response) + private function addAllowHeader(ResponseInterface $response): ResponseInterface { $methods = join(",", $this->getAllowedMethods()); return $response->withHeader("Allow", $methods); } - private function getAllowedMethods() + /** + * @return string[] + */ + private function getAllowedMethods(): array { $methods = array_keys($this->map); // Add HEAD if GET is allowed and HEAD is not present. @@ -111,16 +116,16 @@ class MethodMap } /** - * @param $middleware + * @param mixed $middleware * @param ServerRequestInterface $request * @param ResponseInterface $response - * @param $next + * @param callable $next * @return ResponseInterface */ private function dispatchMiddleware( $middleware, ServerRequestInterface $request, - ResponseInterface &$response, + ResponseInterface $response, $next ) { return $this->dispatcher->dispatch($middleware, $request, $response, $next); diff --git a/src/Routing/Route/PrefixRoute.php b/src/Routing/Route/PrefixRoute.php index 37a0d0f..f93c382 100644 --- a/src/Routing/Route/PrefixRoute.php +++ b/src/Routing/Route/PrefixRoute.php @@ -4,12 +4,12 @@ namespace WellRESTed\Routing\Route; class PrefixRoute extends Route { - public function __construct($target, $methodMap) + public function __construct(string $target, MethodMap $methodMap) { parent::__construct(rtrim($target, "*"), $methodMap); } - public function getType() + public function getType(): int { return RouteInterface::TYPE_PREFIX; } @@ -20,7 +20,7 @@ class PrefixRoute extends Route * @param string $requestTarget * @return boolean */ - public function matchesRequestTarget($requestTarget) + public function matchesRequestTarget(string $requestTarget): bool { return strrpos($requestTarget, $this->target, -strlen($requestTarget)) !== false; } @@ -28,7 +28,7 @@ class PrefixRoute extends Route /** * Always returns an empty array. */ - public function getPathVariables() + public function getPathVariables(): array { return []; } diff --git a/src/Routing/Route/RegexRoute.php b/src/Routing/Route/RegexRoute.php index 4afd45a..8f41bdc 100644 --- a/src/Routing/Route/RegexRoute.php +++ b/src/Routing/Route/RegexRoute.php @@ -4,9 +4,10 @@ namespace WellRESTed\Routing\Route; class RegexRoute extends Route { - private $captures; + /** @var array */ + private $captures = []; - public function getType() + public function getType(): int { return RouteInterface::TYPE_PATTERN; } @@ -17,7 +18,7 @@ class RegexRoute extends Route * @param string $requestTarget * @return boolean */ - public function matchesRequestTarget($requestTarget) + public function matchesRequestTarget(string $requestTarget): bool { $this->captures = []; $matched = preg_match($this->getTarget(), $requestTarget, $captures); @@ -36,7 +37,7 @@ class RegexRoute extends Route * @see \preg_match * @return array */ - public function getPathVariables() + public function getPathVariables(): array { return $this->captures; } diff --git a/src/Routing/Route/Route.php b/src/Routing/Route/Route.php index 2cbe7ca..0ba21ce 100644 --- a/src/Routing/Route/Route.php +++ b/src/Routing/Route/Route.php @@ -12,16 +12,13 @@ abstract class Route implements RouteInterface /** @var MethodMap */ protected $methodMap; - public function __construct($target, $methodMap) + public function __construct(string $target, MethodMap $methodMap) { $this->target = $target; $this->methodMap = $methodMap; } - /** - * @return string - */ - public function getTarget() + public function getTarget(): string { return $this->target; } @@ -40,7 +37,7 @@ abstract class Route implements RouteInterface * @param string $method * @param mixed $dispatchable */ - public function register($method, $dispatchable) + public function register(string $method, $dispatchable): void { $this->methodMap->register($method, $dispatchable); } diff --git a/src/Routing/Route/RouteInterface.php b/src/Routing/Route/RouteInterface.php index 22413a3..8eaa017 100644 --- a/src/Routing/Route/RouteInterface.php +++ b/src/Routing/Route/RouteInterface.php @@ -34,7 +34,7 @@ interface RouteInterface extends MiddlewareInterface * * @return int One of the RouteInterface::TYPE_ constants. */ - public function getType(); + public function getType(): int; /** * Return an array of variables extracted from the path most recently @@ -45,7 +45,7 @@ interface RouteInterface extends MiddlewareInterface * * @return array */ - public function getPathVariables(); + public function getPathVariables(): array; /** * Examines a request target to see if it is a match for the route. @@ -55,7 +55,7 @@ interface RouteInterface extends MiddlewareInterface * @throw \RuntimeException Error occurred testing the target such as an * invalid regular expression */ - public function matchesRequestTarget($requestTarget); + public function matchesRequestTarget(string $requestTarget): bool; /** * Register a dispatchable (handler or middleware) with a method. @@ -71,5 +71,5 @@ interface RouteInterface extends MiddlewareInterface * @param string $method * @param mixed $dispatchable */ - public function register($method, $dispatchable); + public function register(string $method, $dispatchable): void; } diff --git a/src/Routing/Route/StaticRoute.php b/src/Routing/Route/StaticRoute.php index d31b84c..6cf9d77 100644 --- a/src/Routing/Route/StaticRoute.php +++ b/src/Routing/Route/StaticRoute.php @@ -4,7 +4,7 @@ namespace WellRESTed\Routing\Route; class StaticRoute extends Route { - public function getType() + public function getType(): int { return RouteInterface::TYPE_STATIC; } @@ -15,7 +15,7 @@ class StaticRoute extends Route * @param string $requestTarget * @return boolean */ - public function matchesRequestTarget($requestTarget) + public function matchesRequestTarget(string $requestTarget): bool { return $requestTarget === $this->getTarget(); } @@ -23,7 +23,7 @@ class StaticRoute extends Route /** * Always returns an empty array. */ - public function getPathVariables() + public function getPathVariables(): array { return []; } diff --git a/src/Routing/Route/TemplateRoute.php b/src/Routing/Route/TemplateRoute.php index 8b71790..9396f11 100644 --- a/src/Routing/Route/TemplateRoute.php +++ b/src/Routing/Route/TemplateRoute.php @@ -4,25 +4,27 @@ namespace WellRESTed\Routing\Route; class TemplateRoute extends Route { - private $pathVariables; - private $explosions; + /** @var array */ + private $pathVariables = []; + /** @var array */ + private $explosions = []; + /** Regular expression matching a URI template variable (e.g., {id}) */ + public const URI_TEMPLATE_EXPRESSION_RE = '/{([+.\/]?[a-zA-Z0-9_,]+\*?)}/'; /** * Regular expression matching 1 or more unreserved characters. * ALPHA / DIGIT / "-" / "." / "_" / "~" */ - const RE_UNRESERVED = '[0-9a-zA-Z\-._\~%]*'; - /** Regular expression matching a URI template variable (e.g., {id}) */ - const URI_TEMPLATE_EXPRESSION_RE = '/{([+.\/]?[a-zA-Z0-9_,]+\*?)}/'; + private const RE_UNRESERVED = '[0-9a-zA-Z\-._\~%]*'; - public function getType() + public function getType(): int { return RouteInterface::TYPE_PATTERN; } - public function getPathVariables() + public function getPathVariables(): array { - return $this->pathVariables ?: []; + return $this->pathVariables; } /** @@ -31,7 +33,7 @@ class TemplateRoute extends Route * @param string $requestTarget * @return bool */ - public function matchesRequestTarget($requestTarget) + public function matchesRequestTarget(string $requestTarget): bool { $this->pathVariables = []; $this->explosions = []; @@ -49,11 +51,7 @@ class TemplateRoute extends Route return false; } - /** - * @param $requestTarget - * @return bool - */ - private function matchesStartOfRequestTarget($requestTarget) + private function matchesStartOfRequestTarget(string $requestTarget): bool { $firstVarPos = strpos($this->target, "{"); if ($firstVarPos === false) { @@ -62,7 +60,7 @@ class TemplateRoute extends Route return (substr($requestTarget, 0, $firstVarPos) === substr($this->target, 0, $firstVarPos)); } - private function processMatches($matches) + private function processMatches(array $matches): array { $variables = []; @@ -87,7 +85,7 @@ class TemplateRoute extends Route return $variables; } - private function getMatchingPattern() + private function getMatchingPattern(): string { // Convert the template into the pattern $pattern = $this->target; @@ -119,7 +117,7 @@ class TemplateRoute extends Route return $pattern; } - private function uriVariableReplacementCallback($matches) + private function uriVariableReplacementCallback(array $matches): string { $name = $matches[1]; $pattern = self::RE_UNRESERVED; diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index 993e411..694e53a 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -23,8 +23,7 @@ class RouteTest extends TestCase public function setUp(): void { $this->methodMap = $this->prophesize(MethodMap::class); - $this->methodMap->register(Argument::cetera()) - ->willReturn(); + $this->methodMap->register(Argument::cetera()); $this->methodMap->__invoke(Argument::cetera()) ->willReturn(new Response()); diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index c480db2..37a63d5 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -57,7 +57,7 @@ class TemplateRouteTest extends TestCase /** @dataProvider nonMatchingTargetProvider */ public function testFailsToMatchNonMatchingTarget($template, $target) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertFalse($route->matchesRequestTarget($target)); } @@ -77,14 +77,14 @@ class TemplateRouteTest extends TestCase /** @dataProvider simpleStringProvider */ public function testMatchesSimpleStrings($template, $target) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } /** @dataProvider simpleStringProvider */ public function testCapturesFromSimpleStrings($template, $target, $variables) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } @@ -106,14 +106,14 @@ class TemplateRouteTest extends TestCase /** @dataProvider reservedStringProvider */ public function testMatchesReservedStrings($template, $target) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } /** @dataProvider reservedStringProvider */ public function testCapturesFromReservedStrings($template, $target, $variables) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertSame($this->getExpectedValues($variables), $route->getPathVariables()); } @@ -133,14 +133,14 @@ class TemplateRouteTest extends TestCase /** @dataProvider labelWithDotPrefixProvider */ public function testMatchesLabelWithDotPrefix($template, $target) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } /** @dataProvider labelWithDotPrefixProvider */ public function testCapturesFromLabelWithDotPrefix($template, $target, $variables) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } @@ -160,14 +160,14 @@ class TemplateRouteTest extends TestCase /** @dataProvider pathSegmentProvider */ public function testMatchesPathSegments($template, $target) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } /** @dataProvider pathSegmentProvider */ public function testCapturesFromPathSegments($template, $target, $variables) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } @@ -187,14 +187,14 @@ class TemplateRouteTest extends TestCase /** @dataProvider pathExplosionProvider */ public function testMatchesExplosion($template, $target) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } /** @dataProvider pathExplosionProvider */ public function testCapturesFromExplosion($template, $target, $variables) { - $route = new TemplateRoute($template, $this->methodMap); + $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } From ca204a07e79c9a6d1244ed4f5a683f76a0dada64 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 14:27:29 -0400 Subject: [PATCH 14/53] Add type hints to Router --- src/Routing/Router.php | 55 ++++++++++---------------- test/tests/unit/Routing/RouterTest.php | 26 ++++++------ 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/src/Routing/Router.php b/src/Routing/Router.php index b836538..b368d6e 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -48,8 +48,10 @@ class Router * Attribute name for matched path variables. A null value sets * attributes directly. */ - public function __construct($dispatcher = null, $pathVariablesAttributeName = null) - { + public function __construct( + ?DispatcherInterface $dispatcher = null, + ?string $pathVariablesAttributeName = null + ) { $this->dispatcher = $dispatcher ?: $this->getDefaultDispatcher(); $this->pathVariablesAttributeName = $pathVariablesAttributeName; $this->factory = $this->getRouteFactory($this->dispatcher); @@ -63,8 +65,8 @@ class Router public function __invoke( ServerRequestInterface $request, ResponseInterface $response, - $next - ) { + callable $next + ): ResponseInterface { // Use only the path for routing. $requestTarget = parse_url($request->getRequestTarget(), PHP_URL_PATH); @@ -101,11 +103,11 @@ class Router } private function dispatch( - $route, + callable $route, ServerRequestInterface $request, ResponseInterface $response, - $next - ) { + callable $next + ): ResponseInterface { if (!$this->stack) { return $route($request, $response, $next); } @@ -145,12 +147,12 @@ class Router * - An array containing any of the items in this list. * @see DispatchedInterface::dispatch * - * @param string $target Request target or pattern to match * @param string $method HTTP method(s) to match + * @param string $target Request target or pattern to match * @param mixed $dispatchable Handler or middleware to dispatch * @return static */ - public function register($method, $target, $dispatchable) + public function register(string $method, string $target, $dispatchable): Router { $route = $this->getRouteForTarget($target); $route->register($method, $dispatchable); @@ -174,7 +176,7 @@ class Router * @param mixed $middleware Middleware to dispatch in sequence * @return static */ - public function add($middleware) + public function add($middleware): Router { $this->stack[] = $middleware; return $this; @@ -186,38 +188,23 @@ class Router * * @return static */ - public function continueOnNotFound() + public function continueOnNotFound(): Router { $this->continueOnNotFound = true; return $this; } - /** - * Return an instance to dispatch middleware. - * - * @return DispatcherInterface - */ - protected function getDefaultDispatcher() + protected function getDefaultDispatcher(): DispatcherInterface { return new Dispatcher(); } - /** - * @param DispatcherInterface $dispatcher - * @return RouteFactoryInterface - */ - protected function getRouteFactory($dispatcher) + protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactoryInterface { return new RouteFactory($dispatcher); } - /** - * Return the route for a given target. - * - * @param $target - * @return RouteInterface - */ - private function getRouteForTarget($target) + private function getRouteForTarget(string $target): RouteInterface { if (isset($this->routes[$target])) { $route = $this->routes[$target]; @@ -228,7 +215,7 @@ class Router return $route; } - private function registerRouteForTarget($route, $target) + private function registerRouteForTarget(RouteInterface $route, string $target): void { // Store the route to the hash indexed by original target. $this->routes[$target] = $route; @@ -247,7 +234,7 @@ class Router } } - private function getStaticRoute($requestTarget) + private function getStaticRoute(string $requestTarget): ?RouteInterface { if (isset($this->staticRoutes[$requestTarget])) { return $this->staticRoutes[$requestTarget]; @@ -255,7 +242,7 @@ class Router return null; } - private function getPrefixRoute($requestTarget) + private function getPrefixRoute(string $requestTarget): ?RouteInterface { // Find all prefixes that match the start of this path. $prefixes = array_keys($this->prefixRoutes); @@ -273,7 +260,7 @@ class Router // If there are multiple matches, sort them to find the one with the // longest string length. if (count($matches) > 1) { - $compareByLength = function ($a, $b) { + $compareByLength = function (string $a, string $b): int { return strlen($b) - strlen($a); }; usort($matches, $compareByLength); @@ -283,7 +270,7 @@ class Router return $this->prefixRoutes[$bestMatch]; } - private function startsWith($haystack, $needle) + private function startsWith(string $haystack, string $needle): bool { $length = strlen($needle); return (substr($haystack, 0, $length) === $needle); diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 2587c51..3780ff1 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -5,9 +5,11 @@ namespace WellRESTed\Test\Unit\Routing; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use WellRESTed\Dispatching\Dispatcher; +use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; use WellRESTed\Routing\Route\RouteFactory; +use WellRESTed\Routing\Route\RouteFactoryInterface; use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Router; use WellRESTed\Test\Doubles\NextMock; @@ -30,7 +32,7 @@ class RouterTest extends TestCase $this->route = $this->prophesize(RouteInterface::class); $this->route->__invoke(Argument::cetera())->willReturn(new Response()); - $this->route->register(Argument::cetera())->willReturn(); + $this->route->register(Argument::cetera()); $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); $this->route->getTarget()->willReturn("/"); $this->route->getPathVariables()->willReturn([]); @@ -134,13 +136,13 @@ class RouterTest extends TestCase public function testDispatchesStaticRouteBeforePrefixRoute() { $staticRoute = $this->prophesize(RouteInterface::class); - $staticRoute->register(Argument::cetera())->willReturn(); + $staticRoute->register(Argument::cetera()); $staticRoute->getTarget()->willReturn("/cats/"); $staticRoute->getType()->willReturn(RouteInterface::TYPE_STATIC); $staticRoute->__invoke(Argument::cetera())->willReturn(new Response()); $prefixRoute = $this->prophesize(RouteInterface::class); - $prefixRoute->register(Argument::cetera())->willReturn(); + $prefixRoute->register(Argument::cetera()); $prefixRoute->getTarget()->willReturn("/cats/*"); $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); @@ -163,13 +165,13 @@ class RouterTest extends TestCase // Note: The longest route is also good for 2 points in Settlers of Catan. $shortRoute = $this->prophesize(RouteInterface::class); - $shortRoute->register(Argument::cetera())->willReturn(); + $shortRoute->register(Argument::cetera()); $shortRoute->getTarget()->willReturn("/animals/*"); $shortRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $shortRoute->__invoke(Argument::cetera())->willReturn(new Response()); $longRoute = $this->prophesize(RouteInterface::class); - $longRoute->register(Argument::cetera())->willReturn(); + $longRoute->register(Argument::cetera()); $longRoute->getTarget()->willReturn("/animals/cats/*"); $longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $longRoute->__invoke(Argument::cetera())->willReturn(new Response()); @@ -191,13 +193,13 @@ class RouterTest extends TestCase public function testDispatchesPrefixRouteBeforePatternRoute() { $prefixRoute = $this->prophesize(RouteInterface::class); - $prefixRoute->register(Argument::cetera())->willReturn(); + $prefixRoute->register(Argument::cetera()); $prefixRoute->getTarget()->willReturn("/cats/*"); $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); $patternRoute = $this->prophesize(RouteInterface::class); - $patternRoute->register(Argument::cetera())->willReturn(); + $patternRoute->register(Argument::cetera()); $patternRoute->getTarget()->willReturn("/cats/{id}"); $patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute->__invoke(Argument::cetera())->willReturn(new Response()); @@ -218,7 +220,7 @@ class RouterTest extends TestCase public function testDispatchesFirstMatchingPatternRoute() { $patternRoute1 = $this->prophesize(RouteInterface::class); - $patternRoute1->register(Argument::cetera())->willReturn(); + $patternRoute1->register(Argument::cetera()); $patternRoute1->getTarget()->willReturn("/cats/{id}"); $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); @@ -226,7 +228,7 @@ class RouterTest extends TestCase $patternRoute1->__invoke(Argument::cetera())->willReturn(new Response()); $patternRoute2 = $this->prophesize(RouteInterface::class); - $patternRoute2->register(Argument::cetera())->willReturn(); + $patternRoute2->register(Argument::cetera()); $patternRoute2->getTarget()->willReturn("/cats/{name}"); $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); @@ -249,7 +251,7 @@ class RouterTest extends TestCase public function testStopsTestingPatternsAfterFirstSuccessfulMatch() { $patternRoute1 = $this->prophesize(RouteInterface::class); - $patternRoute1->register(Argument::cetera())->willReturn(); + $patternRoute1->register(Argument::cetera()); $patternRoute1->getTarget()->willReturn("/cats/{id}"); $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); @@ -257,7 +259,7 @@ class RouterTest extends TestCase $patternRoute1->__invoke(Argument::cetera())->willReturn(new Response()); $patternRoute2 = $this->prophesize(RouteInterface::class); - $patternRoute2->register(Argument::cetera())->willReturn(); + $patternRoute2->register(Argument::cetera()); $patternRoute2->getTarget()->willReturn("/cats/{name}"); $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); @@ -447,7 +449,7 @@ class RouterWithFactory extends Router { static $routeFactory; - protected function getRouteFactory($dispatcher) + protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactoryInterface { return self::$routeFactory; } From 98014d8c59ffa7453ffb6abf97c463373f27319c Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 14:30:19 -0400 Subject: [PATCH 15/53] Add type hints to Transmitter --- src/Transmission/Transmitter.php | 14 ++++++-------- src/Transmission/TransmitterInterface.php | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Transmission/Transmitter.php b/src/Transmission/Transmitter.php index a23c31c..8bed7d5 100644 --- a/src/Transmission/Transmitter.php +++ b/src/Transmission/Transmitter.php @@ -27,7 +27,7 @@ class Transmitter implements TransmitterInterface public function transmit( ServerRequestInterface $request, ResponseInterface $response - ) { + ): void { // Prepare the response for output. $response = $this->prepareResponse($request, $response); @@ -48,10 +48,7 @@ class Transmitter implements TransmitterInterface } } - /** - * @param int $chunkSize - */ - public function setChunkSize($chunkSize) + public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } @@ -59,7 +56,8 @@ class Transmitter implements TransmitterInterface protected function prepareResponse( ServerRequestInterface $request, ResponseInterface $response - ) { + ): ResponseInterface { + // Add a Content-length header to the response when all of these are true: // // - Response does not have a Content-length header @@ -77,7 +75,7 @@ class Transmitter implements TransmitterInterface return $response; } - private function getStatusLine(ResponseInterface $response) + private function getStatusLine(ResponseInterface $response): string { $protocol = $response->getProtocolVersion(); $statusCode = $response->getStatusCode(); @@ -89,7 +87,7 @@ class Transmitter implements TransmitterInterface } } - private function outputBody(StreamInterface $body) + private function outputBody(StreamInterface $body): void { if ($this->chunkSize > 0) { if ($body->isSeekable()) { diff --git a/src/Transmission/TransmitterInterface.php b/src/Transmission/TransmitterInterface.php index 4a639dd..9d6e947 100644 --- a/src/Transmission/TransmitterInterface.php +++ b/src/Transmission/TransmitterInterface.php @@ -18,5 +18,5 @@ interface TransmitterInterface * @param ServerRequestInterface $request * @param ResponseInterface $response Response to output */ - public function transmit(ServerRequestInterface $request, ResponseInterface $response); + public function transmit(ServerRequestInterface $request, ResponseInterface $response): void; } From 09dd1d7a320ad321e1d50ff58a6cf81a60d2fe5c Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 14:51:43 -0400 Subject: [PATCH 16/53] Add type hints to Server; construct defaults for most dependencies --- src/Server.php | 74 +++++++++++----------------------- test/tests/unit/ServerTest.php | 2 +- 2 files changed, 24 insertions(+), 52 deletions(-) diff --git a/src/Server.php b/src/Server.php index 5b2b485..1c104b5 100644 --- a/src/Server.php +++ b/src/Server.php @@ -14,14 +14,14 @@ use WellRESTed\Transmission\TransmitterInterface; class Server { - /** @var array */ - protected $attributes; + /** @var mixed[] */ + protected $attributes = []; /** @var DispatcherInterface */ private $dispatcher; - /** @var string ServerRequestInterface attribute name for matched path variables */ - private $pathVariablesAttributeName; - /** @var ServerRequestInterface */ - private $request; + /** @var string|null attribute name for matched path variables */ + private $pathVariablesAttributeName = null; + /** @var ServerRequestInterface|null */ + private $request = null; /** @var ResponseInterface */ private $response; /** @var TransmitterInterface */ @@ -31,6 +31,9 @@ class Server public function __construct() { $this->stack = []; + $this->response = new Response(); + $this->dispatcher = new Dispatcher(); + $this->transmitter = new Transmitter(); } /** @@ -39,7 +42,7 @@ class Server * @param mixed $middleware Middleware to dispatch in sequence * @return Server */ - public function add($middleware) + public function add($middleware): Server { $this->stack[] = $middleware; return $this; @@ -50,10 +53,10 @@ class Server * * @return Router */ - public function createRouter() + public function createRouter(): Router { return new Router( - $this->getDispatcher(), + $this->dispatcher, $this->pathVariablesAttributeName ); } @@ -64,25 +67,26 @@ class Server * This method reads a server request, dispatches the request through the * server's stack of middleware, and outputs the response via a Transmitter. */ - public function respond() + public function respond(): void { $request = $this->getRequest(); - foreach ($this->getAttributes() as $name => $value) { + foreach ($this->attributes as $name => $value) { $request = $request->withAttribute($name, $value); } - $response = $this->getResponse(); - - $next = function ($rqst, $resp) { + $next = function ( + ServerRequestInterface $rqst, + ResponseInterface $resp + ): ResponseInterface { return $resp; }; - $dispatcher = $this->getDispatcher(); - $response = $dispatcher->dispatch( + $response = $this->response; + + $response = $this->dispatcher->dispatch( $this->stack, $request, $response, $next); - $transmitter = $this->getTransmitter(); - $transmitter->transmit($request, $response); + $this->transmitter->transmit($request, $response); } // ------------------------------------------------------------------------- @@ -150,43 +154,11 @@ class Server // ------------------------------------------------------------------------- /* Defaults */ - private function getAttributes() - { - if (!$this->attributes) { - $this->attributes = []; - } - return $this->attributes; - } - - private function getDispatcher() - { - if (!$this->dispatcher) { - $this->dispatcher = new Dispatcher(); - } - return $this->dispatcher; - } - - private function getRequest() + private function getRequest(): ServerRequestInterface { if (!$this->request) { $this->request = ServerRequest::getServerRequest(); } return $this->request; } - - private function getResponse() - { - if (!$this->response) { - $this->response = new Response(); - } - return $this->response; - } - - private function getTransmitter() - { - if (!$this->transmitter) { - $this->transmitter = new Transmitter(); - } - return $this->transmitter; - } } diff --git a/test/tests/unit/ServerTest.php b/test/tests/unit/ServerTest.php index 7dabfc2..b490ff4 100644 --- a/test/tests/unit/ServerTest.php +++ b/test/tests/unit/ServerTest.php @@ -27,7 +27,7 @@ class ServerTest extends TestCase parent::setUp(); $this->transmitter = $this->prophesize(TransmitterInterface::class); - $this->transmitter->transmit(Argument::cetera())->willReturn(); + $this->transmitter->transmit(Argument::cetera()); $this->server = new Server(); $this->server->setTransmitter($this->transmitter->reveal()); From d98789ebfd3c892eebe564c7c473ed25b08e9436 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 9 Aug 2020 14:54:26 -0400 Subject: [PATCH 17/53] Fix test broken by Transmitter change --- test/tests/integration/RoutingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/integration/RoutingTest.php b/test/tests/integration/RoutingTest.php index 2f7fa38..65ca2bb 100644 --- a/test/tests/integration/RoutingTest.php +++ b/test/tests/integration/RoutingTest.php @@ -185,7 +185,7 @@ class TransmitterMock implements TransmitterInterface public function transmit( ServerRequestInterface $request, ResponseInterface $response - ) { + ): void { $this->response = $response; } } From a73ad17ddd60db648734b41da6ed97b4e1180446 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Mon, 10 Aug 2020 06:48:32 -0400 Subject: [PATCH 18/53] Add php-cs-fixer as dev dependency --- .gitattributes | 1 + .gitignore | 3 + .php_cs.dist | 15 + composer.json | 1 + composer.lock | 1160 +++++++++++++++++++++++++++++++++++++++-- docker/php/Dockerfile | 3 +- 6 files changed, 1137 insertions(+), 46 deletions(-) create mode 100644 .php_cs.dist diff --git a/.gitattributes b/.gitattributes index aa941fb..82dde02 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,7 @@ /.env export-ignore /.gitattributes export-ignore /.gitignore export-ignore +/.php_cs* export-ignore /.travis.yml export-ignore /composer.lock export-ignore /docker export-ignore diff --git a/.gitignore b/.gitignore index 1d41a9c..a4a4c4c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ phpdoc/ coverage/ report/ +# Cache +.php_cs.cache + # Sphinx Documentation docs/build diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000..953b9d1 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,15 @@ +files() + ->in(__DIR__ . '/src') + ->in(__DIR__ . '/test'); + +return PhpCsFixer\Config::create() + ->setFinder($finder) + ->setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + 'strict_param' => true, + 'array_syntax' => ['syntax' => 'short'], + ]); diff --git a/composer.json b/composer.json index 6f415d9..cf398b3 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "psr/http-server-middleware": "~1.0" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^2", "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9", "vimeo/psalm": "^3.4" diff --git a/composer.lock b/composer.lock index 9daf443..02cddea 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "591aa22398b48f0252eca221eea45e04", + "content-hash": "4d35c0aa434d9f710cd5a8a7246367d4", "packages": [ { "name": "psr/http-message", @@ -316,29 +316,28 @@ }, { "name": "composer/semver", - "version": "3.0.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940" + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3426bd5efa8a12d230824536c42a8a4ad30b7940", - "reference": "3426bd5efa8a12d230824536c42a8a4ad30b7940", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.19", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpunit/phpunit": "^4.5 || ^5.0.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -374,21 +373,7 @@ "validation", "versioning" ], - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2020-05-26T18:22:04+00:00" + "time": "2020-01-13T12:06:48+00:00" }, { "name": "composer/xdebug-handler", @@ -448,6 +433,75 @@ ], "time": "2020-06-04T11:16:35+00:00" }, + { + "name": "doctrine/annotations", + "version": "1.10.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d", + "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "^7.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2020-05-25T17:24:27+00:00" + }, { "name": "doctrine/instantiator", "version": "1.3.1", @@ -518,6 +572,82 @@ ], "time": "2020-05-29T17:27:14+00:00" }, + { + "name": "doctrine/lexer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2020-05-25T17:44:05+00:00" + }, { "name": "felixfbecker/advanced-json-rpc", "version": "v3.1.1", @@ -606,6 +736,103 @@ ], "time": "2019-06-23T21:03:50+00:00" }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v2.16.4", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "1023c3458137ab052f6ff1e09621a721bfdeca13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/1023c3458137ab052f6ff1e09621a721bfdeca13", + "reference": "1023c3458137ab052f6ff1e09621a721bfdeca13", + "shasum": "" + }, + "require": { + "composer/semver": "^1.4", + "composer/xdebug-handler": "^1.2", + "doctrine/annotations": "^1.2", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^5.6 || ^7.0", + "php-cs-fixer/diff": "^1.3", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "symfony/event-dispatcher": "^3.0 || ^4.0 || ^5.0", + "symfony/filesystem": "^3.0 || ^4.0 || ^5.0", + "symfony/finder": "^3.0 || ^4.0 || ^5.0", + "symfony/options-resolver": "^3.0 || ^4.0 || ^5.0", + "symfony/polyfill-php70": "^1.0", + "symfony/polyfill-php72": "^1.4", + "symfony/process": "^3.0 || ^4.0 || ^5.0", + "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0" + }, + "require-dev": { + "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0", + "justinrainbow/json-schema": "^5.0", + "keradus/cli-executor": "^1.2", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.1", + "php-cs-fixer/accessible-object": "^1.0", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.1", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.1", + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.1", + "phpunitgoodpractices/traits": "^1.8", + "symfony/phpunit-bridge": "^5.1", + "symfony/yaml": "^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters.", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.", + "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + }, + "classmap": [ + "tests/Test/AbstractFixerTestCase.php", + "tests/Test/AbstractIntegrationCaseFactory.php", + "tests/Test/AbstractIntegrationTestCase.php", + "tests/Test/Assert/AssertTokensTrait.php", + "tests/Test/IntegrationCase.php", + "tests/Test/IntegrationCaseFactory.php", + "tests/Test/IntegrationCaseFactoryInterface.php", + "tests/Test/InternalIntegrationCaseFactory.php", + "tests/Test/IsIdenticalConstraint.php", + "tests/TestCase.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2020-06-27T23:57:46+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.10.1", @@ -708,16 +935,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.7.0", + "version": "v4.8.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "21dce06dfbf0365c6a7cc8fdbdc995926c6a9300" + "reference": "8c58eb4cd4f3883f82611abeac2efbc3dbed787e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/21dce06dfbf0365c6a7cc8fdbdc995926c6a9300", - "reference": "21dce06dfbf0365c6a7cc8fdbdc995926c6a9300", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8c58eb4cd4f3883f82611abeac2efbc3dbed787e", + "reference": "8c58eb4cd4f3883f82611abeac2efbc3dbed787e", "shasum": "" }, "require": { @@ -725,8 +952,8 @@ "php": ">=7.0" }, "require-dev": { - "ircmaxell/php-yacc": "0.0.5", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + "ircmaxell/php-yacc": "^0.0.6", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -734,7 +961,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.7-dev" + "dev-master": "4.8-dev" } }, "autoload": { @@ -756,7 +983,7 @@ "parser", "php" ], - "time": "2020-07-25T13:18:53+00:00" + "time": "2020-08-09T10:23:20+00:00" }, { "name": "ocramius/package-versions", @@ -868,6 +1095,51 @@ ], "time": "2019-03-29T20:06:56+00:00" }, + { + "name": "paragonie/random_compat", + "version": "v9.99.99", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "shasum": "" + }, + "require": { + "php": "^7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "time": "2018-07-02T15:55:56+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.1", @@ -971,6 +1243,57 @@ "description": "Library for handling version information and constraints", "time": "2020-06-27T14:39:04+00:00" }, + { + "name": "php-cs-fixer/diff", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/diff.git", + "reference": "78bb099e9c16361126c86ce82ec4405ebab8e756" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/78bb099e9c16361126c86ce82ec4405ebab8e756", + "reference": "78bb099e9c16361126c86ce82ec4405ebab8e756", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3", + "symfony/process": "^3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "SpacePossum" + } + ], + "description": "sebastian/diff v2 backport support for PHP5.6", + "homepage": "https://github.com/PHP-CS-Fixer", + "keywords": [ + "diff" + ], + "time": "2018-02-15T16:58:55+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -1230,16 +1553,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.0.0", + "version": "9.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ee24e82baca11d7d6fb3513e127d6000f541cf90" + "reference": "5210f9269e44e6d34419cb92242ef11aee9351ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ee24e82baca11d7d6fb3513e127d6000f541cf90", - "reference": "ee24e82baca11d7d6fb3513e127d6000f541cf90", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5210f9269e44e6d34419cb92242ef11aee9351ac", + "reference": "5210f9269e44e6d34419cb92242ef11aee9351ac", "shasum": "" }, "require": { @@ -1267,7 +1590,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.0-dev" + "dev-master": "9.1-dev" } }, "autoload": { @@ -1299,7 +1622,7 @@ "type": "github" } ], - "time": "2020-08-07T04:12:30+00:00" + "time": "2020-08-10T07:24:51+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1528,16 +1851,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.3.3", + "version": "9.3.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "7e3942a29e7705cf109aa58c6e5d80997796d1dc" + "reference": "7115b00b23bcd4f62a73855c9615694d2f206e71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7e3942a29e7705cf109aa58c6e5d80997796d1dc", - "reference": "7e3942a29e7705cf109aa58c6e5d80997796d1dc", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7115b00b23bcd4f62a73855c9615694d2f206e71", + "reference": "7115b00b23bcd4f62a73855c9615694d2f206e71", "shasum": "" }, "require": { @@ -1553,7 +1876,7 @@ "phar-io/version": "^3.0.2", "php": "^7.3 || ^8.0", "phpspec/prophecy": "^1.11.1", - "phpunit/php-code-coverage": "^9.0", + "phpunit/php-code-coverage": "^9.1.1", "phpunit/php-file-iterator": "^3.0.4", "phpunit/php-invoker": "^3.1", "phpunit/php-text-template": "^2.0.2", @@ -1622,7 +1945,7 @@ "type": "github" } ], - "time": "2020-08-08T05:12:01+00:00" + "time": "2020-08-10T06:50:08+00:00" }, { "name": "psr/container", @@ -1673,6 +1996,52 @@ ], "time": "2017-02-14T16:28:37+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "time": "2019-01-08T18:20:26+00:00" + }, { "name": "psr/log", "version": "1.1.3", @@ -2661,6 +3030,429 @@ ], "time": "2020-07-06T13:23:11+00:00" }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14", + "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-06-06T08:49:21+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "7827d55911f91c070fc293ea51a06eec80797d76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7827d55911f91c070fc293ea51a06eec80797d76", + "reference": "7827d55911f91c070fc293ea51a06eec80797d76", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/event-dispatcher-contracts": "^2", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^4.4|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "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 EventDispatcher Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-06-18T18:24:02+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f6f613d74cfc5a623fc36294d3451eb7fa5a042b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f6f613d74cfc5a623fc36294d3451eb7fa5a042b", + "reference": "f6f613d74cfc5a623fc36294d3451eb7fa5a042b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-06T13:23:11+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "6e4320f06d5f2cce0d96530162491f4465179157" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/6e4320f06d5f2cce0d96530162491f4465179157", + "reference": "6e4320f06d5f2cce0d96530162491f4465179157", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "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 Filesystem Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-05-30T20:35:19+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/4298870062bfc667cb78d2b379be4bf5dec5f187", + "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "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 Finder Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-05-20T17:43:50+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "9ff59517938f88d90b6e65311fef08faa640f681" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/9ff59517938f88d90b6e65311fef08faa640f681", + "reference": "9ff59517938f88d90b6e65311fef08faa640f681", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "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 OptionsResolver Component", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-12T12:58:00+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.18.1", @@ -2973,6 +3765,156 @@ ], "time": "2020-07-14T12:35:20+00:00" }, + { + "name": "symfony/polyfill-php70", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", + "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "~1.0|~2.0|~9.99", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php70\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "639447d008615574653fb3bc60d1986d7172eaae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae", + "reference": "639447d008615574653fb3bc60d1986d7172eaae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, { "name": "symfony/polyfill-php73", "version": "v1.18.1", @@ -3129,6 +4071,70 @@ ], "time": "2020-07-14T12:35:20+00:00" }, + { + "name": "symfony/process", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "1864216226af21eb76d9477f691e7cbf198e0402" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/1864216226af21eb76d9477f691e7cbf198e0402", + "reference": "1864216226af21eb76d9477f691e7cbf198e0402", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "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 Process Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-23T08:36:24+00:00" + }, { "name": "symfony/service-contracts", "version": "v2.1.3", @@ -3205,6 +4211,70 @@ ], "time": "2020-07-06T13:23:11+00:00" }, + { + "name": "symfony/stopwatch", + "version": "v5.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "0f7c58cf81dbb5dd67d423a89d577524a2ec0323" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/0f7c58cf81dbb5dd67d423a89d577524a2ec0323", + "reference": "0f7c58cf81dbb5dd67d423a89d577524a2ec0323", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/service-contracts": "^1.0|^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "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 Stopwatch Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-05-20T17:43:50+00:00" + }, { "name": "symfony/string", "version": "v5.1.3", @@ -3582,7 +4652,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.0" + "php": ">=7.2" }, "platform-dev": [], "plugin-api-version": "1.1.0" diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 2030c9c..aeae46a 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -32,7 +32,8 @@ COPY ./test /usr/local/src/wellrested/test COPY ./composer.* /usr/local/src/wellrested/ COPY ./phpunit.xml.dist /usr/local/src/wellrested/ -# Add symlinks for phpunit and psalm for easier running +# Add symlinks for php-cs-fixer, phpunit, and psalm for easier running +RUN ln -s /usr/local/src/wellrested/vendor/bin/php-cs-fixer /usr/local/bin/php-cs-fixer RUN ln -s /usr/local/src/wellrested/vendor/bin/phpunit /usr/local/bin/phpunit RUN ln -s /usr/local/src/wellrested/vendor/bin/psalm /usr/local/bin/psalm From fb18d2ee1ea82a2a89364ea595ac808504f2db40 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Mon, 10 Aug 2020 07:09:37 -0400 Subject: [PATCH 19/53] Code style fixes --- .php_cs.dist | 2 -- src/Message/ServerRequest.php | 9 ++++-- src/Message/Uri.php | 2 +- src/Routing/Route/TemplateRoute.php | 2 -- src/Routing/Router.php | 5 ++- src/Server.php | 12 +++++-- test/tests/integration/RoutingTest.php | 32 +++++++++++++------ .../tests/unit/Dispatching/DispatcherTest.php | 6 ++-- test/tests/unit/Message/MessageTest.php | 6 ++-- .../unit/Routing/Route/MethodMapTest.php | 6 ++-- test/tests/unit/Routing/Route/RouteTest.php | 4 ++- test/tests/unit/Routing/RouterTest.php | 5 +-- 12 files changed, 62 insertions(+), 29 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 953b9d1..989dd81 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -7,9 +7,7 @@ $finder = PhpCsFixer\Finder::create() return PhpCsFixer\Config::create() ->setFinder($finder) - ->setRiskyAllowed(true) ->setRules([ '@PSR2' => true, - 'strict_param' => true, 'array_syntax' => ['syntax' => 'short'], ]); diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index 8e8e458..ba64930 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -195,7 +195,8 @@ class ServerRequest extends Request implements ServerRequestInterface { if (!$this->isValidUploadedFilesTree($uploadedFiles)) { throw new \InvalidArgumentException( - "withUploadedFiles expects an array tree with UploadedFileInterface leaves."); + "withUploadedFiles expects an array tree with UploadedFileInterface leaves." + ); } $request = clone $this; @@ -413,7 +414,11 @@ class ServerRequest extends Request implements ServerRequestInterface } else { // All expected keys are present and are not arrays. This is an uploaded file. $uploadedFile = new UploadedFile( - $value["name"], $value["type"], $value["size"], $value["tmp_name"], $value["error"] + $value["name"], + $value["type"], + $value["size"], + $value["tmp_name"], + $value["error"] ); $branch[$name] = $uploadedFile; } diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 78007b8..4574e56 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -130,7 +130,7 @@ class Uri implements UriInterface $port = $this->getPort(); if ($port !== null) { $scheme = $this->getScheme(); - if (($scheme === "http" && $port !== 80 ) || ($scheme === "https" && $port !== 443)) { + if (($scheme === "http" && $port !== 80) || ($scheme === "https" && $port !== 443)) { $authority .= ":" . $port; } } diff --git a/src/Routing/Route/TemplateRoute.php b/src/Routing/Route/TemplateRoute.php index 9396f11..d2fb3a5 100644 --- a/src/Routing/Route/TemplateRoute.php +++ b/src/Routing/Route/TemplateRoute.php @@ -69,7 +69,6 @@ class TemplateRoute extends Route // Store named captures to the variables. foreach ($keys as $key) { - $value = $matches[$key]; if (isset($this->explosions[$key])) { @@ -79,7 +78,6 @@ class TemplateRoute extends Route $value = urldecode($value); $variables[$key] = $value; } - } return $variables; diff --git a/src/Routing/Router.php b/src/Routing/Router.php index b368d6e..172d214 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -113,7 +113,10 @@ class Router } $stack = array_merge($this->stack, [$route]); return $this->dispatcher->dispatch( - $stack, $request, $response, $next + $stack, + $request, + $response, + $next ); } diff --git a/src/Server.php b/src/Server.php index 1c104b5..613dc98 100644 --- a/src/Server.php +++ b/src/Server.php @@ -29,7 +29,8 @@ class Server /** @var mixed[] List array of middleware */ private $stack; - public function __construct() { + public function __construct() + { $this->stack = []; $this->response = new Response(); $this->dispatcher = new Dispatcher(); @@ -84,7 +85,11 @@ class Server $response = $this->response; $response = $this->dispatcher->dispatch( - $this->stack, $request, $response, $next); + $this->stack, + $request, + $response, + $next + ); $this->transmitter->transmit($request, $response); } @@ -116,7 +121,8 @@ class Server * @param string $name * @return Server */ - public function setPathVariablesAttributeName(string $name): Server { + public function setPathVariablesAttributeName(string $name): Server + { $this->pathVariablesAttributeName = $name; return $this; } diff --git a/test/tests/integration/RoutingTest.php b/test/tests/integration/RoutingTest.php index 65ca2bb..cbc238c 100644 --- a/test/tests/integration/RoutingTest.php +++ b/test/tests/integration/RoutingTest.php @@ -108,7 +108,9 @@ class RoutingTest extends TestCase ->register('GET', '/oscar', new StringHandler('Oscar')); $this->server->add(new HeaderAdderMiddleware( - 'Content-type', 'application/cat')); + 'Content-type', + 'application/cat' + )); $this->server->add($router); $this->request = $this->request @@ -118,15 +120,19 @@ class RoutingTest extends TestCase $response = $this->respond(); $this->assertEquals('Molly', (string) $response->getBody()); - $this->assertEquals('application/cat', - $response->getHeaderLine('Content-type')); + $this->assertEquals( + 'application/cat', + $response->getHeaderLine('Content-type') + ); } public function testDispatchesMiddlewareSpecificToRouter() { $catRouter = $this->server->createRouter() ->add(new HeaderAdderMiddleware( - 'Content-type', 'application/cat')) + 'Content-type', + 'application/cat' + )) ->register('GET', '/molly', new StringHandler('Molly')) ->register('GET', '/oscar', new StringHandler('Oscar')) ->continueOnNotFound(); @@ -134,7 +140,9 @@ class RoutingTest extends TestCase $dogRouter = $this->server->createRouter() ->add(new HeaderAdderMiddleware( - 'Content-type', 'application/dog')) + 'Content-type', + 'application/dog' + )) ->register('GET', '/bear', new StringHandler('Bear')); $this->server->add($dogRouter); @@ -145,15 +153,19 @@ class RoutingTest extends TestCase $response = $this->respond(); $this->assertEquals('Bear', (string) $response->getBody()); - $this->assertEquals('application/dog', - $response->getHeaderLine('Content-type')); + $this->assertEquals( + 'application/dog', + $response->getHeaderLine('Content-type') + ); } public function testResponds404WhenNoRouteMatched() { $catRouter = $this->server->createRouter() ->add(new HeaderAdderMiddleware( - 'Content-type', 'application/cat')) + 'Content-type', + 'application/cat' + )) ->register('GET', '/molly', new StringHandler('Molly')) ->register('GET', '/oscar', new StringHandler('Oscar')) ->continueOnNotFound(); @@ -161,7 +173,9 @@ class RoutingTest extends TestCase $dogRouter = $this->server->createRouter() ->add(new HeaderAdderMiddleware( - 'Content-type', 'application/dog')) + 'Content-type', + 'application/dog' + )) ->register('GET', '/bear', new StringHandler('Bear')); $this->server->add($dogRouter); diff --git a/test/tests/unit/Dispatching/DispatcherTest.php b/test/tests/unit/Dispatching/DispatcherTest.php index 6fd5c6c..63c6019 100644 --- a/test/tests/unit/Dispatching/DispatcherTest.php +++ b/test/tests/unit/Dispatching/DispatcherTest.php @@ -70,7 +70,8 @@ class DispatcherTest extends TestCase // ------------------------------------------------------------------------- // PSR-15 Middleware - public function testDispatchesPsr15MiddlewareWithDelegate() { + public function testDispatchesPsr15MiddlewareWithDelegate() + { $this->next->upstreamResponse = $this->stubResponse; $middleware = new MiddlewareDouble(); @@ -78,7 +79,8 @@ class DispatcherTest extends TestCase $this->assertSame($this->stubResponse, $response); } - public function testDispatchesPsr15MiddlewareFromFactoryWithDelegate() { + public function testDispatchesPsr15MiddlewareFromFactoryWithDelegate() + { $this->next->upstreamResponse = $this->stubResponse; $factory = function () { return new MiddlewareDouble(); diff --git a/test/tests/unit/Message/MessageTest.php b/test/tests/unit/Message/MessageTest.php index 6bdc81b..093331e 100644 --- a/test/tests/unit/Message/MessageTest.php +++ b/test/tests/unit/Message/MessageTest.php @@ -41,7 +41,8 @@ class MessageTest extends TestCase $this->assertNotEquals( $message1->getHeader('Content-type'), - $message2->getHeader('Content-type')); + $message2->getHeader('Content-type') + ); } // ------------------------------------------------------------------------ @@ -121,7 +122,8 @@ class MessageTest extends TestCase $cookies = $message->getHeader('Set-Cookie'); $this->assertTrue( in_array('cat=Molly', $cookies) && - in_array('dog=Bear', $cookies)); + in_array('dog=Bear', $cookies) + ); } public function testWithoutHeaderRemovesHeader() diff --git a/test/tests/unit/Routing/Route/MethodMapTest.php b/test/tests/unit/Routing/Route/MethodMapTest.php index 6da2b8f..285279d 100644 --- a/test/tests/unit/Routing/Route/MethodMapTest.php +++ b/test/tests/unit/Routing/Route/MethodMapTest.php @@ -27,7 +27,8 @@ class MethodMapTest extends TestCase $this->dispatcher = new Dispatcher(); } - private function getMethodMap() { + private function getMethodMap() + { return new MethodMap($this->dispatcher); } @@ -194,7 +195,8 @@ class MethodMapTest extends TestCase ]; } - private function assertContainsEach($expectedList, $actual) { + private function assertContainsEach($expectedList, $actual) + { foreach ($expectedList as $expected) { if (strpos($actual, $expected) === false) { $this->assertTrue(false, "'$actual' does not contain expected '$expected'"); diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index 694e53a..8c9af5d 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -28,7 +28,9 @@ class RouteTest extends TestCase ->willReturn(new Response()); $this->route = new StaticRoute( - self::TARGET, $this->methodMap->reveal()); + self::TARGET, + $this->methodMap->reveal() + ); } public function testReturnsTarget() diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 3780ff1..2387e7e 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -414,7 +414,8 @@ class RouterTest extends TestCase $this->route->__invoke( $middlewareRequest, $middlewareResponse, - Argument::any())->shouldHaveBeenCalled(); + Argument::any() + )->shouldHaveBeenCalled(); } public function testDoesNotCallRouterMiddlewareWhenNoRouteMatches() @@ -447,7 +448,7 @@ class RouterTest extends TestCase class RouterWithFactory extends Router { - static $routeFactory; + public static $routeFactory; protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactoryInterface { From 002bdb7541ef25e86bf7df6f150cacae7dcf6690 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Mon, 10 Aug 2020 07:13:50 -0400 Subject: [PATCH 20/53] Convert simple string literals to single quotes --- .php_cs.dist | 1 + src/Message/NullStream.php | 12 +- src/Message/Request.php | 18 +- src/Message/Response.php | 118 +++--- src/Message/ServerRequest.php | 84 ++-- src/Message/Stream.php | 40 +- src/Message/UploadedFile.php | 12 +- src/Message/Uri.php | 60 +-- src/Routing/Route/MethodMap.php | 26 +- src/Routing/Route/PrefixRoute.php | 2 +- src/Routing/Route/RegexRoute.php | 2 +- src/Routing/Route/RouteFactory.php | 4 +- src/Routing/Route/TemplateRoute.php | 52 +-- src/Routing/Router.php | 2 +- src/Transmission/Transmitter.php | 6 +- .../unit/Dispatching/DispatchStackTest.php | 8 +- .../unit/Message/HeaderCollectionTest.php | 58 +-- test/tests/unit/Message/NullStreamTest.php | 10 +- test/tests/unit/Message/RequestTest.php | 52 +-- test/tests/unit/Message/ResponseTest.php | 88 ++-- test/tests/unit/Message/ServerRequestTest.php | 388 +++++++++--------- test/tests/unit/Message/StreamTest.php | 58 +-- test/tests/unit/Message/UploadedFileTest.php | 50 +-- test/tests/unit/Message/UriTest.php | 296 ++++++------- .../unit/Routing/Route/MethodMapTest.php | 64 +-- test/tests/unit/Routing/RouterTest.php | 140 +++---- test/tests/unit/ServerTest.php | 8 +- .../unit/Transmission/TransmitterTest.php | 40 +- 28 files changed, 850 insertions(+), 849 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 989dd81..e5c0d64 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -10,4 +10,5 @@ return PhpCsFixer\Config::create() ->setRules([ '@PSR2' => true, 'array_syntax' => ['syntax' => 'short'], + 'single_quote' => true ]); diff --git a/src/Message/NullStream.php b/src/Message/NullStream.php index bf3a34d..f8826d1 100644 --- a/src/Message/NullStream.php +++ b/src/Message/NullStream.php @@ -18,7 +18,7 @@ class NullStream implements StreamInterface */ public function __toString() { - return ""; + return ''; } /** @@ -96,7 +96,7 @@ class NullStream implements StreamInterface */ public function seek($offset, $whence = SEEK_SET) { - throw new \RuntimeException("Unable to seek to position."); + throw new \RuntimeException('Unable to seek to position.'); } /** @@ -109,7 +109,7 @@ class NullStream implements StreamInterface */ public function rewind() { - throw new \RuntimeException("Unable to rewind stream."); + throw new \RuntimeException('Unable to rewind stream.'); } /** @@ -131,7 +131,7 @@ class NullStream implements StreamInterface */ public function write($string) { - throw new \RuntimeException("Unable to write to stream."); + throw new \RuntimeException('Unable to write to stream.'); } /** @@ -156,7 +156,7 @@ class NullStream implements StreamInterface */ public function read($length) { - return ""; + return ''; } /** @@ -168,7 +168,7 @@ class NullStream implements StreamInterface */ public function getContents() { - return ""; + return ''; } /** diff --git a/src/Message/Request.php b/src/Message/Request.php index 412bc98..0b24d83 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -89,11 +89,11 @@ class Request extends Message implements RequestInterface $target = $this->uri->getPath(); $query = $this->uri->getQuery(); if ($query) { - $target .= "?" . $query; + $target .= '?' . $query; } // Return "/" if the origin form is empty. - return $target ?: "/"; + return $target ?: '/'; } /** @@ -187,18 +187,18 @@ class Request extends Message implements RequestInterface $request = clone $this; $newHost = $uri->getHost(); - $oldHost = isset($request->headers["Host"]) ? $request->headers["Host"] : ""; + $oldHost = isset($request->headers['Host']) ? $request->headers['Host'] : ''; if ($preserveHost === false) { // Update Host if ($newHost && $newHost !== $oldHost) { - unset($request->headers["Host"]); - $request->headers["Host"] = $newHost; + unset($request->headers['Host']); + $request->headers['Host'] = $newHost; } } else { // Preserve Host if (!$oldHost && $newHost) { - $request->headers["Host"] = $newHost; + $request->headers['Host'] = $newHost; } } @@ -216,11 +216,11 @@ class Request extends Message implements RequestInterface private function getValidatedMethod($method) { if (!is_string($method)) { - throw new \InvalidArgumentException("Method must be a string."); + throw new \InvalidArgumentException('Method must be a string.'); } $method = trim($method); - if (strpos($method, " ") !== false) { - throw new \InvalidArgumentException("Method cannot contain spaces."); + if (strpos($method, ' ') !== false) { + throw new \InvalidArgumentException('Method cannot contain spaces.'); } return $method; } diff --git a/src/Message/Response.php b/src/Message/Response.php index aca9c0c..da4397b 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -79,7 +79,7 @@ class Response extends Message implements ResponseInterface * @return static * @throws \InvalidArgumentException For invalid status code arguments. */ - public function withStatus($code, $reasonPhrase = "") + public function withStatus($code, $reasonPhrase = '') { $response = clone $this; $response->statusCode = $code; @@ -111,64 +111,64 @@ class Response extends Message implements ResponseInterface private function getDefaultReasonPhraseForStatusCode($statusCode) { $reasonPhraseLookup = [ - 100 => "Continue", - 101 => "Switching Protocols", - 102 => "Processing", - 200 => "OK", - 201 => "Created", - 202 => "Accepted", - 203 => "Non-Authoritative Information", - 204 => "No Content", - 205 => "Reset Content", - 206 => "Partial Content", - 207 => "Multi-Status", - 208 => "Already Reported", - 226 => "IM Used", - 300 => "Multiple Choices", - 301 => "Moved Permanently", - 302 => "Found", - 303 => "See Other", - 304 => "Not Modified", - 305 => "Use Proxy", - 307 => "Temporary Redirect", - 308 => "Permanent Redirect", - 400 => "Bad Request", - 401 => "Unauthorized", - 402 => "Payment Required", - 403 => "Forbidden", - 404 => "Not Found", - 405 => "Method Not Allowed", - 406 => "Not Acceptable", - 407 => "Proxy Authentication Required", - 408 => "Request Timeout", - 409 => "Conflict", - 410 => "Gone", - 411 => "Length Required", - 412 => "Precondition Failed", - 413 => "Payload Too Large", - 414 => "URI Too Long", - 415 => "Unsupported Media Type", - 416 => "Range Not Satisfiable", - 417 => "Expectation Failed", - 421 => "Misdirected Request", - 422 => "Unprocessable Entity", - 423 => "Locked", - 424 => "Failed Dependency", - 426 => "Upgrade Required", - 428 => "Precondition Required", - 429 => "Too Many Requests", - 431 => "Request Header Fields Too Large", - 500 => "Internal Server Error", - 501 => "Not Implemented", - 502 => "Bad Gateway", - 503 => "Service Unavailable", - 504 => "Gateway Timeout", - 505 => "HTTP Version Not Supported", - 506 => "Variant Also Negotiates", - 507 => "Insufficient Storage", - 508 => "Loop Detected", - 510 => "Not Extended", - 511 => "Network Authentication Required" + 100 => 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 208 => 'Already Reported', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Payload Too Large', + 414 => 'URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Range Not Satisfiable', + 417 => 'Expectation Failed', + 421 => 'Misdirected Request', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 426 => 'Upgrade Required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 510 => 'Not Extended', + 511 => 'Network Authentication Required' ]; return $reasonPhraseLookup[$statusCode] ?? ''; } diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index ba64930..f592913 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -195,7 +195,7 @@ class ServerRequest extends Request implements ServerRequestInterface { if (!$this->isValidUploadedFilesTree($uploadedFiles)) { throw new \InvalidArgumentException( - "withUploadedFiles expects an array tree with UploadedFileInterface leaves." + 'withUploadedFiles expects an array tree with UploadedFileInterface leaves.' ); } @@ -249,7 +249,7 @@ class ServerRequest extends Request implements ServerRequestInterface public function withParsedBody($data) { if (!(is_null($data) || is_array($data) || is_object($data))) { - throw new \InvalidArgumentException("Parsed body must be null, array, or object."); + throw new \InvalidArgumentException('Parsed body must be null, array, or object.'); } $request = clone $this; @@ -350,15 +350,15 @@ class ServerRequest extends Request implements ServerRequestInterface $this->readUploadedFiles($_FILES); $this->queryParams = []; $this->uri = $this->readUri(); - if (isset($_SERVER["QUERY_STRING"])) { - parse_str($_SERVER["QUERY_STRING"], $this->queryParams); + if (isset($_SERVER['QUERY_STRING'])) { + parse_str($_SERVER['QUERY_STRING'], $this->queryParams); } - if (isset($_SERVER["SERVER_PROTOCOL"]) && $_SERVER["SERVER_PROTOCOL"] === "HTTP/1.0") { + if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0') { // The default is 1.1, so only update if 1.0 - $this->protocolVersion = "1.0"; + $this->protocolVersion = '1.0'; } - if (isset($_SERVER["REQUEST_METHOD"])) { - $this->method = $_SERVER["REQUEST_METHOD"]; + if (isset($_SERVER['REQUEST_METHOD'])) { + $this->method = $_SERVER['REQUEST_METHOD']; } $headers = $this->getServerRequestHeaders(); foreach ($headers as $key => $value) { @@ -366,9 +366,9 @@ class ServerRequest extends Request implements ServerRequestInterface } $this->body = $this->getStreamForBody(); - $contentType = $this->getHeaderLine("Content-type"); - if (strpos($contentType, "application/x-www-form-urlencoded") !== false - || strpos($contentType, "multipart/form-data") !== false) { + $contentType = $this->getHeaderLine('Content-type'); + if (strpos($contentType, 'application/x-www-form-urlencoded') !== false + || strpos($contentType, 'multipart/form-data') !== false) { $this->parsedBody = $_POST; } } @@ -388,37 +388,37 @@ class ServerRequest extends Request implements ServerRequestInterface array $value ): void { // Check for each of the expected keys. - if (isset($value["name"], $value["type"], $value["tmp_name"], $value["error"], $value["size"])) { + if (isset($value['name'], $value['type'], $value['tmp_name'], $value['error'], $value['size'])) { // This is a file. It may be a single file, or a list of files. // Check if these items are arrays. - if (is_array($value["name"]) - && is_array($value["type"]) - && is_array($value["tmp_name"]) - && is_array($value["error"]) - && is_array($value["size"]) + if (is_array($value['name']) + && is_array($value['type']) + && is_array($value['tmp_name']) + && is_array($value['error']) + && is_array($value['size']) ) { // Each item is an array. This is a list of uploaded files. $files = []; - $keys = array_keys($value["name"]); + $keys = array_keys($value['name']); foreach ($keys as $key) { $files[$key] = new UploadedFile( - $value["name"][$key], - $value["type"][$key], - $value["size"][$key], - $value["tmp_name"][$key], - $value["error"][$key] + $value['name'][$key], + $value['type'][$key], + $value['size'][$key], + $value['tmp_name'][$key], + $value['error'][$key] ); } $branch[$name] = $files; } else { // All expected keys are present and are not arrays. This is an uploaded file. $uploadedFile = new UploadedFile( - $value["name"], - $value["type"], - $value["size"], - $value["tmp_name"], - $value["error"] + $value['name'], + $value['type'], + $value['size'], + $value['tmp_name'], + $value['error'] ); $branch[$name] = $uploadedFile; } @@ -434,21 +434,21 @@ class ServerRequest extends Request implements ServerRequestInterface protected function readUri(): UriInterface { - $uri = ""; + $uri = ''; - $scheme = "http"; - if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] && $_SERVER["HTTPS"] !== "off") { - $scheme = "https"; + $scheme = 'http'; + if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && $_SERVER['HTTPS'] !== 'off') { + $scheme = 'https'; } - if (isset($_SERVER["HTTP_HOST"])) { - $authority = $_SERVER["HTTP_HOST"]; + if (isset($_SERVER['HTTP_HOST'])) { + $authority = $_SERVER['HTTP_HOST']; $uri .= "$scheme://$authority"; } // Path and query string - if (isset($_SERVER["REQUEST_URI"])) { - $uri .= $_SERVER["REQUEST_URI"]; + if (isset($_SERVER['REQUEST_URI'])) { + $uri .= $_SERVER['REQUEST_URI']; } return new Uri($uri); @@ -478,8 +478,8 @@ class ServerRequest extends Request implements ServerRequestInterface */ protected function getStreamForBody() { - $input = fopen("php://input", "rb"); - $temp = fopen("php://temp", "wb+"); + $input = fopen('php://input', 'rb'); + $temp = fopen('php://temp', 'wb+'); stream_copy_to_stream($input, $temp); rewind($temp); return new Stream($temp); @@ -495,7 +495,7 @@ class ServerRequest extends Request implements ServerRequestInterface // http://www.php.net/manual/en/function.getallheaders.php#84262 $headers = []; foreach ($_SERVER as $name => $value) { - if (substr($name, 0, 5) === "HTTP_") { + if (substr($name, 0, 5) === 'HTTP_') { $name = $this->normalizeHeaderName(substr($name, 5)); $headers[$name] = trim($value); } elseif ($this->isContentHeader($name) && !empty(trim($value))) { @@ -517,8 +517,8 @@ class ServerRequest extends Request implements ServerRequestInterface */ private function normalizeHeaderName($name) { - $name = ucwords(strtolower(str_replace("_", " ", $name))); - return str_replace(" ", "-", $name); + $name = ucwords(strtolower(str_replace('_', ' ', $name))); + return str_replace(' ', '-', $name); } /** @@ -534,7 +534,7 @@ class ServerRequest extends Request implements ServerRequestInterface // If not empty, the array MUST have all string keys. $keys = array_keys($root); - if (count($keys) !== count(array_filter($keys, "is_string"))) { + if (count($keys) !== count(array_filter($keys, 'is_string'))) { return false; } diff --git a/src/Message/Stream.php b/src/Message/Stream.php index 7bcd6f9..7103115 100644 --- a/src/Message/Stream.php +++ b/src/Message/Stream.php @@ -22,17 +22,17 @@ class Stream implements StreamInterface * @param resource|string $resource A file system pointer resource or * string */ - public function __construct($resource = "") + public function __construct($resource = '') { - if (is_resource($resource) && get_resource_type($resource) === "stream") { + if (is_resource($resource) && get_resource_type($resource) === 'stream') { $this->resource = $resource; } elseif (is_string($resource)) { - $this->resource = fopen("php://temp", "wb+"); - if ($resource !== "") { + $this->resource = fopen('php://temp', 'wb+'); + if ($resource !== '') { $this->write($resource); } } else { - throw new \InvalidArgumentException("Expected a resource handler."); + throw new \InvalidArgumentException('Expected a resource handler.'); } } @@ -103,8 +103,8 @@ class Stream implements StreamInterface } $statistics = fstat($this->resource); - if ($statistics && $statistics["size"]) { - return $statistics["size"]; + if ($statistics && $statistics['size']) { + return $statistics['size']; } return null; } @@ -118,12 +118,12 @@ class Stream implements StreamInterface public function tell() { if ($this->resource === null) { - throw new \RuntimeException("Unable to retrieve current position of detached stream."); + throw new \RuntimeException('Unable to retrieve current position of detached stream.'); } $position = ftell($this->resource); if ($position === false) { - throw new \RuntimeException("Unable to retrieve current position of file pointer."); + throw new \RuntimeException('Unable to retrieve current position of file pointer.'); } return $position; } @@ -153,7 +153,7 @@ class Stream implements StreamInterface return false; } - return $this->getMetadata("seekable") == 1; + return $this->getMetadata('seekable') == 1; } /** @@ -172,7 +172,7 @@ class Stream implements StreamInterface public function seek($offset, $whence = SEEK_SET) { if ($this->resource === null) { - throw new \RuntimeException("Unable to seek detached stream."); + throw new \RuntimeException('Unable to seek detached stream.'); } $result = -1; @@ -180,7 +180,7 @@ class Stream implements StreamInterface $result = fseek($this->resource, $offset, $whence); } if ($result === -1) { - throw new \RuntimeException("Unable to seek to position."); + throw new \RuntimeException('Unable to seek to position.'); } } @@ -198,7 +198,7 @@ class Stream implements StreamInterface public function rewind() { if ($this->resource === null) { - throw new \RuntimeException("Unable to seek detached stream."); + throw new \RuntimeException('Unable to seek detached stream.'); } $result = false; @@ -206,7 +206,7 @@ class Stream implements StreamInterface $result = rewind($this->resource); } if ($result === false) { - throw new \RuntimeException("Unable to rewind."); + throw new \RuntimeException('Unable to rewind.'); } } @@ -235,7 +235,7 @@ class Stream implements StreamInterface public function write($string) { if ($this->resource === null) { - throw new \RuntimeException("Unable to write to detached stream."); + throw new \RuntimeException('Unable to write to detached stream.'); } $result = false; @@ -243,7 +243,7 @@ class Stream implements StreamInterface $result = fwrite($this->resource, $string); } if ($result === false) { - throw new \RuntimeException("Unable to write to stream."); + throw new \RuntimeException('Unable to write to stream.'); } return $result; } @@ -276,7 +276,7 @@ class Stream implements StreamInterface public function read($length) { if ($this->resource === null) { - throw new \RuntimeException("Unable to read to detached stream."); + throw new \RuntimeException('Unable to read to detached stream.'); } $result = false; @@ -284,7 +284,7 @@ class Stream implements StreamInterface $result = fread($this->resource, $length); } if ($result === false) { - throw new \RuntimeException("Unable to read from stream."); + throw new \RuntimeException('Unable to read from stream.'); } return $result; } @@ -299,7 +299,7 @@ class Stream implements StreamInterface public function getContents() { if ($this->resource === null) { - throw new \RuntimeException("Unable to read to detached stream."); + throw new \RuntimeException('Unable to read to detached stream.'); } $result = false; @@ -307,7 +307,7 @@ class Stream implements StreamInterface $result = stream_get_contents($this->resource); } if ($result === false) { - throw new \RuntimeException("Unable to read from stream."); + throw new \RuntimeException('Unable to read from stream.'); } return $result; } diff --git a/src/Message/UploadedFile.php b/src/Message/UploadedFile.php index aa8094e..dad8b3d 100644 --- a/src/Message/UploadedFile.php +++ b/src/Message/UploadedFile.php @@ -91,13 +91,13 @@ class UploadedFile implements UploadedFileInterface public function getStream() { if ($this->tmpName === null) { - throw new \RuntimeException("Unable to read uploaded file."); + throw new \RuntimeException('Unable to read uploaded file.'); } if ($this->moved) { - throw new \RuntimeException("File has already been moved."); + throw new \RuntimeException('File has already been moved.'); } - if (php_sapi_name() !== "cli" && !is_uploaded_file($this->tmpName)) { - throw new \RuntimeException("File is not an uploaded file."); + if (php_sapi_name() !== 'cli' && !is_uploaded_file($this->tmpName)) { + throw new \RuntimeException('File is not an uploaded file.'); } return $this->stream; } @@ -124,9 +124,9 @@ class UploadedFile implements UploadedFileInterface public function moveTo($path) { if ($this->tmpName === null || !file_exists($this->tmpName)) { - throw new \RuntimeException("File " . $this->tmpName . " does not exist."); + throw new \RuntimeException('File ' . $this->tmpName . ' does not exist.'); } - if (php_sapi_name() === "cli") { + if (php_sapi_name() === 'cli') { rename($this->tmpName, $path); } else { move_uploaded_file($this->tmpName, $path); diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 4574e56..b21cb31 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -21,21 +21,21 @@ class Uri implements UriInterface const MAX_PORT = 65535; /** @var string */ - private $scheme = ""; + private $scheme = ''; /** @var string */ - private $user = ""; + private $user = ''; /** @var string|null */ private $password; /** @var string */ - private $host = ""; + private $host = ''; /** @var int|null */ private $port; /** @var string */ - private $path = ""; + private $path = ''; /** @var string */ - private $query = ""; + private $query = ''; /** @var string */ - private $fragment = ""; + private $fragment = ''; /** * @param string $uri A string representation of a URI. @@ -112,15 +112,15 @@ class Uri implements UriInterface */ public function getAuthority() { - $authority = ""; + $authority = ''; $host = $this->getHost(); - if ($host !== "") { + if ($host !== '') { // User Info $userInfo = $this->getUserInfo(); - if ($userInfo !== "") { - $authority .= $userInfo . "@"; + if ($userInfo !== '') { + $authority .= $userInfo . '@'; } // Host @@ -130,8 +130,8 @@ class Uri implements UriInterface $port = $this->getPort(); if ($port !== null) { $scheme = $this->getScheme(); - if (($scheme === "http" && $port !== 80) || ($scheme === "https" && $port !== 443)) { - $authority .= ":" . $port; + if (($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443)) { + $authority .= ':' . $port; } } } @@ -158,7 +158,7 @@ class Uri implements UriInterface { $userInfo = $this->user; if ($userInfo && $this->password) { - $userInfo .= ":" . $this->password; + $userInfo .= ':' . $this->password; } return $userInfo; } @@ -198,9 +198,9 @@ class Uri implements UriInterface { if ($this->port === null) { switch ($this->scheme) { - case "http": + case 'http': return 80; - case "https": + case 'https': return 443; default: return null; @@ -236,7 +236,7 @@ class Uri implements UriInterface */ public function getPath() { - if ($this->path === "*") { + if ($this->path === '*') { return $this->path; } return $this->percentEncode($this->path); @@ -305,9 +305,9 @@ class Uri implements UriInterface */ public function withScheme($scheme) { - $scheme = $scheme ? strtolower($scheme) : ""; - if (!in_array($scheme, ["", "http", "https"])) { - throw new \InvalidArgumentException("Scheme must be http, https, or empty."); + $scheme = $scheme ? strtolower($scheme) : ''; + if (!in_array($scheme, ['', 'http', 'https'])) { + throw new \InvalidArgumentException('Scheme must be http, https, or empty.'); } $uri = clone $this; $uri->scheme = $scheme; @@ -351,7 +351,7 @@ class Uri implements UriInterface public function withHost($host) { if (!is_string($host)) { - throw new \InvalidArgumentException("Host must be a string."); + throw new \InvalidArgumentException('Host must be a string.'); } $uri = clone $this; @@ -380,12 +380,12 @@ class Uri implements UriInterface { if (is_numeric($port)) { if ($port < self::MIN_PORT || $port > self::MAX_PORT) { - $message = sprintf("Port must be between %s and %s.", self::MIN_PORT, self::MAX_PORT); + $message = sprintf('Port must be between %s and %s.', self::MIN_PORT, self::MAX_PORT); throw new \InvalidArgumentException($message); } $port = (int) $port; } elseif ($port !== null) { - throw new \InvalidArgumentException("Port must be an int or null."); + throw new \InvalidArgumentException('Port must be an int or null.'); } $uri = clone $this; @@ -413,7 +413,7 @@ class Uri implements UriInterface public function withPath($path) { if (!is_string($path)) { - throw new \InvalidArgumentException("Path must be a string"); + throw new \InvalidArgumentException('Path must be a string'); } $uri = clone $this; $uri->path = $path; @@ -488,29 +488,29 @@ class Uri implements UriInterface */ public function __toString() { - $string = ""; + $string = ''; $authority = $this->getAuthority(); - if ($authority !== "") { + if ($authority !== '') { $scheme = $this->getScheme(); - if ($scheme !== "") { - $string = $scheme . ":"; + if ($scheme !== '') { + $string = $scheme . ':'; } $string .= "//$authority"; } $path = $this->getPath(); - if ($path !== "") { + if ($path !== '') { $string .= $path; } $query = $this->getQuery(); - if ($query !== "") { + if ($query !== '') { $string .= "?$query"; } $fragment = $this->getFragment(); - if ($fragment !== "") { + if ($fragment !== '') { $string .= "#$fragment"; } diff --git a/src/Routing/Route/MethodMap.php b/src/Routing/Route/MethodMap.php index 0e49959..51014b7 100644 --- a/src/Routing/Route/MethodMap.php +++ b/src/Routing/Route/MethodMap.php @@ -43,8 +43,8 @@ class MethodMap */ public function register($method, $dispatchable): void { - $methods = explode(",", $method); - $methods = array_map("trim", $methods); + $methods = explode(',', $method); + $methods = array_map('trim', $methods); foreach ($methods as $method) { $this->map[$method] = $dispatchable; } @@ -71,18 +71,18 @@ class MethodMap return $this->dispatchMiddleware($middleware, $request, $response, $next); } // For HEAD, dispatch GET by default. - if ($method === "HEAD" && isset($this->map["GET"])) { - $middleware = $this->map["GET"]; + if ($method === 'HEAD' && isset($this->map['GET'])) { + $middleware = $this->map['GET']; return $this->dispatchMiddleware($middleware, $request, $response, $next); } // Dispatch * middleware, if registered. - if (isset($this->map["*"])) { - $middleware = $this->map["*"]; + if (isset($this->map['*'])) { + $middleware = $this->map['*']; return $this->dispatchMiddleware($middleware, $request, $response, $next); } // Respond describing the allowed methods, either as a 405 response or // in response to an OPTIONS request. - if ($method === "OPTIONS") { + if ($method === 'OPTIONS') { $response = $response->withStatus(200); } else { $response = $response->withStatus(405); @@ -94,8 +94,8 @@ class MethodMap private function addAllowHeader(ResponseInterface $response): ResponseInterface { - $methods = join(",", $this->getAllowedMethods()); - return $response->withHeader("Allow", $methods); + $methods = join(',', $this->getAllowedMethods()); + return $response->withHeader('Allow', $methods); } /** @@ -105,12 +105,12 @@ class MethodMap { $methods = array_keys($this->map); // Add HEAD if GET is allowed and HEAD is not present. - if (in_array("GET", $methods) && !in_array("HEAD", $methods)) { - $methods[] = "HEAD"; + if (in_array('GET', $methods) && !in_array('HEAD', $methods)) { + $methods[] = 'HEAD'; } // Add OPTIONS if not already present. - if (!in_array("OPTIONS", $methods)) { - $methods[] = "OPTIONS"; + if (!in_array('OPTIONS', $methods)) { + $methods[] = 'OPTIONS'; } return $methods; } diff --git a/src/Routing/Route/PrefixRoute.php b/src/Routing/Route/PrefixRoute.php index f93c382..75efd99 100644 --- a/src/Routing/Route/PrefixRoute.php +++ b/src/Routing/Route/PrefixRoute.php @@ -6,7 +6,7 @@ class PrefixRoute extends Route { public function __construct(string $target, MethodMap $methodMap) { - parent::__construct(rtrim($target, "*"), $methodMap); + parent::__construct(rtrim($target, '*'), $methodMap); } public function getType(): int diff --git a/src/Routing/Route/RegexRoute.php b/src/Routing/Route/RegexRoute.php index 8f41bdc..9ff6fb9 100644 --- a/src/Routing/Route/RegexRoute.php +++ b/src/Routing/Route/RegexRoute.php @@ -26,7 +26,7 @@ class RegexRoute extends Route $this->captures = $captures; return true; } elseif ($matched === false) { - throw new \RuntimeException("Invalid regular expression: " . $this->getTarget()); + throw new \RuntimeException('Invalid regular expression: ' . $this->getTarget()); } return false; } diff --git a/src/Routing/Route/RouteFactory.php b/src/Routing/Route/RouteFactory.php index d1bd2ca..6007e44 100644 --- a/src/Routing/Route/RouteFactory.php +++ b/src/Routing/Route/RouteFactory.php @@ -29,12 +29,12 @@ class RouteFactory implements RouteFactoryInterface */ public function create($target) { - if ($target[0] === "/") { + if ($target[0] === '/') { // Possible static, prefix, or template // PrefixRoutes end with * - if (substr($target, -1) === "*") { + if (substr($target, -1) === '*') { return new PrefixRoute($target, new MethodMap($this->dispatcher)); } diff --git a/src/Routing/Route/TemplateRoute.php b/src/Routing/Route/TemplateRoute.php index d2fb3a5..730b3a9 100644 --- a/src/Routing/Route/TemplateRoute.php +++ b/src/Routing/Route/TemplateRoute.php @@ -53,7 +53,7 @@ class TemplateRoute extends Route private function matchesStartOfRequestTarget(string $requestTarget): bool { - $firstVarPos = strpos($this->target, "{"); + $firstVarPos = strpos($this->target, '{'); if ($firstVarPos === false) { return $requestTarget === $this->target; } @@ -65,7 +65,7 @@ class TemplateRoute extends Route $variables = []; // Isolate the named captures. - $keys = array_filter(array_keys($matches), "is_string"); + $keys = array_filter(array_keys($matches), 'is_string'); // Store named captures to the variables. foreach ($keys as $key) { @@ -73,7 +73,7 @@ class TemplateRoute extends Route if (isset($this->explosions[$key])) { $values = explode($this->explosions[$key], $value); - $variables[$key] = array_map("urldecode", $values); + $variables[$key] = array_map('urldecode', $values); } else { $value = urldecode($value); $variables[$key] = $value; @@ -90,16 +90,16 @@ class TemplateRoute extends Route // Escape allowable characters with regex meaning. $escape = [ - "." => "\\.", - "-" => "\\-", - "+" => "\\+", - "*" => "\\*" + '.' => '\\.', + '-' => '\\-', + '+' => '\\+', + '*' => '\\*' ]; $pattern = str_replace(array_keys($escape), array_values($escape), $pattern); $unescape = [ - "{\\+" => "{+", - "{\\." => "{.", - "\\*}" => "*}" + '{\\+' => '{+', + '{\\.' => '{.', + '\\*}' => '*}' ]; $pattern = str_replace(array_keys($unescape), array_values($unescape), $pattern); @@ -108,7 +108,7 @@ class TemplateRoute extends Route $pattern = preg_replace_callback( self::URI_TEMPLATE_EXPRESSION_RE, - [$this, "uriVariableReplacementCallback"], + [$this, 'uriVariableReplacementCallback'], $pattern ); @@ -120,35 +120,35 @@ class TemplateRoute extends Route $name = $matches[1]; $pattern = self::RE_UNRESERVED; - $prefix = ""; - $delimiter = ","; - $explodeDelimiter = ","; + $prefix = ''; + $delimiter = ','; + $explodeDelimiter = ','; // Read the first character as an operator. This determines which // characters to allow in the match. $operator = $name[0]; // Read the last character as the modifier. - $explosion = (substr($name, -1, 1) === "*"); + $explosion = (substr($name, -1, 1) === '*'); switch ($operator) { - case "+": + case '+': $name = substr($name, 1); - $pattern = ".*"; + $pattern = '.*'; break; - case ".": + case '.': $name = substr($name, 1); - $prefix = "\\."; - $delimiter = "\\."; - $explodeDelimiter = "."; + $prefix = '\\.'; + $delimiter = '\\.'; + $explodeDelimiter = '.'; break; - case "/": + case '/': $name = substr($name, 1); - $prefix = "\\/"; - $delimiter = "\\/"; + $prefix = '\\/'; + $delimiter = '\\/'; if ($explosion) { $pattern = '[0-9a-zA-Z\-._\~%,\/]*'; // Unreserved + "," and "/" - $explodeDelimiter = "/"; + $explodeDelimiter = '/'; } break; } @@ -162,7 +162,7 @@ class TemplateRoute extends Route $this->explosions[$name] = $explodeDelimiter; } - $names = explode(",", $name); + $names = explode(',', $name); $results = []; foreach ($names as $name) { $results[] = "(?<{$name}>{$pattern})"; diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 172d214..860892c 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -229,7 +229,7 @@ class Router $this->staticRoutes[$route->getTarget()] = $route; break; case RouteInterface::TYPE_PREFIX: - $this->prefixRoutes[rtrim($route->getTarget(), "*")] = $route; + $this->prefixRoutes[rtrim($route->getTarget(), '*')] = $route; break; case RouteInterface::TYPE_PATTERN: $this->patternRoutes[] = $route; diff --git a/src/Transmission/Transmitter.php b/src/Transmission/Transmitter.php index 8bed7d5..768c458 100644 --- a/src/Transmission/Transmitter.php +++ b/src/Transmission/Transmitter.php @@ -64,12 +64,12 @@ class Transmitter implements TransmitterInterface // - Response does not have a Transfer-encoding: chunked header // - Response body stream is readable and reports a non-null size // - if (!$response->hasHeader("Content-length") - && !(strtolower($response->getHeaderLine("Transfer-encoding")) === "chunked") + if (!$response->hasHeader('Content-length') + && !(strtolower($response->getHeaderLine('Transfer-encoding')) === 'chunked') ) { $size = $response->getBody()->getSize(); if ($size !== null) { - $response = $response->withHeader("Content-length", (string) $size); + $response = $response->withHeader('Content-length', (string) $size); } } return $response; diff --git a/test/tests/unit/Dispatching/DispatchStackTest.php b/test/tests/unit/Dispatching/DispatchStackTest.php index 8ed434c..782dded 100644 --- a/test/tests/unit/Dispatching/DispatchStackTest.php +++ b/test/tests/unit/Dispatching/DispatchStackTest.php @@ -29,19 +29,19 @@ class DispatchStackTest extends TestCase $callOrder = []; $stack = new DispatchStack(new Dispatcher()); $stack->add(function ($request, $response, $next) use (&$callOrder) { - $callOrder[] = "first"; + $callOrder[] = 'first'; return $next($request, $response); }); $stack->add(function ($request, $response, $next) use (&$callOrder) { - $callOrder[] = "second"; + $callOrder[] = 'second'; return $next($request, $response); }); $stack->add(function ($request, $response, $next) use (&$callOrder) { - $callOrder[] = "third"; + $callOrder[] = 'third'; return $next($request, $response); }); $stack($this->request, $this->response, $this->next); - $this->assertEquals(["first", "second", "third"], $callOrder); + $this->assertEquals(['first', 'second', 'third'], $callOrder); } public function testCallsNextAfterDispatchingEmptyStack() diff --git a/test/tests/unit/Message/HeaderCollectionTest.php b/test/tests/unit/Message/HeaderCollectionTest.php index 26fa194..730b575 100644 --- a/test/tests/unit/Message/HeaderCollectionTest.php +++ b/test/tests/unit/Message/HeaderCollectionTest.php @@ -10,57 +10,57 @@ class HeaderCollectionTest extends TestCase public function testAddsSingleHeaderAndIndicatesCaseInsensitiveIsset() { $collection = new HeaderCollection(); - $collection["Content-Type"] = "application/json"; - $this->assertTrue(isset($collection["content-type"])); + $collection['Content-Type'] = 'application/json'; + $this->assertTrue(isset($collection['content-type'])); } public function testAddsMultipleHeadersAndIndicatesCaseInsensitiveIsset() { $collection = new HeaderCollection(); - $collection["Set-Cookie"] = "cat=Molly"; - $collection["SET-COOKIE"] = "dog=Bear"; - $this->assertTrue(isset($collection["set-cookie"])); + $collection['Set-Cookie'] = 'cat=Molly'; + $collection['SET-COOKIE'] = 'dog=Bear'; + $this->assertTrue(isset($collection['set-cookie'])); } public function testReturnsHeadersWithCaseInsensitiveHeaderName() { $collection = new HeaderCollection(); - $collection["Set-Cookie"] = "cat=Molly"; - $collection["SET-COOKIE"] = "dog=Bear"; + $collection['Set-Cookie'] = 'cat=Molly'; + $collection['SET-COOKIE'] = 'dog=Bear'; - $headers = $collection["set-cookie"]; - $this->assertEquals(2, count(array_intersect($headers, ["cat=Molly", "dog=Bear"]))); + $headers = $collection['set-cookie']; + $this->assertEquals(2, count(array_intersect($headers, ['cat=Molly', 'dog=Bear']))); } public function testRemovesHeadersWithCaseInsensitiveHeaderName() { $collection = new HeaderCollection(); - $collection["Set-Cookie"] = "cat=Molly"; - $collection["SET-COOKIE"] = "dog=Bear"; - unset($collection["set-cookie"]); - $this->assertFalse(isset($collection["set-cookie"])); + $collection['Set-Cookie'] = 'cat=Molly'; + $collection['SET-COOKIE'] = 'dog=Bear'; + unset($collection['set-cookie']); + $this->assertFalse(isset($collection['set-cookie'])); } /** @coversNothing */ public function testCloneMakesDeepCopyOfHeaders() { $collection = new HeaderCollection(); - $collection["Set-Cookie"] = "cat=Molly"; + $collection['Set-Cookie'] = 'cat=Molly'; $clone = clone $collection; - unset($clone["Set-Cookie"]); + unset($clone['Set-Cookie']); - $this->assertTrue(isset($collection["set-cookie"]) && !isset($clone["set-cookie"])); + $this->assertTrue(isset($collection['set-cookie']) && !isset($clone['set-cookie'])); } public function testIteratesWithOriginalKeys() { $collection = new HeaderCollection(); - $collection["Content-length"] = "100"; - $collection["Set-Cookie"] = "cat=Molly"; - $collection["Set-Cookie"] = "dog=Bear"; - $collection["Content-type"] = "application/json"; - unset($collection["Content-length"]); + $collection['Content-length'] = '100'; + $collection['Set-Cookie'] = 'cat=Molly'; + $collection['Set-Cookie'] = 'dog=Bear'; + $collection['Content-type'] = 'application/json'; + unset($collection['Content-length']); $headers = []; @@ -68,7 +68,7 @@ class HeaderCollectionTest extends TestCase $headers[] = $key; } - $expected = ["Content-type", "Set-Cookie"]; + $expected = ['Content-type', 'Set-Cookie']; $countUnmatched = count(array_diff($expected, $headers)) + count(array_diff($headers, $expected)); $this->assertEquals(0, $countUnmatched); @@ -77,11 +77,11 @@ class HeaderCollectionTest extends TestCase public function testIteratesWithOriginalKeysAndValues() { $collection = new HeaderCollection(); - $collection["Content-length"] = "100"; - $collection["Set-Cookie"] = "cat=Molly"; - $collection["Set-Cookie"] = "dog=Bear"; - $collection["Content-type"] = "application/json"; - unset($collection["Content-length"]); + $collection['Content-length'] = '100'; + $collection['Set-Cookie'] = 'cat=Molly'; + $collection['Set-Cookie'] = 'dog=Bear'; + $collection['Content-type'] = 'application/json'; + unset($collection['Content-length']); $headers = []; @@ -96,8 +96,8 @@ class HeaderCollectionTest extends TestCase } $expected = [ - "Set-Cookie" => ["cat=Molly", "dog=Bear"], - "Content-type" => ["application/json"] + 'Set-Cookie' => ['cat=Molly', 'dog=Bear'], + 'Content-type' => ['application/json'] ]; $this->assertEquals($expected, $headers); diff --git a/test/tests/unit/Message/NullStreamTest.php b/test/tests/unit/Message/NullStreamTest.php index 776bde0..e16d246 100644 --- a/test/tests/unit/Message/NullStreamTest.php +++ b/test/tests/unit/Message/NullStreamTest.php @@ -11,7 +11,7 @@ class NullStreamTest extends TestCase public function testCastsToString() { $stream = new NullStream(); - $this->assertEquals("", (string) $stream); + $this->assertEquals('', (string) $stream); } public function testCloseDoesNothing() @@ -75,7 +75,7 @@ class NullStreamTest extends TestCase { $this->expectException(RuntimeException::class); $stream = new NullStream(); - $stream->write(""); + $stream->write(''); } public function testIsReadableReturnsTrue() @@ -87,13 +87,13 @@ class NullStreamTest extends TestCase public function testReadReturnsEmptyString() { $stream = new NullStream(); - $this->assertEquals("", $stream->read(100)); + $this->assertEquals('', $stream->read(100)); } public function testGetContentsReturnsEmptyString() { $stream = new NullStream(); - $this->assertEquals("", $stream->getContents()); + $this->assertEquals('', $stream->getContents()); } public function testGetMetadataReturnsNull() @@ -105,6 +105,6 @@ class NullStreamTest extends TestCase public function testGetMetadataReturnsNullWithKey() { $stream = new NullStream(); - $this->assertNull($stream->getMetadata("size")); + $this->assertNull($stream->getMetadata('size')); } } diff --git a/test/tests/unit/Message/RequestTest.php b/test/tests/unit/Message/RequestTest.php index 8b8cb9f..ad81f3c 100644 --- a/test/tests/unit/Message/RequestTest.php +++ b/test/tests/unit/Message/RequestTest.php @@ -61,8 +61,8 @@ class RequestTest extends TestCase public function testGetRequestTargetPrefersExplicitRequestTarget() { $request = new Request(); - $request = $request->withRequestTarget("*"); - $this->assertEquals("*", $request->getRequestTarget()); + $request = $request->withRequestTarget('*'); + $this->assertEquals('*', $request->getRequestTarget()); } public function testGetRequestTargetUsesOriginFormOfUri() @@ -70,20 +70,20 @@ class RequestTest extends TestCase $uri = new Uri('/my/path?cat=Molly&dog=Bear'); $request = new Request(); $request = $request->withUri($uri); - $this->assertEquals("/my/path?cat=Molly&dog=Bear", $request->getRequestTarget()); + $this->assertEquals('/my/path?cat=Molly&dog=Bear', $request->getRequestTarget()); } public function testGetRequestTargetReturnsSlashByDefault() { $request = new Request(); - $this->assertEquals("/", $request->getRequestTarget()); + $this->assertEquals('/', $request->getRequestTarget()); } public function testWithRequestTargetCreatesNewInstance() { $request = new Request(); - $request = $request->withRequestTarget("*"); - $this->assertEquals("*", $request->getRequestTarget()); + $request = $request->withRequestTarget('*'); + $this->assertEquals('*', $request->getRequestTarget()); } // ------------------------------------------------------------------------ @@ -92,14 +92,14 @@ class RequestTest extends TestCase public function testGetMethodReturnsGetByDefault() { $request = new Request(); - $this->assertEquals("GET", $request->getMethod()); + $this->assertEquals('GET', $request->getMethod()); } public function testWithMethodCreatesNewInstance() { $request = new Request(); - $request = $request->withMethod("POST"); - $this->assertEquals("POST", $request->getMethod()); + $request = $request->withMethod('POST'); + $this->assertEquals('POST', $request->getMethod()); } /** @@ -117,7 +117,7 @@ class RequestTest extends TestCase return [ [0], [false], - ["WITH SPACE"] + ['WITH SPACE'] ]; } @@ -146,44 +146,44 @@ class RequestTest extends TestCase $request1 = new Request(); $request1 = $request1->withUri($uri1); - $request1 = $request1->withHeader("Accept", "application/json"); + $request1 = $request1->withHeader('Accept', 'application/json'); $request2 = $request1->withUri($uri2); - $request2 = $request2->withHeader("Accept", "text/plain"); + $request2 = $request2->withHeader('Accept', 'text/plain'); - $this->assertNotEquals($request1->getHeader("Accept"), $request2->getHeader("Accept")); + $this->assertNotEquals($request1->getHeader('Accept'), $request2->getHeader('Accept')); } public function testWithUriUpdatesHostHeader() { - $hostname = "bar.com"; + $hostname = 'bar.com'; $uri = new uri("http://$hostname"); $request = new Request(); - $request = $request->withHeader("Host", "foo.com"); + $request = $request->withHeader('Host', 'foo.com'); $request = $request->withUri($uri); - $this->assertSame([$hostname], $request->getHeader("Host")); + $this->assertSame([$hostname], $request->getHeader('Host')); } public function testWithUriDoesNotUpdatesHostHeaderWhenUriHasNoHost() { - $hostname = "foo.com"; + $hostname = 'foo.com'; $uri = new Uri(); $request = new Request(); - $request = $request->withHeader("Host", $hostname); + $request = $request->withHeader('Host', $hostname); $request = $request->withUri($uri); - $this->assertSame([$hostname], $request->getHeader("Host")); + $this->assertSame([$hostname], $request->getHeader('Host')); } public function testPreserveHostUpdatesHostHeaderWhenHeaderIsOriginallyMissing() { - $hostname = "foo.com"; + $hostname = 'foo.com'; $uri = new uri("http://$hostname"); $request = new Request(); $request = $request->withUri($uri, true); - $this->assertSame([$hostname], $request->getHeader("Host")); + $this->assertSame([$hostname], $request->getHeader('Host')); } public function testPreserveHostDoesNotUpdatesWhenBothAreMissingHosts() @@ -192,17 +192,17 @@ class RequestTest extends TestCase $request = new Request(); $request = $request->withUri($uri, true); - $this->assertSame([], $request->getHeader("Host")); + $this->assertSame([], $request->getHeader('Host')); } public function testPreserveHostDoesNotUpdateHostHeader() { - $hostname = "foo.com"; - $uri = new uri("http://bar.com"); + $hostname = 'foo.com'; + $uri = new uri('http://bar.com'); $request = new Request(); - $request = $request->withHeader("Host", $hostname); + $request = $request->withHeader('Host', $hostname); $request = $request->withUri($uri, true); - $this->assertSame([$hostname], $request->getHeader("Host")); + $this->assertSame([$hostname], $request->getHeader('Host')); } } diff --git a/test/tests/unit/Message/ResponseTest.php b/test/tests/unit/Message/ResponseTest.php index 6733040..9f119e5 100644 --- a/test/tests/unit/Message/ResponseTest.php +++ b/test/tests/unit/Message/ResponseTest.php @@ -20,9 +20,9 @@ class ResponseTest extends TestCase public function testSetsHeadersOnConstruction() { $response = new Response(200, [ - "X-foo" => ["bar","baz"] + 'X-foo' => ['bar','baz'] ]); - $this->assertEquals(["bar","baz"], $response->getHeader("X-foo")); + $this->assertEquals(['bar','baz'], $response->getHeader('X-foo')); } public function testSetsBodyOnConstruction() @@ -53,45 +53,45 @@ class ResponseTest extends TestCase public function statusProvider() { return [ - [100, null, "Continue"], - [101, null, "Switching Protocols"], - [200, null, "OK"], - [201, null, "Created"], - [202, null, "Accepted"], - [203, null, "Non-Authoritative Information"], - [204, null, "No Content"], - [205, null, "Reset Content"], - [206, null, "Partial Content"], - [300, null, "Multiple Choices"], - [301, null, "Moved Permanently"], - [302, null, "Found"], - [303, null, "See Other"], - [304, null, "Not Modified"], - [305, null, "Use Proxy"], - [400, null, "Bad Request"], - [401, null, "Unauthorized"], - [402, null, "Payment Required"], - [403, null, "Forbidden"], - [404, null, "Not Found"], - [405, null, "Method Not Allowed"], - [406, null, "Not Acceptable"], - [407, null, "Proxy Authentication Required"], - [408, null, "Request Timeout"], - [409, null, "Conflict"], - [410, null, "Gone"], - [411, null, "Length Required"], - [412, null, "Precondition Failed"], - [413, null, "Payload Too Large"], - [414, null, "URI Too Long"], - [415, null, "Unsupported Media Type"], - [500, null, "Internal Server Error"], - [501, null, "Not Implemented"], - [502, null, "Bad Gateway"], - [503, null, "Service Unavailable"], - [504, null, "Gateway Timeout"], - [505, null, "HTTP Version Not Supported"], - [598, null, ""], - [599, "Nonstandard", "Nonstandard"] + [100, null, 'Continue'], + [101, null, 'Switching Protocols'], + [200, null, 'OK'], + [201, null, 'Created'], + [202, null, 'Accepted'], + [203, null, 'Non-Authoritative Information'], + [204, null, 'No Content'], + [205, null, 'Reset Content'], + [206, null, 'Partial Content'], + [300, null, 'Multiple Choices'], + [301, null, 'Moved Permanently'], + [302, null, 'Found'], + [303, null, 'See Other'], + [304, null, 'Not Modified'], + [305, null, 'Use Proxy'], + [400, null, 'Bad Request'], + [401, null, 'Unauthorized'], + [402, null, 'Payment Required'], + [403, null, 'Forbidden'], + [404, null, 'Not Found'], + [405, null, 'Method Not Allowed'], + [406, null, 'Not Acceptable'], + [407, null, 'Proxy Authentication Required'], + [408, null, 'Request Timeout'], + [409, null, 'Conflict'], + [410, null, 'Gone'], + [411, null, 'Length Required'], + [412, null, 'Precondition Failed'], + [413, null, 'Payload Too Large'], + [414, null, 'URI Too Long'], + [415, null, 'Unsupported Media Type'], + [500, null, 'Internal Server Error'], + [501, null, 'Not Implemented'], + [502, null, 'Bad Gateway'], + [503, null, 'Service Unavailable'], + [504, null, 'Gateway Timeout'], + [505, null, 'HTTP Version Not Supported'], + [598, null, ''], + [599, 'Nonstandard', 'Nonstandard'] ]; } @@ -99,11 +99,11 @@ class ResponseTest extends TestCase { $response1 = new Response(); $response1 = $response1->withStatus(200); - $response1 = $response1->withHeader("Content-type", "application/json"); + $response1 = $response1->withHeader('Content-type', 'application/json'); $response2 = $response1->withStatus(404); - $response2 = $response2->withHeader("Content-type", "text/plain"); + $response2 = $response2->withHeader('Content-type', 'text/plain'); - $this->assertNotEquals($response1->getStatusCode(), $response2->getHeader("Content-type")); + $this->assertNotEquals($response1->getStatusCode(), $response2->getHeader('Content-type')); } } diff --git a/test/tests/unit/Message/ServerRequestTest.php b/test/tests/unit/Message/ServerRequestTest.php index 83faa54..8b5a08c 100644 --- a/test/tests/unit/Message/ServerRequestTest.php +++ b/test/tests/unit/Message/ServerRequestTest.php @@ -18,19 +18,19 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsFromRequest() { $_SERVER = [ - "HTTP_HOST" => "localhost", - "HTTP_ACCEPT" => "application/json", - "HTTP_CONTENT_TYPE" => "application/x-www-form-urlencoded", - "QUERY_STRING" => "guinea_pig=Claude&hamster=Fizzgig" + 'HTTP_HOST' => 'localhost', + 'HTTP_ACCEPT' => 'application/json', + 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded', + 'QUERY_STRING' => 'guinea_pig=Claude&hamster=Fizzgig' ]; $_COOKIE = [ - "cat" => "Molly" + 'cat' => 'Molly' ]; $_FILES = []; $_POST = [ - "dog" => "Bear" + 'dog' => 'Bear' ]; - $attributes = ["guinea_pig" => "Claude"]; + $attributes = ['guinea_pig' => 'Claude']; $request = ServerRequest::getServerRequest($attributes); $this->assertNotNull($request); return $request; @@ -46,9 +46,9 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsProtocolVersion($expectedProtocol, $serverProtocol) { $_SERVER = [ - "HTTP_HOST" => "localhost", - "SERVER_PROTOCOL" => $serverProtocol, - "REQUEST_METHOD" => "GET" + 'HTTP_HOST' => 'localhost', + 'SERVER_PROTOCOL' => $serverProtocol, + 'REQUEST_METHOD' => 'GET' ]; $request = ServerRequest::getServerRequest(); $this->assertEquals($expectedProtocol, $request->getProtocolVersion()); @@ -57,10 +57,10 @@ class ServerRequestTest extends TestCase public function protocolVersionProvider() { return [ - ["1.1", "HTTP/1.1"], - ["1.0", "HTTP/1.0"], - ["1.1", null], - ["1.1", "INVALID"] + ['1.1', 'HTTP/1.1'], + ['1.0', 'HTTP/1.0'], + ['1.1', null], + ['1.1', 'INVALID'] ]; } @@ -71,8 +71,8 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsMethod($expectedMethod, $serverMethod) { $_SERVER = [ - "HTTP_HOST" => "localhost", - "REQUEST_METHOD" => $serverMethod + 'HTTP_HOST' => 'localhost', + 'REQUEST_METHOD' => $serverMethod ]; $request = ServerRequest::getServerRequest(); $this->assertEquals($expectedMethod, $request->getMethod()); @@ -81,12 +81,12 @@ class ServerRequestTest extends TestCase public function methodProvider() { return [ - ["GET", "GET"], - ["POST", "POST"], - ["DELETE", "DELETE"], - ["PUT", "PUT"], - ["OPTIONS", "OPTIONS"], - ["GET", null] + ['GET', 'GET'], + ['POST', 'POST'], + ['DELETE', 'DELETE'], + ['PUT', 'PUT'], + ['OPTIONS', 'OPTIONS'], + ['GET', null] ]; } @@ -97,8 +97,8 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsRequestTargetFromRequest($expectedRequestTarget, $serverRequestUri) { $_SERVER = [ - "HTTP_HOST" => "localhost", - "REQUEST_URI" => $serverRequestUri + 'HTTP_HOST' => 'localhost', + 'REQUEST_URI' => $serverRequestUri ]; $request = ServerRequest::getServerRequest(); $this->assertEquals($expectedRequestTarget, $request->getRequestTarget()); @@ -107,10 +107,10 @@ class ServerRequestTest extends TestCase public function requestTargetProvider() { return [ - ["/", "/"], - ["/hello", "/hello"], - ["/my/path.txt", "/my/path.txt"], - ["/", null] + ['/', '/'], + ['/hello', '/hello'], + ['/my/path.txt', '/my/path.txt'], + ['/', null] ]; } @@ -118,7 +118,7 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsHeaders($request) { /** @var ServerRequest $request */ - $this->assertEquals(["application/json"], $request->getHeader("Accept")); + $this->assertEquals(['application/json'], $request->getHeader('Accept')); } /** @@ -127,12 +127,12 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsContentHeaders() { $_SERVER = [ - "CONTENT_LENGTH" => "1024", - "CONTENT_TYPE" => "application/json" + 'CONTENT_LENGTH' => '1024', + 'CONTENT_TYPE' => 'application/json' ]; $request = ServerRequest::getServerRequest(); - $this->assertEquals("1024", $request->getHeaderLine("Content-length")); - $this->assertEquals("application/json", $request->getHeaderLine("Content-type")); + $this->assertEquals('1024', $request->getHeaderLine('Content-length')); + $this->assertEquals('application/json', $request->getHeaderLine('Content-type')); } /** @@ -141,22 +141,22 @@ class ServerRequestTest extends TestCase public function testGetServerRequestDoesNotReadEmptyContentHeaders() { $_SERVER = [ - "CONTENT_LENGTH" => "", - "CONTENT_TYPE" => " " + 'CONTENT_LENGTH' => '', + 'CONTENT_TYPE' => ' ' ]; $request = ServerRequest::getServerRequest(); - $this->assertFalse($request->hasHeader("Content-length")); - $this->assertFalse($request->hasHeader("Content-type")); + $this->assertFalse($request->hasHeader('Content-length')); + $this->assertFalse($request->hasHeader('Content-type')); } public function testGetServerRequestReadsBody() { $body = new NullStream(); $request = $this->getMockBuilder('WellRESTed\Message\ServerRequest') - ->setMethods(["getStreamForBody"]) + ->setMethods(['getStreamForBody']) ->getMock(); $request->expects($this->any()) - ->method("getStreamForBody") + ->method('getStreamForBody') ->will($this->returnValue($body)); $called = false; @@ -185,30 +185,30 @@ class ServerRequestTest extends TestCase { return [ [ - new Uri("http://localhost/path"), + new Uri('http://localhost/path'), [ - "HTTPS" => "off", - "HTTP_HOST" => "localhost", - "REQUEST_URI" => "/path", - "QUERY_STRING" => "" + 'HTTPS' => 'off', + 'HTTP_HOST' => 'localhost', + 'REQUEST_URI' => '/path', + 'QUERY_STRING' => '' ] ], [ - new Uri("https://foo.com/path/to/stuff?cat=molly"), + new Uri('https://foo.com/path/to/stuff?cat=molly'), [ - "HTTPS" => "1", - "HTTP_HOST" => "foo.com", - "REQUEST_URI" => "/path/to/stuff?cat=molly", - "QUERY_STRING" => "cat=molly" + 'HTTPS' => '1', + 'HTTP_HOST' => 'foo.com', + 'REQUEST_URI' => '/path/to/stuff?cat=molly', + 'QUERY_STRING' => 'cat=molly' ] ], [ - new Uri("http://foo.com:8080/path/to/stuff?cat=molly"), + new Uri('http://foo.com:8080/path/to/stuff?cat=molly'), [ - "HTTP" => "1", - "HTTP_HOST" => "foo.com:8080", - "REQUEST_URI" => "/path/to/stuff?cat=molly", - "QUERY_STRING" => "cat=molly" + 'HTTP' => '1', + 'HTTP_HOST' => 'foo.com:8080', + 'REQUEST_URI' => '/path/to/stuff?cat=molly', + 'QUERY_STRING' => 'cat=molly' ] ] ]; @@ -221,21 +221,21 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsServerParams($request) { /** @var ServerRequest $request */ - $this->assertEquals("localhost", $request->getServerParams()["HTTP_HOST"]); + $this->assertEquals('localhost', $request->getServerParams()['HTTP_HOST']); } /** @depends testGetServerRequestReadsFromRequest */ public function testGetServerRequestReadsCookieParams($request) { /** @var ServerRequest $request */ - $this->assertEquals("Molly", $request->getCookieParams()["cat"]); + $this->assertEquals('Molly', $request->getCookieParams()['cat']); } /** @depends testGetServerRequestReadsFromRequest */ public function testGetServerRequestReadsQueryParams($request) { /** @var ServerRequest $request */ - $this->assertEquals("Claude", $request->getQueryParams()["guinea_pig"]); + $this->assertEquals('Claude', $request->getQueryParams()['guinea_pig']); } /** @@ -245,77 +245,77 @@ class ServerRequestTest extends TestCase public function testGetServerRequestReadsUploadedFiles($file, $path) { $_SERVER = [ - "HTTP_HOST" => "localhost", - "HTTP_ACCEPT" => "application/json", - "HTTP_CONTENT_TYPE" => "application/x-www-form-urlencoded" + 'HTTP_HOST' => 'localhost', + 'HTTP_ACCEPT' => 'application/json', + 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded' ]; $_FILES = [ - "single" => [ - "name" => "single.txt", - "type" => "text/plain", - "tmp_name" => "/tmp/php9hNlHe", - "error" => UPLOAD_ERR_OK, - "size" => 524 + 'single' => [ + 'name' => 'single.txt', + 'type' => 'text/plain', + 'tmp_name' => '/tmp/php9hNlHe', + 'error' => UPLOAD_ERR_OK, + 'size' => 524 ], - "nested" => [ - "level2" => [ - "name" => "nested.json", - "type" => "application/json", - "tmp_name" => "/tmp/phpadhjk", - "error" => UPLOAD_ERR_OK, - "size" => 1024 + 'nested' => [ + 'level2' => [ + 'name' => 'nested.json', + 'type' => 'application/json', + 'tmp_name' => '/tmp/phpadhjk', + 'error' => UPLOAD_ERR_OK, + 'size' => 1024 ] ], - "nestedList" => [ - "level2" => [ - "name" => [ - 0 => "nestedList0.jpg", - 1 => "nestedList1.jpg", - 2 => "" + 'nestedList' => [ + 'level2' => [ + 'name' => [ + 0 => 'nestedList0.jpg', + 1 => 'nestedList1.jpg', + 2 => '' ], - "type" => [ - 0 => "image/jpeg", - 1 => "image/jpeg", - 2 => "" + 'type' => [ + 0 => 'image/jpeg', + 1 => 'image/jpeg', + 2 => '' ], - "tmp_name" => [ - 0 => "/tmp/phpjpg0", - 1 => "/tmp/phpjpg1", - 2 => "" + 'tmp_name' => [ + 0 => '/tmp/phpjpg0', + 1 => '/tmp/phpjpg1', + 2 => '' ], - "error" => [ + 'error' => [ 0 => UPLOAD_ERR_OK, 1 => UPLOAD_ERR_OK, 2 => UPLOAD_ERR_NO_FILE ], - "size" => [ + 'size' => [ 0 => 256, 1 => 4096, 2 => 0 ] ] ], - "nestedDictionary" => [ - "level2" => [ - "name" => [ - "file0" => "nestedDictionary0.jpg", - "file1" => "nestedDictionary1.jpg" + 'nestedDictionary' => [ + 'level2' => [ + 'name' => [ + 'file0' => 'nestedDictionary0.jpg', + 'file1' => 'nestedDictionary1.jpg' ], - "type" => [ - "file0" => "image/png", - "file1" => "image/png" + 'type' => [ + 'file0' => 'image/png', + 'file1' => 'image/png' ], - "tmp_name" => [ - "file0" => "/tmp/phppng0", - "file1" => "/tmp/phppng1" + 'tmp_name' => [ + 'file0' => '/tmp/phppng0', + 'file1' => '/tmp/phppng1' ], - "error" => [ - "file0" => UPLOAD_ERR_OK, - "file1" => UPLOAD_ERR_OK + 'error' => [ + 'file0' => UPLOAD_ERR_OK, + 'file1' => UPLOAD_ERR_OK ], - "size" => [ - "file0" => 256, - "file1" => 4096 + 'size' => [ + 'file0' => 256, + 'file1' => 4096 ] ] ] @@ -331,13 +331,13 @@ class ServerRequestTest extends TestCase public function uploadedFileProvider() { return [ - [new UploadedFile("single.txt", "text/plain", 524, "/tmp/php9hNlHe", UPLOAD_ERR_OK), ["single"]], - [new UploadedFile("nested.json", "application/json", 1024, "/tmp/phpadhjk", UPLOAD_ERR_OK), ["nested", "level2"]], - [new UploadedFile("nestedList0.jpg", "image/jpeg", 256, "/tmp/phpjpg0", UPLOAD_ERR_OK), ["nestedList", "level2", 0]], - [new UploadedFile("nestedList1.jpg", "image/jpeg", 4096, "/tmp/phpjpg1", UPLOAD_ERR_OK), ["nestedList", "level2", 1]], - [new UploadedFile("", "", 0, "", UPLOAD_ERR_NO_FILE), ["nestedList", "level2", 2]], - [new UploadedFile("nestedDictionary0.jpg", "image/png", 256, "/tmp/phppng0", UPLOAD_ERR_OK), ["nestedDictionary", "level2", "file0"]], - [new UploadedFile("nestedDictionary1.jpg", "image/png", 4096, "/tmp/phppngg1", UPLOAD_ERR_OK), ["nestedDictionary", "level2", "file1"]] + [new UploadedFile('single.txt', 'text/plain', 524, '/tmp/php9hNlHe', UPLOAD_ERR_OK), ['single']], + [new UploadedFile('nested.json', 'application/json', 1024, '/tmp/phpadhjk', UPLOAD_ERR_OK), ['nested', 'level2']], + [new UploadedFile('nestedList0.jpg', 'image/jpeg', 256, '/tmp/phpjpg0', UPLOAD_ERR_OK), ['nestedList', 'level2', 0]], + [new UploadedFile('nestedList1.jpg', 'image/jpeg', 4096, '/tmp/phpjpg1', UPLOAD_ERR_OK), ['nestedList', 'level2', 1]], + [new UploadedFile('', '', 0, '', UPLOAD_ERR_NO_FILE), ['nestedList', 'level2', 2]], + [new UploadedFile('nestedDictionary0.jpg', 'image/png', 256, '/tmp/phppng0', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file0']], + [new UploadedFile('nestedDictionary1.jpg', 'image/png', 4096, '/tmp/phppngg1', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file1']] ]; } @@ -348,23 +348,23 @@ class ServerRequestTest extends TestCase public function testGetServerRequestParsesFormBody($contentType) { $_SERVER = [ - "HTTP_HOST" => "localhost", - "HTTP_CONTENT_TYPE" => $contentType, + 'HTTP_HOST' => 'localhost', + 'HTTP_CONTENT_TYPE' => $contentType, ]; $_COOKIE = []; $_FILES = []; $_POST = [ - "dog" => "Bear" + 'dog' => 'Bear' ]; $request = ServerRequest::getServerRequest(); - $this->assertEquals("Bear", $request->getParsedBody()["dog"]); + $this->assertEquals('Bear', $request->getParsedBody()['dog']); } public function formContentTypeProvider() { return [ - ["application/x-www-form-urlencoded"], - ["multipart/form-data"] + ['application/x-www-form-urlencoded'], + ['multipart/form-data'] ]; } @@ -372,7 +372,7 @@ class ServerRequestTest extends TestCase public function testGetServerRequestProvidesAttributesIfPassed($request) { /** @var ServerRequest $request */ - $this->assertEquals("Claude", $request->getAttribute("guinea_pig")); + $this->assertEquals('Claude', $request->getAttribute('guinea_pig')); } // ------------------------------------------------------------------------ @@ -398,9 +398,9 @@ class ServerRequestTest extends TestCase { /** @var ServerRequest $request1 */ $request2 = $request1->withCookieParams([ - "cat" => "Oscar" + 'cat' => 'Oscar' ]); - $this->assertNotEquals($request1->getCookieParams()["cat"], $request2->getCookieParams()["cat"]); + $this->assertNotEquals($request1->getCookieParams()['cat'], $request2->getCookieParams()['cat']); } // ------------------------------------------------------------------------ @@ -417,9 +417,9 @@ class ServerRequestTest extends TestCase { /** @var ServerRequest $request1 */ $request2 = $request1->withQueryParams([ - "guinea_pig" => "Clyde" + 'guinea_pig' => 'Clyde' ]); - $this->assertNotEquals($request1->getQueryParams()["guinea_pig"], $request2->getQueryParams()["guinea_pig"]); + $this->assertNotEquals($request1->getQueryParams()['guinea_pig'], $request2->getQueryParams()['guinea_pig']); } // ------------------------------------------------------------------------ @@ -435,9 +435,9 @@ class ServerRequestTest extends TestCase public function testGetUploadedFilesReturnsEmptyArrayWhenNoFilesAreUploaded() { $_SERVER = [ - "HTTP_HOST" => "localhost", - "HTTP_ACCEPT" => "application/json", - "HTTP_CONTENT_TYPE" => "application/x-www-form-urlencoded" + 'HTTP_HOST' => 'localhost', + 'HTTP_ACCEPT' => 'application/json', + 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded' ]; $_FILES = []; $request = ServerRequest::getServerRequest(); @@ -447,7 +447,7 @@ class ServerRequestTest extends TestCase public function testWithUploadedFilesCreatesNewInstance() { $uploadedFiles = [ - "file" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) + 'file' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0) ]; $request = new ServerRequest(); $request1 = $request->withUploadedFiles([]); @@ -467,20 +467,20 @@ class ServerRequestTest extends TestCase { return [ [[]], - [["files" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)]], - [["nested" => [ - "level2" => new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0) + [['files' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0)]], + [['nested' => [ + 'level2' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0) ]]], - [["nestedList" => [ - "level2" => [ - new UploadedFile("file1.html", "text/html", 524, "/tmp/php9hNlHe", 0), - new UploadedFile("file2.html", "text/html", 524, "/tmp/php9hNshj", 0) + [['nestedList' => [ + 'level2' => [ + new UploadedFile('file1.html', 'text/html', 524, '/tmp/php9hNlHe', 0), + new UploadedFile('file2.html', 'text/html', 524, '/tmp/php9hNshj', 0) ] ]]], - [["nestedDictionary" => [ - "level2" => [ - "file1" => new UploadedFile("file1.html", "text/html", 524, "/tmp/php9hNlHe", 0), - "file2" => new UploadedFile("file2.html", "text/html", 524, "/tmp/php9hNshj", 0) + [['nestedDictionary' => [ + 'level2' => [ + 'file1' => new UploadedFile('file1.html', 'text/html', 524, '/tmp/php9hNlHe', 0), + 'file2' => new UploadedFile('file2.html', 'text/html', 524, '/tmp/php9hNshj', 0) ] ]]] ]; @@ -500,53 +500,53 @@ class ServerRequestTest extends TestCase { return [ // All keys must be strings - [[new UploadedFile("index.html", "text/html", 524, "/tmp/php9hNlHe", 0)]], + [[new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0)]], [ - [new UploadedFile("index1.html", "text/html", 524, "/tmp/php9hNlHe", 0)], - [new UploadedFile("index2.html", "text/html", 524, "/tmp/php9hNlHe", 0)] + [new UploadedFile('index1.html', 'text/html', 524, '/tmp/php9hNlHe', 0)], + [new UploadedFile('index2.html', 'text/html', 524, '/tmp/php9hNlHe', 0)] ], [ - "single" => [ - "name" => "single.txt", - "type" => "text/plain", - "tmp_name" => "/tmp/php9hNlHe", - "error" => UPLOAD_ERR_OK, - "size" => 524 + 'single' => [ + 'name' => 'single.txt', + 'type' => 'text/plain', + 'tmp_name' => '/tmp/php9hNlHe', + 'error' => UPLOAD_ERR_OK, + 'size' => 524 ], - "nested" => [ - "level2" => [ - "name" => "nested.json", - "type" => "application/json", - "tmp_name" => "/tmp/phpadhjk", - "error" => UPLOAD_ERR_OK, - "size" => 1024 + 'nested' => [ + 'level2' => [ + 'name' => 'nested.json', + 'type' => 'application/json', + 'tmp_name' => '/tmp/phpadhjk', + 'error' => UPLOAD_ERR_OK, + 'size' => 1024 ] ] ], [ - "nestedList" => [ - "level2" => [ - "name" => [ - 0 => "nestedList0.jpg", - 1 => "nestedList1.jpg", - 2 => "" + 'nestedList' => [ + 'level2' => [ + 'name' => [ + 0 => 'nestedList0.jpg', + 1 => 'nestedList1.jpg', + 2 => '' ], - "type" => [ - 0 => "image/jpeg", - 1 => "image/jpeg", - 2 => "" + 'type' => [ + 0 => 'image/jpeg', + 1 => 'image/jpeg', + 2 => '' ], - "tmp_name" => [ - 0 => "/tmp/phpjpg0", - 1 => "/tmp/phpjpg1", - 2 => "" + 'tmp_name' => [ + 0 => '/tmp/phpjpg0', + 1 => '/tmp/phpjpg1', + 2 => '' ], - "error" => [ + 'error' => [ 0 => UPLOAD_ERR_OK, 1 => UPLOAD_ERR_OK, 2 => UPLOAD_ERR_NO_FILE ], - "size" => [ + 'size' => [ 0 => 256, 1 => 4096, 2 => 0 @@ -573,7 +573,7 @@ class ServerRequestTest extends TestCase $body1 = $request1->getParsedBody(); $request2 = $request1->withParsedBody([ - "guinea_pig" => "Clyde" + 'guinea_pig' => 'Clyde' ]); $body2 = $request2->getParsedBody(); @@ -601,12 +601,12 @@ class ServerRequestTest extends TestCase public function testCloneMakesDeepCopiesOfParsedBody() { $body = (object) [ - "cat" => "Dog" + 'cat' => 'Dog' ]; $request1 = new ServerRequest(); $request1 = $request1->withParsedBody($body); - $request2 = $request1->withHeader("X-extra", "hello world"); + $request2 = $request1->withHeader('X-extra', 'hello world'); $this->assertTrue( $request1->getParsedBody() == $request2->getParsedBody() @@ -626,11 +626,11 @@ class ServerRequestTest extends TestCase public function testGetAttributesReturnsAllAttributes() { $request = new ServerRequest(); - $request = $request->withAttribute("cat", "Molly"); - $request = $request->withAttribute("dog", "Bear"); + $request = $request->withAttribute('cat', 'Molly'); + $request = $request->withAttribute('dog', 'Bear'); $expected = [ - "cat" => "Molly", - "dog" => "Bear" + 'cat' => 'Molly', + 'dog' => 'Bear' ]; $this->assertEquals($expected, $request->getAttributes()); } @@ -638,24 +638,24 @@ class ServerRequestTest extends TestCase public function testGetAttributeReturnsDefaultIfNotSet() { $request = new ServerRequest(); - $this->assertEquals("Oscar", $request->getAttribute("cat", "Oscar")); + $this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar')); } public function testWithAttributeCreatesNewInstance() { $request = new ServerRequest(); - $request = $request->withAttribute("cat", "Molly"); - $this->assertEquals("Molly", $request->getAttribute("cat")); + $request = $request->withAttribute('cat', 'Molly'); + $this->assertEquals('Molly', $request->getAttribute('cat')); } public function testWithAttributePreserversOtherAttributes() { $request = new ServerRequest(); - $request = $request->withAttribute("cat", "Molly"); - $request = $request->withAttribute("dog", "Bear"); + $request = $request->withAttribute('cat', 'Molly'); + $request = $request->withAttribute('dog', 'Bear'); $expected = [ - "cat" => "Molly", - "dog" => "Bear" + 'cat' => 'Molly', + 'dog' => 'Bear' ]; $this->assertEquals($expected, $request->getAttributes()); } @@ -663,24 +663,24 @@ class ServerRequestTest extends TestCase public function testWithoutAttributeCreatesNewInstance() { $request = new ServerRequest(); - $request = $request->withAttribute("cat", "Molly"); - $this->assertNotEquals($request, $request->withoutAttribute("cat")); + $request = $request->withAttribute('cat', 'Molly'); + $this->assertNotEquals($request, $request->withoutAttribute('cat')); } public function testWithoutAttributeRemovesAttribute() { $request = new ServerRequest(); - $request = $request->withAttribute("cat", "Molly"); - $request = $request->withoutAttribute("cat"); - $this->assertEquals("Oscar", $request->getAttribute("cat", "Oscar")); + $request = $request->withAttribute('cat', 'Molly'); + $request = $request->withoutAttribute('cat'); + $this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar')); } public function testWithoutAttributePreservesOtherAttributes() { $request = new ServerRequest(); - $request = $request->withAttribute("cat", "Molly"); - $request = $request->withAttribute("dog", "Bear"); - $request = $request->withoutAttribute("cat"); - $this->assertEquals("Bear", $request->getAttribute("dog")); + $request = $request->withAttribute('cat', 'Molly'); + $request = $request->withAttribute('dog', 'Bear'); + $request = $request->withoutAttribute('cat'); + $this->assertEquals('Bear', $request->getAttribute('dog')); } } diff --git a/test/tests/unit/Message/StreamTest.php b/test/tests/unit/Message/StreamTest.php index b89db9f..7a8329d 100644 --- a/test/tests/unit/Message/StreamTest.php +++ b/test/tests/unit/Message/StreamTest.php @@ -11,12 +11,12 @@ class StreamTest extends TestCase { private $resource; private $resourceDevNull; - private $content = "Hello, world!"; + private $content = 'Hello, world!'; protected function setUp(): void { - $this->resource = fopen("php://memory", "w+"); - $this->resourceDevNull = fopen("/dev/null", "r"); + $this->resource = fopen('php://memory', 'w+'); + $this->resourceDevNull = fopen('/dev/null', 'r'); fwrite($this->resource, $this->content); } @@ -35,7 +35,7 @@ class StreamTest extends TestCase public function testCreatesInstanceWithString() { - $stream = new Stream("Hello, world!"); + $stream = new Stream('Hello, world!'); $this->assertNotNull($stream); } @@ -123,7 +123,7 @@ class StreamTest extends TestCase { $stream = new Stream($this->resource); $metadata = stream_get_meta_data($this->resource); - $seekable = $metadata["seekable"] == 1; + $seekable = $metadata['seekable'] == 1; $this->assertEquals($seekable, $stream->isSeekable()); } @@ -167,17 +167,17 @@ class StreamTest extends TestCase public function testThrowsExceptionOnErrorWriting() { $this->expectException(RuntimeException::class); - $filename = tempnam(sys_get_temp_dir(), "php"); - $handle = fopen($filename, "r"); + $filename = tempnam(sys_get_temp_dir(), 'php'); + $handle = fopen($filename, 'r'); $stream = new Stream($handle); - $stream->write("Hello, world!"); + $stream->write('Hello, world!'); } public function testThrowsExceptionOnErrorReading() { $this->expectException(RuntimeException::class); - $filename = tempnam(sys_get_temp_dir(), "php"); - $handle = fopen($filename, "w"); + $filename = tempnam(sys_get_temp_dir(), 'php'); + $handle = fopen($filename, 'w'); $stream = new Stream($handle); $stream->read(10); } @@ -187,14 +187,14 @@ class StreamTest extends TestCase $stream = new Stream($this->resource); $stream->seek(7); $string = $stream->read(5); - $this->assertEquals("world", $string); + $this->assertEquals('world', $string); } public function testThrowsExceptionOnErrorReadingToEnd() { $this->expectException(RuntimeException::class); - $filename = tempnam(sys_get_temp_dir(), "php"); - $handle = fopen($filename, "w"); + $filename = tempnam(sys_get_temp_dir(), 'php'); + $handle = fopen($filename, 'w'); $stream = new Stream($handle); $stream->getContents(); } @@ -204,7 +204,7 @@ class StreamTest extends TestCase $stream = new Stream($this->resource); $stream->seek(7); $string = $stream->getContents(); - $this->assertEquals("world!", $string); + $this->assertEquals('world!', $string); } public function testReturnsMetadataArray() @@ -217,7 +217,7 @@ class StreamTest extends TestCase { $stream = new Stream($this->resource); $metadata = stream_get_meta_data($this->resource); - $this->assertEquals($metadata["mode"], $stream->getMetadata("mode")); + $this->assertEquals($metadata['mode'], $stream->getMetadata('mode')); } /** @@ -228,8 +228,8 @@ class StreamTest extends TestCase */ public function testReturnsIsReadableForReadableStreams($mode, $readable, $writable) { - $tmp = tempnam(sys_get_temp_dir(), "php"); - if ($mode[0] === "x") { + $tmp = tempnam(sys_get_temp_dir(), 'php'); + if ($mode[0] === 'x') { unlink($tmp); } $resource = fopen($tmp, $mode); @@ -245,8 +245,8 @@ class StreamTest extends TestCase */ public function testReturnsIsWritableForWritableStreams($mode, $readable, $writable) { - $tmp = tempnam(sys_get_temp_dir(), "php"); - if ($mode[0] === "x") { + $tmp = tempnam(sys_get_temp_dir(), 'php'); + if ($mode[0] === 'x') { unlink($tmp); } $resource = fopen($tmp, $mode); @@ -257,16 +257,16 @@ class StreamTest extends TestCase public function modeProvider() { return [ - ["r", true, false], - ["r+", true, true], - ["w", false, true], - ["w+", true, true], - ["a", false, true], - ["a+", true, true], - ["x", false, true], - ["x+", true, true], - ["c", false, true], - ["c+", true, true] + ['r', true, false], + ['r+', true, true], + ['w', false, true], + ['w+', true, true], + ['a', false, true], + ['a+', true, true], + ['x', false, true], + ['x+', true, true], + ['c', false, true], + ['c+', true, true] ]; } diff --git a/test/tests/unit/Message/UploadedFileTest.php b/test/tests/unit/Message/UploadedFileTest.php index bab21ee..d9162be 100644 --- a/test/tests/unit/Message/UploadedFileTest.php +++ b/test/tests/unit/Message/UploadedFileTest.php @@ -9,7 +9,7 @@ use WellRESTed\Message\UploadedFileState; use WellRESTed\Test\TestCase; // Hides several php core functions for testing. -require_once __DIR__ . "/../../../src/UploadedFileState.php"; +require_once __DIR__ . '/../../../src/UploadedFileState.php'; class UploadedFileTest extends TestCase { @@ -19,9 +19,9 @@ class UploadedFileTest extends TestCase public function setUp(): void { parent::setUp(); - UploadedFileState::$php_sapi_name = "cli"; - $this->tmpName = tempnam(sys_get_temp_dir(), "tst"); - $this->movePath = tempnam(sys_get_temp_dir(), "tst"); + UploadedFileState::$php_sapi_name = 'cli'; + $this->tmpName = tempnam(sys_get_temp_dir(), 'tst'); + $this->movePath = tempnam(sys_get_temp_dir(), 'tst'); } public function tearDown(): void @@ -40,22 +40,22 @@ class UploadedFileTest extends TestCase public function testGetStreamReturnsStreamInterface() { - $file = new UploadedFile("", "", 0, $this->tmpName, 0); + $file = new UploadedFile('', '', 0, $this->tmpName, 0); $this->assertInstanceOf(StreamInterface::class, $file->getStream()); } public function testGetStreamReturnsStreamWrappingUploadedFile() { - $content = "Hello, World!"; + $content = 'Hello, World!'; file_put_contents($this->tmpName, $content); - $file = new UploadedFile("", "", 0, $this->tmpName, ""); + $file = new UploadedFile('', '', 0, $this->tmpName, ''); $stream = $file->getStream(); $this->assertEquals($content, (string) $stream); } public function testGetStreamThrowsRuntimeExceptionForNoFile() { - $file = new UploadedFile("", "", 0, "", 0); + $file = new UploadedFile('', '', 0, '', 0); $this->expectException(RuntimeException::class); $file->getStream(); } @@ -63,9 +63,9 @@ class UploadedFileTest extends TestCase public function testGetStreamThrowsExceptionAfterMoveTo() { $this->expectException(RuntimeException::class); - $content = "Hello, World!"; + $content = 'Hello, World!'; file_put_contents($this->tmpName, $content); - $file = new UploadedFile("", "", 0, $this->tmpName, ""); + $file = new UploadedFile('', '', 0, $this->tmpName, ''); $file->moveTo($this->movePath); $file->getStream(); } @@ -73,9 +73,9 @@ class UploadedFileTest extends TestCase public function testGetStreamThrowsExceptionForNonUploadedFile() { $this->expectException(RuntimeException::class); - UploadedFileState::$php_sapi_name = "apache"; + UploadedFileState::$php_sapi_name = 'apache'; UploadedFileState::$is_uploaded_file = false; - $file = new UploadedFile("", "", 0, "", 0); + $file = new UploadedFile('', '', 0, '', 0); $file->getStream(); } @@ -84,13 +84,13 @@ class UploadedFileTest extends TestCase public function testMoveToSapiRelocatesUploadedFileToDestinationIfExists() { - UploadedFileState::$php_sapi_name = "fpm-fcgi"; + UploadedFileState::$php_sapi_name = 'fpm-fcgi'; - $content = "Hello, World!"; + $content = 'Hello, World!'; file_put_contents($this->tmpName, $content); $originalMd5 = md5_file($this->tmpName); - $file = new UploadedFile("", "", 0, $this->tmpName, ""); + $file = new UploadedFile('', '', 0, $this->tmpName, ''); $file->moveTo($this->movePath); $this->assertEquals($originalMd5, md5_file($this->movePath)); @@ -98,11 +98,11 @@ class UploadedFileTest extends TestCase public function testMoveToNonSapiRelocatesUploadedFileToDestinationIfExists() { - $content = "Hello, World!"; + $content = 'Hello, World!'; file_put_contents($this->tmpName, $content); $originalMd5 = md5_file($this->tmpName); - $file = new UploadedFile("", "", 0, $this->tmpName, ""); + $file = new UploadedFile('', '', 0, $this->tmpName, ''); $file->moveTo($this->movePath); $this->assertEquals($originalMd5, md5_file($this->movePath)); @@ -112,10 +112,10 @@ class UploadedFileTest extends TestCase { $this->expectException(RuntimeException::class); - $content = "Hello, World!"; + $content = 'Hello, World!'; file_put_contents($this->tmpName, $content); - $file = new UploadedFile("", "", 0, $this->tmpName, ""); + $file = new UploadedFile('', '', 0, $this->tmpName, ''); $file->moveTo($this->movePath); $file->moveTo($this->movePath); } @@ -125,7 +125,7 @@ class UploadedFileTest extends TestCase public function testGetSizeReturnsSize() { - $file = new UploadedFile("", "", 1024, "", 0); + $file = new UploadedFile('', '', 1024, '', 0); $this->assertEquals(1024, $file->getSize()); } @@ -134,7 +134,7 @@ class UploadedFileTest extends TestCase public function testGetErrorReturnsError() { - $file = new UploadedFile("", "", 1024, "", UPLOAD_ERR_INI_SIZE); + $file = new UploadedFile('', '', 1024, '', UPLOAD_ERR_INI_SIZE); $this->assertEquals(UPLOAD_ERR_INI_SIZE, $file->getError()); } @@ -143,8 +143,8 @@ class UploadedFileTest extends TestCase public function testGetClientFilenameReturnsClientFilename() { - $file = new UploadedFile("clientFilename", "", 0, "", 0); - $this->assertEquals("clientFilename", $file->getClientFilename()); + $file = new UploadedFile('clientFilename', '', 0, '', 0); + $this->assertEquals('clientFilename', $file->getClientFilename()); } // ------------------------------------------------------------------------ @@ -152,7 +152,7 @@ class UploadedFileTest extends TestCase public function testGetClientMediaTypeReturnsClientMediaType() { - $file = new UploadedFile("", "clientMediaType", 0, "", 0); - $this->assertEquals("clientMediaType", $file->getClientMediaType()); + $file = new UploadedFile('', 'clientMediaType', 0, '', 0); + $this->assertEquals('clientMediaType', $file->getClientMediaType()); } } diff --git a/test/tests/unit/Message/UriTest.php b/test/tests/unit/Message/UriTest.php index 6ff36ac..61ed2aa 100644 --- a/test/tests/unit/Message/UriTest.php +++ b/test/tests/unit/Message/UriTest.php @@ -14,7 +14,7 @@ class UriTest extends TestCase public function testDefaultSchemeIsEmpty() { $uri = new Uri(); - $this->assertSame("", $uri->getScheme()); + $this->assertSame('', $uri->getScheme()); } /** @dataProvider schemeProvider */ @@ -28,12 +28,12 @@ class UriTest extends TestCase public function schemeProvider() { return [ - ["http", "http"], - ["https", "https"], - ["http", "HTTP"], - ["https", "HTTPS"], - ["", null], - ["", ""] + ['http', 'http'], + ['https', 'https'], + ['http', 'HTTP'], + ['https', 'HTTPS'], + ['', null], + ['', ''] ]; } @@ -41,7 +41,7 @@ class UriTest extends TestCase { $this->expectException(InvalidArgumentException::class); $uri = new Uri(); - $uri->withScheme("gopher"); + $uri->withScheme('gopher'); } // ------------------------------------------------------------------------ @@ -50,7 +50,7 @@ class UriTest extends TestCase public function testDefaultAuthorityIsEmpty() { $uri = new Uri(); - $this->assertSame("", $uri->getAuthority()); + $this->assertSame('', $uri->getAuthority()); } public function testRespectsMyAuthoritah() @@ -63,25 +63,25 @@ class UriTest extends TestCase { $uri = new Uri(); - if (isset($components["scheme"])) { - $uri = $uri->withScheme($components["scheme"]); + if (isset($components['scheme'])) { + $uri = $uri->withScheme($components['scheme']); } - if (isset($components["user"])) { - $user = $components["user"]; + if (isset($components['user'])) { + $user = $components['user']; $password = null; - if (isset($components["password"])) { - $password = $components["password"]; + if (isset($components['password'])) { + $password = $components['password']; } $uri = $uri->withUserInfo($user, $password); } - if (isset($components["host"])) { - $uri = $uri->withHost($components["host"]); + if (isset($components['host'])) { + $uri = $uri->withHost($components['host']); } - if (isset($components["port"])) { - $uri = $uri->withPort($components["port"]); + if (isset($components['port'])) { + $uri = $uri->withPort($components['port']); } $this->assertEquals($expected, $uri->getAuthority()); @@ -91,73 +91,73 @@ class UriTest extends TestCase { return [ [ - "localhost", + 'localhost', [ - "host" => "localhost" + 'host' => 'localhost' ] ], [ - "user@localhost", + 'user@localhost', [ - "host" => "localhost", - "user" => "user" + 'host' => 'localhost', + 'user' => 'user' ] ], [ - "user:password@localhost", + 'user:password@localhost', [ - "host" => "localhost", - "user" => "user", - "password" => "password" + 'host' => 'localhost', + 'user' => 'user', + 'password' => 'password' ] ], [ - "localhost", + 'localhost', [ - "host" => "localhost", - "password" => "password" + 'host' => 'localhost', + 'password' => 'password' ] ], [ - "localhost", + 'localhost', [ - "scheme" => "http", - "host" => "localhost", - "port" => 80 + 'scheme' => 'http', + 'host' => 'localhost', + 'port' => 80 ] ], [ - "localhost", + 'localhost', [ - "scheme" => "https", - "host" => "localhost", - "port" => 443 + 'scheme' => 'https', + 'host' => 'localhost', + 'port' => 443 ] ], [ - "localhost:4430", + 'localhost:4430', [ - "scheme" => "https", - "host" => "localhost", - "port" => 4430 + 'scheme' => 'https', + 'host' => 'localhost', + 'port' => 4430 ] ], [ - "localhost:8080", + 'localhost:8080', [ - "scheme" => "http", - "host" => "localhost", - "port" => 8080 + 'scheme' => 'http', + 'host' => 'localhost', + 'port' => 8080 ] ], [ - "user:password@localhost:4430", + 'user:password@localhost:4430', [ - "scheme" => "https", - "user" => "user", - "password" => "password", - "host" => "localhost", - "port" => 4430 + 'scheme' => 'https', + 'user' => 'user', + 'password' => 'password', + 'host' => 'localhost', + 'port' => 4430 ] ], ]; @@ -169,7 +169,7 @@ class UriTest extends TestCase public function testDefaultUserInfoIsEmpty() { $uri = new Uri(); - $this->assertSame("", $uri->getUserInfo()); + $this->assertSame('', $uri->getUserInfo()); } /** @@ -189,11 +189,11 @@ class UriTest extends TestCase public function userInfoProvider() { return [ - ["user:password", "user", "password"], - ["user", "user", ""], - ["user", "user", null], - ["", "", "password"], - ["", "", ""] + ['user:password', 'user', 'password'], + ['user', 'user', ''], + ['user', 'user', null], + ['', '', 'password'], + ['', '', ''] ]; } @@ -203,7 +203,7 @@ class UriTest extends TestCase public function testDefaultHostIsEmpty() { $uri = new Uri(); - $this->assertSame("", $uri->getHost()); + $this->assertSame('', $uri->getHost()); } /** @dataProvider hostProvider */ @@ -217,10 +217,10 @@ class UriTest extends TestCase public function hostProvider() { return [ - ["", ""], - ["localhost", "localhost"], - ["localhost", "LOCALHOST"], - ["foo.com", "FOO.com"] + ['', ''], + ['localhost', 'localhost'], + ['localhost', 'LOCALHOST'], + ['foo.com', 'FOO.com'] ]; } @@ -255,13 +255,13 @@ class UriTest extends TestCase public function testDefaultPortForHttpSchemeIs80() { $uri = new Uri(); - $this->assertSame(80, $uri->withScheme("http")->getPort()); + $this->assertSame(80, $uri->withScheme('http')->getPort()); } public function testDefaultPortForHttpsSchemeIs443() { $uri = new Uri(); - $this->assertSame(443, $uri->withScheme("https")->getPort()); + $this->assertSame(443, $uri->withScheme('https')->getPort()); } /** @dataProvider portAndSchemeProvider */ @@ -275,12 +275,12 @@ class UriTest extends TestCase public function portAndSchemeProvider() { return [ - [null, "", null], - [80, "http", null], - [443, "https", null], - [8080, "", 8080], - [8080, "http", "8080"], - [8080, "https", 8080.0] + [null, '', null], + [80, 'http', null], + [443, 'https', null], + [8080, '', 8080], + [8080, 'http', '8080'], + [8080, 'https', 8080.0] ]; } @@ -300,7 +300,7 @@ class UriTest extends TestCase [true], [-1], [65536], - ["dog"] + ['dog'] ]; } @@ -310,7 +310,7 @@ class UriTest extends TestCase public function testDefaultPathIsEmpty() { $uri = new Uri(); - $this->assertSame("", $uri->getPath()); + $this->assertSame('', $uri->getPath()); } /** @dataProvider pathProvider */ @@ -333,13 +333,13 @@ class UriTest extends TestCase public function pathProvider() { return [ - ["", ""], - ["/", "/"], - ["*", "*"], - ["/my/path", "/my/path"], - ["/encoded%2Fslash", "/encoded%2Fslash"], - ["/percent/%25", "/percent/%"], - ["/%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA", "/áéíóú"] + ['', ''], + ['/', '/'], + ['*', '*'], + ['/my/path', '/my/path'], + ['/encoded%2Fslash', '/encoded%2Fslash'], + ['/percent/%25', '/percent/%'], + ['/%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA', '/áéíóú'] ]; } @@ -349,7 +349,7 @@ class UriTest extends TestCase public function testDefaultQueryIsEmpty() { $uri = new Uri(); - $this->assertSame("", $uri->getQuery()); + $this->assertSame('', $uri->getQuery()); } /** @dataProvider queryProvider */ @@ -372,9 +372,9 @@ class UriTest extends TestCase public function queryProvider() { return [ - ["cat=molly", "cat=molly"], - ["cat=molly&dog=bear", "cat=molly&dog=bear"], - ["accents=%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA", "accents=áéíóú"] + ['cat=molly', 'cat=molly'], + ['cat=molly&dog=bear', 'cat=molly&dog=bear'], + ['accents=%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA', 'accents=áéíóú'] ]; } @@ -403,7 +403,7 @@ class UriTest extends TestCase public function testDefaultFragmentIsEmpty() { $uri = new Uri(); - $this->assertSame("", $uri->getFragment()); + $this->assertSame('', $uri->getFragment()); } /** @dataProvider fragmentProvider */ @@ -426,9 +426,9 @@ class UriTest extends TestCase public function fragmentProvider() { return [ - ["", null], - ["molly", "molly"], - ["%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA", "áéíóú"] + ['', null], + ['molly', 'molly'], + ['%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA', 'áéíóú'] ]; } @@ -440,37 +440,37 @@ class UriTest extends TestCase { $uri = new Uri(); - if (isset($components["scheme"])) { - $uri = $uri->withScheme($components["scheme"]); + if (isset($components['scheme'])) { + $uri = $uri->withScheme($components['scheme']); } - if (isset($components["user"])) { - $user = $components["user"]; + if (isset($components['user'])) { + $user = $components['user']; $password = null; - if (isset($components["password"])) { - $password = $components["password"]; + if (isset($components['password'])) { + $password = $components['password']; } $uri = $uri->withUserInfo($user, $password); } - if (isset($components["host"])) { - $uri = $uri->withHost($components["host"]); + if (isset($components['host'])) { + $uri = $uri->withHost($components['host']); } - if (isset($components["port"])) { - $uri = $uri->withPort($components["port"]); + if (isset($components['port'])) { + $uri = $uri->withPort($components['port']); } - if (isset($components["path"])) { - $uri = $uri->withPath($components["path"]); + if (isset($components['path'])) { + $uri = $uri->withPath($components['path']); } - if (isset($components["query"])) { - $uri = $uri->withQuery($components["query"]); + if (isset($components['query'])) { + $uri = $uri->withQuery($components['query']); } - if (isset($components["fragment"])) { - $uri = $uri->withFragment($components["fragment"]); + if (isset($components['fragment'])) { + $uri = $uri->withFragment($components['fragment']); } $this->assertEquals($expected, (string) $uri); @@ -480,59 +480,59 @@ class UriTest extends TestCase { return [ [ - "http://localhost/path", + 'http://localhost/path', [ - "scheme" => "http", - "host" => "localhost", - "path" => "/path" + 'scheme' => 'http', + 'host' => 'localhost', + 'path' => '/path' ] ], [ - "//localhost/path", + '//localhost/path', [ - "host" => "localhost", - "path" => "/path" + 'host' => 'localhost', + 'path' => '/path' ] ], [ - "/path", + '/path', [ - "path" => "/path" + 'path' => '/path' ] ], [ - "/path?cat=molly&dog=bear", + '/path?cat=molly&dog=bear', [ - "path" => "/path", - "query" => "cat=molly&dog=bear" + 'path' => '/path', + 'query' => 'cat=molly&dog=bear' ] ], [ - "/path?cat=molly&dog=bear#fragment", + '/path?cat=molly&dog=bear#fragment', [ - "path" => "/path", - "query" => "cat=molly&dog=bear", - "fragment" => "fragment" + 'path' => '/path', + 'query' => 'cat=molly&dog=bear', + 'fragment' => 'fragment' ] ], [ - "https://user:password@localhost:4430/path?cat=molly&dog=bear#fragment", + 'https://user:password@localhost:4430/path?cat=molly&dog=bear#fragment', [ - "scheme" => "https", - "user" => "user", - "password" => "password", - "host" => "localhost", - "port" => 4430, - "path" => "/path", - "query" => "cat=molly&dog=bear", - "fragment" => "fragment" + 'scheme' => 'https', + 'user' => 'user', + 'password' => 'password', + 'host' => 'localhost', + 'port' => 4430, + 'path' => '/path', + 'query' => 'cat=molly&dog=bear', + 'fragment' => 'fragment' ] ], // Asterisk Form [ - "*", + '*', [ - "path" => "*" + 'path' => '*' ] ], ]; @@ -549,36 +549,36 @@ class UriTest extends TestCase { return [ [ - "http://localhost/path", - "http://localhost:80/path" + 'http://localhost/path', + 'http://localhost:80/path' ], [ - "https://localhost/path", - "https://localhost:443/path" + 'https://localhost/path', + 'https://localhost:443/path' ], [ - "https://my.sub.sub.domain.com/path", - "https://my.sub.sub.domain.com/path" + 'https://my.sub.sub.domain.com/path', + 'https://my.sub.sub.domain.com/path' ], [ - "https://user:password@localhost:4430/path?cat=molly&dog=bear#fragment", - "https://user:password@localhost:4430/path?cat=molly&dog=bear#fragment" + 'https://user:password@localhost:4430/path?cat=molly&dog=bear#fragment', + 'https://user:password@localhost:4430/path?cat=molly&dog=bear#fragment' ], [ - "/path", - "/path" + '/path', + '/path' ], [ - "//double/slash", - "//double/slash" + '//double/slash', + '//double/slash' ], [ - "no/slash", - "no/slash" + 'no/slash', + 'no/slash' ], [ - "*", - "*" + '*', + '*' ] ]; } diff --git a/test/tests/unit/Routing/Route/MethodMapTest.php b/test/tests/unit/Routing/Route/MethodMapTest.php index 285279d..7e92756 100644 --- a/test/tests/unit/Routing/Route/MethodMapTest.php +++ b/test/tests/unit/Routing/Route/MethodMapTest.php @@ -36,10 +36,10 @@ class MethodMapTest extends TestCase public function testDispatchesMiddlewareWithMatchingMethod() { - $this->request = $this->request->withMethod("GET"); + $this->request = $this->request->withMethod('GET'); $map = $this->getMethodMap(); - $map->register("GET", $this->middleware); + $map->register('GET', $this->middleware); $map($this->request, $this->response, $this->next); $this->assertTrue($this->middleware->called); @@ -47,14 +47,14 @@ class MethodMapTest extends TestCase public function testTreatsMethodNamesCaseSensitively() { - $this->request = $this->request->withMethod("get"); + $this->request = $this->request->withMethod('get'); $middlewareUpper = new MiddlewareMock(); $middlewareLower = new MiddlewareMock(); $map = $this->getMethodMap(); - $map->register("GET", $middlewareUpper); - $map->register("get", $middlewareLower); + $map->register('GET', $middlewareUpper); + $map->register('get', $middlewareLower); $map($this->request, $this->response, $this->next); $this->assertTrue($middlewareLower->called); @@ -62,10 +62,10 @@ class MethodMapTest extends TestCase public function testDispatchesWildcardMiddlewareWithNonMatchingMethod() { - $this->request = $this->request->withMethod("GET"); + $this->request = $this->request->withMethod('GET'); $map = $this->getMethodMap(); - $map->register("*", $this->middleware); + $map->register('*', $this->middleware); $map($this->request, $this->response, $this->next); $this->assertTrue($this->middleware->called); @@ -73,10 +73,10 @@ class MethodMapTest extends TestCase public function testDispatchesGetMiddlewareForHeadByDefault() { - $this->request = $this->request->withMethod("HEAD"); + $this->request = $this->request->withMethod('HEAD'); $map = $this->getMethodMap(); - $map->register("GET", $this->middleware); + $map->register('GET', $this->middleware); $map($this->request, $this->response, $this->next); $this->assertTrue($this->middleware->called); @@ -85,12 +85,12 @@ class MethodMapTest extends TestCase public function testRegistersMiddlewareForMultipleMethods() { $map = $this->getMethodMap(); - $map->register("GET,POST", $this->middleware); + $map->register('GET,POST', $this->middleware); - $this->request = $this->request->withMethod("GET"); + $this->request = $this->request->withMethod('GET'); $map($this->request, $this->response, $this->next); - $this->request = $this->request->withMethod("POST"); + $this->request = $this->request->withMethod('POST'); $map($this->request, $this->response, $this->next); $this->assertEquals(2, $this->middleware->callCount); @@ -98,11 +98,11 @@ class MethodMapTest extends TestCase public function testSettingNullDeregistersMiddleware() { - $this->request = $this->request->withMethod("POST"); + $this->request = $this->request->withMethod('POST'); $map = $this->getMethodMap(); - $map->register("POST", $this->middleware); - $map->register("POST", null); + $map->register('POST', $this->middleware); + $map->register('POST', null); $response = $map($this->request, $this->response, $this->next); $this->assertEquals(405, $response->getStatusCode()); @@ -110,10 +110,10 @@ class MethodMapTest extends TestCase public function testSetsStatusTo200ForOptions() { - $this->request = $this->request->withMethod("OPTIONS"); + $this->request = $this->request->withMethod('OPTIONS'); $map = $this->getMethodMap(); - $map->register("GET", $this->middleware); + $map->register('GET', $this->middleware); $response = $map($this->request, $this->response, $this->next); $this->assertEquals(200, $response->getStatusCode()); @@ -121,10 +121,10 @@ class MethodMapTest extends TestCase public function testStopsPropagatingAfterOptions() { - $this->request = $this->request->withMethod("OPTIONS"); + $this->request = $this->request->withMethod('OPTIONS'); $map = $this->getMethodMap(); - $map->register("GET", $this->middleware); + $map->register('GET', $this->middleware); $map($this->request, $this->response, $this->next); $this->assertFalse($this->next->called); @@ -133,7 +133,7 @@ class MethodMapTest extends TestCase /** @dataProvider allowedMethodProvider */ public function testSetsAllowHeaderForOptions($methodsDeclared, $methodsAllowed) { - $this->request = $this->request->withMethod("OPTIONS"); + $this->request = $this->request->withMethod('OPTIONS'); $map = $this->getMethodMap(); foreach ($methodsDeclared as $method) { @@ -141,16 +141,16 @@ class MethodMapTest extends TestCase } $response = $map($this->request, $this->response, $this->next); - $this->assertContainsEach($methodsAllowed, $response->getHeaderLine("Allow")); + $this->assertContainsEach($methodsAllowed, $response->getHeaderLine('Allow')); } /** @dataProvider allowedMethodProvider */ public function testSetsStatusTo405ForBadMethod() { - $this->request = $this->request->withMethod("POST"); + $this->request = $this->request->withMethod('POST'); $map = $this->getMethodMap(); - $map->register("GET", $this->middleware); + $map->register('GET', $this->middleware); $response = $map($this->request, $this->response, $this->next); $this->assertEquals(405, $response->getStatusCode()); @@ -162,10 +162,10 @@ class MethodMapTest extends TestCase */ public function testStopsPropagatingAfterBadMethod() { - $this->request = $this->request->withMethod("POST"); + $this->request = $this->request->withMethod('POST'); $map = $this->getMethodMap(); - $map->register("GET", $this->middleware); + $map->register('GET', $this->middleware); $map($this->request, $this->response, $this->next); $this->assertFalse($this->next->called); } @@ -173,7 +173,7 @@ class MethodMapTest extends TestCase /** @dataProvider allowedMethodProvider */ public function testSetsAllowHeaderForBadMethod($methodsDeclared, $methodsAllowed) { - $this->request = $this->request->withMethod("BAD"); + $this->request = $this->request->withMethod('BAD'); $map = $this->getMethodMap(); foreach ($methodsDeclared as $method) { @@ -181,17 +181,17 @@ class MethodMapTest extends TestCase } $response = $map($this->request, $this->response, $this->next); - $this->assertContainsEach($methodsAllowed, $response->getHeaderLine("Allow")); + $this->assertContainsEach($methodsAllowed, $response->getHeaderLine('Allow')); } public function allowedMethodProvider() { return [ - [["GET"], ["GET", "HEAD", "OPTIONS"]], - [["GET", "POST"], ["GET", "POST", "HEAD", "OPTIONS"]], - [["POST"], ["POST", "OPTIONS"]], - [["POST"], ["POST", "OPTIONS"]], - [["GET", "PUT,DELETE"], ["GET", "PUT", "DELETE", "HEAD", "OPTIONS"]], + [['GET'], ['GET', 'HEAD', 'OPTIONS']], + [['GET', 'POST'], ['GET', 'POST', 'HEAD', 'OPTIONS']], + [['POST'], ['POST', 'OPTIONS']], + [['POST'], ['POST', 'OPTIONS']], + [['GET', 'PUT,DELETE'], ['GET', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']], ]; } diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 2387e7e..5653fdf 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -34,7 +34,7 @@ class RouterTest extends TestCase $this->route->__invoke(Argument::cetera())->willReturn(new Response()); $this->route->register(Argument::cetera()); $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); - $this->route->getTarget()->willReturn("/"); + $this->route->getTarget()->willReturn('/'); $this->route->getPathVariables()->willReturn([]); $this->factory = $this->prophesize(RouteFactory::class); @@ -64,24 +64,24 @@ class RouterTest extends TestCase public function testCreatesRouteForTarget() { - $this->router->register("GET", "/", "middleware"); + $this->router->register('GET', '/', 'middleware'); - $this->factory->create("/")->shouldHaveBeenCalled(); + $this->factory->create('/')->shouldHaveBeenCalled(); } public function testDoesNotRecreateRouteForExistingTarget() { - $this->router->register("GET", "/", "middleware"); - $this->router->register("POST", "/", "middleware"); + $this->router->register('GET', '/', 'middleware'); + $this->router->register('POST', '/', 'middleware'); - $this->factory->create("/")->shouldHaveBeenCalledTimes(1); + $this->factory->create('/')->shouldHaveBeenCalledTimes(1); } public function testPassesMethodAndMiddlewareToRoute() { - $this->router->register("GET", "/", "middleware"); + $this->router->register('GET', '/', 'middleware'); - $this->route->register("GET", "middleware")->shouldHaveBeenCalled(); + $this->route->register('GET', 'middleware')->shouldHaveBeenCalled(); } // ------------------------------------------------------------------------ @@ -89,13 +89,13 @@ class RouterTest extends TestCase public function testDispatchesStaticRoute() { - $target = "/"; + $target = '/'; $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); - $this->router->register("GET", $target, "middleware"); + $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $this->route->__invoke(Argument::cetera()) @@ -104,13 +104,13 @@ class RouterTest extends TestCase public function testDispatchesPrefixRoute() { - $target = "/animals/cats/*"; - $this->request = $this->request->withRequestTarget("/animals/cats/molly"); + $target = '/animals/cats/*'; + $this->request = $this->request->withRequestTarget('/animals/cats/molly'); $this->route->getTarget()->willReturn($target); $this->route->getType()->willReturn(RouteInterface::TYPE_PREFIX); - $this->router->register("GET", $target, "middleware"); + $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $this->route->__invoke(Argument::cetera()) @@ -119,14 +119,14 @@ class RouterTest extends TestCase public function testDispatchesPatternRoute() { - $target = "/"; + $target = '/'; $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); - $this->router->register("GET", $target, "middleware"); + $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $this->route->__invoke(Argument::cetera()) @@ -137,23 +137,23 @@ class RouterTest extends TestCase { $staticRoute = $this->prophesize(RouteInterface::class); $staticRoute->register(Argument::cetera()); - $staticRoute->getTarget()->willReturn("/cats/"); + $staticRoute->getTarget()->willReturn('/cats/'); $staticRoute->getType()->willReturn(RouteInterface::TYPE_STATIC); $staticRoute->__invoke(Argument::cetera())->willReturn(new Response()); $prefixRoute = $this->prophesize(RouteInterface::class); $prefixRoute->register(Argument::cetera()); - $prefixRoute->getTarget()->willReturn("/cats/*"); + $prefixRoute->getTarget()->willReturn('/cats/*'); $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $this->request = $this->request->withRequestTarget("/cats/"); + $this->request = $this->request->withRequestTarget('/cats/'); - $this->factory->create("/cats/")->willReturn($staticRoute->reveal()); - $this->factory->create("/cats/*")->willReturn($prefixRoute->reveal()); + $this->factory->create('/cats/')->willReturn($staticRoute->reveal()); + $this->factory->create('/cats/*')->willReturn($prefixRoute->reveal()); - $this->router->register("GET", "/cats/", "middleware"); - $this->router->register("GET", "/cats/*", "middleware"); + $this->router->register('GET', '/cats/', 'middleware'); + $this->router->register('GET', '/cats/*', 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $staticRoute->__invoke(Argument::cetera()) @@ -166,24 +166,24 @@ class RouterTest extends TestCase $shortRoute = $this->prophesize(RouteInterface::class); $shortRoute->register(Argument::cetera()); - $shortRoute->getTarget()->willReturn("/animals/*"); + $shortRoute->getTarget()->willReturn('/animals/*'); $shortRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $shortRoute->__invoke(Argument::cetera())->willReturn(new Response()); $longRoute = $this->prophesize(RouteInterface::class); $longRoute->register(Argument::cetera()); - $longRoute->getTarget()->willReturn("/animals/cats/*"); + $longRoute->getTarget()->willReturn('/animals/cats/*'); $longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $longRoute->__invoke(Argument::cetera())->willReturn(new Response()); $this->request = $this->request - ->withRequestTarget("/animals/cats/molly"); + ->withRequestTarget('/animals/cats/molly'); - $this->factory->create("/animals/*")->willReturn($shortRoute->reveal()); - $this->factory->create("/animals/cats/*")->willReturn($longRoute->reveal()); + $this->factory->create('/animals/*')->willReturn($shortRoute->reveal()); + $this->factory->create('/animals/cats/*')->willReturn($longRoute->reveal()); - $this->router->register("GET", "/animals/*", "middleware"); - $this->router->register("GET", "/animals/cats/*", "middleware"); + $this->router->register('GET', '/animals/*', 'middleware'); + $this->router->register('GET', '/animals/cats/*', 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $longRoute->__invoke(Argument::cetera()) @@ -194,23 +194,23 @@ class RouterTest extends TestCase { $prefixRoute = $this->prophesize(RouteInterface::class); $prefixRoute->register(Argument::cetera()); - $prefixRoute->getTarget()->willReturn("/cats/*"); + $prefixRoute->getTarget()->willReturn('/cats/*'); $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); $patternRoute = $this->prophesize(RouteInterface::class); $patternRoute->register(Argument::cetera()); - $patternRoute->getTarget()->willReturn("/cats/{id}"); + $patternRoute->getTarget()->willReturn('/cats/{id}'); $patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $this->request = $this->request->withRequestTarget("/cats/"); + $this->request = $this->request->withRequestTarget('/cats/'); - $this->factory->create("/cats/*")->willReturn($prefixRoute->reveal()); - $this->factory->create("/cats/{id}")->willReturn($patternRoute->reveal()); + $this->factory->create('/cats/*')->willReturn($prefixRoute->reveal()); + $this->factory->create('/cats/{id}')->willReturn($patternRoute->reveal()); - $this->router->register("GET", "/cats/*", "middleware"); - $this->router->register("GET", "/cats/{id}", "middleware"); + $this->router->register('GET', '/cats/*', 'middleware'); + $this->router->register('GET', '/cats/{id}', 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $prefixRoute->__invoke(Argument::cetera()) @@ -221,7 +221,7 @@ class RouterTest extends TestCase { $patternRoute1 = $this->prophesize(RouteInterface::class); $patternRoute1->register(Argument::cetera()); - $patternRoute1->getTarget()->willReturn("/cats/{id}"); + $patternRoute1->getTarget()->willReturn('/cats/{id}'); $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); $patternRoute1->matchesRequestTarget(Argument::any())->willReturn(true); @@ -229,19 +229,19 @@ class RouterTest extends TestCase $patternRoute2 = $this->prophesize(RouteInterface::class); $patternRoute2->register(Argument::cetera()); - $patternRoute2->getTarget()->willReturn("/cats/{name}"); + $patternRoute2->getTarget()->willReturn('/cats/{name}'); $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->__invoke(Argument::cetera())->willReturn(new Response()); - $this->request = $this->request->withRequestTarget("/cats/molly"); + $this->request = $this->request->withRequestTarget('/cats/molly'); - $this->factory->create("/cats/{id}")->willReturn($patternRoute1->reveal()); - $this->factory->create("/cats/{name}")->willReturn($patternRoute2->reveal()); + $this->factory->create('/cats/{id}')->willReturn($patternRoute1->reveal()); + $this->factory->create('/cats/{name}')->willReturn($patternRoute2->reveal()); - $this->router->register("GET", "/cats/{id}", "middleware"); - $this->router->register("GET", "/cats/{name}", "middleware"); + $this->router->register('GET', '/cats/{id}', 'middleware'); + $this->router->register('GET', '/cats/{name}', 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $patternRoute1->__invoke(Argument::cetera()) @@ -252,7 +252,7 @@ class RouterTest extends TestCase { $patternRoute1 = $this->prophesize(RouteInterface::class); $patternRoute1->register(Argument::cetera()); - $patternRoute1->getTarget()->willReturn("/cats/{id}"); + $patternRoute1->getTarget()->willReturn('/cats/{id}'); $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); $patternRoute1->matchesRequestTarget(Argument::any())->willReturn(true); @@ -260,19 +260,19 @@ class RouterTest extends TestCase $patternRoute2 = $this->prophesize(RouteInterface::class); $patternRoute2->register(Argument::cetera()); - $patternRoute2->getTarget()->willReturn("/cats/{name}"); + $patternRoute2->getTarget()->willReturn('/cats/{name}'); $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->__invoke(Argument::cetera())->willReturn(new Response()); - $this->request = $this->request->withRequestTarget("/cats/molly"); + $this->request = $this->request->withRequestTarget('/cats/molly'); - $this->factory->create("/cats/{id}")->willReturn($patternRoute1->reveal()); - $this->factory->create("/cats/{name}")->willReturn($patternRoute2->reveal()); + $this->factory->create('/cats/{id}')->willReturn($patternRoute1->reveal()); + $this->factory->create('/cats/{name}')->willReturn($patternRoute2->reveal()); - $this->router->register("GET", "/cats/{id}", "middleware"); - $this->router->register("GET", "/cats/{name}", "middleware"); + $this->router->register('GET', '/cats/{id}', 'middleware'); + $this->router->register('GET', '/cats/{name}', 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $patternRoute2->matchesRequestTarget(Argument::any()) @@ -281,7 +281,7 @@ class RouterTest extends TestCase public function testMatchesPathAgainstRouteWithoutQuery() { - $target = "/my/path?cat=molly&dog=bear"; + $target = '/my/path?cat=molly&dog=bear'; $this->request = $this->request->withRequestTarget($target); @@ -289,10 +289,10 @@ class RouterTest extends TestCase $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); - $this->router->register("GET", $target, "middleware"); + $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); - $this->route->matchesRequestTarget("/my/path")->shouldHaveBeenCalled(); + $this->route->matchesRequestTarget('/my/path')->shouldHaveBeenCalled(); } // ------------------------------------------------------------------------ @@ -301,10 +301,10 @@ class RouterTest extends TestCase /** @dataProvider pathVariableProvider */ public function testSetPathVariablesAttributeIndividually($name, $value) { - $target = "/"; + $target = '/'; $variables = [ - "id" => "1024", - "name" => "Molly" + 'id' => '1024', + 'name' => 'Molly' ]; $this->request = $this->request->withRequestTarget($target); @@ -314,7 +314,7 @@ class RouterTest extends TestCase $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->getPathVariables()->willReturn($variables); - $this->router->register("GET", $target, "middleware"); + $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $isRequestWithExpectedAttribute = function ($request) use ($name, $value) { @@ -330,19 +330,19 @@ class RouterTest extends TestCase public function pathVariableProvider() { return [ - ["id", "1024"], - ["name", "Molly"] + ['id', '1024'], + ['name', 'Molly'] ]; } public function testSetPathVariablesAttributeAsArray() { - $attributeName = "pathVariables"; + $attributeName = 'pathVariables'; - $target = "/"; + $target = '/'; $variables = [ - "id" => "1024", - "name" => "Molly" + 'id' => '1024', + 'name' => 'Molly' ]; $this->request = $this->request->withRequestTarget($target); @@ -353,7 +353,7 @@ class RouterTest extends TestCase $this->route->getPathVariables()->willReturn($variables); $this->router->__construct(new Dispatcher(), $attributeName); - $this->router->register("GET", $target, "middleware"); + $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); $isRequestWithExpectedAttribute = function ($request) use ($attributeName, $variables) { @@ -371,21 +371,21 @@ class RouterTest extends TestCase public function testWhenNoRouteMatchesByDefaultResponds404() { - $this->request = $this->request->withRequestTarget("/no/match"); + $this->request = $this->request->withRequestTarget('/no/match'); $response = $this->router->__invoke($this->request, $this->response, $this->next); $this->assertEquals(404, $response->getStatusCode()); } public function testWhenNoRouteMatchesByDefaultDoesNotPropagatesToNextMiddleware() { - $this->request = $this->request->withRequestTarget("/no/match"); + $this->request = $this->request->withRequestTarget('/no/match'); $this->router->__invoke($this->request, $this->response, $this->next); $this->assertFalse($this->next->called); } public function testWhenNoRouteMatchesAndContinueModePropagatesToNextMiddleware() { - $this->request = $this->request->withRequestTarget("/no/match"); + $this->request = $this->request->withRequestTarget('/no/match'); $this->router->continueOnNotFound(); $this->router->__invoke($this->request, $this->response, $this->next); $this->assertTrue($this->next->called); @@ -407,7 +407,7 @@ class RouterTest extends TestCase }; $this->router->add($middleware); - $this->router->register("GET", "/", "Handler"); + $this->router->register('GET', '/', 'Handler'); $this->router->__invoke($this->request, $this->response, $this->next); @@ -433,10 +433,10 @@ class RouterTest extends TestCase return $next($middlewareRequest, $middlewareResponse); }; - $this->request = $this->request->withRequestTarget("/no/match"); + $this->request = $this->request->withRequestTarget('/no/match'); $this->router->add($middleware); - $this->router->register("GET", "/", "Handler"); + $this->router->register('GET', '/', 'Handler'); $this->router->__invoke($this->request, $this->response, $this->next); diff --git a/test/tests/unit/ServerTest.php b/test/tests/unit/ServerTest.php index b490ff4..a2a854d 100644 --- a/test/tests/unit/ServerTest.php +++ b/test/tests/unit/ServerTest.php @@ -147,15 +147,15 @@ class ServerTest extends TestCase $this->server->setPathVariablesAttributeName('pathVariables'); $request = (new ServerRequest()) - ->withMethod("GET") - ->withRequestTarget("/"); + ->withMethod('GET') + ->withRequestTarget('/'); $response = new Response(); $next = function ($rqst, $resp) { return $resp; }; $router = $this->server->createRouter(); - $router->register("GET", "/", "middleware"); + $router->register('GET', '/', 'middleware'); $router($request, $response, $next); $dispatcher->dispatch(Argument::cetera()) @@ -209,7 +209,7 @@ class ServerTest extends TestCase public function testCreatesStockTransmitterByDefault() { - $content = "Hello, world!"; + $content = 'Hello, world!'; $response = (new Response()) ->withBody(new Stream($content)); diff --git a/test/tests/unit/Transmission/TransmitterTest.php b/test/tests/unit/Transmission/TransmitterTest.php index 8f7ae47..2a221e2 100644 --- a/test/tests/unit/Transmission/TransmitterTest.php +++ b/test/tests/unit/Transmission/TransmitterTest.php @@ -11,7 +11,7 @@ use WellRESTed\Test\TestCase; use WellRESTed\Transmission\HeaderStack; use WellRESTed\Transmission\Transmitter; -require_once __DIR__ . "/../../../src/HeaderStack.php"; +require_once __DIR__ . '/../../../src/HeaderStack.php'; class TransmitterTest extends TestCase { @@ -26,7 +26,7 @@ class TransmitterTest extends TestCase HeaderStack::reset(); $this->request = (new ServerRequest()) - ->withMethod("HEAD"); + ->withMethod('HEAD'); $this->body = $this->prophesize(StreamInterface::class); $this->body->isReadable()->willReturn(false); @@ -43,7 +43,7 @@ class TransmitterTest extends TestCase { $transmitter = new Transmitter(); $transmitter->transmit($this->request, $this->response); - $this->assertContains("HTTP/1.1 200 OK", HeaderStack::getHeaders()); + $this->assertContains('HTTP/1.1 200 OK', HeaderStack::getHeaders()); } public function testSendStatusCodeWithoutReasonPhrase() @@ -52,15 +52,15 @@ class TransmitterTest extends TestCase $transmitter = new Transmitter(); $transmitter->transmit($this->request, $this->response); - $this->assertContains("HTTP/1.1 999", HeaderStack::getHeaders()); + $this->assertContains('HTTP/1.1 999', HeaderStack::getHeaders()); } /** @dataProvider headerProvider */ public function testSendsHeaders($header) { $this->response = $this->response - ->withHeader("Content-length", ["2048"]) - ->withHeader("X-foo", ["bar", "baz"]); + ->withHeader('Content-length', ['2048']) + ->withHeader('X-foo', ['bar', 'baz']); $transmitter = new Transmitter(); $transmitter->transmit($this->request, $this->response); @@ -70,15 +70,15 @@ class TransmitterTest extends TestCase public function headerProvider() { return [ - ["Content-length: 2048"], - ["X-foo: bar"], - ["X-foo: baz"] + ['Content-length: 2048'], + ['X-foo: bar'], + ['X-foo: baz'] ]; } public function testOutputsBody() { - $content = "Hello, world!"; + $content = 'Hello, world!'; $this->body->isReadable()->willReturn(true); $this->body->__toString()->willReturn($content); @@ -96,7 +96,7 @@ class TransmitterTest extends TestCase public function testOutputsBodyInChunks() { - $content = "Hello, world!"; + $content = 'Hello, world!'; $chunkSize = 3; $position = 0; @@ -129,7 +129,7 @@ class TransmitterTest extends TestCase public function testOutputsUnseekableStreamInChunks() { - $content = "Hello, world!"; + $content = 'Hello, world!'; $chunkSize = 3; $position = 0; @@ -167,7 +167,7 @@ class TransmitterTest extends TestCase { $bodySize = 1024; $this->body->isReadable()->willReturn(true); - $this->body->__toString()->willReturn(""); + $this->body->__toString()->willReturn(''); $this->body->getSize()->willReturn($bodySize); $transmitter = new Transmitter(); @@ -182,10 +182,10 @@ class TransmitterTest extends TestCase $streamSize = 1024; $headerSize = 2048; - $this->response = $this->response->withHeader("Content-length", $headerSize); + $this->response = $this->response->withHeader('Content-length', $headerSize); $this->body->isReadable()->willReturn(true); - $this->body->__toString()->willReturn(""); + $this->body->__toString()->willReturn(''); $this->body->getSize()->willReturn($streamSize); $transmitter = new Transmitter(); @@ -199,30 +199,30 @@ class TransmitterTest extends TestCase { $bodySize = 1024; - $this->response = $this->response->withHeader("Transfer-encoding", "CHUNKED"); + $this->response = $this->response->withHeader('Transfer-encoding', 'CHUNKED'); $this->body->isReadable()->willReturn(true); - $this->body->__toString()->willReturn(""); + $this->body->__toString()->willReturn(''); $this->body->getSize()->willReturn($bodySize); $transmitter = new Transmitter(); $transmitter->setChunkSize(0); $transmitter->transmit($this->request, $this->response); - $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), "Content-length:"); + $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); } public function testDoesNotAddContentLengthHeaderWhenBodySizeIsNull() { $this->body->isReadable()->willReturn(true); - $this->body->__toString()->willReturn(""); + $this->body->__toString()->willReturn(''); $this->body->getSize()->willReturn(null); $transmitter = new Transmitter(); $transmitter->setChunkSize(0); $transmitter->transmit($this->request, $this->response); - $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), "Content-length:"); + $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); } private function assertArrayDoesNotContainValueWithPrefix($arr, $prefix) From ff28f3c6eb4df03e02b4455616a37024fa8c64bd Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Mon, 10 Aug 2020 07:30:04 -0400 Subject: [PATCH 21/53] Update CS rules --- .php_cs.dist | 4 ++++ test/tests/unit/Dispatching/DispatcherTest.php | 1 + 2 files changed, 5 insertions(+) diff --git a/.php_cs.dist b/.php_cs.dist index e5c0d64..2f69e56 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -9,6 +9,10 @@ return PhpCsFixer\Config::create() ->setFinder($finder) ->setRules([ '@PSR2' => true, + 'align_multiline_comment' => true, 'array_syntax' => ['syntax' => 'short'], + 'blank_line_after_opening_tag' => true, + 'cast_spaces' => true, + 'class_attributes_separation' => ['elements' => ['method']], 'single_quote' => true ]); diff --git a/test/tests/unit/Dispatching/DispatcherTest.php b/test/tests/unit/Dispatching/DispatcherTest.php index 63c6019..fd7e712 100644 --- a/test/tests/unit/Dispatching/DispatcherTest.php +++ b/test/tests/unit/Dispatching/DispatcherTest.php @@ -190,6 +190,7 @@ class HandlerDouble implements RequestHandlerInterface { /** @var ResponseInterface */ private $response; + public function __construct(ResponseInterface $response) { $this->response = $response; From e6d1398bb12408116bc7a8d720c31e2aa8dd7513 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Mon, 10 Aug 2020 07:31:06 -0400 Subject: [PATCH 22/53] Normalize imports for global namespace --- .php_cs.dist | 5 +++ src/Dispatching/DispatchException.php | 4 +- src/Message/Message.php | 13 +++--- src/Message/NullStream.php | 19 ++++---- src/Message/Request.php | 9 ++-- src/Message/Response.php | 3 +- src/Message/ServerRequest.php | 7 +-- src/Message/Stream.php | 43 ++++++++++--------- src/Message/UploadedFile.php | 16 ++++--- src/Message/Uri.php | 21 ++++----- src/Routing/Route/RegexRoute.php | 4 +- .../unit/Transmission/TransmitterTest.php | 3 +- 12 files changed, 84 insertions(+), 63 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 2f69e56..7808176 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -14,5 +14,10 @@ return PhpCsFixer\Config::create() 'blank_line_after_opening_tag' => true, 'cast_spaces' => true, 'class_attributes_separation' => ['elements' => ['method']], + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], 'single_quote' => true ]); diff --git a/src/Dispatching/DispatchException.php b/src/Dispatching/DispatchException.php index 9a7d9da..9422e61 100644 --- a/src/Dispatching/DispatchException.php +++ b/src/Dispatching/DispatchException.php @@ -2,6 +2,8 @@ namespace WellRESTed\Dispatching; -class DispatchException extends \InvalidArgumentException +use InvalidArgumentException; + +class DispatchException extends InvalidArgumentException { } diff --git a/src/Message/Message.php b/src/Message/Message.php index b5e1a5e..af80d3b 100644 --- a/src/Message/Message.php +++ b/src/Message/Message.php @@ -4,6 +4,7 @@ namespace WellRESTed\Message; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\StreamInterface; +use InvalidArgumentException; /** * Message defines core functionality for classes that represent HTTP messages. @@ -189,7 +190,7 @@ abstract class Message implements MessageInterface * @param string $name Case-insensitive header field name. * @param string|string[] $value Header value(s). * @return static - * @throws \InvalidArgumentException for invalid header names or values. + * @throws InvalidArgumentException for invalid header names or values. */ public function withHeader($name, $value) { @@ -213,7 +214,7 @@ abstract class Message implements MessageInterface * @param string $name Case-insensitive header field name to add. * @param string|string[] $value Header value(s). * @return static - * @throws \InvalidArgumentException for invalid header names or values. + * @throws InvalidArgumentException for invalid header names or values. */ public function withAddedHeader($name, $value) { @@ -256,7 +257,7 @@ abstract class Message implements MessageInterface * * @param StreamInterface $body Body. * @return static - * @throws \InvalidArgumentException When the body is not valid. + * @throws InvalidArgumentException When the body is not valid. */ public function withBody(StreamInterface $body) { @@ -271,13 +272,13 @@ abstract class Message implements MessageInterface * @param mixed $name * @param mixed|mixed[] $values * @return string[] - * @throws \InvalidArgumentException Name is not a string or value is not + * @throws InvalidArgumentException Name is not a string or value is not * a string or array of strings */ private function getValidatedHeaders($name, $values) { if (!is_string($name)) { - throw new \InvalidArgumentException('Header name must be a string'); + throw new InvalidArgumentException('Header name must be a string'); } if (!is_array($values)) { @@ -290,7 +291,7 @@ abstract class Message implements MessageInterface $invalid = array_filter($values, $isNotStringOrNumber); if ($invalid) { - throw new \InvalidArgumentException('Header values must be a string or string[]'); + throw new InvalidArgumentException('Header values must be a string or string[]'); } return array_map('strval', $values); diff --git a/src/Message/NullStream.php b/src/Message/NullStream.php index f8826d1..0f25741 100644 --- a/src/Message/NullStream.php +++ b/src/Message/NullStream.php @@ -3,6 +3,7 @@ namespace WellRESTed\Message; use Psr\Http\Message\StreamInterface; +use RuntimeException; /** * NullStream is a minimal, always-empty, non-writable stream. @@ -54,7 +55,7 @@ class NullStream implements StreamInterface * Returns the current position of the file read/write pointer * * @return int Position of the file pointer - * @throws \RuntimeException on error. + * @throws RuntimeException on error. */ public function tell() { @@ -92,11 +93,11 @@ class NullStream implements StreamInterface * offset bytes SEEK_CUR: Set position to current location plus offset * SEEK_END: Set position to end-of-stream plus offset. * @return void - * @throws \RuntimeException on failure. + * @throws RuntimeException on failure. */ public function seek($offset, $whence = SEEK_SET) { - throw new \RuntimeException('Unable to seek to position.'); + throw new RuntimeException('Unable to seek to position.'); } /** @@ -105,11 +106,11 @@ class NullStream implements StreamInterface * @see seek() * @link http://www.php.net/manual/en/function.fseek.php * @return void - * @throws \RuntimeException on failure. + * @throws RuntimeException on failure. */ public function rewind() { - throw new \RuntimeException('Unable to rewind stream.'); + throw new RuntimeException('Unable to rewind stream.'); } /** @@ -127,11 +128,11 @@ class NullStream implements StreamInterface * * @param string $string The string that is to be written. * @return int Returns the number of bytes written to the stream. - * @throws \RuntimeException on failure. + * @throws RuntimeException on failure. */ public function write($string) { - throw new \RuntimeException('Unable to write to stream.'); + throw new RuntimeException('Unable to write to stream.'); } /** @@ -152,7 +153,7 @@ class NullStream implements StreamInterface * call returns fewer bytes. * @return string Returns the data read from the stream, or an empty string * if no bytes are available. - * @throws \RuntimeException if an error occurs. + * @throws RuntimeException if an error occurs. */ public function read($length) { @@ -163,7 +164,7 @@ class NullStream implements StreamInterface * Returns the remaining contents in a string * * @return string - * @throws \RuntimeException if unable to read or an error occurs while + * @throws RuntimeException if unable to read or an error occurs while * reading. */ public function getContents() diff --git a/src/Message/Request.php b/src/Message/Request.php index 0b24d83..83016cd 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -5,6 +5,7 @@ namespace WellRESTed\Message; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; +use InvalidArgumentException; /** * Representation of an outgoing, client-side request. @@ -135,7 +136,7 @@ class Request extends Message implements RequestInterface * * @param string $method Case-insensitive method. * @return static - * @throws \InvalidArgumentException for invalid HTTP methods. + * @throws InvalidArgumentException for invalid HTTP methods. */ public function withMethod($method) { @@ -211,16 +212,16 @@ class Request extends Message implements RequestInterface /** * @param mixed $method * @return string - * @throws \InvalidArgumentException + * @throws InvalidArgumentException */ private function getValidatedMethod($method) { if (!is_string($method)) { - throw new \InvalidArgumentException('Method must be a string.'); + throw new InvalidArgumentException('Method must be a string.'); } $method = trim($method); if (strpos($method, ' ') !== false) { - throw new \InvalidArgumentException('Method cannot contain spaces.'); + throw new InvalidArgumentException('Method cannot contain spaces.'); } return $method; } diff --git a/src/Message/Response.php b/src/Message/Response.php index da4397b..09d7480 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -4,6 +4,7 @@ namespace WellRESTed\Message; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; +use InvalidArgumentException; /** * Representation of an outgoing, server-side response. @@ -77,7 +78,7 @@ class Response extends Message implements ResponseInterface * provided status code; if none is provided, implementations MAY * use the defaults as suggested in the HTTP specification. * @return static - * @throws \InvalidArgumentException For invalid status code arguments. + * @throws InvalidArgumentException For invalid status code arguments. */ public function withStatus($code, $reasonPhrase = '') { diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index f592913..ff38f79 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; use Psr\Http\Message\UriInterface; +use InvalidArgumentException; /** * Representation of an incoming, server-side HTTP request. @@ -189,12 +190,12 @@ class ServerRequest extends Request implements ServerRequestInterface * * @param array $uploadedFiles An array tree of UploadedFileInterface instances. * @return static - * @throws \InvalidArgumentException if an invalid structure is provided. + * @throws InvalidArgumentException if an invalid structure is provided. */ public function withUploadedFiles(array $uploadedFiles) { if (!$this->isValidUploadedFilesTree($uploadedFiles)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'withUploadedFiles expects an array tree with UploadedFileInterface leaves.' ); } @@ -249,7 +250,7 @@ class ServerRequest extends Request implements ServerRequestInterface public function withParsedBody($data) { if (!(is_null($data) || is_array($data) || is_object($data))) { - throw new \InvalidArgumentException('Parsed body must be null, array, or object.'); + throw new InvalidArgumentException('Parsed body must be null, array, or object.'); } $request = clone $this; diff --git a/src/Message/Stream.php b/src/Message/Stream.php index 7103115..cf75406 100644 --- a/src/Message/Stream.php +++ b/src/Message/Stream.php @@ -3,6 +3,9 @@ namespace WellRESTed\Message; use Psr\Http\Message\StreamInterface; +use InvalidArgumentException; +use Exception; +use RuntimeException; class Stream implements StreamInterface { @@ -32,7 +35,7 @@ class Stream implements StreamInterface $this->write($resource); } } else { - throw new \InvalidArgumentException('Expected a resource handler.'); + throw new InvalidArgumentException('Expected a resource handler.'); } } @@ -54,7 +57,7 @@ class Stream implements StreamInterface $this->rewind(); } return $this->getContents(); - } catch (\Exception $e) { + } catch (Exception $e) { // Silence exceptions in order to conform with PHP's string casting // operations. return ''; @@ -113,17 +116,17 @@ class Stream implements StreamInterface * Returns the current position of the file read/write pointer * * @return int Position of the file pointer - * @throws \RuntimeException on error. + * @throws RuntimeException on error. */ public function tell() { if ($this->resource === null) { - throw new \RuntimeException('Unable to retrieve current position of detached stream.'); + throw new RuntimeException('Unable to retrieve current position of detached stream.'); } $position = ftell($this->resource); if ($position === false) { - throw new \RuntimeException('Unable to retrieve current position of file pointer.'); + throw new RuntimeException('Unable to retrieve current position of file pointer.'); } return $position; } @@ -167,12 +170,12 @@ class Stream implements StreamInterface * offset bytes SEEK_CUR: Set position to current location plus offset * SEEK_END: Set position to end-of-stream plus offset. * @return void - * @throws \RuntimeException on failure. + * @throws RuntimeException on failure. */ public function seek($offset, $whence = SEEK_SET) { if ($this->resource === null) { - throw new \RuntimeException('Unable to seek detached stream.'); + throw new RuntimeException('Unable to seek detached stream.'); } $result = -1; @@ -180,7 +183,7 @@ class Stream implements StreamInterface $result = fseek($this->resource, $offset, $whence); } if ($result === -1) { - throw new \RuntimeException('Unable to seek to position.'); + throw new RuntimeException('Unable to seek to position.'); } } @@ -193,12 +196,12 @@ class Stream implements StreamInterface * @see seek() * @link http://www.php.net/manual/en/function.fseek.php * @return void - * @throws \RuntimeException on failure. + * @throws RuntimeException on failure. */ public function rewind() { if ($this->resource === null) { - throw new \RuntimeException('Unable to seek detached stream.'); + throw new RuntimeException('Unable to seek detached stream.'); } $result = false; @@ -206,7 +209,7 @@ class Stream implements StreamInterface $result = rewind($this->resource); } if ($result === false) { - throw new \RuntimeException('Unable to rewind.'); + throw new RuntimeException('Unable to rewind.'); } } @@ -230,12 +233,12 @@ class Stream implements StreamInterface * * @param string $string The string that is to be written. * @return int Returns the number of bytes written to the stream. - * @throws \RuntimeException on failure. + * @throws RuntimeException on failure. */ public function write($string) { if ($this->resource === null) { - throw new \RuntimeException('Unable to write to detached stream.'); + throw new RuntimeException('Unable to write to detached stream.'); } $result = false; @@ -243,7 +246,7 @@ class Stream implements StreamInterface $result = fwrite($this->resource, $string); } if ($result === false) { - throw new \RuntimeException('Unable to write to stream.'); + throw new RuntimeException('Unable to write to stream.'); } return $result; } @@ -271,12 +274,12 @@ class Stream implements StreamInterface * call returns fewer bytes. * @return string Returns the data read from the stream, or an empty string * if no bytes are available. - * @throws \RuntimeException if an error occurs. + * @throws RuntimeException if an error occurs. */ public function read($length) { if ($this->resource === null) { - throw new \RuntimeException('Unable to read to detached stream.'); + throw new RuntimeException('Unable to read to detached stream.'); } $result = false; @@ -284,7 +287,7 @@ class Stream implements StreamInterface $result = fread($this->resource, $length); } if ($result === false) { - throw new \RuntimeException('Unable to read from stream.'); + throw new RuntimeException('Unable to read from stream.'); } return $result; } @@ -293,13 +296,13 @@ class Stream implements StreamInterface * Returns the remaining contents in a string * * @return string - * @throws \RuntimeException if unable to read or an error occurs while + * @throws RuntimeException if unable to read or an error occurs while * reading. */ public function getContents() { if ($this->resource === null) { - throw new \RuntimeException('Unable to read to detached stream.'); + throw new RuntimeException('Unable to read to detached stream.'); } $result = false; @@ -307,7 +310,7 @@ class Stream implements StreamInterface $result = stream_get_contents($this->resource); } if ($result === false) { - throw new \RuntimeException('Unable to read from stream.'); + throw new RuntimeException('Unable to read from stream.'); } return $result; } diff --git a/src/Message/UploadedFile.php b/src/Message/UploadedFile.php index dad8b3d..42dbb62 100644 --- a/src/Message/UploadedFile.php +++ b/src/Message/UploadedFile.php @@ -4,6 +4,8 @@ namespace WellRESTed\Message; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; +use InvalidArgumentException; +use RuntimeException; /** * Value object representing a file uploaded through an HTTP request. @@ -85,19 +87,19 @@ class UploadedFile implements UploadedFileInterface * raise an exception. * * @return StreamInterface Stream representation of the uploaded file. - * @throws \RuntimeException in cases when no stream is available or can + * @throws RuntimeException in cases when no stream is available or can * be created. */ public function getStream() { if ($this->tmpName === null) { - throw new \RuntimeException('Unable to read uploaded file.'); + throw new RuntimeException('Unable to read uploaded file.'); } if ($this->moved) { - throw new \RuntimeException('File has already been moved.'); + throw new RuntimeException('File has already been moved.'); } if (php_sapi_name() !== 'cli' && !is_uploaded_file($this->tmpName)) { - throw new \RuntimeException('File is not an uploaded file.'); + throw new RuntimeException('File is not an uploaded file.'); } return $this->stream; } @@ -117,14 +119,14 @@ class UploadedFile implements UploadedFileInterface * @see http://php.net/move_uploaded_file * @param string $path Path to which to move the uploaded file. * @return void - * @throws \InvalidArgumentException if the $path specified is invalid. - * @throws \RuntimeException on any error during the move operation, or on + * @throws InvalidArgumentException if the $path specified is invalid. + * @throws RuntimeException on any error during the move operation, or on * the second or subsequent call to the method. */ public function moveTo($path) { if ($this->tmpName === null || !file_exists($this->tmpName)) { - throw new \RuntimeException('File ' . $this->tmpName . ' does not exist.'); + throw new RuntimeException('File ' . $this->tmpName . ' does not exist.'); } if (php_sapi_name() === 'cli') { rename($this->tmpName, $path); diff --git a/src/Message/Uri.php b/src/Message/Uri.php index b21cb31..0449276 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -3,6 +3,7 @@ namespace WellRESTed\Message; use Psr\Http\Message\UriInterface; +use InvalidArgumentException; /** * Value object representing a URI. @@ -301,13 +302,13 @@ class Uri implements UriInterface * * @param string $scheme The scheme to use with the new instance. * @return static A new instance with the specified scheme. - * @throws \InvalidArgumentException for invalid or unsupported schemes. + * @throws InvalidArgumentException for invalid or unsupported schemes. */ public function withScheme($scheme) { $scheme = $scheme ? strtolower($scheme) : ''; if (!in_array($scheme, ['', 'http', 'https'])) { - throw new \InvalidArgumentException('Scheme must be http, https, or empty.'); + throw new InvalidArgumentException('Scheme must be http, https, or empty.'); } $uri = clone $this; $uri->scheme = $scheme; @@ -346,12 +347,12 @@ class Uri implements UriInterface * * @param string $host The hostname to use with the new instance. * @return static A new instance with the specified host. - * @throws \InvalidArgumentException for invalid hostnames. + * @throws InvalidArgumentException for invalid hostnames. */ public function withHost($host) { if (!is_string($host)) { - throw new \InvalidArgumentException('Host must be a string.'); + throw new InvalidArgumentException('Host must be a string.'); } $uri = clone $this; @@ -374,18 +375,18 @@ class Uri implements UriInterface * @param null|int $port The port to use with the new instance; a null value * removes the port information. * @return static A new instance with the specified port. - * @throws \InvalidArgumentException for invalid ports. + * @throws InvalidArgumentException for invalid ports. */ public function withPort($port) { if (is_numeric($port)) { if ($port < self::MIN_PORT || $port > self::MAX_PORT) { $message = sprintf('Port must be between %s and %s.', self::MIN_PORT, self::MAX_PORT); - throw new \InvalidArgumentException($message); + throw new InvalidArgumentException($message); } $port = (int) $port; } elseif ($port !== null) { - throw new \InvalidArgumentException('Port must be an int or null.'); + throw new InvalidArgumentException('Port must be an int or null.'); } $uri = clone $this; @@ -408,12 +409,12 @@ class Uri implements UriInterface * * @param string $path The path to use with the new instance. * @return static A new instance with the specified path. - * @throws \InvalidArgumentException for invalid paths. + * @throws InvalidArgumentException for invalid paths. */ public function withPath($path) { if (!is_string($path)) { - throw new \InvalidArgumentException('Path must be a string'); + throw new InvalidArgumentException('Path must be a string'); } $uri = clone $this; $uri->path = $path; @@ -433,7 +434,7 @@ class Uri implements UriInterface * * @param string $query The query string to use with the new instance. * @return static A new instance with the specified query string. - * @throws \InvalidArgumentException for invalid query strings. + * @throws InvalidArgumentException for invalid query strings. */ public function withQuery($query) { diff --git a/src/Routing/Route/RegexRoute.php b/src/Routing/Route/RegexRoute.php index 9ff6fb9..8e2a046 100644 --- a/src/Routing/Route/RegexRoute.php +++ b/src/Routing/Route/RegexRoute.php @@ -2,6 +2,8 @@ namespace WellRESTed\Routing\Route; +use RuntimeException; + class RegexRoute extends Route { /** @var array */ @@ -26,7 +28,7 @@ class RegexRoute extends Route $this->captures = $captures; return true; } elseif ($matched === false) { - throw new \RuntimeException('Invalid regular expression: ' . $this->getTarget()); + throw new RuntimeException('Invalid regular expression: ' . $this->getTarget()); } return false; } diff --git a/test/tests/unit/Transmission/TransmitterTest.php b/test/tests/unit/Transmission/TransmitterTest.php index 2a221e2..9fe0c44 100644 --- a/test/tests/unit/Transmission/TransmitterTest.php +++ b/test/tests/unit/Transmission/TransmitterTest.php @@ -10,6 +10,7 @@ use WellRESTed\Message\ServerRequest; use WellRESTed\Test\TestCase; use WellRESTed\Transmission\HeaderStack; use WellRESTed\Transmission\Transmitter; +use RuntimeException; require_once __DIR__ . '/../../../src/HeaderStack.php'; @@ -135,7 +136,7 @@ class TransmitterTest extends TestCase $this->body->isSeekable()->willReturn(false); $this->body->isReadable()->willReturn(true); - $this->body->rewind()->willThrow(new \RuntimeException()); + $this->body->rewind()->willThrow(new RuntimeException()); $this->body->eof()->willReturn(false); $this->body->read(Argument::any())->will( function ($args) use ($content, &$position) { From cd2e4448e2252b2c6c71fb9f843bc898e1d7906b Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Mon, 10 Aug 2020 07:39:55 -0400 Subject: [PATCH 23/53] Update CS rules --- .php_cs.dist | 38 ++++++++++++++++++- src/Message/Message.php | 2 +- src/Message/Request.php | 2 +- src/Message/Response.php | 2 +- src/Message/ServerRequest.php | 4 +- src/Message/Stream.php | 4 +- src/Message/UploadedFile.php | 2 +- src/Message/Uri.php | 2 +- src/Routing/Route/TemplateRoute.php | 2 +- src/Routing/Router.php | 2 +- .../unit/Routing/Route/PrefixRouteTest.php | 2 +- .../unit/Transmission/TransmitterTest.php | 2 +- 12 files changed, 50 insertions(+), 14 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 7808176..09ee1bf 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -7,6 +7,7 @@ $finder = PhpCsFixer\Finder::create() return PhpCsFixer\Config::create() ->setFinder($finder) + ->setRiskyAllowed(true) ->setRules([ '@PSR2' => true, 'align_multiline_comment' => true, @@ -19,5 +20,40 @@ return PhpCsFixer\Config::create() 'import_constants' => true, 'import_functions' => true, ], - 'single_quote' => true + 'linebreak_after_opening_tag' => true, + 'lowercase_cast' => true, + 'lowercase_static_reference' => true, + 'method_chaining_indentation' => true, + 'modernize_types_casting' => true, + 'multiline_comment_opening_closing' => true, + 'multiline_whitespace_before_semicolons' => true, + 'native_function_casing' => true, + 'no_alternative_syntax' => true, + 'no_extra_blank_lines' => true, + 'no_leading_import_slash' => true, + 'no_mixed_echo_print' => ['use' => 'print'], + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_around_offset' => true, + 'no_trailing_comma_in_list_call' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unused_imports' => true, + 'no_useless_return' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'normalize_index_brace' => true, + 'nullable_type_declaration_for_default_null_value' => true, + 'ordered_imports' => [ + 'sort_algorithm' => 'alpha' + ], + 'ordered_interfaces' => [ + 'direction' => 'ascend', + 'order' => 'alpha', + ], + 'single_quote' => true, + 'space_after_semicolon' => true, + 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_null_coalescing' => true ]); diff --git a/src/Message/Message.php b/src/Message/Message.php index af80d3b..cfe0581 100644 --- a/src/Message/Message.php +++ b/src/Message/Message.php @@ -2,9 +2,9 @@ namespace WellRESTed\Message; +use InvalidArgumentException; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\StreamInterface; -use InvalidArgumentException; /** * Message defines core functionality for classes that represent HTTP messages. diff --git a/src/Message/Request.php b/src/Message/Request.php index 83016cd..33cddc0 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -2,10 +2,10 @@ namespace WellRESTed\Message; +use InvalidArgumentException; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; -use InvalidArgumentException; /** * Representation of an outgoing, client-side request. diff --git a/src/Message/Response.php b/src/Message/Response.php index 09d7480..2269186 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -2,9 +2,9 @@ namespace WellRESTed\Message; +use InvalidArgumentException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; -use InvalidArgumentException; /** * Representation of an outgoing, server-side response. diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index ff38f79..df6fb0a 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -2,11 +2,11 @@ namespace WellRESTed\Message; +use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; use Psr\Http\Message\UriInterface; -use InvalidArgumentException; /** * Representation of an incoming, server-side HTTP request. @@ -509,7 +509,7 @@ class ServerRequest extends Request implements ServerRequestInterface private function isContentHeader(string $name): bool { - return ($name === 'CONTENT_LENGTH' || $name === 'CONTENT_TYPE'); + return $name === 'CONTENT_LENGTH' || $name === 'CONTENT_TYPE'; } /** diff --git a/src/Message/Stream.php b/src/Message/Stream.php index cf75406..c8deb1d 100644 --- a/src/Message/Stream.php +++ b/src/Message/Stream.php @@ -2,9 +2,9 @@ namespace WellRESTed\Message; -use Psr\Http\Message\StreamInterface; -use InvalidArgumentException; use Exception; +use InvalidArgumentException; +use Psr\Http\Message\StreamInterface; use RuntimeException; class Stream implements StreamInterface diff --git a/src/Message/UploadedFile.php b/src/Message/UploadedFile.php index 42dbb62..c18c4b8 100644 --- a/src/Message/UploadedFile.php +++ b/src/Message/UploadedFile.php @@ -2,9 +2,9 @@ namespace WellRESTed\Message; +use InvalidArgumentException; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; -use InvalidArgumentException; use RuntimeException; /** diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 0449276..8e0e273 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -2,8 +2,8 @@ namespace WellRESTed\Message; -use Psr\Http\Message\UriInterface; use InvalidArgumentException; +use Psr\Http\Message\UriInterface; /** * Value object representing a URI. diff --git a/src/Routing/Route/TemplateRoute.php b/src/Routing/Route/TemplateRoute.php index 730b3a9..df2f99c 100644 --- a/src/Routing/Route/TemplateRoute.php +++ b/src/Routing/Route/TemplateRoute.php @@ -57,7 +57,7 @@ class TemplateRoute extends Route if ($firstVarPos === false) { return $requestTarget === $this->target; } - return (substr($requestTarget, 0, $firstVarPos) === substr($this->target, 0, $firstVarPos)); + return substr($requestTarget, 0, $firstVarPos) === substr($this->target, 0, $firstVarPos); } private function processMatches(array $matches): array diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 860892c..73b3902 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -276,6 +276,6 @@ class Router private function startsWith(string $haystack, string $needle): bool { $length = strlen($needle); - return (substr($haystack, 0, $length) === $needle); + return substr($haystack, 0, $length) === $needle; } } diff --git a/test/tests/unit/Routing/Route/PrefixRouteTest.php b/test/tests/unit/Routing/Route/PrefixRouteTest.php index dd884e2..dad929e 100644 --- a/test/tests/unit/Routing/Route/PrefixRouteTest.php +++ b/test/tests/unit/Routing/Route/PrefixRouteTest.php @@ -11,7 +11,7 @@ use WellRESTed\Test\TestCase; class PrefixRouteTest extends TestCase { use ProphecyTrait; - + public function testTrimsAsteriskFromEndOfTarget() { $methodMap = $this->prophesize(MethodMap::class); diff --git a/test/tests/unit/Transmission/TransmitterTest.php b/test/tests/unit/Transmission/TransmitterTest.php index 9fe0c44..506c845 100644 --- a/test/tests/unit/Transmission/TransmitterTest.php +++ b/test/tests/unit/Transmission/TransmitterTest.php @@ -5,12 +5,12 @@ namespace WellRESTed\Test\Unit\Transmission; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\StreamInterface; +use RuntimeException; use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; use WellRESTed\Test\TestCase; use WellRESTed\Transmission\HeaderStack; use WellRESTed\Transmission\Transmitter; -use RuntimeException; require_once __DIR__ . '/../../../src/HeaderStack.php'; From 168867206e12e93b4503e6f7d6a3f1d1b48348c3 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Tue, 11 Aug 2020 09:11:30 -0400 Subject: [PATCH 24/53] Extract server request marshalling to own class. --- composer.json | 1 + src/Message/ServerRequest.php | 200 +------- src/Message/ServerRequestMarshaller.php | 201 ++++++++ src/Server.php | 5 +- .../Message/ServerRequestMarshallerTest.php | 381 +++++++++++++++ test/tests/unit/Message/ServerRequestTest.php | 432 ++---------------- test/tests/unit/ServerTest.php | 28 +- 7 files changed, 618 insertions(+), 630 deletions(-) create mode 100644 src/Message/ServerRequestMarshaller.php create mode 100644 test/tests/unit/Message/ServerRequestMarshallerTest.php diff --git a/composer.json b/composer.json index cf398b3..a8623c3 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ }, "autoload-dev": { "psr-4": { + "WellRESTed\\": "test/tests/unit/", "WellRESTed\\Test\\": "test/src/" } } diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index df6fb0a..fd81fcd 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -4,9 +4,7 @@ namespace WellRESTed\Message; use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; -use Psr\Http\Message\UriInterface; /** * Representation of an incoming, server-side HTTP request. @@ -53,22 +51,13 @@ class ServerRequest extends Request implements ServerRequestInterface // ------------------------------------------------------------------------ - /** - * Creates a new, empty representation of a server-side HTTP request. - * - * To obtain a ServerRequest representing the request sent to the server - * instantiating the request, use the factory method - * ServerRequest::getServerRequest - * - * @see ServerRequest::getServerRequest - */ - public function __construct() + public function __construct(array $serverParams = []) { parent::__construct(); - $this->attributes = []; + $this->serverParams = $serverParams; $this->cookieParams = []; $this->queryParams = []; - $this->serverParams = []; + $this->attributes = []; $this->uploadedFiles = []; } @@ -339,189 +328,6 @@ class ServerRequest extends Request implements ServerRequestInterface // ------------------------------------------------------------------------ - /** - * @param array $attributes - * @return void - */ - protected function readFromServerRequest(array $attributes = []) - { - $this->attributes = $attributes; - $this->serverParams = $_SERVER; - $this->cookieParams = $_COOKIE; - $this->readUploadedFiles($_FILES); - $this->queryParams = []; - $this->uri = $this->readUri(); - if (isset($_SERVER['QUERY_STRING'])) { - parse_str($_SERVER['QUERY_STRING'], $this->queryParams); - } - if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0') { - // The default is 1.1, so only update if 1.0 - $this->protocolVersion = '1.0'; - } - if (isset($_SERVER['REQUEST_METHOD'])) { - $this->method = $_SERVER['REQUEST_METHOD']; - } - $headers = $this->getServerRequestHeaders(); - foreach ($headers as $key => $value) { - $this->headers[$key] = $value; - } - $this->body = $this->getStreamForBody(); - - $contentType = $this->getHeaderLine('Content-type'); - if (strpos($contentType, 'application/x-www-form-urlencoded') !== false - || strpos($contentType, 'multipart/form-data') !== false) { - $this->parsedBody = $_POST; - } - } - - protected function readUploadedFiles(array $input): void - { - $uploadedFiles = []; - foreach ($input as $name => $value) { - $this->addUploadedFilesToBranch($uploadedFiles, $name, $value); - } - $this->uploadedFiles = $uploadedFiles; - } - - protected function addUploadedFilesToBranch( - array &$branch, - string $name, - array $value - ): void { - // Check for each of the expected keys. - if (isset($value['name'], $value['type'], $value['tmp_name'], $value['error'], $value['size'])) { - // This is a file. It may be a single file, or a list of files. - - // Check if these items are arrays. - if (is_array($value['name']) - && is_array($value['type']) - && is_array($value['tmp_name']) - && is_array($value['error']) - && is_array($value['size']) - ) { - // Each item is an array. This is a list of uploaded files. - $files = []; - $keys = array_keys($value['name']); - foreach ($keys as $key) { - $files[$key] = new UploadedFile( - $value['name'][$key], - $value['type'][$key], - $value['size'][$key], - $value['tmp_name'][$key], - $value['error'][$key] - ); - } - $branch[$name] = $files; - } else { - // All expected keys are present and are not arrays. This is an uploaded file. - $uploadedFile = new UploadedFile( - $value['name'], - $value['type'], - $value['size'], - $value['tmp_name'], - $value['error'] - ); - $branch[$name] = $uploadedFile; - } - } else { - // Add another branch - $nextBranch = []; - foreach ($value as $nextName => $nextValue) { - $this->addUploadedFilesToBranch($nextBranch, $nextName, $nextValue); - } - $branch[$name] = $nextBranch; - } - } - - protected function readUri(): UriInterface - { - $uri = ''; - - $scheme = 'http'; - if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && $_SERVER['HTTPS'] !== 'off') { - $scheme = 'https'; - } - - if (isset($_SERVER['HTTP_HOST'])) { - $authority = $_SERVER['HTTP_HOST']; - $uri .= "$scheme://$authority"; - } - - // Path and query string - if (isset($_SERVER['REQUEST_URI'])) { - $uri .= $_SERVER['REQUEST_URI']; - } - - return new Uri($uri); - } - - /** - * Return a reference to the singleton instance of the Request derived - * from the server's information about the request sent to the server. - * - * @param array $attributes Key-value pairs to add to the request. - * @return static - * @static - */ - public static function getServerRequest(array $attributes = []) - { - $request = new static(); - $request->readFromServerRequest($attributes); - return $request; - } - - /** - * Return a stream representing the request's body. - * - * Override this method to use a specific StreamInterface implementation. - * - * @return StreamInterface - */ - protected function getStreamForBody() - { - $input = fopen('php://input', 'rb'); - $temp = fopen('php://temp', 'wb+'); - stream_copy_to_stream($input, $temp); - rewind($temp); - return new Stream($temp); - } - - /** - * Read and return all request headers from the request issued to the server. - * - * @return array Associative array of headers - */ - protected function getServerRequestHeaders() - { - // http://www.php.net/manual/en/function.getallheaders.php#84262 - $headers = []; - foreach ($_SERVER as $name => $value) { - if (substr($name, 0, 5) === 'HTTP_') { - $name = $this->normalizeHeaderName(substr($name, 5)); - $headers[$name] = trim($value); - } elseif ($this->isContentHeader($name) && !empty(trim($value))) { - $name = $this->normalizeHeaderName($name); - $headers[$name] = trim($value); - } - } - return $headers; - } - - private function isContentHeader(string $name): bool - { - return $name === 'CONTENT_LENGTH' || $name === 'CONTENT_TYPE'; - } - - /** - * @param string $name - * @return string - */ - private function normalizeHeaderName($name) - { - $name = ucwords(strtolower(str_replace('_', ' ', $name))); - return str_replace(' ', '-', $name); - } - /** * @param array $root * @return bool diff --git a/src/Message/ServerRequestMarshaller.php b/src/Message/ServerRequestMarshaller.php new file mode 100644 index 0000000..9b67065 --- /dev/null +++ b/src/Message/ServerRequestMarshaller.php @@ -0,0 +1,201 @@ +withProtocolVersion(self::parseProtocolVersion($serverParams)) + ->withMethod(self::parseMethod($serverParams)) + ->withBody(self::readBody($inputStream)) + ->withUri(self::readUri($serverParams)) + ->withUploadedFiles(self::readUploadedFiles($fileParams)) + ->withCookieParams($cookieParams) + ->withQueryParams($queryParams); + + $headers = self::parseHeaders($serverParams); + foreach ($headers as $name => $value) { + $request = $request->withAddedHeader($name, $value); + } + + if (self::isForm($request)) { + $request = $request->withParsedBody($postParams); + } + + return $request; + } + + private static function parseQuery(array $serverParams): array + { + $queryParams = []; + if (isset($serverParams['QUERY_STRING'])) { + parse_str($serverParams['QUERY_STRING'], $queryParams); + } + return $queryParams; + } + + private static function parseProtocolVersion(array $serverParams): string + { + if (isset($serverParams['SERVER_PROTOCOL']) + && $serverParams['SERVER_PROTOCOL'] === 'HTTP/1.0') { + return '1.0'; + } + return '1.1'; + } + + private static function parseHeaders(array $serverParams): array + { + // http://www.php.net/manual/en/function.getallheaders.php#84262 + $headers = []; + foreach ($serverParams as $name => $value) { + if (substr($name, 0, 5) === 'HTTP_') { + $name = self::normalizeHeaderName(substr($name, 5)); + $headers[$name] = trim($value); + } elseif (self::isContentHeader($name) && !empty(trim($value))) { + $name = self::normalizeHeaderName($name); + $headers[$name] = trim($value); + } + } + return $headers; + } + + private static function normalizeHeaderName(string $name): string + { + $name = ucwords(strtolower(str_replace('_', ' ', $name))); + return str_replace(' ', '-', $name); + } + + private static function isContentHeader(string $name): bool + { + return $name === 'CONTENT_LENGTH' || $name === 'CONTENT_TYPE'; + } + + private static function parseMethod(array $serverParams): string + { + return $serverParams['REQUEST_METHOD'] ?? 'GET'; + } + + private static function readBody(string $inputStream): StreamInterface + { + $input = fopen($inputStream, 'rb'); + $temp = fopen('php://temp', 'wb+'); + stream_copy_to_stream($input, $temp); + rewind($temp); + return new Stream($temp); + } + + private static function readUri(array $serverParams): UriInterface + { + $uri = ''; + + $scheme = 'http'; + if (isset($serverParams['HTTPS']) && $serverParams['HTTPS'] && $serverParams['HTTPS'] !== 'off') { + $scheme = 'https'; + } + + if (isset($serverParams['HTTP_HOST'])) { + $authority = $serverParams['HTTP_HOST']; + $uri .= "$scheme://$authority"; + } + + // Path and query string + if (isset($serverParams['REQUEST_URI'])) { + $uri .= $serverParams['REQUEST_URI']; + } + + return new Uri($uri); + } + + private static function isForm(ServerRequestInterface $request): bool + { + $contentType = $request->getHeaderLine('Content-type'); + return (strpos($contentType, 'application/x-www-form-urlencoded') !== false) + || (strpos($contentType, 'multipart/form-data') !== false); + } + + private static function readUploadedFiles(array $input): array + { + $uploadedFiles = []; + foreach ($input as $name => $value) { + self::addUploadedFilesToBranch($uploadedFiles, $name, $value); + } + return $uploadedFiles; + } + + private static function addUploadedFilesToBranch( + array &$branch, + string $name, + array $value + ): void { + if (self::isUploadedFile($value)) { + if (self::isUploadedFileList($value)) { + $files = []; + $keys = array_keys($value['name']); + foreach ($keys as $key) { + $files[$key] = new UploadedFile( + $value['name'][$key], + $value['type'][$key], + $value['size'][$key], + $value['tmp_name'][$key], + $value['error'][$key] + ); + } + $branch[$name] = $files; + } else { + // Single uploaded file + $uploadedFile = new UploadedFile( + $value['name'], + $value['type'], + $value['size'], + $value['tmp_name'], + $value['error'] + ); + $branch[$name] = $uploadedFile; + } + } else { + // Add another branch + $nextBranch = []; + foreach ($value as $nextName => $nextValue) { + self::addUploadedFilesToBranch($nextBranch, $nextName, $nextValue); + } + $branch[$name] = $nextBranch; + } + } + + private static function isUploadedFile(array $value): bool + { + // Check for each of the expected keys. If all are present, this is a + // a file. It may be a single file, or a list of files. + return isset($value['name'], $value['type'], $value['tmp_name'], $value['error'], $value['size']); + } + + private static function isUploadedFileList(array $value): bool + { + // When each item is an array, this is a list of uploaded files. + return is_array($value['name']) + && is_array($value['type']) + && is_array($value['tmp_name']) + && is_array($value['error']) + && is_array($value['size']); + } +} diff --git a/src/Server.php b/src/Server.php index 613dc98..c513e9d 100644 --- a/src/Server.php +++ b/src/Server.php @@ -7,7 +7,7 @@ use Psr\Http\Message\ServerRequestInterface; use WellRESTed\Dispatching\Dispatcher; use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Message\Response; -use WellRESTed\Message\ServerRequest; +use WellRESTed\Message\ServerRequestMarshaller; use WellRESTed\Routing\Router; use WellRESTed\Transmission\Transmitter; use WellRESTed\Transmission\TransmitterInterface; @@ -163,7 +163,8 @@ class Server private function getRequest(): ServerRequestInterface { if (!$this->request) { - $this->request = ServerRequest::getServerRequest(); + $marshaller = new ServerRequestMarshaller(); + return $marshaller->getServerRequest(); } return $this->request; } diff --git a/test/tests/unit/Message/ServerRequestMarshallerTest.php b/test/tests/unit/Message/ServerRequestMarshallerTest.php new file mode 100644 index 0000000..dddedb7 --- /dev/null +++ b/test/tests/unit/Message/ServerRequestMarshallerTest.php @@ -0,0 +1,381 @@ + 'localhost', + 'HTTP_ACCEPT' => 'application/json', + 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded', + 'QUERY_STRING' => 'cat=molly&kitten=aggie' + ]; + + $_COOKIE = [ + 'dog' => 'Bear', + 'hamster' => 'Dusty' + ]; + + $this->marshaller = new ServerRequestMarshaller(); + } + + // ------------------------------------------------------------------------- + // Psr\Http\Message\MessageInterface + + // ------------------------------------------------------------------------- + // Protocol Version + + /** + * @dataProvider protocolVersionProvider + * @param $expectedProtocol + * @param $actualProtocol + */ + public function testProvidesProtocolVersion(string $expectedProtocol, ?string $actualProtocol): void + { + $_SERVER['SERVER_PROTOCOL'] = $actualProtocol; + $request = $this->marshaller->getServerRequest(); + $this->assertEquals($expectedProtocol, $request->getProtocolVersion()); + } + + public function protocolVersionProvider(): array + { + return [ + ['1.1', 'HTTP/1.1'], + ['1.0', 'HTTP/1.0'], + ['1.1', null], + ['1.1', 'INVALID'] + ]; + } + + // ------------------------------------------------------------------------- + // Headers + + public function testProvidesHeadersFromHttpFields(): void + { + $_SERVER = [ + 'HTTP_ACCEPT' => 'application/json', + 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded' + ]; + $request = $this->marshaller->getServerRequest(); + $this->assertEquals(['application/json'], $request->getHeader('Accept')); + $this->assertEquals(['application/x-www-form-urlencoded'], $request->getHeader('Content-type')); + } + + public function testProvidesApacheContentHeaders(): void + { + $_SERVER = [ + 'CONTENT_LENGTH' => '1024', + 'CONTENT_TYPE' => 'application/json' + ]; + $request = $this->marshaller->getServerRequest(); + $this->assertEquals('1024', $request->getHeaderLine('Content-length')); + $this->assertEquals('application/json', $request->getHeaderLine('Content-type')); + } + + public function testDoesNotProvideEmptyApacheContentHeaders(): void + { + $_SERVER = [ + 'CONTENT_LENGTH' => '', + 'CONTENT_TYPE' => ' ' + ]; + $request = $this->marshaller->getServerRequest(); + $this->assertFalse($request->hasHeader('Content-length')); + $this->assertFalse($request->hasHeader('Content-type')); + } + + // ------------------------------------------------------------------------- + // Body + + public function testProvidesBodyFromInputStream(): void + { + $tempFilePath = tempnam(sys_get_temp_dir(), 'test'); + $content = 'Body content'; + file_put_contents($tempFilePath, $content); + + $request = $this->marshaller->getServerRequest( + null, + null, + null, + null, + null, + $tempFilePath + ); + unlink($tempFilePath); + + $this->assertEquals($content, (string) $request->getBody()); + } + + // ------------------------------------------------------------------------- + // Psr\Http\Message\RequestInterface + + // ------------------------------------------------------------------------ + // Request Target + + /** + * @dataProvider requestTargetProvider + * @param $expectedRequestTarget + * @param $actualRequestUri + */ + public function testProvidesRequestTarget(string $expectedRequestTarget, ?string $actualRequestUri): void + { + $_SERVER['REQUEST_URI'] = $actualRequestUri; + $request = $this->marshaller->getServerRequest(); + $this->assertEquals($expectedRequestTarget, $request->getRequestTarget()); + } + + public function requestTargetProvider(): array + { + return [ + ['/', '/'], + ['/hello', '/hello'], + ['/my/path.txt', '/my/path.txt'], + ['/', null] + ]; + } + + // ------------------------------------------------------------------------ + // Method + + /** + * @dataProvider methodProvider + * @param $expectedMethod + * @param $serverMethod + */ + public function testProvidesMethod($expectedMethod, $serverMethod) + { + $_SERVER['REQUEST_METHOD'] = $serverMethod; + $request = $this->marshaller->getServerRequest(); + $this->assertEquals($expectedMethod, $request->getMethod()); + } + + public function methodProvider() + { + return [ + ['GET', 'GET'], + ['POST', 'POST'], + ['DELETE', 'DELETE'], + ['PUT', 'PUT'], + ['OPTIONS', 'OPTIONS'], + ['GET', null] + ]; + } + + // ------------------------------------------------------------------------ + // URI + + /** + * @dataProvider uriProvider + * @param UriInterface $expected + * @param array $serverParams + */ + public function testProvidesUri(UriInterface $expected, array $serverParams): void + { + $request = $this->marshaller->getServerRequest($serverParams); + $this->assertEquals($expected, $request->getUri()); + } + + public function uriProvider() + { + return [ + [ + new Uri('http://localhost/path'), + [ + 'HTTPS' => 'off', + 'HTTP_HOST' => 'localhost', + 'REQUEST_URI' => '/path', + 'QUERY_STRING' => '' + ] + ], + [ + new Uri('https://foo.com/path/to/stuff?cat=molly'), + [ + 'HTTPS' => '1', + 'HTTP_HOST' => 'foo.com', + 'REQUEST_URI' => '/path/to/stuff?cat=molly', + 'QUERY_STRING' => 'cat=molly' + ] + ], + [ + new Uri('http://foo.com:8080/path/to/stuff?cat=molly'), + [ + 'HTTP' => '1', + 'HTTP_HOST' => 'foo.com:8080', + 'REQUEST_URI' => '/path/to/stuff?cat=molly', + 'QUERY_STRING' => 'cat=molly' + ] + ] + ]; + } + + // ------------------------------------------------------------------------- + // Psr\Http\Message\ServerRequestInterface + + // ------------------------------------------------------------------------- + // Server Params + + public function testProvidesServerParams(): void + { + $request = $this->marshaller->getServerRequest(); + $this->assertEquals($_SERVER, $request->getServerParams()); + } + + // ------------------------------------------------------------------------ + // Cookies + + public function testProvidesCookieParams(): void + { + $request = $this->marshaller->getServerRequest(); + $this->assertEquals($_COOKIE, $request->getCookieParams()); + } + + // ------------------------------------------------------------------------ + // Query + + public function testProvidesQueryParams(): void + { + $request = $this->marshaller->getServerRequest(); + $query = $request->getQueryParams(); + $this->assertCount(2, $query); + $this->assertEquals('molly', $query['cat']); + $this->assertEquals('aggie', $query['kitten']); + } + + // ------------------------------------------------------------------------ + // Uploaded Files + + /** + * @dataProvider uploadedFileProvider + * @param UploadedFileInterface $file + * @param array $path + */ + public function testGetServerRequestReadsUploadedFiles(UploadedFileInterface $file, array $path): void + { + $_FILES = [ + 'single' => [ + 'name' => 'single.txt', + 'type' => 'text/plain', + 'tmp_name' => '/tmp/php9hNlHe', + 'error' => UPLOAD_ERR_OK, + 'size' => 524 + ], + 'nested' => [ + 'level2' => [ + 'name' => 'nested.json', + 'type' => 'application/json', + 'tmp_name' => '/tmp/phpadhjk', + 'error' => UPLOAD_ERR_OK, + 'size' => 1024 + ] + ], + 'nestedList' => [ + 'level2' => [ + 'name' => [ + 0 => 'nestedList0.jpg', + 1 => 'nestedList1.jpg', + 2 => '' + ], + 'type' => [ + 0 => 'image/jpeg', + 1 => 'image/jpeg', + 2 => '' + ], + 'tmp_name' => [ + 0 => '/tmp/phpjpg0', + 1 => '/tmp/phpjpg1', + 2 => '' + ], + 'error' => [ + 0 => UPLOAD_ERR_OK, + 1 => UPLOAD_ERR_OK, + 2 => UPLOAD_ERR_NO_FILE + ], + 'size' => [ + 0 => 256, + 1 => 4096, + 2 => 0 + ] + ] + ], + 'nestedDictionary' => [ + 'level2' => [ + 'name' => [ + 'file0' => 'nestedDictionary0.jpg', + 'file1' => 'nestedDictionary1.jpg' + ], + 'type' => [ + 'file0' => 'image/png', + 'file1' => 'image/png' + ], + 'tmp_name' => [ + 'file0' => '/tmp/phppng0', + 'file1' => '/tmp/phppng1' + ], + 'error' => [ + 'file0' => UPLOAD_ERR_OK, + 'file1' => UPLOAD_ERR_OK + ], + 'size' => [ + 'file0' => 256, + 'file1' => 4096 + ] + ] + ] + ]; + $request = $this->marshaller->getServerRequest(); + $current = $request->getUploadedFiles(); + foreach ($path as $item) { + $current = $current[$item]; + } + $this->assertEquals($file, $current); + } + + public function uploadedFileProvider(): array + { + return [ + [new UploadedFile('single.txt', 'text/plain', 524, '/tmp/php9hNlHe', UPLOAD_ERR_OK), ['single']], + [new UploadedFile('nested.json', 'application/json', 1024, '/tmp/phpadhjk', UPLOAD_ERR_OK), ['nested', 'level2']], + [new UploadedFile('nestedList0.jpg', 'image/jpeg', 256, '/tmp/phpjpg0', UPLOAD_ERR_OK), ['nestedList', 'level2', 0]], + [new UploadedFile('nestedList1.jpg', 'image/jpeg', 4096, '/tmp/phpjpg1', UPLOAD_ERR_OK), ['nestedList', 'level2', 1]], + [new UploadedFile('', '', 0, '', UPLOAD_ERR_NO_FILE), ['nestedList', 'level2', 2]], + [new UploadedFile('nestedDictionary0.jpg', 'image/png', 256, '/tmp/phppng0', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file0']], + [new UploadedFile('nestedDictionary1.jpg', 'image/png', 4096, '/tmp/phppngg1', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file1']] + ]; + } + + // ------------------------------------------------------------------------ + // Parsed Body + + /** + * @dataProvider formContentTypeProvider + * @param string $contentType + */ + public function testProvidesParsedBodyForForms(string $contentType): void + { + $_SERVER['HTTP_CONTENT_TYPE'] = $contentType; + $_POST = [ + 'dog' => 'Bear' + ]; + $request = $this->marshaller->getServerRequest(); + $this->assertEquals('Bear', $request->getParsedBody()['dog']); + } + + public function formContentTypeProvider(): array + { + return [ + ['application/x-www-form-urlencoded'], + ['multipart/form-data'] + ]; + } +} diff --git a/test/tests/unit/Message/ServerRequestTest.php b/test/tests/unit/Message/ServerRequestTest.php index 8b5a08c..22916f2 100644 --- a/test/tests/unit/Message/ServerRequestTest.php +++ b/test/tests/unit/Message/ServerRequestTest.php @@ -1,380 +1,12 @@ 'localhost', - 'HTTP_ACCEPT' => 'application/json', - 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded', - 'QUERY_STRING' => 'guinea_pig=Claude&hamster=Fizzgig' - ]; - $_COOKIE = [ - 'cat' => 'Molly' - ]; - $_FILES = []; - $_POST = [ - 'dog' => 'Bear' - ]; - $attributes = ['guinea_pig' => 'Claude']; - $request = ServerRequest::getServerRequest($attributes); - $this->assertNotNull($request); - return $request; - } - - // ------------------------------------------------------------------------ - // Marshalling Request Information - - /** - * @backupGlobals enabled - * @dataProvider protocolVersionProvider - */ - public function testGetServerRequestReadsProtocolVersion($expectedProtocol, $serverProtocol) - { - $_SERVER = [ - 'HTTP_HOST' => 'localhost', - 'SERVER_PROTOCOL' => $serverProtocol, - 'REQUEST_METHOD' => 'GET' - ]; - $request = ServerRequest::getServerRequest(); - $this->assertEquals($expectedProtocol, $request->getProtocolVersion()); - } - - public function protocolVersionProvider() - { - return [ - ['1.1', 'HTTP/1.1'], - ['1.0', 'HTTP/1.0'], - ['1.1', null], - ['1.1', 'INVALID'] - ]; - } - - /** - * @backupGlobals enabled - * @dataProvider methodProvider - */ - public function testGetServerRequestReadsMethod($expectedMethod, $serverMethod) - { - $_SERVER = [ - 'HTTP_HOST' => 'localhost', - 'REQUEST_METHOD' => $serverMethod - ]; - $request = ServerRequest::getServerRequest(); - $this->assertEquals($expectedMethod, $request->getMethod()); - } - - public function methodProvider() - { - return [ - ['GET', 'GET'], - ['POST', 'POST'], - ['DELETE', 'DELETE'], - ['PUT', 'PUT'], - ['OPTIONS', 'OPTIONS'], - ['GET', null] - ]; - } - - /** - * @backupGlobals enabled - * @dataProvider requestTargetProvider - */ - public function testGetServerRequestReadsRequestTargetFromRequest($expectedRequestTarget, $serverRequestUri) - { - $_SERVER = [ - 'HTTP_HOST' => 'localhost', - 'REQUEST_URI' => $serverRequestUri - ]; - $request = ServerRequest::getServerRequest(); - $this->assertEquals($expectedRequestTarget, $request->getRequestTarget()); - } - - public function requestTargetProvider() - { - return [ - ['/', '/'], - ['/hello', '/hello'], - ['/my/path.txt', '/my/path.txt'], - ['/', null] - ]; - } - - /** @depends testGetServerRequestReadsFromRequest */ - public function testGetServerRequestReadsHeaders($request) - { - /** @var ServerRequest $request */ - $this->assertEquals(['application/json'], $request->getHeader('Accept')); - } - - /** - * @backupGlobals enabled - */ - public function testGetServerRequestReadsContentHeaders() - { - $_SERVER = [ - 'CONTENT_LENGTH' => '1024', - 'CONTENT_TYPE' => 'application/json' - ]; - $request = ServerRequest::getServerRequest(); - $this->assertEquals('1024', $request->getHeaderLine('Content-length')); - $this->assertEquals('application/json', $request->getHeaderLine('Content-type')); - } - - /** - * @backupGlobals enabled - */ - public function testGetServerRequestDoesNotReadEmptyContentHeaders() - { - $_SERVER = [ - 'CONTENT_LENGTH' => '', - 'CONTENT_TYPE' => ' ' - ]; - $request = ServerRequest::getServerRequest(); - $this->assertFalse($request->hasHeader('Content-length')); - $this->assertFalse($request->hasHeader('Content-type')); - } - - public function testGetServerRequestReadsBody() - { - $body = new NullStream(); - $request = $this->getMockBuilder('WellRESTed\Message\ServerRequest') - ->setMethods(['getStreamForBody']) - ->getMock(); - $request->expects($this->any()) - ->method('getStreamForBody') - ->will($this->returnValue($body)); - - $called = false; - $callReadFromServerRequest = function () use (&$called) { - $called = true; - $this->readFromServerRequest(); - }; - $callReadFromServerRequest = $callReadFromServerRequest->bindTo($request, $request); - $callReadFromServerRequest(); - - $this->assertSame($body, $request->getBody()); - } - - /** - * @backupGlobals enabled - * @dataProvider uriProvider - */ - public function testGetServerRequestReadsUri($expected, $server) - { - $_SERVER = $server; - $request = ServerRequest::getServerRequest(); - $this->assertEquals($expected, $request->getUri()); - } - - public function uriProvider() - { - return [ - [ - new Uri('http://localhost/path'), - [ - 'HTTPS' => 'off', - 'HTTP_HOST' => 'localhost', - 'REQUEST_URI' => '/path', - 'QUERY_STRING' => '' - ] - ], - [ - new Uri('https://foo.com/path/to/stuff?cat=molly'), - [ - 'HTTPS' => '1', - 'HTTP_HOST' => 'foo.com', - 'REQUEST_URI' => '/path/to/stuff?cat=molly', - 'QUERY_STRING' => 'cat=molly' - ] - ], - [ - new Uri('http://foo.com:8080/path/to/stuff?cat=molly'), - [ - 'HTTP' => '1', - 'HTTP_HOST' => 'foo.com:8080', - 'REQUEST_URI' => '/path/to/stuff?cat=molly', - 'QUERY_STRING' => 'cat=molly' - ] - ] - ]; - } - - // ------------------------------------------------------------------------ - // Marshalling ServerRequest Information - - /** @depends testGetServerRequestReadsFromRequest */ - public function testGetServerRequestReadsServerParams($request) - { - /** @var ServerRequest $request */ - $this->assertEquals('localhost', $request->getServerParams()['HTTP_HOST']); - } - - /** @depends testGetServerRequestReadsFromRequest */ - public function testGetServerRequestReadsCookieParams($request) - { - /** @var ServerRequest $request */ - $this->assertEquals('Molly', $request->getCookieParams()['cat']); - } - - /** @depends testGetServerRequestReadsFromRequest */ - public function testGetServerRequestReadsQueryParams($request) - { - /** @var ServerRequest $request */ - $this->assertEquals('Claude', $request->getQueryParams()['guinea_pig']); - } - - /** - * @backupGlobals enabled - * @dataProvider uploadedFileProvider - */ - public function testGetServerRequestReadsUploadedFiles($file, $path) - { - $_SERVER = [ - 'HTTP_HOST' => 'localhost', - 'HTTP_ACCEPT' => 'application/json', - 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded' - ]; - $_FILES = [ - 'single' => [ - 'name' => 'single.txt', - 'type' => 'text/plain', - 'tmp_name' => '/tmp/php9hNlHe', - 'error' => UPLOAD_ERR_OK, - 'size' => 524 - ], - 'nested' => [ - 'level2' => [ - 'name' => 'nested.json', - 'type' => 'application/json', - 'tmp_name' => '/tmp/phpadhjk', - 'error' => UPLOAD_ERR_OK, - 'size' => 1024 - ] - ], - 'nestedList' => [ - 'level2' => [ - 'name' => [ - 0 => 'nestedList0.jpg', - 1 => 'nestedList1.jpg', - 2 => '' - ], - 'type' => [ - 0 => 'image/jpeg', - 1 => 'image/jpeg', - 2 => '' - ], - 'tmp_name' => [ - 0 => '/tmp/phpjpg0', - 1 => '/tmp/phpjpg1', - 2 => '' - ], - 'error' => [ - 0 => UPLOAD_ERR_OK, - 1 => UPLOAD_ERR_OK, - 2 => UPLOAD_ERR_NO_FILE - ], - 'size' => [ - 0 => 256, - 1 => 4096, - 2 => 0 - ] - ] - ], - 'nestedDictionary' => [ - 'level2' => [ - 'name' => [ - 'file0' => 'nestedDictionary0.jpg', - 'file1' => 'nestedDictionary1.jpg' - ], - 'type' => [ - 'file0' => 'image/png', - 'file1' => 'image/png' - ], - 'tmp_name' => [ - 'file0' => '/tmp/phppng0', - 'file1' => '/tmp/phppng1' - ], - 'error' => [ - 'file0' => UPLOAD_ERR_OK, - 'file1' => UPLOAD_ERR_OK - ], - 'size' => [ - 'file0' => 256, - 'file1' => 4096 - ] - ] - ] - ]; - $request = ServerRequest::getServerRequest(); - $current = $request->getUploadedFiles(); - foreach ($path as $item) { - $current = $current[$item]; - } - $this->assertEquals($file, $current); - } - - public function uploadedFileProvider() - { - return [ - [new UploadedFile('single.txt', 'text/plain', 524, '/tmp/php9hNlHe', UPLOAD_ERR_OK), ['single']], - [new UploadedFile('nested.json', 'application/json', 1024, '/tmp/phpadhjk', UPLOAD_ERR_OK), ['nested', 'level2']], - [new UploadedFile('nestedList0.jpg', 'image/jpeg', 256, '/tmp/phpjpg0', UPLOAD_ERR_OK), ['nestedList', 'level2', 0]], - [new UploadedFile('nestedList1.jpg', 'image/jpeg', 4096, '/tmp/phpjpg1', UPLOAD_ERR_OK), ['nestedList', 'level2', 1]], - [new UploadedFile('', '', 0, '', UPLOAD_ERR_NO_FILE), ['nestedList', 'level2', 2]], - [new UploadedFile('nestedDictionary0.jpg', 'image/png', 256, '/tmp/phppng0', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file0']], - [new UploadedFile('nestedDictionary1.jpg', 'image/png', 4096, '/tmp/phppngg1', UPLOAD_ERR_OK), ['nestedDictionary', 'level2', 'file1']] - ]; - } - - /** - * @backupGlobals enabled - * @dataProvider formContentTypeProvider - */ - public function testGetServerRequestParsesFormBody($contentType) - { - $_SERVER = [ - 'HTTP_HOST' => 'localhost', - 'HTTP_CONTENT_TYPE' => $contentType, - ]; - $_COOKIE = []; - $_FILES = []; - $_POST = [ - 'dog' => 'Bear' - ]; - $request = ServerRequest::getServerRequest(); - $this->assertEquals('Bear', $request->getParsedBody()['dog']); - } - - public function formContentTypeProvider() - { - return [ - ['application/x-www-form-urlencoded'], - ['multipart/form-data'] - ]; - } - - /** @depends testGetServerRequestReadsFromRequest */ - public function testGetServerRequestProvidesAttributesIfPassed($request) - { - /** @var ServerRequest $request */ - $this->assertEquals('Claude', $request->getAttribute('guinea_pig')); - } - // ------------------------------------------------------------------------ // Server Params @@ -393,14 +25,17 @@ class ServerRequestTest extends TestCase $this->assertEquals([], $request->getCookieParams()); } - /** @depends testGetServerRequestReadsFromRequest */ - public function testWithCookieParamsCreatesNewInstance($request1) + public function testWithCookieParamsCreatesNewInstanceWithCookies() { - /** @var ServerRequest $request1 */ - $request2 = $request1->withCookieParams([ + $cookies = [ 'cat' => 'Oscar' - ]); - $this->assertNotEquals($request1->getCookieParams()['cat'], $request2->getCookieParams()['cat']); + ]; + + $request1 = new ServerRequest(); + $request2 = $request1->withCookieParams($cookies); + + $this->assertEquals($cookies, $request2->getCookieParams()); + $this->assertNotSame($request2, $request1); } // ------------------------------------------------------------------------ @@ -412,14 +47,17 @@ class ServerRequestTest extends TestCase $this->assertEquals([], $request->getQueryParams()); } - /** @depends testGetServerRequestReadsFromRequest */ - public function testWithQueryParamsCreatesNewInstance($request1) + public function testWithQueryParamsCreatesNewInstance() { - /** @var ServerRequest $request1 */ - $request2 = $request1->withQueryParams([ - 'guinea_pig' => 'Clyde' - ]); - $this->assertNotEquals($request1->getQueryParams()['guinea_pig'], $request2->getQueryParams()['guinea_pig']); + $query = [ + 'cat' => 'Aggie' + ]; + + $request1 = new ServerRequest(); + $request2 = $request1->withQueryParams($query); + + $this->assertEquals($query, $request2->getQueryParams()); + $this->assertNotSame($request2, $request1); } // ------------------------------------------------------------------------ @@ -431,19 +69,6 @@ class ServerRequestTest extends TestCase $this->assertEquals([], $request->getUploadedFiles()); } - /** @backupGlobals enabled */ - public function testGetUploadedFilesReturnsEmptyArrayWhenNoFilesAreUploaded() - { - $_SERVER = [ - 'HTTP_HOST' => 'localhost', - 'HTTP_ACCEPT' => 'application/json', - 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded' - ]; - $_FILES = []; - $request = ServerRequest::getServerRequest(); - $this->assertSame([], $request->getUploadedFiles()); - } - public function testWithUploadedFilesCreatesNewInstance() { $uploadedFiles = [ @@ -566,18 +191,17 @@ class ServerRequestTest extends TestCase $this->assertNull($request->getParsedBody()); } - /** @depends testGetServerRequestReadsFromRequest */ - public function testWithParsedBodyCreatesNewInstance($request1) + public function testWithParsedBodyCreatesNewInstance() { - /** @var ServerRequest $request1 */ - $body1 = $request1->getParsedBody(); - - $request2 = $request1->withParsedBody([ + $body = [ 'guinea_pig' => 'Clyde' - ]); - $body2 = $request2->getParsedBody(); + ]; - $this->assertNotSame($body1, $body2); + $request1 = new ServerRequest(); + $request2 = $request1->withParsedBody($body); + + $this->assertEquals($body, $request2->getParsedBody()); + $this->assertNotSame($request2, $request1); } /** diff --git a/test/tests/unit/ServerTest.php b/test/tests/unit/ServerTest.php index a2a854d..6f42d49 100644 --- a/test/tests/unit/ServerTest.php +++ b/test/tests/unit/ServerTest.php @@ -1,19 +1,15 @@ shouldHaveBeenCalled(); } - - // ------------------------------------------------------------------------- - - public function testCreatesStockTransmitterByDefault() - { - $content = 'Hello, world!'; - - $response = (new Response()) - ->withBody(new Stream($content)); - - $server = new Server(); - $server->add(function () use ($response) { - return $response; - }); - - ob_start(); - $server->respond(); - $captured = ob_get_contents(); - ob_end_clean(); - - $this->assertEquals($content, $captured); - } } From 2e3475b8822499c917877d902f635c923c69f819 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Wed, 12 Aug 2020 07:12:42 -0400 Subject: [PATCH 25/53] Refactor HeaderCollection --- src/Message/HeaderCollection.php | 37 ++++++++----------- .../unit/Message/HeaderCollectionTest.php | 21 +++++------ 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/Message/HeaderCollection.php b/src/Message/HeaderCollection.php index 97c3c99..6367e66 100644 --- a/src/Message/HeaderCollection.php +++ b/src/Message/HeaderCollection.php @@ -7,51 +7,44 @@ use Iterator; /** * HeaderCollection provides case-insensitive access to lists of header values. - * - * This class is an internal class used by Message and is not intended for - * direct use by consumers. - * + ** * HeaderCollection preserves the cases of keys as they are set, but treats key * access case insensitively. * * Any values added to HeaderCollection are added to list arrays. Subsequent * calls to add a value for a given key will append the new value to the list * array of values for that key. + * + * @internal This class is an internal class used by Message and is not intended + * for direct use by consumers. */ class HeaderCollection implements ArrayAccess, Iterator { /** - * @var array - * * Hash array mapping lowercase header names to original case header names. + * + * @var array */ - private $fields; + private $fields = []; /** - * @var array - * * Hash array mapping lowercase header names to values as string[] + * + * @var array */ - private $values; + private $values = []; /** - * @var string[] - * * List array of lowercase header names. + * + * @var string[] */ - private $keys; + private $keys = []; /** @var int */ private $position = 0; - public function __construct() - { - $this->keys = []; - $this->fields = []; - $this->values = []; - } - - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // ArrayAccess /** @@ -111,7 +104,7 @@ class HeaderCollection implements ArrayAccess, Iterator } } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Iterator public function current() diff --git a/test/tests/unit/Message/HeaderCollectionTest.php b/test/tests/unit/Message/HeaderCollectionTest.php index 730b575..568dcbc 100644 --- a/test/tests/unit/Message/HeaderCollectionTest.php +++ b/test/tests/unit/Message/HeaderCollectionTest.php @@ -1,20 +1,19 @@ assertTrue(isset($collection['content-type'])); } - public function testAddsMultipleHeadersAndIndicatesCaseInsensitiveIsset() + public function testAddsMultipleHeadersAndIndicatesCaseInsensitiveIsset(): void { $collection = new HeaderCollection(); $collection['Set-Cookie'] = 'cat=Molly'; @@ -22,17 +21,18 @@ class HeaderCollectionTest extends TestCase $this->assertTrue(isset($collection['set-cookie'])); } - public function testReturnsHeadersWithCaseInsensitiveHeaderName() + public function testReturnsHeadersWithCaseInsensitiveHeaderName(): void { $collection = new HeaderCollection(); $collection['Set-Cookie'] = 'cat=Molly'; $collection['SET-COOKIE'] = 'dog=Bear'; $headers = $collection['set-cookie']; - $this->assertEquals(2, count(array_intersect($headers, ['cat=Molly', 'dog=Bear']))); + $matched = array_intersect($headers, ['cat=Molly', 'dog=Bear']); + $this->assertCount(2, $matched); } - public function testRemovesHeadersWithCaseInsensitiveHeaderName() + public function testRemovesHeadersWithCaseInsensitiveHeaderName(): void { $collection = new HeaderCollection(); $collection['Set-Cookie'] = 'cat=Molly'; @@ -41,8 +41,7 @@ class HeaderCollectionTest extends TestCase $this->assertFalse(isset($collection['set-cookie'])); } - /** @coversNothing */ - public function testCloneMakesDeepCopyOfHeaders() + public function testCloneMakesDeepCopyOfHeaders(): void { $collection = new HeaderCollection(); $collection['Set-Cookie'] = 'cat=Molly'; @@ -53,7 +52,7 @@ class HeaderCollectionTest extends TestCase $this->assertTrue(isset($collection['set-cookie']) && !isset($clone['set-cookie'])); } - public function testIteratesWithOriginalKeys() + public function testIteratesWithOriginalKeys(): void { $collection = new HeaderCollection(); $collection['Content-length'] = '100'; @@ -74,7 +73,7 @@ class HeaderCollectionTest extends TestCase $this->assertEquals(0, $countUnmatched); } - public function testIteratesWithOriginalKeysAndValues() + public function testIteratesWithOriginalKeysAndValues(): void { $collection = new HeaderCollection(); $collection['Content-length'] = '100'; From 4a3545cd3cc1884d3cf8eed19cd139377f1036a2 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Wed, 12 Aug 2020 07:42:33 -0400 Subject: [PATCH 26/53] Refactor Message classes --- src/Message/Request.php | 15 ++-- src/Message/Response.php | 3 +- test/tests/unit/Message/MessageTest.php | 71 +++++++++---------- test/tests/unit/Message/RequestTest.php | 50 +++++++------ test/tests/unit/Message/ResponseTest.php | 30 ++++---- test/tests/unit/Message/ServerRequestTest.php | 51 +++++++------ 6 files changed, 116 insertions(+), 104 deletions(-) diff --git a/src/Message/Request.php b/src/Message/Request.php index 33cddc0..9e7feac 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -33,11 +33,18 @@ class Request extends Message implements RequestInterface /** * Create a new Request. * - * @see \WellRESTed\Message\Message - * @param string|UriInterface $uri + * $headers is an optional associative array with header field names as + * (string) keys and lists of header field values (string[]) as values. + * + * If no StreamInterface is provided for $body, the instance will create + * a NullStream instance for the message body. + * * @param string $method - * @param array $headers - * @param StreamInterface|null $body + * @param string|UriInterface $uri + * @param array $headers Associative array with header field names as + * (string) keys and lists of header field values (string[]) as values. + * @param StreamInterface|null $body A stream representation of the message + * entity body */ public function __construct( string $method = 'GET', diff --git a/src/Message/Response.php b/src/Message/Response.php index 2269186..99a02c2 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -35,6 +35,7 @@ class Response extends Message implements ResponseInterface * a NullStream instance for the message body. * * @see \WellRESTed\Message\Message + * * @param int $statusCode * @param array $headers * @param StreamInterface|null $body @@ -58,7 +59,7 @@ class Response extends Message implements ResponseInterface * The status code is a 3-digit integer result code of the server's attempt * to understand and satisfy the request. * - * @return integer Status code. + * @return int Status code. */ public function getStatusCode() { diff --git a/test/tests/unit/Message/MessageTest.php b/test/tests/unit/Message/MessageTest.php index 093331e..03c9c62 100644 --- a/test/tests/unit/Message/MessageTest.php +++ b/test/tests/unit/Message/MessageTest.php @@ -1,38 +1,27 @@ message = new Response(); - } - - public function testSetsHeadersOnConstruction() + public function testSetsHeadersOnConstruction(): void { $headers = ['X-foo' => ['bar', 'baz']]; $message = new Response(200, $headers); $this->assertEquals(['bar', 'baz'], $message->getHeader('X-foo')); } - public function testSetsBodyOnConstruction() + public function testSetsBodyOnConstruction(): void { $body = new Stream('Hello, world'); $message = new Response(200, [], $body); $this->assertSame($body, $message->getBody()); } - public function testCloneMakesDeepCopyOfHeaders() + public function testCloneMakesDeepCopyOfHeaders(): void { $message1 = (new Response()) ->withHeader('Content-type', 'text/plain'); @@ -48,20 +37,20 @@ class MessageTest extends TestCase // ------------------------------------------------------------------------ // Protocol Version - public function testGetProtocolVersionReturnsProtocolVersion1Point1ByDefault() + public function testGetProtocolVersionReturnsProtocolVersion1Point1ByDefault(): void { $message = new Response(); $this->assertEquals('1.1', $message->getProtocolVersion()); } - public function testGetProtocolVersionReturnsProtocolVersion() + public function testGetProtocolVersionReturnsProtocolVersion(): void { $message = (new Response()) ->withProtocolVersion('1.0'); $this->assertEquals('1.0', $message->getProtocolVersion()); } - public function testGetProtocolVersionReplacesProtocolVersion() + public function testGetProtocolVersionReplacesProtocolVersion(): void { $message = (new Response()) ->withProtocolVersion('1.0'); @@ -71,8 +60,12 @@ class MessageTest extends TestCase // ------------------------------------------------------------------------ // Headers - /** @dataProvider validHeaderValueProvider */ - public function testWithHeaderReplacesHeader($expected, $value) + /** + * @dataProvider validHeaderValueProvider + * @param array $expected + * @param mixed $value + */ + public function testWithHeaderReplacesHeader(array $expected, $value): void { $message = (new Response()) ->withHeader('X-foo', 'Original value') @@ -80,7 +73,7 @@ class MessageTest extends TestCase $this->assertEquals($expected, $message->getHeader('X-foo')); } - public function validHeaderValueProvider() + public function validHeaderValueProvider(): array { return [ [['0'], 0], @@ -90,15 +83,17 @@ class MessageTest extends TestCase /** * @dataProvider invalidHeaderProvider + * @param mixed $name + * @param mixed $value */ - public function testWithHeaderThrowsExceptionWithInvalidArgument($name, $value) + public function testWithHeaderThrowsExceptionWithInvalidArgument($name, $value): void { $this->expectException(InvalidArgumentException::class); - $message = (new Response()) + (new Response()) ->withHeader($name, $value); } - public function invalidHeaderProvider() + public function invalidHeaderProvider(): array { return [ [0, 1024], @@ -107,14 +102,14 @@ class MessageTest extends TestCase ]; } - public function testWithAddedHeaderSetsHeader() + public function testWithAddedHeaderSetsHeader(): void { $message = (new Response()) ->withAddedHeader('Content-type', 'application/json'); $this->assertEquals(['application/json'], $message->getHeader('Content-type')); } - public function testWithAddedHeaderAppendsValue() + public function testWithAddedHeaderAppendsValue(): void { $message = (new Response()) ->withAddedHeader('Set-Cookie', ['cat=Molly']) @@ -126,7 +121,7 @@ class MessageTest extends TestCase ); } - public function testWithoutHeaderRemovesHeader() + public function testWithoutHeaderRemovesHeader(): void { $message = (new Response()) ->withHeader('Content-type', 'application/json') @@ -134,20 +129,20 @@ class MessageTest extends TestCase $this->assertFalse($message->hasHeader('Content-type')); } - public function testGetHeaderReturnsEmptyArrayForUnsetHeader() + public function testGetHeaderReturnsEmptyArrayForUnsetHeader(): void { $message = new Response(); $this->assertEquals([], $message->getHeader('X-name')); } - public function testGetHeaderReturnsSingleHeader() + public function testGetHeaderReturnsSingleHeader(): void { $message = (new Response()) ->withAddedHeader('Content-type', 'application/json'); $this->assertEquals(['application/json'], $message->getHeader('Content-type')); } - public function testGetHeaderReturnsMultipleValuesForHeader() + public function testGetHeaderReturnsMultipleValuesForHeader(): void { $message = (new Response()) ->withAddedHeader('X-name', 'cat=Molly') @@ -155,13 +150,13 @@ class MessageTest extends TestCase $this->assertEquals(['cat=Molly', 'dog=Bear'], $message->getHeader('X-name')); } - public function testGetHeaderLineReturnsEmptyStringForUnsetHeader() + public function testGetHeaderLineReturnsEmptyStringForUnsetHeader(): void { $message = new Response(); $this->assertSame('', $message->getHeaderLine('X-not-set')); } - public function testGetHeaderLineReturnsMultipleHeadersJoinedByCommas() + public function testGetHeaderLineReturnsMultipleHeadersJoinedByCommas(): void { $message = (new Response()) ->withAddedHeader('X-name', 'cat=Molly') @@ -169,20 +164,20 @@ class MessageTest extends TestCase $this->assertEquals('cat=Molly, dog=Bear', $message->getHeaderLine('X-name')); } - public function testHasHeaderReturnsTrueWhenHeaderIsSet() + public function testHasHeaderReturnsTrueWhenHeaderIsSet(): void { $message = (new Response()) ->withHeader('Content-type', 'application/json'); $this->assertTrue($message->hasHeader('Content-type')); } - public function testHasHeaderReturnsFalseWhenHeaderIsNotSet() + public function testHasHeaderReturnsFalseWhenHeaderIsNotSet(): void { $message = new Response(); $this->assertFalse($message->hasHeader('Content-type')); } - public function testGetHeadersReturnOriginalHeaderNamesAsKeys() + public function testGetHeadersReturnOriginalHeaderNamesAsKeys(): void { $message = (new Response()) ->withHeader('Set-Cookie', 'cat=Molly') @@ -201,7 +196,7 @@ class MessageTest extends TestCase $this->assertEquals(0, $countUnmatched); } - public function testGetHeadersReturnOriginalHeaderNamesAndValues() + public function testGetHeadersReturnOriginalHeaderNamesAndValues(): void { $message = (new Response()) ->withHeader('Set-Cookie', 'cat=Molly') @@ -231,13 +226,13 @@ class MessageTest extends TestCase // ------------------------------------------------------------------------ // Body - public function testGetBodyReturnsEmptyStreamByDefault() + public function testGetBodyReturnsEmptyStreamByDefault(): void { $message = new Response(); $this->assertEquals('', (string) $message->getBody()); } - public function testGetBodyReturnsAttachedStream() + public function testGetBodyReturnsAttachedStream(): void { $stream = new Stream('Hello, world!'); diff --git a/test/tests/unit/Message/RequestTest.php b/test/tests/unit/Message/RequestTest.php index ad81f3c..3474a40 100644 --- a/test/tests/unit/Message/RequestTest.php +++ b/test/tests/unit/Message/RequestTest.php @@ -1,11 +1,8 @@ assertNotNull($request); } - public function testCreatesInstanceWithMethod() + public function testCreatesInstanceWithMethod(): void { $method = 'POST'; $request = new Request($method); $this->assertSame($method, $request->getMethod()); } - public function testCreatesInstanceWithUri() + public function testCreatesInstanceWithUri(): void { $uri = new Uri(); $request = new Request('GET', $uri); $this->assertSame($uri, $request->getUri()); } - public function testCreatesInstanceWithStringUri() + public function testCreatesInstanceWithStringUri(): void { $uri = 'http://localhost:8080'; $request = new Request('GET', $uri); $this->assertSame($uri, (string) $request->getUri()); } - public function testSetsHeadersOnConstruction() + public function testSetsHeadersOnConstruction(): void { $request = new Request('GET', '/', [ 'X-foo' => ['bar', 'baz'] @@ -48,7 +45,7 @@ class RequestTest extends TestCase $this->assertEquals(['bar', 'baz'], $request->getHeader('X-foo')); } - public function testSetsBodyOnConstruction() + public function testSetsBodyOnConstruction(): void { $body = new NullStream(); $request = new Request('GET', '/', [], $body); @@ -58,14 +55,14 @@ class RequestTest extends TestCase // ------------------------------------------------------------------------ // Request Target - public function testGetRequestTargetPrefersExplicitRequestTarget() + public function testGetRequestTargetPrefersExplicitRequestTarget(): void { $request = new Request(); $request = $request->withRequestTarget('*'); $this->assertEquals('*', $request->getRequestTarget()); } - public function testGetRequestTargetUsesOriginFormOfUri() + public function testGetRequestTargetUsesOriginFormOfUri(): void { $uri = new Uri('/my/path?cat=Molly&dog=Bear'); $request = new Request(); @@ -73,13 +70,13 @@ class RequestTest extends TestCase $this->assertEquals('/my/path?cat=Molly&dog=Bear', $request->getRequestTarget()); } - public function testGetRequestTargetReturnsSlashByDefault() + public function testGetRequestTargetReturnsSlashByDefault(): void { $request = new Request(); $this->assertEquals('/', $request->getRequestTarget()); } - public function testWithRequestTargetCreatesNewInstance() + public function testWithRequestTargetCreatesNewInstance(): void { $request = new Request(); $request = $request->withRequestTarget('*'); @@ -89,13 +86,13 @@ class RequestTest extends TestCase // ------------------------------------------------------------------------ // Method - public function testGetMethodReturnsGetByDefault() + public function testGetMethodReturnsGetByDefault(): void { $request = new Request(); $this->assertEquals('GET', $request->getMethod()); } - public function testWithMethodCreatesNewInstance() + public function testWithMethodCreatesNewInstance(): void { $request = new Request(); $request = $request->withMethod('POST'); @@ -104,15 +101,16 @@ class RequestTest extends TestCase /** * @dataProvider invalidMethodProvider + * @param mixed $method */ - public function testWithMethodThrowsExceptionOnInvalidMethod($method) + public function testWithMethodThrowsExceptionOnInvalidMethod($method): void { $this->expectException(InvalidArgumentException::class); $request = new Request(); $request->withMethod($method); } - public function invalidMethodProvider() + public function invalidMethodProvider(): array { return [ [0], @@ -124,14 +122,14 @@ class RequestTest extends TestCase // ------------------------------------------------------------------------ // Request URI - public function testGetUriReturnsEmptyUriByDefault() + public function testGetUriReturnsEmptyUriByDefault(): void { $request = new Request(); $uri = new Uri(); $this->assertEquals($uri, $request->getUri()); } - public function testWithUriCreatesNewInstance() + public function testWithUriCreatesNewInstance(): void { $uri = new Uri(); $request = new Request(); @@ -139,7 +137,7 @@ class RequestTest extends TestCase $this->assertSame($uri, $request->getUri()); } - public function testWithUriPreservesOriginalRequest() + public function testWithUriPreservesOriginalRequest(): void { $uri1 = new Uri(); $uri2 = new Uri(); @@ -154,7 +152,7 @@ class RequestTest extends TestCase $this->assertNotEquals($request1->getHeader('Accept'), $request2->getHeader('Accept')); } - public function testWithUriUpdatesHostHeader() + public function testWithUriUpdatesHostHeader(): void { $hostname = 'bar.com'; $uri = new uri("http://$hostname"); @@ -165,7 +163,7 @@ class RequestTest extends TestCase $this->assertSame([$hostname], $request->getHeader('Host')); } - public function testWithUriDoesNotUpdatesHostHeaderWhenUriHasNoHost() + public function testWithUriDoesNotUpdatesHostHeaderWhenUriHasNoHost(): void { $hostname = 'foo.com'; $uri = new Uri(); @@ -176,7 +174,7 @@ class RequestTest extends TestCase $this->assertSame([$hostname], $request->getHeader('Host')); } - public function testPreserveHostUpdatesHostHeaderWhenHeaderIsOriginallyMissing() + public function testPreserveHostUpdatesHostHeaderWhenHeaderIsOriginallyMissing(): void { $hostname = 'foo.com'; $uri = new uri("http://$hostname"); @@ -186,7 +184,7 @@ class RequestTest extends TestCase $this->assertSame([$hostname], $request->getHeader('Host')); } - public function testPreserveHostDoesNotUpdatesWhenBothAreMissingHosts() + public function testPreserveHostDoesNotUpdatesWhenBothAreMissingHosts(): void { $uri = new Uri(); @@ -195,7 +193,7 @@ class RequestTest extends TestCase $this->assertSame([], $request->getHeader('Host')); } - public function testPreserveHostDoesNotUpdateHostHeader() + public function testPreserveHostDoesNotUpdateHostHeader(): void { $hostname = 'foo.com'; $uri = new uri('http://bar.com'); diff --git a/test/tests/unit/Message/ResponseTest.php b/test/tests/unit/Message/ResponseTest.php index 9f119e5..57b4e35 100644 --- a/test/tests/unit/Message/ResponseTest.php +++ b/test/tests/unit/Message/ResponseTest.php @@ -1,9 +1,7 @@ assertSame(200, $response->getStatusCode()); } - public function testSetsHeadersOnConstruction() + public function testSetsHeadersOnConstruction(): void { $response = new Response(200, [ 'X-foo' => ['bar','baz'] @@ -25,7 +23,7 @@ class ResponseTest extends TestCase $this->assertEquals(['bar','baz'], $response->getHeader('X-foo')); } - public function testSetsBodyOnConstruction() + public function testSetsBodyOnConstruction(): void { $body = new NullStream(); $response = new Response(200, [], $body); @@ -35,22 +33,30 @@ class ResponseTest extends TestCase // ------------------------------------------------------------------------ // Status and Reason Phrase - public function testCreatesNewInstanceWithStatusCode() + public function testCreatesNewInstanceWithStatusCode(): void { $response = new Response(); $copy = $response->withStatus(200); $this->assertEquals(200, $copy->getStatusCode()); } - /** @dataProvider statusProvider */ - public function testCreatesNewInstanceWithReasonPhrase($code, $reasonPhrase, $expected) - { + /** + * @dataProvider statusProvider + * @param int $code + * @param string|null $reasonPhrase + * @param string $expected + */ + public function testCreatesNewInstanceWithReasonPhrase( + int $code, + ?string $reasonPhrase, + string $expected + ): void { $response = new Response(); $copy = $response->withStatus($code, $reasonPhrase); $this->assertEquals($expected, $copy->getReasonPhrase()); } - public function statusProvider() + public function statusProvider(): array { return [ [100, null, 'Continue'], @@ -95,7 +101,7 @@ class ResponseTest extends TestCase ]; } - public function testWithStatusCodePreservesOriginalResponse() + public function testWithStatusCodePreservesOriginalResponse(): void { $response1 = new Response(); $response1 = $response1->withStatus(200); diff --git a/test/tests/unit/Message/ServerRequestTest.php b/test/tests/unit/Message/ServerRequestTest.php index 22916f2..10fcc60 100644 --- a/test/tests/unit/Message/ServerRequestTest.php +++ b/test/tests/unit/Message/ServerRequestTest.php @@ -10,7 +10,7 @@ class ServerRequestTest extends TestCase // ------------------------------------------------------------------------ // Server Params - public function testGetServerParamsReturnsEmptyArrayByDefault() + public function testGetServerParamsReturnsEmptyArrayByDefault(): void { $request = new ServerRequest(); $this->assertEquals([], $request->getServerParams()); @@ -19,13 +19,13 @@ class ServerRequestTest extends TestCase // ------------------------------------------------------------------------ // Cookies - public function testGetCookieParamsReturnsEmptyArrayByDefault() + public function testGetCookieParamsReturnsEmptyArrayByDefault(): void { $request = new ServerRequest(); $this->assertEquals([], $request->getCookieParams()); } - public function testWithCookieParamsCreatesNewInstanceWithCookies() + public function testWithCookieParamsCreatesNewInstanceWithCookies(): void { $cookies = [ 'cat' => 'Oscar' @@ -41,13 +41,13 @@ class ServerRequestTest extends TestCase // ------------------------------------------------------------------------ // Query - public function testGetQueryParamsReturnsEmptyArrayByDefault() + public function testGetQueryParamsReturnsEmptyArrayByDefault(): void { $request = new ServerRequest(); $this->assertEquals([], $request->getQueryParams()); } - public function testWithQueryParamsCreatesNewInstance() + public function testWithQueryParamsCreatesNewInstance(): void { $query = [ 'cat' => 'Aggie' @@ -63,13 +63,13 @@ class ServerRequestTest extends TestCase // ------------------------------------------------------------------------ // Uploaded Files - public function testGetUploadedFilesReturnsEmptyArrayByDefault() + public function testGetUploadedFilesReturnsEmptyArrayByDefault(): void { $request = new ServerRequest(); $this->assertEquals([], $request->getUploadedFiles()); } - public function testWithUploadedFilesCreatesNewInstance() + public function testWithUploadedFilesCreatesNewInstance(): void { $uploadedFiles = [ 'file' => new UploadedFile('index.html', 'text/html', 524, '/tmp/php9hNlHe', 0) @@ -80,15 +80,18 @@ class ServerRequestTest extends TestCase $this->assertNotSame($request2, $request1); } - /** @dataProvider validUploadedFilesProvider */ - public function testWithUploadedFilesStoresPassedUploadedFiles($uploadedFiles) + /** + * @dataProvider validUploadedFilesProvider + * @param array $uploadedFiles + */ + public function testWithUploadedFilesStoresPassedUploadedFiles(array $uploadedFiles): void { $request = new ServerRequest(); $request = $request->withUploadedFiles($uploadedFiles); $this->assertSame($uploadedFiles, $request->getUploadedFiles()); } - public function validUploadedFilesProvider() + public function validUploadedFilesProvider(): array { return [ [[]], @@ -113,8 +116,9 @@ class ServerRequestTest extends TestCase /** * @dataProvider invalidUploadedFilesProvider + * @param array $uploadedFiles */ - public function testWithUploadedFilesThrowsExceptionWithInvalidTree($uploadedFiles) + public function testWithUploadedFilesThrowsExceptionWithInvalidTree(array $uploadedFiles): void { $this->expectException(InvalidArgumentException::class); $request = new ServerRequest(); @@ -185,13 +189,13 @@ class ServerRequestTest extends TestCase // ------------------------------------------------------------------------ // Parsed Body - public function testGetParsedBodyReturnsNullByDefault() + public function testGetParsedBodyReturnsNullByDefault(): void { $request = new ServerRequest(); $this->assertNull($request->getParsedBody()); } - public function testWithParsedBodyCreatesNewInstance() + public function testWithParsedBodyCreatesNewInstance(): void { $body = [ 'guinea_pig' => 'Clyde' @@ -206,8 +210,9 @@ class ServerRequestTest extends TestCase /** * @dataProvider invalidParsedBodyProvider + * @param mixed $body */ - public function testWithParsedBodyThrowsExceptionWithInvalidType($body) + public function testWithParsedBodyThrowsExceptionWithInvalidType($body): void { $this->expectException(InvalidArgumentException::class); $request = new ServerRequest(); @@ -222,7 +227,7 @@ class ServerRequestTest extends TestCase ]; } - public function testCloneMakesDeepCopiesOfParsedBody() + public function testCloneMakesDeepCopiesOfParsedBody(): void { $body = (object) [ 'cat' => 'Dog' @@ -241,13 +246,13 @@ class ServerRequestTest extends TestCase // ------------------------------------------------------------------------ // Attributes - public function testGetAttributesReturnsEmptyArrayByDefault() + public function testGetAttributesReturnsEmptyArrayByDefault(): void { $request = new ServerRequest(); $this->assertEquals([], $request->getAttributes()); } - public function testGetAttributesReturnsAllAttributes() + public function testGetAttributesReturnsAllAttributes(): void { $request = new ServerRequest(); $request = $request->withAttribute('cat', 'Molly'); @@ -259,20 +264,20 @@ class ServerRequestTest extends TestCase $this->assertEquals($expected, $request->getAttributes()); } - public function testGetAttributeReturnsDefaultIfNotSet() + public function testGetAttributeReturnsDefaultIfNotSet(): void { $request = new ServerRequest(); $this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar')); } - public function testWithAttributeCreatesNewInstance() + public function testWithAttributeCreatesNewInstance(): void { $request = new ServerRequest(); $request = $request->withAttribute('cat', 'Molly'); $this->assertEquals('Molly', $request->getAttribute('cat')); } - public function testWithAttributePreserversOtherAttributes() + public function testWithAttributePreserversOtherAttributes(): void { $request = new ServerRequest(); $request = $request->withAttribute('cat', 'Molly'); @@ -284,14 +289,14 @@ class ServerRequestTest extends TestCase $this->assertEquals($expected, $request->getAttributes()); } - public function testWithoutAttributeCreatesNewInstance() + public function testWithoutAttributeCreatesNewInstance(): void { $request = new ServerRequest(); $request = $request->withAttribute('cat', 'Molly'); $this->assertNotEquals($request, $request->withoutAttribute('cat')); } - public function testWithoutAttributeRemovesAttribute() + public function testWithoutAttributeRemovesAttribute(): void { $request = new ServerRequest(); $request = $request->withAttribute('cat', 'Molly'); @@ -299,7 +304,7 @@ class ServerRequestTest extends TestCase $this->assertEquals('Oscar', $request->getAttribute('cat', 'Oscar')); } - public function testWithoutAttributePreservesOtherAttributes() + public function testWithoutAttributePreservesOtherAttributes(): void { $request = new ServerRequest(); $request = $request->withAttribute('cat', 'Molly'); From 83c2290a2f442e89ee33a78ac2d6991a29fe8401 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 06:21:19 -0400 Subject: [PATCH 27/53] Refactor streams --- src/Message/Stream.php | 4 +- test/tests/unit/Message/NullStreamTest.php | 35 ++++++------- test/tests/unit/Message/StreamTest.php | 61 +++++++++++----------- 3 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/Message/Stream.php b/src/Message/Stream.php index c8deb1d..73c2572 100644 --- a/src/Message/Stream.php +++ b/src/Message/Stream.php @@ -16,7 +16,7 @@ class Stream implements StreamInterface private $resource; /** - * Create a new Stream passing either a stream resource handle (e.g., + * Create a new Stream by passing either a stream resource handle (e.g., * from fopen) or a string. * * If $resource is a string, the Stream will open a php://temp stream, @@ -35,7 +35,7 @@ class Stream implements StreamInterface $this->write($resource); } } else { - throw new InvalidArgumentException('Expected a resource handler.'); + throw new InvalidArgumentException('Expected resource or string.'); } } diff --git a/test/tests/unit/Message/NullStreamTest.php b/test/tests/unit/Message/NullStreamTest.php index e16d246..ef6cd7b 100644 --- a/test/tests/unit/Message/NullStreamTest.php +++ b/test/tests/unit/Message/NullStreamTest.php @@ -1,108 +1,107 @@ assertEquals('', (string) $stream); } - public function testCloseDoesNothing() + public function testCloseDoesNothing(): void { $stream = new NullStream(); $stream->close(); $this->assertTrue(true); // Asserting no exception occurred. } - public function testDetachReturnsNull() + public function testDetachReturnsNull(): void { $stream = new NullStream(); $this->assertNull($stream->detach()); } - public function testSizeReturnsZero() + public function testSizeReturnsZero(): void { $stream = new NullStream(); $this->assertEquals(0, $stream->getSize()); } - public function testTellReturnsZero() + public function testTellReturnsZero(): void { $stream = new NullStream(); $this->assertEquals(0, $stream->tell()); } - public function testEofReturnsTrue() + public function testEofReturnsTrue(): void { $stream = new NullStream(); $this->assertTrue($stream->eof()); } - public function testIsSeekableReturnsFalse() + public function testIsSeekableReturnsFalse(): void { $stream = new NullStream(); $this->assertFalse($stream->isSeekable()); } - public function testSeekReturnsFalse() + public function testSeekReturnsFalse(): void { $this->expectException(RuntimeException::class); $stream = new NullStream(); $stream->seek(10); } - public function testRewindThrowsException() + public function testRewindThrowsException(): void { $this->expectException(RuntimeException::class); $stream = new NullStream(); $stream->rewind(); } - public function testIsWritableReturnsFalse() + public function testIsWritableReturnsFalse(): void { $stream = new NullStream(); $this->assertFalse($stream->isWritable()); } - public function testWriteThrowsException() + public function testWriteThrowsException(): void { $this->expectException(RuntimeException::class); $stream = new NullStream(); $stream->write(''); } - public function testIsReadableReturnsTrue() + public function testIsReadableReturnsTrue(): void { $stream = new NullStream(); $this->assertTrue($stream->isReadable()); } - public function testReadReturnsEmptyString() + public function testReadReturnsEmptyString(): void { $stream = new NullStream(); $this->assertEquals('', $stream->read(100)); } - public function testGetContentsReturnsEmptyString() + public function testGetContentsReturnsEmptyString(): void { $stream = new NullStream(); $this->assertEquals('', $stream->getContents()); } - public function testGetMetadataReturnsNull() + public function testGetMetadataReturnsNull(): void { $stream = new NullStream(); $this->assertNull($stream->getMetadata()); } - public function testGetMetadataReturnsNullWithKey() + public function testGetMetadataReturnsNullWithKey(): void { $stream = new NullStream(); $this->assertNull($stream->getMetadata('size')); diff --git a/test/tests/unit/Message/StreamTest.php b/test/tests/unit/Message/StreamTest.php index 7a8329d..b70b920 100644 --- a/test/tests/unit/Message/StreamTest.php +++ b/test/tests/unit/Message/StreamTest.php @@ -1,10 +1,9 @@ resource); $this->assertNotNull($stream); } - public function testCreatesInstanceWithString() + public function testCreatesInstanceWithString(): void { $stream = new Stream('Hello, world!'); $this->assertNotNull($stream); @@ -43,13 +42,13 @@ class StreamTest extends TestCase * @dataProvider invalidResourceProvider * @param mixed $resource */ - public function testThrowsExceptionWithInvalidResource($resource) + public function testThrowsExceptionWithInvalidResource($resource): void { $this->expectException(InvalidArgumentException::class); new Stream($resource); } - public function invalidResourceProvider() + public function invalidResourceProvider(): array { return [ [null], @@ -59,59 +58,59 @@ class StreamTest extends TestCase ]; } - public function testCastsToString() + public function testCastsToString(): void { $stream = new Stream($this->resource); $this->assertEquals($this->content, (string) $stream); } - public function testClosesHandle() + public function testClosesHandle(): void { $stream = new Stream($this->resource); $stream->close(); $this->assertFalse(is_resource($this->resource)); } - public function testDetachReturnsHandle() + public function testDetachReturnsHandle(): void { $stream = new Stream($this->resource); $this->assertSame($this->resource, $stream->detach()); } - public function testDetachUnsetsInstanceVariable() + public function testDetachUnsetsInstanceVariable(): void { $stream = new Stream($this->resource); $stream->detach(); $this->assertNull($stream->detach()); } - public function testReturnsSize() + public function testReturnsSize(): void { $stream = new Stream($this->resource); $this->assertEquals(strlen($this->content), $stream->getSize()); } - public function testReturnsNullForSizeWhenUnableToReadFromFstat() + public function testReturnsNullForSizeWhenUnableToReadFromFstat(): void { $stream = new Stream($this->resourceDevNull); $this->assertNull($stream->getSize()); } - public function testTellReturnsHandlePosition() + public function testTellReturnsHandlePosition(): void { $stream = new Stream($this->resource); fseek($this->resource, 10); $this->assertEquals(10, $stream->tell()); } - public function testTellThrowsRuntimeExceptionWhenUnableToReadStreamPosition() + public function testTellThrowsRuntimeExceptionWhenUnableToReadStreamPosition(): void { $stream = new Stream($this->resourceDevNull); $this->expectException(RuntimeException::class); $stream->tell(); } - public function testReturnsOef() + public function testReturnsOef(): void { $stream = new Stream($this->resource); $stream->rewind(); @@ -119,7 +118,7 @@ class StreamTest extends TestCase $this->assertTrue($stream->eof()); } - public function testReadsSeekableStatusFromMetadata() + public function testReadsSeekableStatusFromMetadata(): void { $stream = new Stream($this->resource); $metadata = stream_get_meta_data($this->resource); @@ -127,21 +126,21 @@ class StreamTest extends TestCase $this->assertEquals($seekable, $stream->isSeekable()); } - public function testSeeksToPosition() + public function testSeeksToPosition(): void { $stream = new Stream($this->resource); $stream->seek(10); $this->assertEquals(10, ftell($this->resource)); } - public function testSeekThrowsRuntimeExceptionWhenUnableToSeek() + public function testSeekThrowsRuntimeExceptionWhenUnableToSeek(): void { $stream = new Stream($this->resourceDevNull); $this->expectException(RuntimeException::class); $stream->seek(10); } - public function testRewindReturnsToBeginning() + public function testRewindReturnsToBeginning(): void { $stream = new Stream($this->resource); $stream->seek(10); @@ -149,14 +148,14 @@ class StreamTest extends TestCase $this->assertEquals(0, ftell($this->resource)); } - public function testRewindThrowsRuntimeExceptionWhenUnableToRewind() + public function testRewindThrowsRuntimeExceptionWhenUnableToRewind(): void { $stream = new Stream($this->resourceDevNull); $this->expectException(RuntimeException::class); $stream->rewind(); } - public function testWritesToHandle() + public function testWritesToHandle(): void { $message = "\nThis is a stream."; $stream = new Stream($this->resource); @@ -164,7 +163,7 @@ class StreamTest extends TestCase $this->assertEquals($this->content . $message, (string) $stream); } - public function testThrowsExceptionOnErrorWriting() + public function testThrowsExceptionOnErrorWriting(): void { $this->expectException(RuntimeException::class); $filename = tempnam(sys_get_temp_dir(), 'php'); @@ -173,7 +172,7 @@ class StreamTest extends TestCase $stream->write('Hello, world!'); } - public function testThrowsExceptionOnErrorReading() + public function testThrowsExceptionOnErrorReading(): void { $this->expectException(RuntimeException::class); $filename = tempnam(sys_get_temp_dir(), 'php'); @@ -182,7 +181,7 @@ class StreamTest extends TestCase $stream->read(10); } - public function testReadsFromStream() + public function testReadsFromStream(): void { $stream = new Stream($this->resource); $stream->seek(7); @@ -190,7 +189,7 @@ class StreamTest extends TestCase $this->assertEquals('world', $string); } - public function testThrowsExceptionOnErrorReadingToEnd() + public function testThrowsExceptionOnErrorReadingToEnd(): void { $this->expectException(RuntimeException::class); $filename = tempnam(sys_get_temp_dir(), 'php'); @@ -199,7 +198,7 @@ class StreamTest extends TestCase $stream->getContents(); } - public function testReadsToEnd() + public function testReadsToEnd(): void { $stream = new Stream($this->resource); $stream->seek(7); @@ -207,13 +206,13 @@ class StreamTest extends TestCase $this->assertEquals('world!', $string); } - public function testReturnsMetadataArray() + public function testReturnsMetadataArray(): void { $stream = new Stream($this->resource); $this->assertEquals(stream_get_meta_data($this->resource), $stream->getMetadata()); } - public function testReturnsMetadataItem() + public function testReturnsMetadataItem(): void { $stream = new Stream($this->resource); $metadata = stream_get_meta_data($this->resource); @@ -226,7 +225,7 @@ class StreamTest extends TestCase * @param bool $readable The stream should be readable * @param bool $writable The stream should be writeable */ - public function testReturnsIsReadableForReadableStreams($mode, $readable, $writable) + public function testReturnsIsReadableForReadableStreams(string $mode, bool $readable, bool $writable): void { $tmp = tempnam(sys_get_temp_dir(), 'php'); if ($mode[0] === 'x') { @@ -243,7 +242,7 @@ class StreamTest extends TestCase * @param bool $readable The stream should be readable * @param bool $writable The stream should be writeable */ - public function testReturnsIsWritableForWritableStreams($mode, $readable, $writable) + public function testReturnsIsWritableForWritableStreams(string $mode, bool $readable, bool $writable): void { $tmp = tempnam(sys_get_temp_dir(), 'php'); if ($mode[0] === 'x') { @@ -254,7 +253,7 @@ class StreamTest extends TestCase $this->assertEquals($writable, $stream->isWritable()); } - public function modeProvider() + public function modeProvider(): array { return [ ['r', true, false], From 899ebb24924daa2a4e00000bf00a0c4d7211c257 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 06:37:51 -0400 Subject: [PATCH 28/53] Move UploadedFileState test components into test file --- src/Message/UploadedFile.php | 6 +- test/src/UploadedFileState.php | 24 ------- test/tests/unit/Message/UploadedFileTest.php | 69 +++++++++++++------- 3 files changed, 48 insertions(+), 51 deletions(-) delete mode 100644 test/src/UploadedFileState.php diff --git a/src/Message/UploadedFile.php b/src/Message/UploadedFile.php index c18c4b8..cb08460 100644 --- a/src/Message/UploadedFile.php +++ b/src/Message/UploadedFile.php @@ -28,7 +28,7 @@ class UploadedFile implements UploadedFileInterface private $tmpName; /** - * Create a new Uri. The arguments correspond with keys from arrays + * Create a new UploadedFile. The arguments correspond with keys from arrays * provided by $_FILES. For example, given this structure for $_FILES: * * array( @@ -66,7 +66,7 @@ class UploadedFile implements UploadedFileInterface $this->size = $size; if (file_exists($tmpName)) { - $this->stream = new Stream(fopen($tmpName, 'r')); + $this->stream = new Stream(fopen($tmpName, 'rb')); $this->tmpName = $tmpName; } else { $this->stream = new NullStream(); @@ -126,7 +126,7 @@ class UploadedFile implements UploadedFileInterface public function moveTo($path) { if ($this->tmpName === null || !file_exists($this->tmpName)) { - throw new RuntimeException('File ' . $this->tmpName . ' does not exist.'); + throw new RuntimeException("File {$this->tmpName} does not exist."); } if (php_sapi_name() === 'cli') { rename($this->tmpName, $path); diff --git a/test/src/UploadedFileState.php b/test/src/UploadedFileState.php deleted file mode 100644 index d0fdf1d..0000000 --- a/test/src/UploadedFileState.php +++ /dev/null @@ -1,24 +0,0 @@ -tmpName, 0); $this->assertInstanceOf(StreamInterface::class, $file->getStream()); } - public function testGetStreamReturnsStreamWrappingUploadedFile() + public function testGetStreamReturnsStreamWrappingUploadedFile(): void { $content = 'Hello, World!'; file_put_contents($this->tmpName, $content); @@ -53,14 +48,14 @@ class UploadedFileTest extends TestCase $this->assertEquals($content, (string) $stream); } - public function testGetStreamThrowsRuntimeExceptionForNoFile() + public function testGetStreamThrowsRuntimeExceptionForNoFile(): void { $file = new UploadedFile('', '', 0, '', 0); $this->expectException(RuntimeException::class); $file->getStream(); } - public function testGetStreamThrowsExceptionAfterMoveTo() + public function testGetStreamThrowsExceptionAfterMoveTo(): void { $this->expectException(RuntimeException::class); $content = 'Hello, World!'; @@ -70,7 +65,7 @@ class UploadedFileTest extends TestCase $file->getStream(); } - public function testGetStreamThrowsExceptionForNonUploadedFile() + public function testGetStreamThrowsExceptionForNonUploadedFile(): void { $this->expectException(RuntimeException::class); UploadedFileState::$php_sapi_name = 'apache'; @@ -79,10 +74,10 @@ class UploadedFileTest extends TestCase $file->getStream(); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // moveTo - public function testMoveToSapiRelocatesUploadedFileToDestinationIfExists() + public function testMoveToSapiRelocatesUploadedFileToDestinationIfExists(): void { UploadedFileState::$php_sapi_name = 'fpm-fcgi'; @@ -96,7 +91,7 @@ class UploadedFileTest extends TestCase $this->assertEquals($originalMd5, md5_file($this->movePath)); } - public function testMoveToNonSapiRelocatesUploadedFileToDestinationIfExists() + public function testMoveToNonSapiRelocatesUploadedFileToDestinationIfExists(): void { $content = 'Hello, World!'; file_put_contents($this->tmpName, $content); @@ -108,7 +103,7 @@ class UploadedFileTest extends TestCase $this->assertEquals($originalMd5, md5_file($this->movePath)); } - public function testMoveToThrowsExceptionOnSubsequentCall() + public function testMoveToThrowsExceptionOnSubsequentCall(): void { $this->expectException(RuntimeException::class); @@ -120,39 +115,65 @@ class UploadedFileTest extends TestCase $file->moveTo($this->movePath); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // getSize - public function testGetSizeReturnsSize() + public function testGetSizeReturnsSize(): void { $file = new UploadedFile('', '', 1024, '', 0); $this->assertEquals(1024, $file->getSize()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // getError - public function testGetErrorReturnsError() + public function testGetErrorReturnsError(): void { $file = new UploadedFile('', '', 1024, '', UPLOAD_ERR_INI_SIZE); $this->assertEquals(UPLOAD_ERR_INI_SIZE, $file->getError()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // clientFilename - public function testGetClientFilenameReturnsClientFilename() + public function testGetClientFilenameReturnsClientFilename(): void { $file = new UploadedFile('clientFilename', '', 0, '', 0); $this->assertEquals('clientFilename', $file->getClientFilename()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // clientMediaType - public function testGetClientMediaTypeReturnsClientMediaType() + public function testGetClientMediaTypeReturnsClientMediaType(): void { $file = new UploadedFile('', 'clientMediaType', 0, '', 0); $this->assertEquals('clientMediaType', $file->getClientMediaType()); } } + +// ----------------------------------------------------------------------------- + +// Declare functions in this namespace so the class under test will use these +// instead of the internal global functions during testing. + +class UploadedFileState +{ + public static $php_sapi_name; + public static $is_uploaded_file; +} + +function php_sapi_name() +{ + return UploadedFileState::$php_sapi_name; +} + +function move_uploaded_file($source, $target) +{ + return rename($source, $target); +} + +function is_uploaded_file($file) +{ + return UploadedFileState::$is_uploaded_file; +} From d8294d3ac3bbfe82d2b0a91f50bb2322c69134ba Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 07:08:41 -0400 Subject: [PATCH 29/53] Refactor Uri --- src/Message/Uri.php | 41 ++++---- test/tests/unit/Message/UriTest.php | 155 ++++++++++++++++++---------- 2 files changed, 125 insertions(+), 71 deletions(-) diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 8e0e273..24e72e3 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -113,33 +113,38 @@ class Uri implements UriInterface */ public function getAuthority() { + $host = $this->getHost(); + if (!$host) { + return ''; + } + $authority = ''; - $host = $this->getHost(); - if ($host !== '') { + // User Info + $userInfo = $this->getUserInfo(); + if ($userInfo) { + $authority .= $userInfo . '@'; + } - // User Info - $userInfo = $this->getUserInfo(); - if ($userInfo !== '') { - $authority .= $userInfo . '@'; - } + // Host + $authority .= $host; - // Host - $authority .= $host; - - // Port: Include only if set AND non-standard. - $port = $this->getPort(); - if ($port !== null) { - $scheme = $this->getScheme(); - if (($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443)) { - $authority .= ':' . $port; - } - } + // Port: Include only if non-standard + if ($this->nonStandardPort()) { + $authority .= ':' . $this->getPort(); } return $authority; } + private function nonStandardPort(): bool + { + $port = $this->getPort(); + $scheme = $this->getScheme(); + return $scheme === 'http' && $port !== 80 + || $scheme === 'https' && $port !== 443; + } + /** * Retrieve the user information component of the URI. * diff --git a/test/tests/unit/Message/UriTest.php b/test/tests/unit/Message/UriTest.php index 61ed2aa..57c9dbd 100644 --- a/test/tests/unit/Message/UriTest.php +++ b/test/tests/unit/Message/UriTest.php @@ -1,9 +1,8 @@ assertSame('', $uri->getScheme()); } /** @dataProvider schemeProvider */ - public function testSetsSchemeCaseInsensitively($expected, $scheme) + public function testSetsSchemeCaseInsensitively($expected, $scheme): void { $uri = new Uri(); $uri = $uri->withScheme($scheme); $this->assertSame($expected, $uri->getScheme()); } - public function schemeProvider() + public function schemeProvider(): array { return [ ['http', 'http'], @@ -37,7 +36,7 @@ class UriTest extends TestCase ]; } - public function testInvalidSchemeThrowsException() + public function testInvalidSchemeThrowsException(): void { $this->expectException(InvalidArgumentException::class); $uri = new Uri(); @@ -47,20 +46,26 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // Authority - public function testDefaultAuthorityIsEmpty() + public function testDefaultAuthorityIsEmpty(): void { $uri = new Uri(); $this->assertSame('', $uri->getAuthority()); } - public function testRespectsMyAuthoritah() + public function testRespectsMyAuthoritah(): void { $this->assertTrue(true); } - /** @dataProvider authorityProvider */ - public function testConcatenatesAuthorityFromHostAndUserInfo($expected, $components) - { + /** + * @dataProvider authorityProvider + * @param string $expected + * @param array $components + */ + public function testConcatenatesAuthorityFromHostAndUserInfo( + string $expected, + array $components + ): void { $uri = new Uri(); if (isset($components['scheme'])) { @@ -166,7 +171,7 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // User Info - public function testDefaultUserInfoIsEmpty() + public function testDefaultUserInfoIsEmpty(): void { $uri = new Uri(); $this->assertSame('', $uri->getUserInfo()); @@ -177,16 +182,16 @@ class UriTest extends TestCase * * @param string $expected The combined user:password value * @param string $user The username to set - * @param string $password The password to set + * @param string|null $password The password to set */ - public function testSetsUserInfo($expected, $user, $password) + public function testSetsUserInfo(string $expected, string $user, ?string $password): void { $uri = new Uri(); $uri = $uri->withUserInfo($user, $password); $this->assertSame($expected, $uri->getUserInfo()); } - public function userInfoProvider() + public function userInfoProvider(): array { return [ ['user:password', 'user', 'password'], @@ -200,21 +205,25 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // Host - public function testDefaultHostIsEmpty() + public function testDefaultHostIsEmpty(): void { $uri = new Uri(); $this->assertSame('', $uri->getHost()); } - /** @dataProvider hostProvider */ - public function testSetsHost($expected, $host) + /** + * @dataProvider hostProvider + * @param string $expected + * @param string $host + */ + public function testSetsHost(string $expected, string $host): void { $uri = new Uri(); $uri = $uri->withHost($host); $this->assertSame($expected, $uri->getHost()); } - public function hostProvider() + public function hostProvider(): array { return [ ['', ''], @@ -226,15 +235,16 @@ class UriTest extends TestCase /** * @dataProvider invalidHostProvider + * @param mixed $host */ - public function testInvalidHostThrowsException($host) + public function testInvalidHostThrowsException($host): void { $this->expectException(InvalidArgumentException::class); $uri = new Uri(); $uri->withHost($host); } - public function invalidHostProvider() + public function invalidHostProvider(): array { return [ [null], @@ -246,33 +256,38 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // Port - public function testDefaultPortWithNoSchemeIsNull() + public function testDefaultPortWithNoSchemeIsNull(): void { $uri = new Uri(); $this->assertNull($uri->getPort()); } - public function testDefaultPortForHttpSchemeIs80() + public function testDefaultPortForHttpSchemeIs80(): void { $uri = new Uri(); $this->assertSame(80, $uri->withScheme('http')->getPort()); } - public function testDefaultPortForHttpsSchemeIs443() + public function testDefaultPortForHttpsSchemeIs443(): void { $uri = new Uri(); $this->assertSame(443, $uri->withScheme('https')->getPort()); } - /** @dataProvider portAndSchemeProvider */ - public function testReturnsPortWithSchemeDefaults($expectedPort, $scheme, $port) + /** + * @dataProvider portAndSchemeProvider + * @param mixed $expectedPort + * @param mixed $scheme + * @param mixed $port + */ + public function testReturnsPortWithSchemeDefaults($expectedPort, $scheme, $port): void { $uri = new Uri(); $uri = $uri->withScheme($scheme)->withPort($port); $this->assertSame($expectedPort, $uri->getPort()); } - public function portAndSchemeProvider() + public function portAndSchemeProvider(): array { return [ [null, '', null], @@ -286,15 +301,16 @@ class UriTest extends TestCase /** * @dataProvider invalidPortProvider + * @param mixed $port */ - public function testInvalidPortThrowsException($port) + public function testInvalidPortThrowsException($port): void { $this->expectException(InvalidArgumentException::class); $uri = new Uri(); $uri->withPort($port); } - public function invalidPortProvider() + public function invalidPortProvider(): array { return [ [true], @@ -307,22 +323,30 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // Path - public function testDefaultPathIsEmpty() + public function testDefaultPathIsEmpty(): void { $uri = new Uri(); $this->assertSame('', $uri->getPath()); } - /** @dataProvider pathProvider */ - public function testSetsEncodedPath($expected, $path) + /** + * @dataProvider pathProvider + * @param string $expected + * @param string $path + */ + public function testSetsEncodedPath(string $expected, string $path): void { $uri = new Uri(); $uri = $uri->withPath($path); $this->assertSame($expected, $uri->getPath()); } - /** @dataProvider pathProvider */ - public function testDoesNotDoubleEncodePath($expected, $path) + /** + * @dataProvider pathProvider + * @param string $expected + * @param string $path + */ + public function testDoesNotDoubleEncodePath(string $expected, string $path): void { $uri = new Uri(); $uri = $uri->withPath($path); @@ -346,22 +370,30 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // Query - public function testDefaultQueryIsEmpty() + public function testDefaultQueryIsEmpty(): void { $uri = new Uri(); $this->assertSame('', $uri->getQuery()); } - /** @dataProvider queryProvider */ - public function testSetsEncodedQuery($expected, $query) + /** + * @dataProvider queryProvider + * @param string $expected + * @param string $query + */ + public function testSetsEncodedQuery(string $expected, string $query): void { $uri = new Uri(); $uri = $uri->withQuery($query); $this->assertSame($expected, $uri->getQuery()); } - /** @dataProvider queryProvider */ - public function testDoesNotDoubleEncodeQuery($expected, $query) + /** + * @dataProvider queryProvider + * @param string $expected + * @param string $query + */ + public function testDoesNotDoubleEncodeQuery(string $expected, string $query): void { $uri = new Uri(); $uri = $uri->withQuery($query); @@ -369,7 +401,7 @@ class UriTest extends TestCase $this->assertSame($expected, $uri->getQuery()); } - public function queryProvider() + public function queryProvider(): array { return [ ['cat=molly', 'cat=molly'], @@ -380,15 +412,16 @@ class UriTest extends TestCase /** * @dataProvider invalidPathProvider + * @param mixed $path */ - public function testInvalidPathThrowsException($path) + public function testInvalidPathThrowsException($path): void { $this->expectException(InvalidArgumentException::class); $uri = new Uri(); $uri->withPath($path); } - public function invalidPathProvider() + public function invalidPathProvider(): array { return [ [null], @@ -400,22 +433,30 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // Fragment - public function testDefaultFragmentIsEmpty() + public function testDefaultFragmentIsEmpty(): void { $uri = new Uri(); $this->assertSame('', $uri->getFragment()); } - /** @dataProvider fragmentProvider */ - public function testSetsEncodedFragment($expected, $fragment) + /** + * @dataProvider fragmentProvider + * @param string $expected + * @param string|null $fragment + */ + public function testSetsEncodedFragment(string $expected, ?string $fragment): void { $uri = new Uri(); $uri = $uri->withFragment($fragment); $this->assertSame($expected, $uri->getFragment()); } - /** @dataProvider fragmentProvider */ - public function testDoesNotDoubleEncodeFragment($expected, $fragment) + /** + * @dataProvider fragmentProvider + * @param string $expected + * @param string|null $fragment + */ + public function testDoesNotDoubleEncodeFragment(string $expected, ?string $fragment): void { $uri = new Uri(); $uri = $uri->withFragment($fragment); @@ -423,7 +464,7 @@ class UriTest extends TestCase $this->assertSame($expected, $uri->getFragment()); } - public function fragmentProvider() + public function fragmentProvider(): array { return [ ['', null], @@ -435,8 +476,12 @@ class UriTest extends TestCase // ------------------------------------------------------------------------ // Concatenation - /** @dataProvider componentProvider */ - public function testConcatenatesComponents($expected, $components) + /** + * @dataProvider componentProvider + * @param string $expected + * @param array $components + */ + public function testConcatenatesComponents(string $expected, array $components): void { $uri = new Uri(); @@ -538,14 +583,18 @@ class UriTest extends TestCase ]; } - /** @dataProvider stringUriProvider */ - public function testUriCreatedFromStringNormalizesString($expected, $input) + /** + * @dataProvider stringUriProvider + * @param string $expected + * @param string $input + */ + public function testUriCreatedFromStringNormalizesString(string $expected, string $input): void { $uri = new Uri($input); $this->assertSame($expected, (string) $uri); } - public function stringUriProvider() + public function stringUriProvider(): array { return [ [ From 86490907746413f06893dad9880b953b0407d507 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 07:13:14 -0400 Subject: [PATCH 30/53] Fix visibility for setUp, tearDown to match PHPUnit base class --- test/tests/integration/RoutingTest.php | 2 +- test/tests/unit/Dispatching/DispatchStackTest.php | 2 +- test/tests/unit/Dispatching/DispatcherTest.php | 2 +- test/tests/unit/Message/UploadedFileTest.php | 4 ++-- test/tests/unit/Routing/Route/MethodMapTest.php | 2 +- test/tests/unit/Routing/Route/RegexRouteTest.php | 2 +- test/tests/unit/Routing/Route/RouteFactoryTest.php | 2 +- test/tests/unit/Routing/Route/RouteTest.php | 2 +- test/tests/unit/Routing/Route/TemplateRouteTest.php | 2 +- test/tests/unit/Routing/RouterTest.php | 2 +- test/tests/unit/ServerTest.php | 2 +- test/tests/unit/Transmission/TransmitterTest.php | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test/tests/integration/RoutingTest.php b/test/tests/integration/RoutingTest.php index cbc238c..4be0791 100644 --- a/test/tests/integration/RoutingTest.php +++ b/test/tests/integration/RoutingTest.php @@ -25,7 +25,7 @@ class RoutingTest extends TestCase /** @var ResponseInterface */ private $response; - public function setUp(): void + protected function setUp(): void { parent::setUp(); diff --git a/test/tests/unit/Dispatching/DispatchStackTest.php b/test/tests/unit/Dispatching/DispatchStackTest.php index 782dded..c473ae8 100644 --- a/test/tests/unit/Dispatching/DispatchStackTest.php +++ b/test/tests/unit/Dispatching/DispatchStackTest.php @@ -15,7 +15,7 @@ class DispatchStackTest extends TestCase private $response; private $next; - public function setUp(): void + protected function setUp(): void { parent::setUp(); $this->request = new ServerRequest(); diff --git a/test/tests/unit/Dispatching/DispatcherTest.php b/test/tests/unit/Dispatching/DispatcherTest.php index fd7e712..8fa2824 100644 --- a/test/tests/unit/Dispatching/DispatcherTest.php +++ b/test/tests/unit/Dispatching/DispatcherTest.php @@ -24,7 +24,7 @@ class DispatcherTest extends TestCase /** @var ResponseInterface */ private $stubResponse; - public function setUp(): void + protected function setUp(): void { $this->request = new ServerRequest(); $this->response = new Response(); diff --git a/test/tests/unit/Message/UploadedFileTest.php b/test/tests/unit/Message/UploadedFileTest.php index f38ab7d..e208e40 100644 --- a/test/tests/unit/Message/UploadedFileTest.php +++ b/test/tests/unit/Message/UploadedFileTest.php @@ -11,7 +11,7 @@ class UploadedFileTest extends TestCase private $tmpName; private $movePath; - public function setUp(): void + protected function setUp(): void { parent::setUp(); UploadedFileState::$php_sapi_name = 'cli'; @@ -19,7 +19,7 @@ class UploadedFileTest extends TestCase $this->movePath = tempnam(sys_get_temp_dir(), 'tst'); } - public function tearDown(): void + protected function tearDown(): void { parent::tearDown(); if (file_exists($this->tmpName)) { diff --git a/test/tests/unit/Routing/Route/MethodMapTest.php b/test/tests/unit/Routing/Route/MethodMapTest.php index 7e92756..ae9f1a7 100644 --- a/test/tests/unit/Routing/Route/MethodMapTest.php +++ b/test/tests/unit/Routing/Route/MethodMapTest.php @@ -18,7 +18,7 @@ class MethodMapTest extends TestCase private $next; private $middleware; - public function setUp(): void + protected function setUp(): void { $this->request = new ServerRequest(); $this->response = new Response(); diff --git a/test/tests/unit/Routing/Route/RegexRouteTest.php b/test/tests/unit/Routing/Route/RegexRouteTest.php index 88410b2..887738d 100644 --- a/test/tests/unit/Routing/Route/RegexRouteTest.php +++ b/test/tests/unit/Routing/Route/RegexRouteTest.php @@ -15,7 +15,7 @@ class RegexRouteTest extends TestCase private $methodMap; - public function setUp(): void + protected function setUp(): void { $this->methodMap = $this->prophesize(MethodMap::class); } diff --git a/test/tests/unit/Routing/Route/RouteFactoryTest.php b/test/tests/unit/Routing/Route/RouteFactoryTest.php index e7a18b2..1ec246d 100644 --- a/test/tests/unit/Routing/Route/RouteFactoryTest.php +++ b/test/tests/unit/Routing/Route/RouteFactoryTest.php @@ -14,7 +14,7 @@ class RouteFactoryTest extends TestCase private $dispatcher; - public function setUp(): void + protected function setUp(): void { $this->dispatcher = $this->prophesize(DispatcherInterface::class); } diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index 8c9af5d..f57bed4 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -20,7 +20,7 @@ class RouteTest extends TestCase private $methodMap; private $route; - public function setUp(): void + protected function setUp(): void { $this->methodMap = $this->prophesize(MethodMap::class); $this->methodMap->register(Argument::cetera()); diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index 37a63d5..b5a6af0 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -14,7 +14,7 @@ class TemplateRouteTest extends TestCase private $methodMap; - public function setUp(): void + protected function setUp(): void { $this->methodMap = $this->prophesize(MethodMap::class); } diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 5653fdf..c889ea0 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -26,7 +26,7 @@ class RouterTest extends TestCase private $router; private $next; - public function setUp(): void + protected function setUp(): void { parent::setUp(); diff --git a/test/tests/unit/ServerTest.php b/test/tests/unit/ServerTest.php index 6f42d49..030a44d 100644 --- a/test/tests/unit/ServerTest.php +++ b/test/tests/unit/ServerTest.php @@ -18,7 +18,7 @@ class ServerTest extends TestCase /** @var Server */ private $server; - public function setUp(): void + protected function setUp(): void { parent::setUp(); diff --git a/test/tests/unit/Transmission/TransmitterTest.php b/test/tests/unit/Transmission/TransmitterTest.php index 506c845..93810b1 100644 --- a/test/tests/unit/Transmission/TransmitterTest.php +++ b/test/tests/unit/Transmission/TransmitterTest.php @@ -22,7 +22,7 @@ class TransmitterTest extends TestCase private $response; private $body; - public function setUp(): void + protected function setUp(): void { HeaderStack::reset(); From 4796e1d5c5d5a19f42e74a4edd5548c532662ccf Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 07:26:19 -0400 Subject: [PATCH 31/53] Refactor Transmitter --- src/Transmission/Transmitter.php | 19 +++--- test/src/HeaderStack.php | 28 -------- .../unit/Transmission/TransmitterTest.php | 65 ++++++++++++++----- 3 files changed, 57 insertions(+), 55 deletions(-) delete mode 100644 test/src/HeaderStack.php diff --git a/src/Transmission/Transmitter.php b/src/Transmission/Transmitter.php index 768c458..451131b 100644 --- a/src/Transmission/Transmitter.php +++ b/src/Transmission/Transmitter.php @@ -53,25 +53,26 @@ class Transmitter implements TransmitterInterface $this->chunkSize = $chunkSize; } - protected function prepareResponse( + private function prepareResponse( ServerRequestInterface $request, ResponseInterface $response ): ResponseInterface { - // Add a Content-length header to the response when all of these are true: + // Add Content-length header to the response when all of these are true: // // - Response does not have a Content-length header // - Response does not have a Transfer-encoding: chunked header // - Response body stream is readable and reports a non-null size // - if (!$response->hasHeader('Content-length') - && !(strtolower($response->getHeaderLine('Transfer-encoding')) === 'chunked') - ) { - $size = $response->getBody()->getSize(); - if ($size !== null) { - $response = $response->withHeader('Content-length', (string) $size); - } + $contentLengthMissing = !$response->hasHeader('Content-length'); + $notChunked = strtolower($response->getHeaderLine('Transfer-encoding')) + !== 'chunked'; + $size = $response->getBody()->getSize(); + + if ($contentLengthMissing && $notChunked && $size !== null) { + $response = $response->withHeader('Content-length', (string) $size); } + return $response; } diff --git a/test/src/HeaderStack.php b/test/src/HeaderStack.php deleted file mode 100644 index 23e309f..0000000 --- a/test/src/HeaderStack.php +++ /dev/null @@ -1,28 +0,0 @@ -withBody($stream); } - public function testSendStatusCodeWithReasonPhrase() + public function testSendStatusCodeWithReasonPhrase(): void { $transmitter = new Transmitter(); $transmitter->transmit($this->request, $this->response); $this->assertContains('HTTP/1.1 200 OK', HeaderStack::getHeaders()); } - public function testSendStatusCodeWithoutReasonPhrase() + public function testSendStatusCodeWithoutReasonPhrase(): void { $this->response = $this->response->withStatus(999); @@ -56,8 +52,11 @@ class TransmitterTest extends TestCase $this->assertContains('HTTP/1.1 999', HeaderStack::getHeaders()); } - /** @dataProvider headerProvider */ - public function testSendsHeaders($header) + /** + * @dataProvider headerProvider + * @param string $header + */ + public function testSendsHeaders(string $header): void { $this->response = $this->response ->withHeader('Content-length', ['2048']) @@ -68,7 +67,7 @@ class TransmitterTest extends TestCase $this->assertContains($header, HeaderStack::getHeaders()); } - public function headerProvider() + public function headerProvider(): array { return [ ['Content-length: 2048'], @@ -77,7 +76,7 @@ class TransmitterTest extends TestCase ]; } - public function testOutputsBody() + public function testOutputsBody(): void { $content = 'Hello, world!'; @@ -95,7 +94,7 @@ class TransmitterTest extends TestCase $this->assertEquals($content, $captured); } - public function testOutputsBodyInChunks() + public function testOutputsBodyInChunks(): void { $content = 'Hello, world!'; $chunkSize = 3; @@ -128,7 +127,7 @@ class TransmitterTest extends TestCase $this->assertEquals($content, $captured); } - public function testOutputsUnseekableStreamInChunks() + public function testOutputsUnseekableStreamInChunks(): void { $content = 'Hello, world!'; $chunkSize = 3; @@ -164,7 +163,7 @@ class TransmitterTest extends TestCase // ------------------------------------------------------------------------ // Preparation - public function testAddContentLengthHeader() + public function testAddContentLengthHeader(): void { $bodySize = 1024; $this->body->isReadable()->willReturn(true); @@ -178,7 +177,7 @@ class TransmitterTest extends TestCase $this->assertContains("Content-length: $bodySize", HeaderStack::getHeaders()); } - public function testDoesNotReplaceContentLengthHeaderWhenContentLengthIsAlreadySet() + public function testDoesNotReplaceContentLengthHeaderWhenContentLengthIsAlreadySet(): void { $streamSize = 1024; $headerSize = 2048; @@ -196,7 +195,7 @@ class TransmitterTest extends TestCase $this->assertContains("Content-length: $headerSize", HeaderStack::getHeaders()); } - public function testDoesNotAddContentLengthHeaderWhenTransferEncodingIsChunked() + public function testDoesNotAddContentLengthHeaderWhenTransferEncodingIsChunked(): void { $bodySize = 1024; @@ -213,7 +212,7 @@ class TransmitterTest extends TestCase $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); } - public function testDoesNotAddContentLengthHeaderWhenBodySizeIsNull() + public function testDoesNotAddContentLengthHeaderWhenBodySizeIsNull(): void { $this->body->isReadable()->willReturn(true); $this->body->__toString()->willReturn(''); @@ -226,7 +225,7 @@ class TransmitterTest extends TestCase $this->assertArrayDoesNotContainValueWithPrefix(HeaderStack::getHeaders(), 'Content-length:'); } - private function assertArrayDoesNotContainValueWithPrefix($arr, $prefix) + private function assertArrayDoesNotContainValueWithPrefix(array $arr, string $prefix): void { $normalPrefix = strtolower($prefix); foreach ($arr as $item) { @@ -238,3 +237,33 @@ class TransmitterTest extends TestCase $this->assertTrue(true); } } + +// ----------------------------------------------------------------------------- + +// Declare header function in this namespace so the class under test will use +// this instead of the internal global functions during testing. + +class HeaderStack +{ + private static $headers; + + public static function reset() + { + self::$headers = []; + } + + public static function push($header) + { + self::$headers[] = $header; + } + + public static function getHeaders() + { + return self::$headers; + } +} + +function header($string, $dummy = true) +{ + HeaderStack::push($string); +} From 2d7db1ed837d52c410f8ab773c0d49c12b27c99e Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 07:36:30 -0400 Subject: [PATCH 32/53] Change visibility from protected to private where possible --- src/Dispatching/Dispatcher.php | 2 +- src/Server.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Dispatching/Dispatcher.php b/src/Dispatching/Dispatcher.php index f420c4f..fe0bcd1 100644 --- a/src/Dispatching/Dispatcher.php +++ b/src/Dispatching/Dispatcher.php @@ -71,7 +71,7 @@ class Dispatcher implements DispatcherInterface * @param mixed[] $dispatchables * @return DispatchStack */ - protected function getDispatchStack($dispatchables) + private function getDispatchStack($dispatchables) { $stack = new DispatchStack($this); foreach ($dispatchables as $dispatchable) { diff --git a/src/Server.php b/src/Server.php index c513e9d..85b00a8 100644 --- a/src/Server.php +++ b/src/Server.php @@ -15,7 +15,7 @@ use WellRESTed\Transmission\TransmitterInterface; class Server { /** @var mixed[] */ - protected $attributes = []; + private $attributes = []; /** @var DispatcherInterface */ private $dispatcher; /** @var string|null attribute name for matched path variables */ From f542aaf3a9971eff332a4a21d8b4cbe9d6ca77c3 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 13 Aug 2020 07:38:00 -0400 Subject: [PATCH 33/53] Normalize length of dividers --- src/Message/Message.php | 4 ++-- src/Message/Request.php | 6 +++--- src/Message/Response.php | 2 +- src/Message/ServerRequest.php | 6 +++--- src/Routing/Route/MethodMap.php | 8 ++++---- test/tests/unit/Message/MessageTest.php | 6 +++--- test/tests/unit/Message/RequestTest.php | 8 ++++---- test/tests/unit/Message/ResponseTest.php | 4 ++-- .../Message/ServerRequestMarshallerTest.php | 14 +++++++------- test/tests/unit/Message/ServerRequestTest.php | 12 ++++++------ test/tests/unit/Message/UriTest.php | 18 +++++++++--------- .../unit/Routing/Route/TemplateRouteTest.php | 14 +++++++------- test/tests/unit/Routing/RouterTest.php | 12 ++++++------ .../unit/Transmission/TransmitterTest.php | 2 +- 14 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/Message/Message.php b/src/Message/Message.php index cfe0581..c5f9758 100644 --- a/src/Message/Message.php +++ b/src/Message/Message.php @@ -57,7 +57,7 @@ abstract class Message implements MessageInterface $this->headers = clone $this->headers; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Psr\Http\Message\MessageInterface /** @@ -266,7 +266,7 @@ abstract class Message implements MessageInterface return $message; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- /** * @param mixed $name diff --git a/src/Message/Request.php b/src/Message/Request.php index 9e7feac..ca22f56 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -28,7 +28,7 @@ class Request extends Message implements RequestInterface /** @var UriInterface */ protected $uri; - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- /** * Create a new Request. @@ -67,7 +67,7 @@ class Request extends Message implements RequestInterface parent::__clone(); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Psr\Http\Message\RequestInterface /** @@ -214,7 +214,7 @@ class Request extends Message implements RequestInterface return $request; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- /** * @param mixed $method diff --git a/src/Message/Response.php b/src/Message/Response.php index 99a02c2..47572db 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -50,7 +50,7 @@ class Response extends Message implements ResponseInterface $this->reasonPhrase = $this->getDefaultReasonPhraseForStatusCode($statusCode); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Psr\Http\Message\ResponseInterface /** diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index fd81fcd..601499f 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -49,7 +49,7 @@ class ServerRequest extends Request implements ServerRequestInterface /** @var array */ private $uploadedFiles; - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- public function __construct(array $serverParams = []) { @@ -69,7 +69,7 @@ class ServerRequest extends Request implements ServerRequestInterface parent::__clone(); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Psr\Http\Message\ServerRequestInterface /** @@ -326,7 +326,7 @@ class ServerRequest extends Request implements ServerRequestInterface return $request; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- /** * @param array $root diff --git a/src/Routing/Route/MethodMap.php b/src/Routing/Route/MethodMap.php index 51014b7..a27d08e 100644 --- a/src/Routing/Route/MethodMap.php +++ b/src/Routing/Route/MethodMap.php @@ -13,7 +13,7 @@ class MethodMap /** @var array */ private $map; - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- public function __construct(DispatcherInterface $dispatcher) { @@ -21,7 +21,7 @@ class MethodMap $this->dispatcher = $dispatcher; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // MethodMapInterface /** @@ -50,7 +50,7 @@ class MethodMap } } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // MiddlewareInterface /** @@ -90,7 +90,7 @@ class MethodMap return $this->addAllowHeader($response); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- private function addAllowHeader(ResponseInterface $response): ResponseInterface { diff --git a/test/tests/unit/Message/MessageTest.php b/test/tests/unit/Message/MessageTest.php index 03c9c62..11d5565 100644 --- a/test/tests/unit/Message/MessageTest.php +++ b/test/tests/unit/Message/MessageTest.php @@ -34,7 +34,7 @@ class MessageTest extends TestCase ); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Protocol Version public function testGetProtocolVersionReturnsProtocolVersion1Point1ByDefault(): void @@ -57,7 +57,7 @@ class MessageTest extends TestCase $this->assertEquals('1.0', $message->getProtocolVersion()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Headers /** @@ -223,7 +223,7 @@ class MessageTest extends TestCase $this->assertEquals($expected, $headers); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Body public function testGetBodyReturnsEmptyStreamByDefault(): void diff --git a/test/tests/unit/Message/RequestTest.php b/test/tests/unit/Message/RequestTest.php index 3474a40..db17647 100644 --- a/test/tests/unit/Message/RequestTest.php +++ b/test/tests/unit/Message/RequestTest.php @@ -7,7 +7,7 @@ use WellRESTed\Test\TestCase; class RequestTest extends TestCase { - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Construction public function testCreatesInstanceWithNoParameters(): void @@ -52,7 +52,7 @@ class RequestTest extends TestCase $this->assertSame($body, $request->getBody()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Request Target public function testGetRequestTargetPrefersExplicitRequestTarget(): void @@ -83,7 +83,7 @@ class RequestTest extends TestCase $this->assertEquals('*', $request->getRequestTarget()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Method public function testGetMethodReturnsGetByDefault(): void @@ -119,7 +119,7 @@ class RequestTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Request URI public function testGetUriReturnsEmptyUriByDefault(): void diff --git a/test/tests/unit/Message/ResponseTest.php b/test/tests/unit/Message/ResponseTest.php index 57b4e35..f02973f 100644 --- a/test/tests/unit/Message/ResponseTest.php +++ b/test/tests/unit/Message/ResponseTest.php @@ -6,7 +6,7 @@ use WellRESTed\Test\TestCase; class ResponseTest extends TestCase { - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Construction public function testSetsStatusCodeOnConstruction(): void @@ -30,7 +30,7 @@ class ResponseTest extends TestCase $this->assertSame($body, $response->getBody()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Status and Reason Phrase public function testCreatesNewInstanceWithStatusCode(): void diff --git a/test/tests/unit/Message/ServerRequestMarshallerTest.php b/test/tests/unit/Message/ServerRequestMarshallerTest.php index dddedb7..c579371 100644 --- a/test/tests/unit/Message/ServerRequestMarshallerTest.php +++ b/test/tests/unit/Message/ServerRequestMarshallerTest.php @@ -120,7 +120,7 @@ class ServerRequestMarshallerTest extends TestCase // ------------------------------------------------------------------------- // Psr\Http\Message\RequestInterface - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Request Target /** @@ -145,7 +145,7 @@ class ServerRequestMarshallerTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Method /** @@ -172,7 +172,7 @@ class ServerRequestMarshallerTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // URI /** @@ -231,7 +231,7 @@ class ServerRequestMarshallerTest extends TestCase $this->assertEquals($_SERVER, $request->getServerParams()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Cookies public function testProvidesCookieParams(): void @@ -240,7 +240,7 @@ class ServerRequestMarshallerTest extends TestCase $this->assertEquals($_COOKIE, $request->getCookieParams()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Query public function testProvidesQueryParams(): void @@ -252,7 +252,7 @@ class ServerRequestMarshallerTest extends TestCase $this->assertEquals('aggie', $query['kitten']); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Uploaded Files /** @@ -354,7 +354,7 @@ class ServerRequestMarshallerTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Parsed Body /** diff --git a/test/tests/unit/Message/ServerRequestTest.php b/test/tests/unit/Message/ServerRequestTest.php index 10fcc60..b0dc3fe 100644 --- a/test/tests/unit/Message/ServerRequestTest.php +++ b/test/tests/unit/Message/ServerRequestTest.php @@ -7,7 +7,7 @@ use WellRESTed\Test\TestCase; class ServerRequestTest extends TestCase { - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Server Params public function testGetServerParamsReturnsEmptyArrayByDefault(): void @@ -16,7 +16,7 @@ class ServerRequestTest extends TestCase $this->assertEquals([], $request->getServerParams()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Cookies public function testGetCookieParamsReturnsEmptyArrayByDefault(): void @@ -38,7 +38,7 @@ class ServerRequestTest extends TestCase $this->assertNotSame($request2, $request1); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Query public function testGetQueryParamsReturnsEmptyArrayByDefault(): void @@ -60,7 +60,7 @@ class ServerRequestTest extends TestCase $this->assertNotSame($request2, $request1); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Uploaded Files public function testGetUploadedFilesReturnsEmptyArrayByDefault(): void @@ -186,7 +186,7 @@ class ServerRequestTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Parsed Body public function testGetParsedBodyReturnsNullByDefault(): void @@ -243,7 +243,7 @@ class ServerRequestTest extends TestCase ); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Attributes public function testGetAttributesReturnsEmptyArrayByDefault(): void diff --git a/test/tests/unit/Message/UriTest.php b/test/tests/unit/Message/UriTest.php index 57c9dbd..5d51fb8 100644 --- a/test/tests/unit/Message/UriTest.php +++ b/test/tests/unit/Message/UriTest.php @@ -7,7 +7,7 @@ use WellRESTed\Test\TestCase; class UriTest extends TestCase { - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Scheme public function testDefaultSchemeIsEmpty(): void @@ -43,7 +43,7 @@ class UriTest extends TestCase $uri->withScheme('gopher'); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Authority public function testDefaultAuthorityIsEmpty(): void @@ -168,7 +168,7 @@ class UriTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // User Info public function testDefaultUserInfoIsEmpty(): void @@ -202,7 +202,7 @@ class UriTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Host public function testDefaultHostIsEmpty(): void @@ -253,7 +253,7 @@ class UriTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Port public function testDefaultPortWithNoSchemeIsNull(): void @@ -320,7 +320,7 @@ class UriTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Path public function testDefaultPathIsEmpty(): void @@ -367,7 +367,7 @@ class UriTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Query public function testDefaultQueryIsEmpty(): void @@ -430,7 +430,7 @@ class UriTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Fragment public function testDefaultFragmentIsEmpty(): void @@ -473,7 +473,7 @@ class UriTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Concatenation /** diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index b5a6af0..8d87bce 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -43,7 +43,7 @@ class TemplateRouteTest extends TestCase $this->assertEquals($expected, $actual); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- public function testReturnsPatternType() { @@ -51,7 +51,7 @@ class TemplateRouteTest extends TestCase $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Matching /** @dataProvider nonMatchingTargetProvider */ @@ -71,7 +71,7 @@ class TemplateRouteTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Matching :: Simple Strings /** @dataProvider simpleStringProvider */ @@ -100,7 +100,7 @@ class TemplateRouteTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Matching :: Reserved /** @dataProvider reservedStringProvider */ @@ -127,7 +127,7 @@ class TemplateRouteTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Matching :: Label Expansion /** @dataProvider labelWithDotPrefixProvider */ @@ -154,7 +154,7 @@ class TemplateRouteTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Matching :: Path Segments /** @dataProvider pathSegmentProvider */ @@ -181,7 +181,7 @@ class TemplateRouteTest extends TestCase ]; } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Matching :: Explosion /** @dataProvider pathExplosionProvider */ diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index c889ea0..58e5355 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -50,7 +50,7 @@ class RouterTest extends TestCase $this->next = new NextMock(); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Construction public function testCreatesInstance() @@ -59,7 +59,7 @@ class RouterTest extends TestCase $this->assertNotNull($router); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Populating public function testCreatesRouteForTarget() @@ -84,7 +84,7 @@ class RouterTest extends TestCase $this->route->register('GET', 'middleware')->shouldHaveBeenCalled(); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Dispatching public function testDispatchesStaticRoute() @@ -295,7 +295,7 @@ class RouterTest extends TestCase $this->route->matchesRequestTarget('/my/path')->shouldHaveBeenCalled(); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Path Variables /** @dataProvider pathVariableProvider */ @@ -366,7 +366,7 @@ class RouterTest extends TestCase )->shouldHaveBeenCalled(); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // No Match public function testWhenNoRouteMatchesByDefaultResponds404() @@ -391,7 +391,7 @@ class RouterTest extends TestCase $this->assertTrue($this->next->called); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Middleware for Routes public function testCallsRouterMiddlewareBeforeRouteMiddleware() diff --git a/test/tests/unit/Transmission/TransmitterTest.php b/test/tests/unit/Transmission/TransmitterTest.php index a757bee..ad1d45d 100644 --- a/test/tests/unit/Transmission/TransmitterTest.php +++ b/test/tests/unit/Transmission/TransmitterTest.php @@ -160,7 +160,7 @@ class TransmitterTest extends TestCase $this->assertEquals($content, $captured); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------- // Preparation public function testAddContentLengthHeader(): void From 288705b77adfa59cd7b7ea2b8dc2fb419dd08cd6 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 06:31:09 -0400 Subject: [PATCH 34/53] Edit comments for Dispatch namespace and clean up tests --- src/Dispatching/DispatchStack.php | 5 +--- src/Dispatching/Dispatcher.php | 6 ++-- src/Dispatching/DispatcherInterface.php | 4 +-- .../unit/Dispatching/DispatchStackTest.php | 12 ++++---- .../tests/unit/Dispatching/DispatcherTest.php | 28 +++++++++---------- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/Dispatching/DispatchStack.php b/src/Dispatching/DispatchStack.php index e7d9b56..67b652f 100644 --- a/src/Dispatching/DispatchStack.php +++ b/src/Dispatching/DispatchStack.php @@ -15,9 +15,6 @@ class DispatchStack implements DispatchStackInterface /** @var DispatcherInterface */ private $dispatcher; - /** - * @param DispatcherInterface $dispatcher - */ public function __construct(DispatcherInterface $dispatcher) { $this->dispatcher = $dispatcher; @@ -42,7 +39,7 @@ class DispatchStack implements DispatchStackInterface * The first middleware that was added is dispatched first. * * Each middleware, when dispatched, receives a $next callable that, when - * called, will dispatch the next middleware in the sequence. + * called, will dispatch the following middleware in the sequence. * * When the stack is dispatched empty, or when all middleware in the stack * call the $next argument they were passed, this method will call the diff --git a/src/Dispatching/Dispatcher.php b/src/Dispatching/Dispatcher.php index fe0bcd1..c806589 100644 --- a/src/Dispatching/Dispatcher.php +++ b/src/Dispatching/Dispatcher.php @@ -8,12 +8,12 @@ use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; /** - * Dispatches handlers and middleware + * Runs a handler or middleware with a request and return the response. */ class Dispatcher implements DispatcherInterface { /** - * Dispatch a handler or middleware and return the response. + * Run a handler or middleware with a request and return the response. * * Dispatcher can dispatch any of the following: * - An instance implementing one of these interfaces: @@ -63,7 +63,7 @@ class Dispatcher implements DispatcherInterface } elseif ($dispatchable instanceof ResponseInterface) { return $dispatchable; } else { - throw new DispatchException('Unable to dispatch middleware.'); + throw new DispatchException('Unable to dispatch handler.'); } } diff --git a/src/Dispatching/DispatcherInterface.php b/src/Dispatching/DispatcherInterface.php index 7be31af..501da5e 100644 --- a/src/Dispatching/DispatcherInterface.php +++ b/src/Dispatching/DispatcherInterface.php @@ -6,12 +6,12 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Dispatches handlers and middleware + * Runs a handler or middleware with a request and return the response. */ interface DispatcherInterface { /** - * Dispatch a handler or middleware and return the response. + * Run a handler or middleware with a request and return the response. * * Dispatchables (middleware and handlers) comes in a number of varieties * (e.g., instance, string, callable). DispatcherInterface interface unpacks diff --git a/test/tests/unit/Dispatching/DispatchStackTest.php b/test/tests/unit/Dispatching/DispatchStackTest.php index c473ae8..9264f2b 100644 --- a/test/tests/unit/Dispatching/DispatchStackTest.php +++ b/test/tests/unit/Dispatching/DispatchStackTest.php @@ -1,9 +1,7 @@ next = new NextMock(); } - public function testDispatchesMiddlewareInOrderAdded() + public function testDispatchesMiddlewareInOrderAdded(): void { // Each middleware will add its "name" to this array. $callOrder = []; @@ -44,14 +42,14 @@ class DispatchStackTest extends TestCase $this->assertEquals(['first', 'second', 'third'], $callOrder); } - public function testCallsNextAfterDispatchingEmptyStack() + public function testCallsNextAfterDispatchingEmptyStack(): void { $stack = new DispatchStack(new Dispatcher()); $stack($this->request, $this->response, $this->next); $this->assertTrue($this->next->called); } - public function testCallsNextAfterDispatchingStack() + public function testCallsNextAfterDispatchingStack(): void { $middleware = function ($request, $response, $next) use (&$callOrder) { return $next($request, $response); @@ -66,7 +64,7 @@ class DispatchStackTest extends TestCase $this->assertTrue($this->next->called); } - public function testDoesNotCallNextWhenStackStopsEarly() + public function testDoesNotCallNextWhenStackStopsEarly(): void { $middlewareGo = function ($request, $response, $next) use (&$callOrder) { return $next($request, $response); diff --git a/test/tests/unit/Dispatching/DispatcherTest.php b/test/tests/unit/Dispatching/DispatcherTest.php index 8fa2824..159bc51 100644 --- a/test/tests/unit/Dispatching/DispatcherTest.php +++ b/test/tests/unit/Dispatching/DispatcherTest.php @@ -1,12 +1,10 @@ stubResponse); $response = $this->dispatch($handler); $this->assertSame($this->stubResponse, $response); } - public function testDispatchesPsr15HandlerFromFactory() + public function testDispatchesPsr15HandlerFromFactory(): void { $factory = function () { return new HandlerDouble($this->stubResponse); @@ -70,7 +70,7 @@ class DispatcherTest extends TestCase // ------------------------------------------------------------------------- // PSR-15 Middleware - public function testDispatchesPsr15MiddlewareWithDelegate() + public function testDispatchesPsr15MiddlewareWithDelegate(): void { $this->next->upstreamResponse = $this->stubResponse; $middleware = new MiddlewareDouble(); @@ -79,7 +79,7 @@ class DispatcherTest extends TestCase $this->assertSame($this->stubResponse, $response); } - public function testDispatchesPsr15MiddlewareFromFactoryWithDelegate() + public function testDispatchesPsr15MiddlewareFromFactoryWithDelegate(): void { $this->next->upstreamResponse = $this->stubResponse; $factory = function () { @@ -93,7 +93,7 @@ class DispatcherTest extends TestCase // ------------------------------------------------------------------------- // Double-Pass Middleware Callable - public function testDispatchesDoublePassMiddlewareCallable() + public function testDispatchesDoublePassMiddlewareCallable(): void { $doublePass = function ($request, $response, $next) { return $next($request, $this->stubResponse); @@ -103,7 +103,7 @@ class DispatcherTest extends TestCase $this->assertSame($this->stubResponse, $response); } - public function testDispatchesDoublePassMiddlewareCallableFromFactory() + public function testDispatchesDoublePassMiddlewareCallableFromFactory(): void { $factory = function () { return function ($request, $response, $next) { @@ -118,14 +118,14 @@ class DispatcherTest extends TestCase // ------------------------------------------------------------------------- // Double-Pass Middleware Instance - public function testDispatchesDoublePassMiddlewareInstance() + public function testDispatchesDoublePassMiddlewareInstance(): void { $doublePass = new DoublePassMiddlewareDouble(); $response = $this->dispatch($doublePass); $this->assertEquals(200, $response->getStatusCode()); } - public function testDispatchesDoublePassMiddlewareInstanceFromFactory() + public function testDispatchesDoublePassMiddlewareInstanceFromFactory(): void { $factory = function () { return new DoublePassMiddlewareDouble(); @@ -137,7 +137,7 @@ class DispatcherTest extends TestCase // ------------------------------------------------------------------------- // String - public function testDispatchesInstanceFromStringName() + public function testDispatchesInstanceFromStringName(): void { $response = $this->dispatch(DoublePassMiddlewareDouble::class); $this->assertEquals(200, $response->getStatusCode()); @@ -146,14 +146,14 @@ class DispatcherTest extends TestCase // ------------------------------------------------------------------------- // Arrays - public function testDispatchesArrayAsDispatchStack() + public function testDispatchesArrayAsDispatchStack(): void { $doublePass = new DoublePassMiddlewareDouble(); $response = $this->dispatch([$doublePass]); $this->assertEquals(200, $response->getStatusCode()); } - public function testThrowsExceptionWhenUnableToDispatch() + public function testThrowsExceptionWhenUnableToDispatch(): void { $this->expectException(DispatchException::class); $this->dispatch(null); From c75168afae4f4f5b4cf18225dc619ff148390c13 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 06:57:13 -0400 Subject: [PATCH 35/53] Stop tracking .env and set default in docker-compose.yml --- .env | 1 - .gitignore | 6 +++++- docker-compose.yml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 25241b7..0000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -PORT=8080 diff --git a/.gitignore b/.gitignore index a4a4c4c..fe38263 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,8 @@ preview workspace.xml # Local scratch files -notes \ No newline at end of file +notes + +# Local overrides +.env +docker-compose.override.yml \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 453612a..97e3292 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,7 +21,7 @@ services: nginx: image: nginx:1.15 ports: - - ${PORT}:80 + - ${PORT:-8080}:80 volumes: - .:/usr/local/src/wellrested - ./docker/nginx/site.conf:/etc/nginx/conf.d/default.conf From 4eec56b5826ec07636c7fb173a2b36abc0484221 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 07:00:50 -0400 Subject: [PATCH 36/53] Mark Routing\Route classes as @internal --- src/Routing/Route/MethodMap.php | 13 ++--- src/Routing/Route/PrefixRoute.php | 3 ++ src/Routing/Route/RegexRoute.php | 3 ++ src/Routing/Route/Route.php | 8 +++ src/Routing/Route/RouteFactory.php | 2 +- src/Routing/Route/RouteFactoryInterface.php | 3 ++ src/Routing/Route/RouteInterface.php | 13 +++-- src/Routing/Route/StaticRoute.php | 3 ++ src/Routing/Route/TemplateRoute.php | 3 ++ .../unit/Routing/Route/MethodMapTest.php | 50 ++++++++++--------- .../unit/Routing/Route/PrefixRouteTest.php | 17 +++---- 11 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/Routing/Route/MethodMap.php b/src/Routing/Route/MethodMap.php index a27d08e..9fa746d 100644 --- a/src/Routing/Route/MethodMap.php +++ b/src/Routing/Route/MethodMap.php @@ -5,8 +5,12 @@ namespace WellRESTed\Routing\Route; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use WellRESTed\Dispatching\DispatcherInterface; +use WellRESTed\MiddlewareInterface; -class MethodMap +/** + * @internal + */ +class MethodMap implements MiddlewareInterface { /** @var DispatcherInterface */ private $dispatcher; @@ -21,11 +25,8 @@ class MethodMap $this->dispatcher = $dispatcher; } - // ------------------------------------------------------------------------- - // MethodMapInterface - /** - * Register a dispatchable (handler or middleware) with a method. + * Register a dispatchable (e.g.m handler or middleware) with a method. * * $method may be: * - A single verb ("GET"), @@ -41,7 +42,7 @@ class MethodMap * @param string $method * @param mixed $dispatchable */ - public function register($method, $dispatchable): void + public function register(string $method, $dispatchable): void { $methods = explode(',', $method); $methods = array_map('trim', $methods); diff --git a/src/Routing/Route/PrefixRoute.php b/src/Routing/Route/PrefixRoute.php index 75efd99..c958f8b 100644 --- a/src/Routing/Route/PrefixRoute.php +++ b/src/Routing/Route/PrefixRoute.php @@ -2,6 +2,9 @@ namespace WellRESTed\Routing\Route; +/** + * @internal + */ class PrefixRoute extends Route { public function __construct(string $target, MethodMap $methodMap) diff --git a/src/Routing/Route/RegexRoute.php b/src/Routing/Route/RegexRoute.php index 8e2a046..536c3d6 100644 --- a/src/Routing/Route/RegexRoute.php +++ b/src/Routing/Route/RegexRoute.php @@ -4,6 +4,9 @@ namespace WellRESTed\Routing\Route; use RuntimeException; +/** + * @internal + */ class RegexRoute extends Route { /** @var array */ diff --git a/src/Routing/Route/Route.php b/src/Routing/Route/Route.php index 0ba21ce..c62b1b2 100644 --- a/src/Routing/Route/Route.php +++ b/src/Routing/Route/Route.php @@ -5,6 +5,9 @@ namespace WellRESTed\Routing\Route; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +/** + * @internal + */ abstract class Route implements RouteInterface { /** @var string */ @@ -18,6 +21,11 @@ abstract class Route implements RouteInterface $this->methodMap = $methodMap; } + /** + * Path, partial path, or pattern to match request paths against. + * + * @return string + */ public function getTarget(): string { return $this->target; diff --git a/src/Routing/Route/RouteFactory.php b/src/Routing/Route/RouteFactory.php index 6007e44..1e16e94 100644 --- a/src/Routing/Route/RouteFactory.php +++ b/src/Routing/Route/RouteFactory.php @@ -5,7 +5,7 @@ namespace WellRESTed\Routing\Route; use WellRESTed\Dispatching\DispatcherInterface; /** - * Class for creating routes + * @internal */ class RouteFactory implements RouteFactoryInterface { diff --git a/src/Routing/Route/RouteFactoryInterface.php b/src/Routing/Route/RouteFactoryInterface.php index 829b806..c169682 100644 --- a/src/Routing/Route/RouteFactoryInterface.php +++ b/src/Routing/Route/RouteFactoryInterface.php @@ -2,6 +2,9 @@ namespace WellRESTed\Routing\Route; +/** + * @internal + */ interface RouteFactoryInterface { /** diff --git a/src/Routing/Route/RouteInterface.php b/src/Routing/Route/RouteInterface.php index 8eaa017..850a6c5 100644 --- a/src/Routing/Route/RouteInterface.php +++ b/src/Routing/Route/RouteInterface.php @@ -4,19 +4,24 @@ namespace WellRESTed\Routing\Route; use WellRESTed\MiddlewareInterface; +/** + * @internal + */ interface RouteInterface extends MiddlewareInterface { - /** Matches when path is an exact match only */ + /** Matches when request path is an exact match to entire target */ const TYPE_STATIC = 0; - /** Matches when path has the expected beginning */ + /** Matches when request path is an exact match to start of target */ const TYPE_PREFIX = 1; - /** Matches by pattern. Use matchesRequestTarget to test for matches */ + /** Matches by request path by pattern and may extract matched varialbes */ const TYPE_PATTERN = 2; /** + * Path, partial path, or pattern to match request paths against. + * * @return string */ - public function getTarget(); + public function getTarget(): string; /** * Return the RouteInterface::TYPE_ constants that identifies the type. diff --git a/src/Routing/Route/StaticRoute.php b/src/Routing/Route/StaticRoute.php index 6cf9d77..79f6c11 100644 --- a/src/Routing/Route/StaticRoute.php +++ b/src/Routing/Route/StaticRoute.php @@ -2,6 +2,9 @@ namespace WellRESTed\Routing\Route; +/** + * @internal + */ class StaticRoute extends Route { public function getType(): int diff --git a/src/Routing/Route/TemplateRoute.php b/src/Routing/Route/TemplateRoute.php index df2f99c..13f99f8 100644 --- a/src/Routing/Route/TemplateRoute.php +++ b/src/Routing/Route/TemplateRoute.php @@ -2,6 +2,9 @@ namespace WellRESTed\Routing\Route; +/** + * @internal + */ class TemplateRoute extends Route { /** @var array */ diff --git a/test/tests/unit/Routing/Route/MethodMapTest.php b/test/tests/unit/Routing/Route/MethodMapTest.php index ae9f1a7..a94aadc 100644 --- a/test/tests/unit/Routing/Route/MethodMapTest.php +++ b/test/tests/unit/Routing/Route/MethodMapTest.php @@ -1,11 +1,10 @@ dispatcher = new Dispatcher(); } - private function getMethodMap() + private function getMethodMap(): MethodMap { return new MethodMap($this->dispatcher); } // ------------------------------------------------------------------------- - public function testDispatchesMiddlewareWithMatchingMethod() + public function testDispatchesMiddlewareWithMatchingMethod(): void { $this->request = $this->request->withMethod('GET'); @@ -45,7 +44,7 @@ class MethodMapTest extends TestCase $this->assertTrue($this->middleware->called); } - public function testTreatsMethodNamesCaseSensitively() + public function testTreatsMethodNamesCaseSensitively(): void { $this->request = $this->request->withMethod('get'); @@ -60,7 +59,7 @@ class MethodMapTest extends TestCase $this->assertTrue($middlewareLower->called); } - public function testDispatchesWildcardMiddlewareWithNonMatchingMethod() + public function testDispatchesWildcardMiddlewareWithNonMatchingMethod(): void { $this->request = $this->request->withMethod('GET'); @@ -71,7 +70,7 @@ class MethodMapTest extends TestCase $this->assertTrue($this->middleware->called); } - public function testDispatchesGetMiddlewareForHeadByDefault() + public function testDispatchesGetMiddlewareForHeadByDefault(): void { $this->request = $this->request->withMethod('HEAD'); @@ -82,7 +81,7 @@ class MethodMapTest extends TestCase $this->assertTrue($this->middleware->called); } - public function testRegistersMiddlewareForMultipleMethods() + public function testRegistersMiddlewareForMultipleMethods(): void { $map = $this->getMethodMap(); $map->register('GET,POST', $this->middleware); @@ -96,7 +95,7 @@ class MethodMapTest extends TestCase $this->assertEquals(2, $this->middleware->callCount); } - public function testSettingNullDeregistersMiddleware() + public function testSettingNullUnregistersMiddleware(): void { $this->request = $this->request->withMethod('POST'); @@ -108,7 +107,7 @@ class MethodMapTest extends TestCase $this->assertEquals(405, $response->getStatusCode()); } - public function testSetsStatusTo200ForOptions() + public function testSetsStatusTo200ForOptions(): void { $this->request = $this->request->withMethod('OPTIONS'); @@ -119,7 +118,7 @@ class MethodMapTest extends TestCase $this->assertEquals(200, $response->getStatusCode()); } - public function testStopsPropagatingAfterOptions() + public function testStopsPropagatingAfterOptions(): void { $this->request = $this->request->withMethod('OPTIONS'); @@ -130,8 +129,12 @@ class MethodMapTest extends TestCase $this->assertFalse($this->next->called); } - /** @dataProvider allowedMethodProvider */ - public function testSetsAllowHeaderForOptions($methodsDeclared, $methodsAllowed) + /** + * @dataProvider allowedMethodProvider + * @param string[] $methodsDeclared + * @param string[] $methodsAllowed + */ + public function testSetsAllowHeaderForOptions(array $methodsDeclared, array $methodsAllowed): void { $this->request = $this->request->withMethod('OPTIONS'); @@ -144,8 +147,7 @@ class MethodMapTest extends TestCase $this->assertContainsEach($methodsAllowed, $response->getHeaderLine('Allow')); } - /** @dataProvider allowedMethodProvider */ - public function testSetsStatusTo405ForBadMethod() + public function testSetsStatusTo405ForBadMethod(): void { $this->request = $this->request->withMethod('POST'); @@ -156,11 +158,7 @@ class MethodMapTest extends TestCase $this->assertEquals(405, $response->getStatusCode()); } - /** - * @coversNothing - * @dataProvider allowedMethodProvider - */ - public function testStopsPropagatingAfterBadMethod() + public function testStopsPropagatingAfterBadMethod(): void { $this->request = $this->request->withMethod('POST'); @@ -170,8 +168,12 @@ class MethodMapTest extends TestCase $this->assertFalse($this->next->called); } - /** @dataProvider allowedMethodProvider */ - public function testSetsAllowHeaderForBadMethod($methodsDeclared, $methodsAllowed) + /** + * @dataProvider allowedMethodProvider + * @param string[] $methodsDeclared + * @param string[] $methodsAllowed + */ + public function testSetsAllowHeaderForBadMethod(array $methodsDeclared, array $methodsAllowed): void { $this->request = $this->request->withMethod('BAD'); @@ -184,7 +186,7 @@ class MethodMapTest extends TestCase $this->assertContainsEach($methodsAllowed, $response->getHeaderLine('Allow')); } - public function allowedMethodProvider() + public function allowedMethodProvider(): array { return [ [['GET'], ['GET', 'HEAD', 'OPTIONS']], @@ -195,7 +197,7 @@ class MethodMapTest extends TestCase ]; } - private function assertContainsEach($expectedList, $actual) + private function assertContainsEach($expectedList, $actual): void { foreach ($expectedList as $expected) { if (strpos($actual, $expected) === false) { diff --git a/test/tests/unit/Routing/Route/PrefixRouteTest.php b/test/tests/unit/Routing/Route/PrefixRouteTest.php index dad929e..2af3d19 100644 --- a/test/tests/unit/Routing/Route/PrefixRouteTest.php +++ b/test/tests/unit/Routing/Route/PrefixRouteTest.php @@ -1,53 +1,50 @@ prophesize(MethodMap::class); $route = new PrefixRoute('/cats/*', $methodMap->reveal()); $this->assertEquals('/cats/', $route->getTarget()); } - public function testReturnsPrefixType() + public function testReturnsPrefixType(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new PrefixRoute('/*', $methodMap->reveal()); $this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType()); } - public function testReturnsEmptyArrayForPathVariables() + public function testReturnsEmptyArrayForPathVariables(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new PrefixRoute('/*', $methodMap->reveal()); $this->assertSame([], $route->getPathVariables()); } - public function testMatchesExactRequestTarget() + public function testMatchesExactRequestTarget(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new PrefixRoute('/*', $methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget('/')); } - public function testMatchesRequestTargetWithSamePrefix() + public function testMatchesRequestTargetWithSamePrefix(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new PrefixRoute('/*', $methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget('/cats/')); } - public function testDoesNotMatchNonmatchingRequestTarget() + public function testDoesNotMatchNonMatchingRequestTarget(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new PrefixRoute('/animals/cats/', $methodMap->reveal()); From fec5a4d4051082d134c6c60776906dbeb0968197 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 07:24:00 -0400 Subject: [PATCH 37/53] Remove RouteInterface --- src/Routing/Route/PrefixRoute.php | 2 +- src/Routing/Route/RegexRoute.php | 2 +- src/Routing/Route/Route.php | 56 ++++++++++++- src/Routing/Route/RouteFactory.php | 2 +- src/Routing/Route/RouteFactoryInterface.php | 2 +- src/Routing/Route/RouteInterface.php | 80 ------------------- src/Routing/Route/StaticRoute.php | 2 +- src/Routing/Route/TemplateRoute.php | 2 +- src/Routing/Router.php | 24 +++--- .../unit/Routing/Route/PrefixRouteTest.php | 2 +- .../unit/Routing/Route/RegexRouteTest.php | 7 +- .../unit/Routing/Route/RouteFactoryTest.php | 12 ++- test/tests/unit/Routing/Route/RouteTest.php | 10 +-- .../unit/Routing/Route/StaticRouteTest.php | 7 +- .../unit/Routing/Route/TemplateRouteTest.php | 7 +- test/tests/unit/Routing/RouterTest.php | 61 +++++++------- 16 files changed, 119 insertions(+), 159 deletions(-) delete mode 100644 src/Routing/Route/RouteInterface.php diff --git a/src/Routing/Route/PrefixRoute.php b/src/Routing/Route/PrefixRoute.php index c958f8b..5aeb865 100644 --- a/src/Routing/Route/PrefixRoute.php +++ b/src/Routing/Route/PrefixRoute.php @@ -14,7 +14,7 @@ class PrefixRoute extends Route public function getType(): int { - return RouteInterface::TYPE_PREFIX; + return Route::TYPE_PREFIX; } /** diff --git a/src/Routing/Route/RegexRoute.php b/src/Routing/Route/RegexRoute.php index 536c3d6..de8d6b6 100644 --- a/src/Routing/Route/RegexRoute.php +++ b/src/Routing/Route/RegexRoute.php @@ -14,7 +14,7 @@ class RegexRoute extends Route public function getType(): int { - return RouteInterface::TYPE_PATTERN; + return Route::TYPE_PATTERN; } /** diff --git a/src/Routing/Route/Route.php b/src/Routing/Route/Route.php index c62b1b2..634c3e9 100644 --- a/src/Routing/Route/Route.php +++ b/src/Routing/Route/Route.php @@ -4,12 +4,21 @@ namespace WellRESTed\Routing\Route; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use RuntimeException; +use WellRESTed\MiddlewareInterface; /** * @internal */ -abstract class Route implements RouteInterface +abstract class Route implements MiddlewareInterface { + /** Matches when request path is an exact match to entire target */ + public const TYPE_STATIC = 0; + /** Matches when request path is an exact match to start of target */ + public const TYPE_PREFIX = 1; + /** Matches by request path by pattern and may extract matched varialbes */ + public const TYPE_PATTERN = 2; + /** @var string */ protected $target; /** @var MethodMap */ @@ -21,6 +30,45 @@ abstract class Route implements RouteInterface $this->methodMap = $methodMap; } + /** + * Return the Route::TYPE_ constants that identifies the type. + * + * TYPE_STATIC indicates the route MUST match only when the path is an + * exact match to the route's entire target. This route type SHOULD NOT + * provide path variables. + * + * TYPE_PREFIX indicates the route MUST match when the route's target + * appears in its entirety at the beginning of the path. + * + * TYPE_PATTERN indicates that matchesRequestTarget MUST be used + * to determine a match against a given path. This route type SHOULD + * provide path variables. + * + * @return int One of the Route::TYPE_ constants. + */ + abstract public function getType(): int; + + /** + * Return an array of variables extracted from the path most recently + * passed to matchesRequestTarget. + * + * If the path does not contain variables, or if matchesRequestTarget + * has not yet been called, this method MUST return an empty array. + * + * @return array + */ + abstract public function getPathVariables(): array; + + /** + * Examines a request target to see if it is a match for the route. + * + * @param string $requestTarget + * @return bool + * @throws RuntimeException Error occurred testing the target such as an + * invalid regular expression + */ + abstract public function matchesRequestTarget(string $requestTarget): bool; + /** * Path, partial path, or pattern to match request paths against. * @@ -50,6 +98,12 @@ abstract class Route implements RouteInterface $this->methodMap->register($method, $dispatchable); } + /** + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @param callable $next + * @return ResponseInterface + */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next) { $map = $this->methodMap; diff --git a/src/Routing/Route/RouteFactory.php b/src/Routing/Route/RouteFactory.php index 1e16e94..d0beb03 100644 --- a/src/Routing/Route/RouteFactory.php +++ b/src/Routing/Route/RouteFactory.php @@ -25,7 +25,7 @@ class RouteFactory implements RouteFactoryInterface * - Regular expressions will create RegexRoutes * * @param string $target Route target or target pattern - * @return RouteInterface + * @return Route */ public function create($target) { diff --git a/src/Routing/Route/RouteFactoryInterface.php b/src/Routing/Route/RouteFactoryInterface.php index c169682..65bd41e 100644 --- a/src/Routing/Route/RouteFactoryInterface.php +++ b/src/Routing/Route/RouteFactoryInterface.php @@ -16,7 +16,7 @@ interface RouteFactoryInterface * - Regular expressions will create RegexRoutes * * @param string $target Route target or target pattern - * @return RouteInterface + * @return Route */ public function create($target); } diff --git a/src/Routing/Route/RouteInterface.php b/src/Routing/Route/RouteInterface.php deleted file mode 100644 index 850a6c5..0000000 --- a/src/Routing/Route/RouteInterface.php +++ /dev/null @@ -1,80 +0,0 @@ -routes[$target])) { $route = $this->routes[$target]; @@ -218,26 +218,26 @@ class Router return $route; } - private function registerRouteForTarget(RouteInterface $route, string $target): void + private function registerRouteForTarget(Route $route, string $target): void { // Store the route to the hash indexed by original target. $this->routes[$target] = $route; // Store the route to the array of routes for its type. switch ($route->getType()) { - case RouteInterface::TYPE_STATIC: + case Route::TYPE_STATIC: $this->staticRoutes[$route->getTarget()] = $route; break; - case RouteInterface::TYPE_PREFIX: + case Route::TYPE_PREFIX: $this->prefixRoutes[rtrim($route->getTarget(), '*')] = $route; break; - case RouteInterface::TYPE_PATTERN: + case Route::TYPE_PATTERN: $this->patternRoutes[] = $route; break; } } - private function getStaticRoute(string $requestTarget): ?RouteInterface + private function getStaticRoute(string $requestTarget): ?Route { if (isset($this->staticRoutes[$requestTarget])) { return $this->staticRoutes[$requestTarget]; @@ -245,7 +245,7 @@ class Router return null; } - private function getPrefixRoute(string $requestTarget): ?RouteInterface + private function getPrefixRoute(string $requestTarget): ?Route { // Find all prefixes that match the start of this path. $prefixes = array_keys($this->prefixRoutes); diff --git a/test/tests/unit/Routing/Route/PrefixRouteTest.php b/test/tests/unit/Routing/Route/PrefixRouteTest.php index 2af3d19..b410b9b 100644 --- a/test/tests/unit/Routing/Route/PrefixRouteTest.php +++ b/test/tests/unit/Routing/Route/PrefixRouteTest.php @@ -20,7 +20,7 @@ class PrefixRouteTest extends TestCase { $methodMap = $this->prophesize(MethodMap::class); $route = new PrefixRoute('/*', $methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType()); + $this->assertSame(Route::TYPE_PREFIX, $route->getType()); } public function testReturnsEmptyArrayForPathVariables(): void diff --git a/test/tests/unit/Routing/Route/RegexRouteTest.php b/test/tests/unit/Routing/Route/RegexRouteTest.php index 887738d..ce10ee9 100644 --- a/test/tests/unit/Routing/Route/RegexRouteTest.php +++ b/test/tests/unit/Routing/Route/RegexRouteTest.php @@ -1,12 +1,9 @@ methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } /** @dataProvider matchingRouteProvider */ diff --git a/test/tests/unit/Routing/Route/RouteFactoryTest.php b/test/tests/unit/Routing/Route/RouteFactoryTest.php index 1ec246d..d818589 100644 --- a/test/tests/unit/Routing/Route/RouteFactoryTest.php +++ b/test/tests/unit/Routing/Route/RouteFactoryTest.php @@ -1,11 +1,9 @@ dispatcher->reveal()); $route = $factory->create('/cats/'); - $this->assertSame(RouteInterface::TYPE_STATIC, $route->getType()); + $this->assertSame(Route::TYPE_STATIC, $route->getType()); } public function testCreatesPrefixRoute() { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('/cats/*'); - $this->assertSame(RouteInterface::TYPE_PREFIX, $route->getType()); + $this->assertSame(Route::TYPE_PREFIX, $route->getType()); } public function testCreatesRegexRoute() { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('~/cat/[0-9]+~'); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } public function testCreatesTemplateRoute() { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('/cat/{id}'); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } } diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index f57bed4..37d6b54 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -1,14 +1,12 @@ assertSame(self::TARGET, $this->route->getTarget()); } - public function testRegistersDispatchableWithMethodMap() + public function testRegistersDispatchableWithMethodMap(): void { $handler = $this->prophesize(RequestHandlerInterface::class)->reveal(); @@ -47,7 +45,7 @@ class RouteTest extends TestCase $this->methodMap->register('GET', $handler)->shouldHaveBeenCalled(); } - public function testDispatchesMethodMap() + public function testDispatchesMethodMap(): void { $request = new ServerRequest(); $response = new Response(); diff --git a/test/tests/unit/Routing/Route/StaticRouteTest.php b/test/tests/unit/Routing/Route/StaticRouteTest.php index 6ca6067..6b86f0c 100644 --- a/test/tests/unit/Routing/Route/StaticRouteTest.php +++ b/test/tests/unit/Routing/Route/StaticRouteTest.php @@ -1,11 +1,8 @@ prophesize(MethodMap::class); $route = new StaticRoute('/', $methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_STATIC, $route->getType()); + $this->assertSame(Route::TYPE_STATIC, $route->getType()); } public function testMatchesExactRequestTarget() diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index 8d87bce..bdf1d84 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -1,11 +1,8 @@ methodMap->reveal()); - $this->assertSame(RouteInterface::TYPE_PATTERN, $route->getType()); + $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } // ------------------------------------------------------------------------- diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 58e5355..012e4c0 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -1,6 +1,6 @@ route = $this->prophesize(RouteInterface::class); + $this->route = $this->prophesize(Route::class); $this->route->__invoke(Argument::cetera())->willReturn(new Response()); $this->route->register(Argument::cetera()); - $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); + $this->route->getType()->willReturn(Route::TYPE_STATIC); $this->route->getTarget()->willReturn('/'); $this->route->getPathVariables()->willReturn([]); @@ -93,7 +92,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); + $this->route->getType()->willReturn(Route::TYPE_STATIC); $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); @@ -108,7 +107,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget('/animals/cats/molly'); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $this->route->getType()->willReturn(Route::TYPE_PREFIX); $this->router->register('GET', $target, 'middleware'); $this->router->__invoke($this->request, $this->response, $this->next); @@ -123,7 +122,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->router->register('GET', $target, 'middleware'); @@ -135,16 +134,16 @@ class RouterTest extends TestCase public function testDispatchesStaticRouteBeforePrefixRoute() { - $staticRoute = $this->prophesize(RouteInterface::class); + $staticRoute = $this->prophesize(Route::class); $staticRoute->register(Argument::cetera()); $staticRoute->getTarget()->willReturn('/cats/'); - $staticRoute->getType()->willReturn(RouteInterface::TYPE_STATIC); + $staticRoute->getType()->willReturn(Route::TYPE_STATIC); $staticRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $prefixRoute = $this->prophesize(RouteInterface::class); + $prefixRoute = $this->prophesize(Route::class); $prefixRoute->register(Argument::cetera()); $prefixRoute->getTarget()->willReturn('/cats/*'); - $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $prefixRoute->getType()->willReturn(Route::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); $this->request = $this->request->withRequestTarget('/cats/'); @@ -164,16 +163,16 @@ class RouterTest extends TestCase { // Note: The longest route is also good for 2 points in Settlers of Catan. - $shortRoute = $this->prophesize(RouteInterface::class); + $shortRoute = $this->prophesize(Route::class); $shortRoute->register(Argument::cetera()); $shortRoute->getTarget()->willReturn('/animals/*'); - $shortRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $shortRoute->getType()->willReturn(Route::TYPE_PREFIX); $shortRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $longRoute = $this->prophesize(RouteInterface::class); + $longRoute = $this->prophesize(Route::class); $longRoute->register(Argument::cetera()); $longRoute->getTarget()->willReturn('/animals/cats/*'); - $longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $longRoute->getType()->willReturn(Route::TYPE_PREFIX); $longRoute->__invoke(Argument::cetera())->willReturn(new Response()); $this->request = $this->request @@ -192,16 +191,16 @@ class RouterTest extends TestCase public function testDispatchesPrefixRouteBeforePatternRoute() { - $prefixRoute = $this->prophesize(RouteInterface::class); + $prefixRoute = $this->prophesize(Route::class); $prefixRoute->register(Argument::cetera()); $prefixRoute->getTarget()->willReturn('/cats/*'); - $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); + $prefixRoute->getType()->willReturn(Route::TYPE_PREFIX); $prefixRoute->__invoke(Argument::cetera())->willReturn(new Response()); - $patternRoute = $this->prophesize(RouteInterface::class); + $patternRoute = $this->prophesize(Route::class); $patternRoute->register(Argument::cetera()); $patternRoute->getTarget()->willReturn('/cats/{id}'); - $patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute->__invoke(Argument::cetera())->willReturn(new Response()); $this->request = $this->request->withRequestTarget('/cats/'); @@ -219,18 +218,18 @@ class RouterTest extends TestCase public function testDispatchesFirstMatchingPatternRoute() { - $patternRoute1 = $this->prophesize(RouteInterface::class); + $patternRoute1 = $this->prophesize(Route::class); $patternRoute1->register(Argument::cetera()); $patternRoute1->getTarget()->willReturn('/cats/{id}'); - $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute1->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); $patternRoute1->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute1->__invoke(Argument::cetera())->willReturn(new Response()); - $patternRoute2 = $this->prophesize(RouteInterface::class); + $patternRoute2 = $this->prophesize(Route::class); $patternRoute2->register(Argument::cetera()); $patternRoute2->getTarget()->willReturn('/cats/{name}'); - $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute2->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->__invoke(Argument::cetera())->willReturn(new Response()); @@ -250,18 +249,18 @@ class RouterTest extends TestCase public function testStopsTestingPatternsAfterFirstSuccessfulMatch() { - $patternRoute1 = $this->prophesize(RouteInterface::class); + $patternRoute1 = $this->prophesize(Route::class); $patternRoute1->register(Argument::cetera()); $patternRoute1->getTarget()->willReturn('/cats/{id}'); - $patternRoute1->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute1->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute1->getPathVariables()->willReturn([]); $patternRoute1->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute1->__invoke(Argument::cetera())->willReturn(new Response()); - $patternRoute2 = $this->prophesize(RouteInterface::class); + $patternRoute2 = $this->prophesize(Route::class); $patternRoute2->register(Argument::cetera()); $patternRoute2->getTarget()->willReturn('/cats/{name}'); - $patternRoute2->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $patternRoute2->getType()->willReturn(Route::TYPE_PATTERN); $patternRoute2->getPathVariables()->willReturn([]); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->__invoke(Argument::cetera())->willReturn(new Response()); @@ -286,7 +285,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->router->register('GET', $target, 'middleware'); @@ -310,7 +309,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->getPathVariables()->willReturn($variables); @@ -348,7 +347,7 @@ class RouterTest extends TestCase $this->request = $this->request->withRequestTarget($target); $this->route->getTarget()->willReturn($target); - $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->getPathVariables()->willReturn($variables); From 79c4799a7b6f8a4d31854752b8f8ffff115b42cb Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 07:38:38 -0400 Subject: [PATCH 38/53] Clean up tests for routes --- src/Routing/Route/RegexRoute.php | 2 +- src/Routing/Route/TemplateRoute.php | 10 +- .../unit/Routing/Route/RegexRouteTest.php | 46 +++++--- .../unit/Routing/Route/StaticRouteTest.php | 8 +- .../unit/Routing/Route/TemplateRouteTest.php | 109 +++++++++++++----- 5 files changed, 121 insertions(+), 54 deletions(-) diff --git a/src/Routing/Route/RegexRoute.php b/src/Routing/Route/RegexRoute.php index de8d6b6..42f0978 100644 --- a/src/Routing/Route/RegexRoute.php +++ b/src/Routing/Route/RegexRoute.php @@ -21,7 +21,7 @@ class RegexRoute extends Route * Examines a request target to see if it is a match for the route. * * @param string $requestTarget - * @return boolean + * @return bool */ public function matchesRequestTarget(string $requestTarget): bool { diff --git a/src/Routing/Route/TemplateRoute.php b/src/Routing/Route/TemplateRoute.php index f4990e5..c0254e0 100644 --- a/src/Routing/Route/TemplateRoute.php +++ b/src/Routing/Route/TemplateRoute.php @@ -7,11 +7,6 @@ namespace WellRESTed\Routing\Route; */ class TemplateRoute extends Route { - /** @var array */ - private $pathVariables = []; - /** @var array */ - private $explosions = []; - /** Regular expression matching a URI template variable (e.g., {id}) */ public const URI_TEMPLATE_EXPRESSION_RE = '/{([+.\/]?[a-zA-Z0-9_,]+\*?)}/'; /** @@ -20,6 +15,11 @@ class TemplateRoute extends Route */ private const RE_UNRESERVED = '[0-9a-zA-Z\-._\~%]*'; + /** @var array */ + private $pathVariables = []; + /** @var array */ + private $explosions = []; + public function getType(): int { return Route::TYPE_PATTERN; diff --git a/test/tests/unit/Routing/Route/RegexRouteTest.php b/test/tests/unit/Routing/Route/RegexRouteTest.php index ce10ee9..f3e5dba 100644 --- a/test/tests/unit/Routing/Route/RegexRouteTest.php +++ b/test/tests/unit/Routing/Route/RegexRouteTest.php @@ -17,35 +17,48 @@ class RegexRouteTest extends TestCase $this->methodMap = $this->prophesize(MethodMap::class); } - public function testReturnsPatternType() + public function testReturnsPatternType(): void { $route = new RegexRoute('/', $this->methodMap->reveal()); $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } - /** @dataProvider matchingRouteProvider */ - public function testMatchesTarget($pattern, $path) + /** + * @dataProvider matchingRouteProvider + * @param string $pattern + * @param string $path + */ + public function testMatchesTarget(string $pattern, string $path): void { $route = new RegexRoute($pattern, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($path)); } - /** @dataProvider matchingRouteProvider */ - public function testMatchesTargetByRegex($pattern, $target) + /** + * @dataProvider matchingRouteProvider + * @param string $pattern + * @param string $path + */ + public function testMatchesTargetByRegex(string $pattern, string $path): void { $route = new RegexRoute($pattern, $this->methodMap->reveal()); - $this->assertTrue($route->matchesRequestTarget($target)); + $this->assertTrue($route->matchesRequestTarget($path)); } - /** @dataProvider matchingRouteProvider */ - public function testExtractsPathVariablesByRegex($pattern, $target, $expectedCaptures) + /** + * @dataProvider matchingRouteProvider + * @param string $pattern + * @param string $path + * @param array $expectedCaptures + */ + public function testExtractsPathVariablesByRegex(string $pattern, string $path, array $expectedCaptures): void { $route = new RegexRoute($pattern, $this->methodMap->reveal()); - $route->matchesRequestTarget($target); + $route->matchesRequestTarget($path); $this->assertEquals($expectedCaptures, $route->getPathVariables()); } - public function matchingRouteProvider() + public function matchingRouteProvider(): array { return [ ['~/cat/[0-9]+~', '/cat/2', [0 => '/cat/2']], @@ -62,14 +75,18 @@ class RegexRouteTest extends TestCase ]; } - /** @dataProvider mismatchingRouteProvider */ - public function testDoesNotMatchNonmatchingTarget($pattern, $path) + /** + * @dataProvider mismatchingRouteProvider + * @param string $pattern + * @param string $path + */ + public function testDoesNotMatchNonMatchingTarget(string $pattern, string $path): void { $route = new RegexRoute($pattern, $this->methodMap->reveal()); $this->assertFalse($route->matchesRequestTarget($path)); } - public function mismatchingRouteProvider() + public function mismatchingRouteProvider(): array { return [ ['~/cat/[0-9]+~', '/cat/molly'], @@ -80,8 +97,9 @@ class RegexRouteTest extends TestCase /** * @dataProvider invalidRouteProvider + * @param string $pattern */ - public function testThrowsExceptionOnInvalidPattern($pattern) + public function testThrowsExceptionOnInvalidPattern(string $pattern): void { $this->expectException(RuntimeException::class); $route = new RegexRoute($pattern, $this->methodMap->reveal()); diff --git a/test/tests/unit/Routing/Route/StaticRouteTest.php b/test/tests/unit/Routing/Route/StaticRouteTest.php index 6b86f0c..aa6e5c9 100644 --- a/test/tests/unit/Routing/Route/StaticRouteTest.php +++ b/test/tests/unit/Routing/Route/StaticRouteTest.php @@ -9,28 +9,28 @@ class StaticRouteTest extends TestCase { use ProphecyTrait; - public function testReturnsStaticType() + public function testReturnsStaticType(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new StaticRoute('/', $methodMap->reveal()); $this->assertSame(Route::TYPE_STATIC, $route->getType()); } - public function testMatchesExactRequestTarget() + public function testMatchesExactRequestTarget(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new StaticRoute('/', $methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget('/')); } - public function testReturnsEmptyArrayForPathVariables() + public function testReturnsEmptyArrayForPathVariables(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new StaticRoute('/', $methodMap->reveal()); $this->assertSame([], $route->getPathVariables()); } - public function testDoesNotMatchNonmatchingRequestTarget() + public function testDoesNotMatchNonMatchingRequestTarget(): void { $methodMap = $this->prophesize(MethodMap::class); $route = new StaticRoute('/', $methodMap->reveal()); diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/test/tests/unit/Routing/Route/TemplateRouteTest.php index bdf1d84..4b85f39 100644 --- a/test/tests/unit/Routing/Route/TemplateRouteTest.php +++ b/test/tests/unit/Routing/Route/TemplateRouteTest.php @@ -16,7 +16,7 @@ class TemplateRouteTest extends TestCase $this->methodMap = $this->prophesize(MethodMap::class); } - private function getExpectedValues($keys) + private function getExpectedValues(array $keys): array { $expectedValues = [ 'var' => 'value', @@ -33,7 +33,7 @@ class TemplateRouteTest extends TestCase return array_intersect_key($expectedValues, array_flip($keys)); } - private function assertArrayHasSameContents($expected, $actual) + private function assertArrayHasSameContents($expected, $actual): void { ksort($expected); ksort($actual); @@ -42,7 +42,7 @@ class TemplateRouteTest extends TestCase // ------------------------------------------------------------------------- - public function testReturnsPatternType() + public function testReturnsPatternType(): void { $route = new TemplateRoute('/', $this->methodMap->reveal()); $this->assertSame(Route::TYPE_PATTERN, $route->getType()); @@ -51,8 +51,12 @@ class TemplateRouteTest extends TestCase // ------------------------------------------------------------------------- // Matching - /** @dataProvider nonMatchingTargetProvider */ - public function testFailsToMatchNonMatchingTarget($template, $target) + /** + * @dataProvider nonMatchingTargetProvider + * @param string $template + * @param string $target + */ + public function testFailsToMatchNonMatchingTarget(string $template, string $target): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertFalse($route->matchesRequestTarget($target)); @@ -71,22 +75,31 @@ class TemplateRouteTest extends TestCase // ------------------------------------------------------------------------- // Matching :: Simple Strings - /** @dataProvider simpleStringProvider */ - public function testMatchesSimpleStrings($template, $target) + /** + * @dataProvider simpleStringProvider + * @param string $template + * @param string $target + */ + public function testMatchesSimpleStrings(string $template, string $target): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } - /** @dataProvider simpleStringProvider */ - public function testCapturesFromSimpleStrings($template, $target, $variables) + /** + * @dataProvider simpleStringProvider + * @param string $template + * @param string $target + * @param string[] $variables + */ + public function testCapturesFromSimpleStrings(string $template, string $target, array $variables): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } - public function simpleStringProvider() + public function simpleStringProvider(): array { return [ ['/foo', '/foo', []], @@ -100,22 +113,31 @@ class TemplateRouteTest extends TestCase // ------------------------------------------------------------------------- // Matching :: Reserved - /** @dataProvider reservedStringProvider */ - public function testMatchesReservedStrings($template, $target) + /** + * @dataProvider reservedStringProvider + * @param string $template + * @param string $target + */ + public function testMatchesReservedStrings(string $template, string $target): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } - /** @dataProvider reservedStringProvider */ - public function testCapturesFromReservedStrings($template, $target, $variables) + /** + * @dataProvider reservedStringProvider + * @param string $template + * @param string $target + * @param array $variables + */ + public function testCapturesFromReservedStrings(string $template, string $target, array $variables): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertSame($this->getExpectedValues($variables), $route->getPathVariables()); } - public function reservedStringProvider() + public function reservedStringProvider(): array { return [ ['/{+var}', '/value', ['var']], @@ -127,22 +149,31 @@ class TemplateRouteTest extends TestCase // ------------------------------------------------------------------------- // Matching :: Label Expansion - /** @dataProvider labelWithDotPrefixProvider */ - public function testMatchesLabelWithDotPrefix($template, $target) + /** + * @dataProvider labelWithDotPrefixProvider + * @param string $template + * @param string $target + */ + public function testMatchesLabelWithDotPrefix(string $template, string $target): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } - /** @dataProvider labelWithDotPrefixProvider */ - public function testCapturesFromLabelWithDotPrefix($template, $target, $variables) + /** + * @dataProvider labelWithDotPrefixProvider + * @param string $template + * @param string $target + * @param array $variables + */ + public function testCapturesFromLabelWithDotPrefix(string $template, string $target, array $variables): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } - public function labelWithDotPrefixProvider() + public function labelWithDotPrefixProvider(): array { return [ ['/{.who}', '/.fred', ['who']], @@ -154,22 +185,31 @@ class TemplateRouteTest extends TestCase // ------------------------------------------------------------------------- // Matching :: Path Segments - /** @dataProvider pathSegmentProvider */ - public function testMatchesPathSegments($template, $target) + /** + * @dataProvider pathSegmentProvider + * @param string $template + * @param string $target + */ + public function testMatchesPathSegments(string $template, string $target): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } - /** @dataProvider pathSegmentProvider */ - public function testCapturesFromPathSegments($template, $target, $variables) + /** + * @dataProvider pathSegmentProvider + * @param string $template + * @param string $target + * @param array $variables + */ + public function testCapturesFromPathSegments(string $template, string $target, array $variables): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } - public function pathSegmentProvider() + public function pathSegmentProvider(): array { return [ ['{/who}', '/fred', ['who']], @@ -181,22 +221,31 @@ class TemplateRouteTest extends TestCase // ------------------------------------------------------------------------- // Matching :: Explosion - /** @dataProvider pathExplosionProvider */ - public function testMatchesExplosion($template, $target) + /** + * @dataProvider pathExplosionProvider + * @param string $template + * @param string $target + */ + public function testMatchesExplosion(string $template, string $target): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $this->assertTrue($route->matchesRequestTarget($target)); } - /** @dataProvider pathExplosionProvider */ - public function testCapturesFromExplosion($template, $target, $variables) + /** + * @dataProvider pathExplosionProvider + * @param string $template + * @param string $target + * @param array $variables + */ + public function testCapturesFromExplosion(string $template, string $target, array $variables): void { $route = new TemplateRoute($template, $this->methodMap->reveal()); $route->matchesRequestTarget($target); $this->assertArrayHasSameContents($this->getExpectedValues($variables), $route->getPathVariables()); } - public function pathExplosionProvider() + public function pathExplosionProvider(): array { return [ ['/{count*}', '/one,two,three', ['count']], From 56503da35ec744ffde93b1235ac63c614db8fd50 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 07:44:00 -0400 Subject: [PATCH 39/53] Remove RouteFactoryInterface --- src/Routing/Route/RouteFactory.php | 4 ++-- src/Routing/Route/RouteFactoryInterface.php | 22 ------------------- src/Routing/Router.php | 5 ++--- .../unit/Routing/Route/RouteFactoryTest.php | 8 +++---- test/tests/unit/Routing/RouterTest.php | 3 +-- 5 files changed, 9 insertions(+), 33 deletions(-) delete mode 100644 src/Routing/Route/RouteFactoryInterface.php diff --git a/src/Routing/Route/RouteFactory.php b/src/Routing/Route/RouteFactory.php index d0beb03..1a167fc 100644 --- a/src/Routing/Route/RouteFactory.php +++ b/src/Routing/Route/RouteFactory.php @@ -7,7 +7,7 @@ use WellRESTed\Dispatching\DispatcherInterface; /** * @internal */ -class RouteFactory implements RouteFactoryInterface +class RouteFactory { private $dispatcher; @@ -27,7 +27,7 @@ class RouteFactory implements RouteFactoryInterface * @param string $target Route target or target pattern * @return Route */ - public function create($target) + public function create(string $target): Route { if ($target[0] === '/') { diff --git a/src/Routing/Route/RouteFactoryInterface.php b/src/Routing/Route/RouteFactoryInterface.php deleted file mode 100644 index 65bd41e..0000000 --- a/src/Routing/Route/RouteFactoryInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -dispatcher = $this->prophesize(DispatcherInterface::class); } - public function testCreatesStaticRoute() + public function testCreatesStaticRoute(): void { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('/cats/'); $this->assertSame(Route::TYPE_STATIC, $route->getType()); } - public function testCreatesPrefixRoute() + public function testCreatesPrefixRoute(): void { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('/cats/*'); $this->assertSame(Route::TYPE_PREFIX, $route->getType()); } - public function testCreatesRegexRoute() + public function testCreatesRegexRoute(): void { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('~/cat/[0-9]+~'); $this->assertSame(Route::TYPE_PATTERN, $route->getType()); } - public function testCreatesTemplateRoute() + public function testCreatesTemplateRoute(): void { $factory = new RouteFactory($this->dispatcher->reveal()); $route = $factory->create('/cat/{id}'); diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 012e4c0..8548db6 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -10,7 +10,6 @@ use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; use WellRESTed\Routing\Route\Route; use WellRESTed\Routing\Route\RouteFactory; -use WellRESTed\Routing\Route\RouteFactoryInterface; use WellRESTed\Test\Doubles\NextMock; use WellRESTed\Test\TestCase; @@ -449,7 +448,7 @@ class RouterWithFactory extends Router { public static $routeFactory; - protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactoryInterface + protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactory { return self::$routeFactory; } From 997582f8d7880b6210cfd4fa1b730f351de04f9d Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Fri, 14 Aug 2020 07:49:33 -0400 Subject: [PATCH 40/53] Router implements MiddlewareInterface; cleanup Router test --- src/Routing/Router.php | 11 ++++-- test/tests/unit/Routing/RouterTest.php | 48 ++++++++++++++------------ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 9656b94..0e279e7 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -6,10 +6,11 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use WellRESTed\Dispatching\Dispatcher; use WellRESTed\Dispatching\DispatcherInterface; +use WellRESTed\MiddlewareInterface; use WellRESTed\Routing\Route\Route; use WellRESTed\Routing\Route\RouteFactory; -class Router +class Router implements MiddlewareInterface { /** @var string|null Attribute name for matched path variables */ private $pathVariablesAttributeName; @@ -61,10 +62,16 @@ class Router $this->stack = []; } + /** + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @param callable $next + * @return ResponseInterface + */ public function __invoke( ServerRequestInterface $request, ResponseInterface $response, - callable $next + $next ): ResponseInterface { // Use only the path for routing. $requestTarget = parse_url($request->getRequestTarget(), PHP_URL_PATH); diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index 8548db6..dd6a479 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -51,7 +51,7 @@ class RouterTest extends TestCase // ------------------------------------------------------------------------- // Construction - public function testCreatesInstance() + public function testCreatesInstance(): void { $router = new Router(); $this->assertNotNull($router); @@ -60,14 +60,14 @@ class RouterTest extends TestCase // ------------------------------------------------------------------------- // Populating - public function testCreatesRouteForTarget() + public function testCreatesRouteForTarget(): void { $this->router->register('GET', '/', 'middleware'); $this->factory->create('/')->shouldHaveBeenCalled(); } - public function testDoesNotRecreateRouteForExistingTarget() + public function testDoesNotRecreateRouteForExistingTarget(): void { $this->router->register('GET', '/', 'middleware'); $this->router->register('POST', '/', 'middleware'); @@ -75,7 +75,7 @@ class RouterTest extends TestCase $this->factory->create('/')->shouldHaveBeenCalledTimes(1); } - public function testPassesMethodAndMiddlewareToRoute() + public function testPassesMethodAndMiddlewareToRoute(): void { $this->router->register('GET', '/', 'middleware'); @@ -85,7 +85,7 @@ class RouterTest extends TestCase // ------------------------------------------------------------------------- // Dispatching - public function testDispatchesStaticRoute() + public function testDispatchesStaticRoute(): void { $target = '/'; $this->request = $this->request->withRequestTarget($target); @@ -100,7 +100,7 @@ class RouterTest extends TestCase ->shouldHaveBeenCalled(); } - public function testDispatchesPrefixRoute() + public function testDispatchesPrefixRoute(): void { $target = '/animals/cats/*'; $this->request = $this->request->withRequestTarget('/animals/cats/molly'); @@ -115,7 +115,7 @@ class RouterTest extends TestCase ->shouldHaveBeenCalled(); } - public function testDispatchesPatternRoute() + public function testDispatchesPatternRoute(): void { $target = '/'; $this->request = $this->request->withRequestTarget($target); @@ -131,7 +131,7 @@ class RouterTest extends TestCase ->shouldHaveBeenCalled(); } - public function testDispatchesStaticRouteBeforePrefixRoute() + public function testDispatchesStaticRouteBeforePrefixRoute(): void { $staticRoute = $this->prophesize(Route::class); $staticRoute->register(Argument::cetera()); @@ -158,7 +158,7 @@ class RouterTest extends TestCase ->shouldHaveBeenCalled(); } - public function testDispatchesLongestMatchingPrefixRoute() + public function testDispatchesLongestMatchingPrefixRoute(): void { // Note: The longest route is also good for 2 points in Settlers of Catan. @@ -188,7 +188,7 @@ class RouterTest extends TestCase ->shouldHaveBeenCalled(); } - public function testDispatchesPrefixRouteBeforePatternRoute() + public function testDispatchesPrefixRouteBeforePatternRoute(): void { $prefixRoute = $this->prophesize(Route::class); $prefixRoute->register(Argument::cetera()); @@ -215,7 +215,7 @@ class RouterTest extends TestCase ->shouldHaveBeenCalled(); } - public function testDispatchesFirstMatchingPatternRoute() + public function testDispatchesFirstMatchingPatternRoute(): void { $patternRoute1 = $this->prophesize(Route::class); $patternRoute1->register(Argument::cetera()); @@ -246,7 +246,7 @@ class RouterTest extends TestCase ->shouldHaveBeenCalled(); } - public function testStopsTestingPatternsAfterFirstSuccessfulMatch() + public function testStopsTestingPatternsAfterFirstSuccessfulMatch(): void { $patternRoute1 = $this->prophesize(Route::class); $patternRoute1->register(Argument::cetera()); @@ -277,7 +277,7 @@ class RouterTest extends TestCase ->shouldNotHaveBeenCalled(); } - public function testMatchesPathAgainstRouteWithoutQuery() + public function testMatchesPathAgainstRouteWithoutQuery(): void { $target = '/my/path?cat=molly&dog=bear'; @@ -296,8 +296,12 @@ class RouterTest extends TestCase // ------------------------------------------------------------------------- // Path Variables - /** @dataProvider pathVariableProvider */ - public function testSetPathVariablesAttributeIndividually($name, $value) + /** + * @dataProvider pathVariableProvider + * @param string $name + * @param string $value + */ + public function testSetPathVariablesAttributeIndividually(string $name, string $value): void { $target = '/'; $variables = [ @@ -325,7 +329,7 @@ class RouterTest extends TestCase )->shouldHaveBeenCalled(); } - public function pathVariableProvider() + public function pathVariableProvider(): array { return [ ['id', '1024'], @@ -333,7 +337,7 @@ class RouterTest extends TestCase ]; } - public function testSetPathVariablesAttributeAsArray() + public function testSetPathVariablesAttributeAsArray(): void { $attributeName = 'pathVariables'; @@ -367,21 +371,21 @@ class RouterTest extends TestCase // ------------------------------------------------------------------------- // No Match - public function testWhenNoRouteMatchesByDefaultResponds404() + public function testWhenNoRouteMatchesByDefaultResponds404(): void { $this->request = $this->request->withRequestTarget('/no/match'); $response = $this->router->__invoke($this->request, $this->response, $this->next); $this->assertEquals(404, $response->getStatusCode()); } - public function testWhenNoRouteMatchesByDefaultDoesNotPropagatesToNextMiddleware() + public function testWhenNoRouteMatchesByDefaultDoesNotPropagatesToNextMiddleware(): void { $this->request = $this->request->withRequestTarget('/no/match'); $this->router->__invoke($this->request, $this->response, $this->next); $this->assertFalse($this->next->called); } - public function testWhenNoRouteMatchesAndContinueModePropagatesToNextMiddleware() + public function testWhenNoRouteMatchesAndContinueModePropagatesToNextMiddleware(): void { $this->request = $this->request->withRequestTarget('/no/match'); $this->router->continueOnNotFound(); @@ -392,7 +396,7 @@ class RouterTest extends TestCase // ------------------------------------------------------------------------- // Middleware for Routes - public function testCallsRouterMiddlewareBeforeRouteMiddleware() + public function testCallsRouterMiddlewareBeforeRouteMiddleware(): void { $middlewareRequest = new ServerRequest(); $middlewareResponse = new Response(); @@ -416,7 +420,7 @@ class RouterTest extends TestCase )->shouldHaveBeenCalled(); } - public function testDoesNotCallRouterMiddlewareWhenNoRouteMatches() + public function testDoesNotCallRouterMiddlewareWhenNoRouteMatches(): void { $middlewareCalled = false; $middlewareRequest = new ServerRequest(); From 1d71f06e71c0611a2d03fc324bf9461cd26238bb Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 15 Aug 2020 07:18:54 -0400 Subject: [PATCH 41/53] Router accepts custom RouteFactory through constructor; removes protected methods --- src/Routing/Router.php | 25 +++--- src/Server.php | 4 +- test/tests/unit/Routing/Route/RouteTest.php | 2 +- test/tests/unit/Routing/RouterTest.php | 92 ++++++++++++--------- 4 files changed, 66 insertions(+), 57 deletions(-) diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 0e279e7..7248f0b 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -42,19 +42,24 @@ class Router implements MiddlewareInterface * stored with the name. The value will be an array containing all of the * path variables. * - * @param DispatcherInterface|null $dispatcher - * Instance to use for dispatching middleware and handlers. + * Use Server->createRouter to instantiate a new Router rather than calling + * this constructor manually. + * * @param string|null $pathVariablesAttributeName * Attribute name for matched path variables. A null value sets * attributes directly. + * @param DispatcherInterface|null $dispatcher + * Instance to use for dispatching middleware and handlers. + * @param RouteFactory|null $routeFactory */ public function __construct( + ?string $pathVariablesAttributeName = null, ?DispatcherInterface $dispatcher = null, - ?string $pathVariablesAttributeName = null + ?RouteFactory $routeFactory = null ) { - $this->dispatcher = $dispatcher ?: $this->getDefaultDispatcher(); $this->pathVariablesAttributeName = $pathVariablesAttributeName; - $this->factory = $this->getRouteFactory($this->dispatcher); + $this->dispatcher = $dispatcher ?? new Dispatcher(); + $this->factory = $routeFactory ?? new RouteFactory($this->dispatcher); $this->routes = []; $this->staticRoutes = []; $this->prefixRoutes = []; @@ -203,16 +208,6 @@ class Router implements MiddlewareInterface return $this; } - protected function getDefaultDispatcher(): DispatcherInterface - { - return new Dispatcher(); - } - - protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactory - { - return new RouteFactory($dispatcher); - } - private function getRouteForTarget(string $target): Route { if (isset($this->routes[$target])) { diff --git a/src/Server.php b/src/Server.php index 85b00a8..c7d4576 100644 --- a/src/Server.php +++ b/src/Server.php @@ -57,8 +57,8 @@ class Server public function createRouter(): Router { return new Router( - $this->dispatcher, - $this->pathVariablesAttributeName + $this->pathVariablesAttributeName, + $this->dispatcher ); } diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index 37d6b54..e37f6d9 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -53,7 +53,7 @@ class RouteTest extends TestCase return $resp; }; - $this->route->__invoke($request, $response, $next); + call_user_func($this->route, $request, $response, $next); $this->methodMap->__invoke(Argument::cetera())->shouldHaveBeenCalled(); } diff --git a/test/tests/unit/Routing/RouterTest.php b/test/tests/unit/Routing/RouterTest.php index dd6a479..d5541aa 100644 --- a/test/tests/unit/Routing/RouterTest.php +++ b/test/tests/unit/Routing/RouterTest.php @@ -4,8 +4,8 @@ namespace WellRESTed\Routing; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; +use Psr\Http\Message\ResponseInterface; use WellRESTed\Dispatching\Dispatcher; -use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Message\Response; use WellRESTed\Message\ServerRequest; use WellRESTed\Routing\Route\Route; @@ -39,22 +39,26 @@ class RouterTest extends TestCase $this->factory->create(Argument::any()) ->willReturn($this->route->reveal()); - RouterWithFactory::$routeFactory = $this->factory->reveal(); - - $this->router = new RouterWithFactory(); + $this->router = new Router(null, null, $this->factory->reveal()); $this->request = new ServerRequest(); $this->response = new Response(); $this->next = new NextMock(); } - // ------------------------------------------------------------------------- - // Construction - - public function testCreatesInstance(): void + /** + * Run a request through the class under test and return the response. + * + * @return ResponseInterface + */ + private function dispatch(): ResponseInterface { - $router = new Router(); - $this->assertNotNull($router); + return call_user_func( + $this->router, + $this->request, + $this->response, + $this->next + ); } // ------------------------------------------------------------------------- @@ -94,7 +98,8 @@ class RouterTest extends TestCase $this->route->getType()->willReturn(Route::TYPE_STATIC); $this->router->register('GET', $target, 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $this->route->__invoke(Argument::cetera()) ->shouldHaveBeenCalled(); @@ -109,7 +114,8 @@ class RouterTest extends TestCase $this->route->getType()->willReturn(Route::TYPE_PREFIX); $this->router->register('GET', $target, 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $this->route->__invoke(Argument::cetera()) ->shouldHaveBeenCalled(); @@ -125,7 +131,8 @@ class RouterTest extends TestCase $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->router->register('GET', $target, 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $this->route->__invoke(Argument::cetera()) ->shouldHaveBeenCalled(); @@ -152,7 +159,8 @@ class RouterTest extends TestCase $this->router->register('GET', '/cats/', 'middleware'); $this->router->register('GET', '/cats/*', 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $staticRoute->__invoke(Argument::cetera()) ->shouldHaveBeenCalled(); @@ -182,7 +190,8 @@ class RouterTest extends TestCase $this->router->register('GET', '/animals/*', 'middleware'); $this->router->register('GET', '/animals/cats/*', 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $longRoute->__invoke(Argument::cetera()) ->shouldHaveBeenCalled(); @@ -209,7 +218,8 @@ class RouterTest extends TestCase $this->router->register('GET', '/cats/*', 'middleware'); $this->router->register('GET', '/cats/{id}', 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $prefixRoute->__invoke(Argument::cetera()) ->shouldHaveBeenCalled(); @@ -240,7 +250,8 @@ class RouterTest extends TestCase $this->router->register('GET', '/cats/{id}', 'middleware'); $this->router->register('GET', '/cats/{name}', 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $patternRoute1->__invoke(Argument::cetera()) ->shouldHaveBeenCalled(); @@ -271,7 +282,8 @@ class RouterTest extends TestCase $this->router->register('GET', '/cats/{id}', 'middleware'); $this->router->register('GET', '/cats/{name}', 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $patternRoute2->matchesRequestTarget(Argument::any()) ->shouldNotHaveBeenCalled(); @@ -288,7 +300,8 @@ class RouterTest extends TestCase $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->router->register('GET', $target, 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $this->route->matchesRequestTarget('/my/path')->shouldHaveBeenCalled(); } @@ -317,7 +330,8 @@ class RouterTest extends TestCase $this->route->getPathVariables()->willReturn($variables); $this->router->register('GET', $target, 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $isRequestWithExpectedAttribute = function ($request) use ($name, $value) { return $request->getAttribute($name) === $value; @@ -354,9 +368,15 @@ class RouterTest extends TestCase $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->getPathVariables()->willReturn($variables); - $this->router->__construct(new Dispatcher(), $attributeName); + $this->router = new Router( + $attributeName, + new Dispatcher(), + $this->factory->reveal() + ); + $this->router->register('GET', $target, 'middleware'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); $isRequestWithExpectedAttribute = function ($request) use ($attributeName, $variables) { return $request->getAttribute($attributeName) === $variables; @@ -374,14 +394,18 @@ class RouterTest extends TestCase public function testWhenNoRouteMatchesByDefaultResponds404(): void { $this->request = $this->request->withRequestTarget('/no/match'); - $response = $this->router->__invoke($this->request, $this->response, $this->next); + + $response = $this->dispatch(); + $this->assertEquals(404, $response->getStatusCode()); } public function testWhenNoRouteMatchesByDefaultDoesNotPropagatesToNextMiddleware(): void { $this->request = $this->request->withRequestTarget('/no/match'); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); + $this->assertFalse($this->next->called); } @@ -389,7 +413,9 @@ class RouterTest extends TestCase { $this->request = $this->request->withRequestTarget('/no/match'); $this->router->continueOnNotFound(); - $this->router->__invoke($this->request, $this->response, $this->next); + + $this->dispatch(); + $this->assertTrue($this->next->called); } @@ -411,7 +437,7 @@ class RouterTest extends TestCase $this->router->add($middleware); $this->router->register('GET', '/', 'Handler'); - $this->router->__invoke($this->request, $this->response, $this->next); + $this->dispatch(); $this->route->__invoke( $middlewareRequest, @@ -440,20 +466,8 @@ class RouterTest extends TestCase $this->router->add($middleware); $this->router->register('GET', '/', 'Handler'); - $this->router->__invoke($this->request, $this->response, $this->next); + $this->dispatch(); $this->assertFalse($middlewareCalled); } } - -// ----------------------------------------------------------------------------- - -class RouterWithFactory extends Router -{ - public static $routeFactory; - - protected function getRouteFactory(DispatcherInterface $dispatcher): RouteFactory - { - return self::$routeFactory; - } -} From c137a2066a7f8d4ec606c2dc9334e551e00a55c7 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 15 Aug 2020 07:24:57 -0400 Subject: [PATCH 42/53] Minor change to Server docblock --- src/Server.php | 2 +- test/tests/unit/ServerTest.php | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Server.php b/src/Server.php index c7d4576..9d436b8 100644 --- a/src/Server.php +++ b/src/Server.php @@ -50,7 +50,7 @@ class Server } /** - * Return a new Router that uses the server's dispatcher. + * Return a new Router that uses the server's configuration. * * @return Router */ diff --git a/test/tests/unit/ServerTest.php b/test/tests/unit/ServerTest.php index 030a44d..cc92f93 100644 --- a/test/tests/unit/ServerTest.php +++ b/test/tests/unit/ServerTest.php @@ -31,7 +31,7 @@ class ServerTest extends TestCase // ------------------------------------------------------------------------- - public function testDispatchesMiddlewareStack() + public function testDispatchesMiddlewareStack(): void { // This test will add a string to this array from each middleware. @@ -63,7 +63,7 @@ class ServerTest extends TestCase $this->assertEquals(['first', 'second', 'third'], $steps); } - public function testDispatchedRequest() + public function testDispatchedRequest(): void { $request = new ServerRequest(); $capturedRequest = null; @@ -78,7 +78,7 @@ class ServerTest extends TestCase $this->assertSame($request, $capturedRequest); } - public function testDispatchedResponse() + public function testDispatchedResponse(): void { $response = new Response(); $capturedResponse = null; @@ -96,7 +96,7 @@ class ServerTest extends TestCase // ------------------------------------------------------------------------- // Respond - public function testRespondSendsResponseToTransmitter() + public function testRespondSendsResponseToTransmitter(): void { $expectedResponse = new Response(200); @@ -129,7 +129,7 @@ class ServerTest extends TestCase // ------------------------------------------------------------------------- // Router - public function testCreatesRouterWithDispatcher() + public function testCreatesRouterWithDispatcher(): void { $dispatcher = $this->prophesize(DispatcherInterface::class); $dispatcher->dispatch(Argument::cetera())->will( @@ -161,7 +161,7 @@ class ServerTest extends TestCase // ------------------------------------------------------------------------- // Attributes - public function testAddsAttributesToRequest() + public function testAddsAttributesToRequest(): void { $this->server->setAttributes([ 'name' => 'value' @@ -181,7 +181,7 @@ class ServerTest extends TestCase // ------------------------------------------------------------------------- // End of Stack - public function testReturnsLastDoublePassResponseAtEndOfStack() + public function testReturnsLastDoublePassResponseAtEndOfStack(): void { $defaultResponse = new Response(404); From 36df1f33c1915e9d66a4924449aae37fc3a5a12f Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 15 Aug 2020 07:51:30 -0400 Subject: [PATCH 43/53] Refactor URI; fix coverage on UploadedFile --- composer.json | 3 +- src/Message/Uri.php | 63 +++++++------------- test/tests/unit/Message/UploadedFileTest.php | 2 +- test/tests/unit/Message/UriTest.php | 6 +- 4 files changed, 30 insertions(+), 44 deletions(-) diff --git a/composer.json b/composer.json index a8623c3..7415688 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ "autoload-dev": { "psr-4": { "WellRESTed\\": "test/tests/unit/", - "WellRESTed\\Test\\": "test/src/" + "WellRESTed\\Test\\": "test/src/", + "WellRESTed\\Test\\Integration\\": "test/tests/integration/" } } } diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 24e72e3..aa65acd 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -18,25 +18,25 @@ use Psr\Http\Message\UriInterface; */ class Uri implements UriInterface { - const MIN_PORT = 0; - const MAX_PORT = 65535; + private const MIN_PORT = 0; + private const MAX_PORT = 65535; /** @var string */ - private $scheme = ''; + private $scheme; /** @var string */ - private $user = ''; - /** @var string|null */ + private $user; + /** @var string */ private $password; - /** @var string */ - private $host = ''; + /** @var string */ + private $host; /** @var int|null */ private $port; - /** @var string */ - private $path = ''; - /** @var string */ - private $query = ''; - /** @var string */ - private $fragment = ''; + /** @var string */ + private $path; + /** @var string */ + private $query; + /** @var string */ + private $fragment; /** * @param string $uri A string representation of a URI. @@ -44,34 +44,15 @@ class Uri implements UriInterface public function __construct(string $uri = '') { $parsed = parse_url($uri); - if (!$parsed) { - return; - } - if (isset($parsed['scheme'])) { - $this->scheme = $parsed['scheme']; - } - if (isset($parsed['host'])) { - $this->host = strtolower($parsed['host']); - } - if (isset($parsed['port'])) { - $this->port = $parsed['port']; - } - if (isset($parsed['user'])) { - $this->user = $parsed['user']; - } - if (isset($parsed['pass'])) { - $this->password = $parsed['pass']; - } - if (isset($parsed['path'])) { - $this->path = $parsed['path']; - } - if (isset($parsed['query'])) { - $this->query = $parsed['query']; - } - if (isset($parsed['fragment'])) { - $this->fragment = $parsed['fragment']; - } + $this->scheme = $parsed['scheme'] ?? ''; + $this->user = $parsed['user'] ?? ''; + $this->password = $parsed['pass'] ?? ''; + $this->host = strtolower($parsed['host'] ?? ''); + $this->port = $parsed['port'] ?? null; + $this->path = $parsed['path'] ?? ''; + $this->query = $parsed['query'] ?? ''; + $this->fragment = $parsed['fragment'] ?? ''; } /** @@ -338,7 +319,7 @@ class Uri implements UriInterface { $uri = clone $this; $uri->user = $user; - $uri->password = $password; + $uri->password = $password ?? ''; return $uri; } diff --git a/test/tests/unit/Message/UploadedFileTest.php b/test/tests/unit/Message/UploadedFileTest.php index e208e40..77b6ac1 100644 --- a/test/tests/unit/Message/UploadedFileTest.php +++ b/test/tests/unit/Message/UploadedFileTest.php @@ -70,7 +70,7 @@ class UploadedFileTest extends TestCase $this->expectException(RuntimeException::class); UploadedFileState::$php_sapi_name = 'apache'; UploadedFileState::$is_uploaded_file = false; - $file = new UploadedFile('', '', 0, '', 0); + $file = new UploadedFile('', '', 0, $this->tmpName, 0); $file->getStream(); } diff --git a/test/tests/unit/Message/UriTest.php b/test/tests/unit/Message/UriTest.php index 5d51fb8..20b9468 100644 --- a/test/tests/unit/Message/UriTest.php +++ b/test/tests/unit/Message/UriTest.php @@ -16,7 +16,11 @@ class UriTest extends TestCase $this->assertSame('', $uri->getScheme()); } - /** @dataProvider schemeProvider */ + /** + * @dataProvider schemeProvider + * @param $expected + * @param $scheme + */ public function testSetsSchemeCaseInsensitively($expected, $scheme): void { $uri = new Uri(); From fe0f1ff8f9a19a4f8c4ba2b4a3d14387588ccd89 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 15 Aug 2020 07:53:03 -0400 Subject: [PATCH 44/53] Ensure typehints for bool are bool and not boolean --- src/Routing/Route/PrefixRoute.php | 2 +- src/Routing/Route/StaticRoute.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Routing/Route/PrefixRoute.php b/src/Routing/Route/PrefixRoute.php index 5aeb865..00a9b1f 100644 --- a/src/Routing/Route/PrefixRoute.php +++ b/src/Routing/Route/PrefixRoute.php @@ -21,7 +21,7 @@ class PrefixRoute extends Route * Examines a request target to see if it is a match for the route. * * @param string $requestTarget - * @return boolean + * @return bool */ public function matchesRequestTarget(string $requestTarget): bool { diff --git a/src/Routing/Route/StaticRoute.php b/src/Routing/Route/StaticRoute.php index 572827b..fec8cdb 100644 --- a/src/Routing/Route/StaticRoute.php +++ b/src/Routing/Route/StaticRoute.php @@ -16,7 +16,7 @@ class StaticRoute extends Route * Examines a request target to see if it is a match for the route. * * @param string $requestTarget - * @return boolean + * @return bool */ public function matchesRequestTarget(string $requestTarget): bool { From 5ba8771e93432cc777ecdd1e256537faa92665fa Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 15 Aug 2020 07:54:08 -0400 Subject: [PATCH 45/53] Ensure all constants have visibility --- test/tests/unit/Routing/Route/RouteTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/test/tests/unit/Routing/Route/RouteTest.php index e37f6d9..e226a37 100644 --- a/test/tests/unit/Routing/Route/RouteTest.php +++ b/test/tests/unit/Routing/Route/RouteTest.php @@ -13,7 +13,7 @@ class RouteTest extends TestCase { use ProphecyTrait; - const TARGET = '/target'; + private const TARGET = '/target'; private $methodMap; private $route; From 79d23e37a4ac9b919943669fd9e3299d68201fce Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 15 Aug 2020 10:11:06 -0400 Subject: [PATCH 46/53] Reorganize Tests --- .gitattributes | 10 ++++++---- .gitignore | 3 ++- .php_cs.dist | 2 +- composer.json | 5 ++--- docker/nginx/site.conf | 5 +++++ phpunit.xml.dist | 7 ++----- .../unit => tests}/Dispatching/DispatchStackTest.php | 0 .../unit => tests}/Dispatching/DispatcherTest.php | 0 {test/src => tests}/Doubles/MiddlewareMock.php | 0 {test/src => tests}/Doubles/NextMock.php | 0 .../unit => tests}/Message/HeaderCollectionTest.php | 0 {test/tests/unit => tests}/Message/MessageTest.php | 0 {test/tests/unit => tests}/Message/NullStreamTest.php | 0 {test/tests/unit => tests}/Message/RequestTest.php | 0 {test/tests/unit => tests}/Message/ResponseTest.php | 0 .../Message/ServerRequestMarshallerTest.php | 0 .../tests/unit => tests}/Message/ServerRequestTest.php | 0 {test/tests/unit => tests}/Message/StreamTest.php | 0 .../tests/unit => tests}/Message/UploadedFileTest.php | 0 {test/tests/unit => tests}/Message/UriTest.php | 0 .../unit => tests}/Routing/Route/MethodMapTest.php | 0 .../unit => tests}/Routing/Route/PrefixRouteTest.php | 0 .../unit => tests}/Routing/Route/RegexRouteTest.php | 0 .../unit => tests}/Routing/Route/RouteFactoryTest.php | 0 {test/tests/unit => tests}/Routing/Route/RouteTest.php | 0 .../unit => tests}/Routing/Route/StaticRouteTest.php | 0 .../unit => tests}/Routing/Route/TemplateRouteTest.php | 0 {test/tests/unit => tests}/Routing/RouterTest.php | 0 .../integration => tests/Routing}/RoutingTest.php | 7 +++++-- {test/tests/unit => tests}/ServerTest.php | 0 {test/src => tests}/TestCase.php | 0 .../unit => tests}/Transmission/TransmitterTest.php | 0 32 files changed, 23 insertions(+), 16 deletions(-) rename {test/tests/unit => tests}/Dispatching/DispatchStackTest.php (100%) rename {test/tests/unit => tests}/Dispatching/DispatcherTest.php (100%) rename {test/src => tests}/Doubles/MiddlewareMock.php (100%) rename {test/src => tests}/Doubles/NextMock.php (100%) rename {test/tests/unit => tests}/Message/HeaderCollectionTest.php (100%) rename {test/tests/unit => tests}/Message/MessageTest.php (100%) rename {test/tests/unit => tests}/Message/NullStreamTest.php (100%) rename {test/tests/unit => tests}/Message/RequestTest.php (100%) rename {test/tests/unit => tests}/Message/ResponseTest.php (100%) rename {test/tests/unit => tests}/Message/ServerRequestMarshallerTest.php (100%) rename {test/tests/unit => tests}/Message/ServerRequestTest.php (100%) rename {test/tests/unit => tests}/Message/StreamTest.php (100%) rename {test/tests/unit => tests}/Message/UploadedFileTest.php (100%) rename {test/tests/unit => tests}/Message/UriTest.php (100%) rename {test/tests/unit => tests}/Routing/Route/MethodMapTest.php (100%) rename {test/tests/unit => tests}/Routing/Route/PrefixRouteTest.php (100%) rename {test/tests/unit => tests}/Routing/Route/RegexRouteTest.php (100%) rename {test/tests/unit => tests}/Routing/Route/RouteFactoryTest.php (100%) rename {test/tests/unit => tests}/Routing/Route/RouteTest.php (100%) rename {test/tests/unit => tests}/Routing/Route/StaticRouteTest.php (100%) rename {test/tests/unit => tests}/Routing/Route/TemplateRouteTest.php (100%) rename {test/tests/unit => tests}/Routing/RouterTest.php (100%) rename {test/tests/integration => tests/Routing}/RoutingTest.php (98%) rename {test/tests/unit => tests}/ServerTest.php (100%) rename {test/src => tests}/TestCase.php (100%) rename {test/tests/unit => tests}/Transmission/TransmitterTest.php (100%) diff --git a/.gitattributes b/.gitattributes index 82dde02..a7b9800 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,10 +4,12 @@ /.php_cs* export-ignore /.travis.yml export-ignore /composer.lock export-ignore +/coverage export-ignore /docker export-ignore -/docker-compose.yml export-ignore +/docker-compose* export-ignore /docs export-ignore -/test export-ignore -/phpunit.xml.dist export-ignore -/psalm.xnk export-ignore +/tests export-ignore +/phpunit.xml* export-ignore +/psalm.xml export-ignore /public export-ignore +/vendor export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index fe38263..b64fb9a 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ notes # Local overrides .env -docker-compose.override.yml \ No newline at end of file +docker-compose.override.yml +phpunit.xml \ No newline at end of file diff --git a/.php_cs.dist b/.php_cs.dist index 09ee1bf..d9747c8 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -3,7 +3,7 @@ $finder = PhpCsFixer\Finder::create() ->files() ->in(__DIR__ . '/src') - ->in(__DIR__ . '/test'); + ->in(__DIR__ . '/tests'); return PhpCsFixer\Config::create() ->setFinder($finder) diff --git a/composer.json b/composer.json index 7415688..ab39b4b 100644 --- a/composer.json +++ b/composer.json @@ -30,9 +30,8 @@ }, "autoload-dev": { "psr-4": { - "WellRESTed\\": "test/tests/unit/", - "WellRESTed\\Test\\": "test/src/", - "WellRESTed\\Test\\Integration\\": "test/tests/integration/" + "WellRESTed\\": "tests", + "WellRESTed\\Test\\": "tests" } } } diff --git a/docker/nginx/site.conf b/docker/nginx/site.conf index 8270b24..453d502 100644 --- a/docker/nginx/site.conf +++ b/docker/nginx/site.conf @@ -13,6 +13,11 @@ server { try_files $uri $uri/ /index.php?$args; } + # Generated Code Coverage Report + location /coverage { + alias /usr/local/src/wellrested/coverage; + } + # Generated Documentation location /docs { alias /usr/local/src/wellrested/docs/build/html; diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 35a3533..08b894e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -14,15 +14,12 @@ ./src - + - ./test/tests/unit - - - ./test/tests/integration + ./tests diff --git a/test/tests/unit/Dispatching/DispatchStackTest.php b/tests/Dispatching/DispatchStackTest.php similarity index 100% rename from test/tests/unit/Dispatching/DispatchStackTest.php rename to tests/Dispatching/DispatchStackTest.php diff --git a/test/tests/unit/Dispatching/DispatcherTest.php b/tests/Dispatching/DispatcherTest.php similarity index 100% rename from test/tests/unit/Dispatching/DispatcherTest.php rename to tests/Dispatching/DispatcherTest.php diff --git a/test/src/Doubles/MiddlewareMock.php b/tests/Doubles/MiddlewareMock.php similarity index 100% rename from test/src/Doubles/MiddlewareMock.php rename to tests/Doubles/MiddlewareMock.php diff --git a/test/src/Doubles/NextMock.php b/tests/Doubles/NextMock.php similarity index 100% rename from test/src/Doubles/NextMock.php rename to tests/Doubles/NextMock.php diff --git a/test/tests/unit/Message/HeaderCollectionTest.php b/tests/Message/HeaderCollectionTest.php similarity index 100% rename from test/tests/unit/Message/HeaderCollectionTest.php rename to tests/Message/HeaderCollectionTest.php diff --git a/test/tests/unit/Message/MessageTest.php b/tests/Message/MessageTest.php similarity index 100% rename from test/tests/unit/Message/MessageTest.php rename to tests/Message/MessageTest.php diff --git a/test/tests/unit/Message/NullStreamTest.php b/tests/Message/NullStreamTest.php similarity index 100% rename from test/tests/unit/Message/NullStreamTest.php rename to tests/Message/NullStreamTest.php diff --git a/test/tests/unit/Message/RequestTest.php b/tests/Message/RequestTest.php similarity index 100% rename from test/tests/unit/Message/RequestTest.php rename to tests/Message/RequestTest.php diff --git a/test/tests/unit/Message/ResponseTest.php b/tests/Message/ResponseTest.php similarity index 100% rename from test/tests/unit/Message/ResponseTest.php rename to tests/Message/ResponseTest.php diff --git a/test/tests/unit/Message/ServerRequestMarshallerTest.php b/tests/Message/ServerRequestMarshallerTest.php similarity index 100% rename from test/tests/unit/Message/ServerRequestMarshallerTest.php rename to tests/Message/ServerRequestMarshallerTest.php diff --git a/test/tests/unit/Message/ServerRequestTest.php b/tests/Message/ServerRequestTest.php similarity index 100% rename from test/tests/unit/Message/ServerRequestTest.php rename to tests/Message/ServerRequestTest.php diff --git a/test/tests/unit/Message/StreamTest.php b/tests/Message/StreamTest.php similarity index 100% rename from test/tests/unit/Message/StreamTest.php rename to tests/Message/StreamTest.php diff --git a/test/tests/unit/Message/UploadedFileTest.php b/tests/Message/UploadedFileTest.php similarity index 100% rename from test/tests/unit/Message/UploadedFileTest.php rename to tests/Message/UploadedFileTest.php diff --git a/test/tests/unit/Message/UriTest.php b/tests/Message/UriTest.php similarity index 100% rename from test/tests/unit/Message/UriTest.php rename to tests/Message/UriTest.php diff --git a/test/tests/unit/Routing/Route/MethodMapTest.php b/tests/Routing/Route/MethodMapTest.php similarity index 100% rename from test/tests/unit/Routing/Route/MethodMapTest.php rename to tests/Routing/Route/MethodMapTest.php diff --git a/test/tests/unit/Routing/Route/PrefixRouteTest.php b/tests/Routing/Route/PrefixRouteTest.php similarity index 100% rename from test/tests/unit/Routing/Route/PrefixRouteTest.php rename to tests/Routing/Route/PrefixRouteTest.php diff --git a/test/tests/unit/Routing/Route/RegexRouteTest.php b/tests/Routing/Route/RegexRouteTest.php similarity index 100% rename from test/tests/unit/Routing/Route/RegexRouteTest.php rename to tests/Routing/Route/RegexRouteTest.php diff --git a/test/tests/unit/Routing/Route/RouteFactoryTest.php b/tests/Routing/Route/RouteFactoryTest.php similarity index 100% rename from test/tests/unit/Routing/Route/RouteFactoryTest.php rename to tests/Routing/Route/RouteFactoryTest.php diff --git a/test/tests/unit/Routing/Route/RouteTest.php b/tests/Routing/Route/RouteTest.php similarity index 100% rename from test/tests/unit/Routing/Route/RouteTest.php rename to tests/Routing/Route/RouteTest.php diff --git a/test/tests/unit/Routing/Route/StaticRouteTest.php b/tests/Routing/Route/StaticRouteTest.php similarity index 100% rename from test/tests/unit/Routing/Route/StaticRouteTest.php rename to tests/Routing/Route/StaticRouteTest.php diff --git a/test/tests/unit/Routing/Route/TemplateRouteTest.php b/tests/Routing/Route/TemplateRouteTest.php similarity index 100% rename from test/tests/unit/Routing/Route/TemplateRouteTest.php rename to tests/Routing/Route/TemplateRouteTest.php diff --git a/test/tests/unit/Routing/RouterTest.php b/tests/Routing/RouterTest.php similarity index 100% rename from test/tests/unit/Routing/RouterTest.php rename to tests/Routing/RouterTest.php diff --git a/test/tests/integration/RoutingTest.php b/tests/Routing/RoutingTest.php similarity index 98% rename from test/tests/integration/RoutingTest.php rename to tests/Routing/RoutingTest.php index 4be0791..e7a7037 100644 --- a/test/tests/integration/RoutingTest.php +++ b/tests/Routing/RoutingTest.php @@ -1,6 +1,6 @@ Date: Sun, 16 Aug 2020 08:49:47 -0400 Subject: [PATCH 47/53] Message constructor accepts $headers values as string or string[] --- src/Message/Message.php | 22 ++++++++++------------ src/Message/Request.php | 4 ++-- tests/Message/MessageTest.php | 9 ++++++++- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/Message/Message.php b/src/Message/Message.php index c5f9758..8490c4e 100644 --- a/src/Message/Message.php +++ b/src/Message/Message.php @@ -22,13 +22,13 @@ abstract class Message implements MessageInterface * Create a new Message, optionally with headers and a body. * * $headers is an optional associative array with header field names as - * (string) keys and lists of header field values (string[]) as values. + * string keys and values as either string or string[]. * * If no StreamInterface is provided for $body, the instance will create * a NullStream instance for the message body. * * @param array $headers Associative array with header field names as - * (string) keys and lists of header field values (string[]) as values. + * keys and values as string|string[] * @param StreamInterface|null $body A stream representation of the message * entity body */ @@ -37,19 +37,17 @@ abstract class Message implements MessageInterface ?StreamInterface $body = null ) { $this->headers = new HeaderCollection(); - if ($headers) { - foreach ($headers as $name => $values) { - foreach ($values as $value) { - $this->headers[$name] = $value; - } + + foreach ($headers as $name => $values) { + if (is_string($values)) { + $values = [$values]; + } + foreach ($values as $value) { + $this->headers[$name] = $value; } } - if ($body !== null) { - $this->body = $body; - } else { - $this->body = new Stream(''); - } + $this->body = $body ?? new Stream(''); } public function __clone() diff --git a/src/Message/Request.php b/src/Message/Request.php index ca22f56..55eeafb 100644 --- a/src/Message/Request.php +++ b/src/Message/Request.php @@ -34,7 +34,7 @@ class Request extends Message implements RequestInterface * Create a new Request. * * $headers is an optional associative array with header field names as - * (string) keys and lists of header field values (string[]) as values. + * string keys and values as either string or string[]. * * If no StreamInterface is provided for $body, the instance will create * a NullStream instance for the message body. @@ -42,7 +42,7 @@ class Request extends Message implements RequestInterface * @param string $method * @param string|UriInterface $uri * @param array $headers Associative array with header field names as - * (string) keys and lists of header field values (string[]) as values. + * keys and values as string|string[] * @param StreamInterface|null $body A stream representation of the message * entity body */ diff --git a/tests/Message/MessageTest.php b/tests/Message/MessageTest.php index 11d5565..5b84cbd 100644 --- a/tests/Message/MessageTest.php +++ b/tests/Message/MessageTest.php @@ -7,7 +7,14 @@ use WellRESTed\Test\TestCase; class MessageTest extends TestCase { - public function testSetsHeadersOnConstruction(): void + public function testSetsHeadersWithStringValueOnConstruction(): void + { + $headers = ['X-foo' => 'bar']; + $message = new Response(200, $headers); + $this->assertEquals(['bar'], $message->getHeader('X-foo')); + } + + public function testSetsHeadersWithArrayValueOnConstruction(): void { $headers = ['X-foo' => ['bar', 'baz']]; $message = new Response(200, $headers); From 9243dd7663ac6b391c352674410ba32b768480d3 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 16 Aug 2020 08:52:33 -0400 Subject: [PATCH 48/53] Refactor ServerRequestMarshaller and ServerRequest --- src/Message/ServerRequest.php | 30 +++++++++-- src/Message/ServerRequestMarshaller.php | 52 ++++++++----------- tests/Message/ServerRequestMarshallerTest.php | 37 +++++++++---- 3 files changed, 76 insertions(+), 43 deletions(-) diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index 601499f..6ec61aa 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -4,7 +4,9 @@ namespace WellRESTed\Message; use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UploadedFileInterface; +use Psr\Http\Message\UriInterface; /** * Representation of an incoming, server-side HTTP request. @@ -51,9 +53,31 @@ class ServerRequest extends Request implements ServerRequestInterface // ------------------------------------------------------------------------- - public function __construct(array $serverParams = []) - { - parent::__construct(); + /** + * Create a new ServerRequest. + * + * $headers is an optional associative array with header field names as + * string keys and values as either string or string[]. + * + * If no StreamInterface is provided for $body, the instance will create + * a NullStream instance for the message body. + * + * @param string $method + * @param string|UriInterface $uri + * @param array $headers Associative array with header field names as + * keys and values as string|string[] + * @param StreamInterface|null $body A stream representation of the message + * entity body + * @param array $serverParams An array of Server API (SAPI) parameters + */ + public function __construct( + string $method = 'GET', + $uri = '', + array $headers = [], + ?StreamInterface $body = null, + array $serverParams = [] + ){ + parent::__construct($method, $uri, $headers, $body); $this->serverParams = $serverParams; $this->cookieParams = []; $this->queryParams = []; diff --git a/src/Message/ServerRequestMarshaller.php b/src/Message/ServerRequestMarshaller.php index 9b67065..ae61317 100644 --- a/src/Message/ServerRequestMarshaller.php +++ b/src/Message/ServerRequestMarshaller.php @@ -8,38 +8,28 @@ use Psr\Http\Message\UriInterface; class ServerRequestMarshaller { - public function getServerRequest( - ?array $serverParams = null, - ?array $cookieParams = null, - ?array $queryParams = null, - ?array $postParams = null, - ?array $fileParams = null, - string $inputStream = 'php://input' - ): ServerRequestInterface { - $serverParams = $serverParams ?? $_SERVER; - $cookieParams = $cookieParams ?? $_COOKIE; - $queryParams = $queryParams ?? self::parseQuery($serverParams); - $postParams = $postParams ?? $_POST; - $fileParams = $fileParams ?? $_FILES; + /** + * Read the request as sent from the client and construct a ServerRequest + * representation. + * + * @return ServerRequestInterface + * @internal + */ + public function getServerRequest(): ServerRequestInterface + { + $method = self::parseMethod($_SERVER); + $uri = self::readUri($_SERVER); + $headers = self::parseHeaders($_SERVER); + $body = self::readBody(); - $request = new ServerRequest($serverParams); - - $request = $request - ->withProtocolVersion(self::parseProtocolVersion($serverParams)) - ->withMethod(self::parseMethod($serverParams)) - ->withBody(self::readBody($inputStream)) - ->withUri(self::readUri($serverParams)) - ->withUploadedFiles(self::readUploadedFiles($fileParams)) - ->withCookieParams($cookieParams) - ->withQueryParams($queryParams); - - $headers = self::parseHeaders($serverParams); - foreach ($headers as $name => $value) { - $request = $request->withAddedHeader($name, $value); - } + $request = (new ServerRequest($method, $uri, $headers, $body, $_SERVER)) + ->withProtocolVersion(self::parseProtocolVersion($_SERVER)) + ->withUploadedFiles(self::readUploadedFiles($_FILES)) + ->withCookieParams($_COOKIE) + ->withQueryParams(self::parseQuery($_SERVER)); if (self::isForm($request)) { - $request = $request->withParsedBody($postParams); + $request = $request->withParsedBody($_POST); } return $request; @@ -95,9 +85,9 @@ class ServerRequestMarshaller return $serverParams['REQUEST_METHOD'] ?? 'GET'; } - private static function readBody(string $inputStream): StreamInterface + private static function readBody(): StreamInterface { - $input = fopen($inputStream, 'rb'); + $input = fopen('php://input', 'rb'); $temp = fopen('php://temp', 'wb+'); stream_copy_to_stream($input, $temp); rewind($temp); diff --git a/tests/Message/ServerRequestMarshallerTest.php b/tests/Message/ServerRequestMarshallerTest.php index c579371..1bf829f 100644 --- a/tests/Message/ServerRequestMarshallerTest.php +++ b/tests/Message/ServerRequestMarshallerTest.php @@ -28,6 +28,8 @@ class ServerRequestMarshallerTest extends TestCase 'hamster' => 'Dusty' ]; + FopenHelper::$inputTempFile = null; + $this->marshaller = new ServerRequestMarshaller(); } @@ -103,15 +105,9 @@ class ServerRequestMarshallerTest extends TestCase $tempFilePath = tempnam(sys_get_temp_dir(), 'test'); $content = 'Body content'; file_put_contents($tempFilePath, $content); + FopenHelper::$inputTempFile = $tempFilePath; - $request = $this->marshaller->getServerRequest( - null, - null, - null, - null, - null, - $tempFilePath - ); + $request = $this->marshaller->getServerRequest(); unlink($tempFilePath); $this->assertEquals($content, (string) $request->getBody()); @@ -182,7 +178,8 @@ class ServerRequestMarshallerTest extends TestCase */ public function testProvidesUri(UriInterface $expected, array $serverParams): void { - $request = $this->marshaller->getServerRequest($serverParams); + $_SERVER = $serverParams; + $request = $this->marshaller->getServerRequest(); $this->assertEquals($expected, $request->getUri()); } @@ -379,3 +376,25 @@ class ServerRequestMarshallerTest extends TestCase ]; } } + +// ----------------------------------------------------------------------------- + +// Declare fopen function in this namespace so the class under test will use +// this instead of the internal global functions during testing. + +class FopenHelper +{ + /** + * @var string Path to temp file to read in place of 'php://input' + */ + public static $inputTempFile; +} + +function fopen($filename, $mode) +{ + if (FopenHelper::$inputTempFile && $filename === 'php://input') { + $filename = FopenHelper::$inputTempFile; + } + + return \fopen($filename, $mode); +} From 95c3be85c9dfb20f016936f44f474e540e22b60d Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 16 Aug 2020 10:47:39 -0400 Subject: [PATCH 49/53] Create implementations for PSR-17 Response- and StreamFactoryInterface --- composer.json | 3 +- composer.lock | 526 +++++++++++++------------- phpunit.xml.dist | 17 +- src/Message/ResponseFactory.php | 27 ++ src/Message/ServerRequest.php | 2 +- src/Message/StreamFactory.php | 53 +++ tests/Message/ResponseFactoryTest.php | 44 +++ tests/Message/StreamFactoryTest.php | 95 +++++ 8 files changed, 493 insertions(+), 274 deletions(-) create mode 100644 src/Message/ResponseFactory.php create mode 100644 src/Message/StreamFactory.php create mode 100644 tests/Message/ResponseFactoryTest.php create mode 100644 tests/Message/StreamFactoryTest.php diff --git a/composer.json b/composer.json index ab39b4b..1a7446c 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "wellrested/wellrested", "description": "Simple PHP Library for RESTful APIs", - "keywords": ["rest", "restful", "api", "http", "psr7", "psr-7", "psr15", "psr-15"], + "keywords": ["rest", "restful", "api", "http", "psr7", "psr-7", "psr15", "psr-15", "psr17", "psr-17"], "homepage": "https://www.wellrested.org", "license": "MIT", "type": "library", @@ -13,6 +13,7 @@ ], "require": { "php": ">=7.2", + "psr/http-factory": "~1.0", "psr/http-message": "~1.0", "psr/http-server-handler": "~1.0", "psr/http-server-middleware": "~1.0" diff --git a/composer.lock b/composer.lock index 02cddea..6f27dbc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,60 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4d35c0aa434d9f710cd5a8a7246367d4", + "content-hash": "041c27e394aba3e5c3bf6cbe8751f845", "packages": [ + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -314,6 +366,75 @@ ], "time": "2020-06-29T18:35:05+00:00" }, + { + "name": "composer/package-versions-deprecated", + "version": "1.10.99.1", + "source": { + "type": "git", + "url": "https://github.com/composer/package-versions-deprecated.git", + "reference": "68c9b502036e820c33445ff4d174327f6bb87486" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/68c9b502036e820c33445ff4d174327f6bb87486", + "reference": "68c9b502036e820c33445ff4d174327f6bb87486", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7 || ^8" + }, + "replace": { + "ocramius/package-versions": "1.10.99" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "ext-zip": "^1.13", + "phpunit/phpunit": "^6.5 || ^7" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-08-13T12:55:41+00:00" + }, { "name": "composer/semver", "version": "1.5.1", @@ -435,16 +556,16 @@ }, { "name": "doctrine/annotations", - "version": "1.10.3", + "version": "1.10.4", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d" + "reference": "bfe91e31984e2ba76df1c1339681770401ec262f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d", - "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/bfe91e31984e2ba76df1c1339681770401ec262f", + "reference": "bfe91e31984e2ba76df1c1339681770401ec262f", "shasum": "" }, "require": { @@ -454,7 +575,8 @@ }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^7.5" + "phpstan/phpstan": "^0.12.20", + "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", "extra": { @@ -500,7 +622,7 @@ "docblock", "parser" ], - "time": "2020-05-25T17:24:27+00:00" + "time": "2020-08-10T19:35:50+00:00" }, { "name": "doctrine/instantiator", @@ -935,16 +1057,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.8.0", + "version": "v4.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "8c58eb4cd4f3883f82611abeac2efbc3dbed787e" + "reference": "c346bbfafe2ff60680258b631afb730d186ed864" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8c58eb4cd4f3883f82611abeac2efbc3dbed787e", - "reference": "8c58eb4cd4f3883f82611abeac2efbc3dbed787e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864", + "reference": "c346bbfafe2ff60680258b631afb730d186ed864", "shasum": "" }, "require": { @@ -952,8 +1074,8 @@ "php": ">=7.0" }, "require-dev": { - "ircmaxell/php-yacc": "^0.0.6", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" @@ -961,7 +1083,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.8-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -983,68 +1105,7 @@ "parser", "php" ], - "time": "2020-08-09T10:23:20+00:00" - }, - { - "name": "ocramius/package-versions", - "version": "1.9.0", - "source": { - "type": "git", - "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "94c9d42a466c57f91390cdd49c81313264f49d85" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/94c9d42a466c57f91390cdd49c81313264f49d85", - "reference": "94c9d42a466c57f91390cdd49c81313264f49d85", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7.4.0" - }, - "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "doctrine/coding-standard": "^7.0.2", - "ext-zip": "^1.15.0", - "infection/infection": "^0.15.3", - "phpunit/phpunit": "^9.1.1", - "vimeo/psalm": "^3.9.3" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.99.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "funding": [ - { - "url": "https://github.com/Ocramius", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/ocramius/package-versions", - "type": "tidelift" - } - ], - "time": "2020-06-22T14:15:44+00:00" + "time": "2020-07-02T17:12:47+00:00" }, { "name": "openlss/lib-array2xml", @@ -1142,29 +1203,28 @@ }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -1194,24 +1254,24 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2020-06-27T14:33:11+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "3.0.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "c6bb6825def89e0a32220f88337f8ceaf1975fa0" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/c6bb6825def89e0a32220f88337f8ceaf1975fa0", - "reference": "c6bb6825def89e0a32220f88337f8ceaf1975fa0", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^5.6 || ^7.0" }, "type": "library", "autoload": { @@ -1241,7 +1301,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2020-06-27T14:39:04+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "php-cs-fixer/diff", @@ -1345,16 +1405,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.0", + "version": "5.2.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "3170448f5769fe19f456173d833734e0ff1b84df" + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/3170448f5769fe19f456173d833734e0ff1b84df", - "reference": "3170448f5769fe19f456173d833734e0ff1b84df", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d870572532cd70bc3fab58f2e23ad423c8404c44", + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44", "shasum": "" }, "require": { @@ -1393,7 +1453,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": "2020-07-20T20:05:34+00:00" + "time": "2020-08-15T11:14:08+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -1553,35 +1613,32 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.1.2", + "version": "8.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "5210f9269e44e6d34419cb92242ef11aee9351ac" + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5210f9269e44e6d34419cb92242ef11aee9351ac", - "reference": "5210f9269e44e6d34419cb92242ef11aee9351ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.7", - "php": "^7.3 || ^8.0", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "php": "^7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-text-template": "^2.0", + "phpunit/php-token-stream": "^4.0", + "sebastian/code-unit-reverse-lookup": "^2.0", + "sebastian/environment": "^5.0", + "sebastian/version": "^3.0", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-pcov": "*", @@ -1590,7 +1647,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.1-dev" + "dev-master": "8.0-dev" } }, "autoload": { @@ -1622,7 +1679,7 @@ "type": "github" } ], - "time": "2020-08-10T07:24:51+00:00" + "time": "2020-05-23T08:02:54+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1850,17 +1907,73 @@ "time": "2020-06-26T11:58:13+00:00" }, { - "name": "phpunit/phpunit", - "version": "9.3.5", + "name": "phpunit/php-token-stream", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "7115b00b23bcd4f62a73855c9615694d2f206e71" + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7115b00b23bcd4f62a73855c9615694d2f206e71", - "reference": "7115b00b23bcd4f62a73855c9615694d2f206e71", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-08-04T08:28:15+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.2.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", "shasum": "" }, "require": { @@ -1871,30 +1984,30 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", - "phar-io/version": "^3.0.2", - "php": "^7.3 || ^8.0", - "phpspec/prophecy": "^1.11.1", - "phpunit/php-code-coverage": "^9.1.1", - "phpunit/php-file-iterator": "^3.0.4", - "phpunit/php-invoker": "^3.1", + "myclabs/deep-copy": "^1.9.5", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.3", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^8.0.2", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-invoker": "^3.0.2", "phpunit/php-text-template": "^2.0.2", "phpunit/php-timer": "^5.0.1", "sebastian/code-unit": "^1.0.5", "sebastian/comparator": "^4.0.3", - "sebastian/diff": "^4.0.2", + "sebastian/diff": "^4.0.1", "sebastian/environment": "^5.1.2", "sebastian/exporter": "^4.0.2", - "sebastian/global-state": "^5.0", + "sebastian/global-state": "^4.0", "sebastian/object-enumerator": "^4.0.2", "sebastian/resource-operations": "^3.0.2", - "sebastian/type": "^2.2.1", + "sebastian/type": "^2.1.1", "sebastian/version": "^3.0.1" }, "require-dev": { "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" + "phpspec/prophecy-phpunit": "^2.0" }, "suggest": { "ext-soap": "*", @@ -1906,7 +2019,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.3-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -1945,7 +2058,7 @@ "type": "github" } ], - "time": "2020-08-10T06:50:08+00:00" + "time": "2020-07-13T17:55:55+00:00" }, { "name": "psr/container", @@ -2262,59 +2375,6 @@ ], "time": "2020-06-26T12:05:46+00:00" }, - { - "name": "sebastian/complexity", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "33fcd6a26656c6546f70871244ecba4b4dced097" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/33fcd6a26656c6546f70871244ecba4b4dced097", - "reference": "33fcd6a26656c6546f70871244ecba4b4dced097", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.7", - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-07-25T14:01:34+00:00" - }, { "name": "sebastian/diff", "version": "4.0.2", @@ -2511,26 +2571,26 @@ }, { "name": "sebastian/global-state", - "version": "5.0.0", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "22ae663c951bdc39da96603edc3239ed3a299097" + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/22ae663c951bdc39da96603edc3239ed3a299097", - "reference": "22ae663c951bdc39da96603edc3239ed3a299097", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", "shasum": "" }, "require": { - "php": "^7.3 || ^8.0", + "php": "^7.3", "sebastian/object-reflector": "^2.0", "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-uopz": "*" @@ -2538,7 +2598,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2561,66 +2621,7 @@ "keywords": [ "global state" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-08-07T04:09:03+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e02bf626f404b5daec382a7b8a6a4456e49017e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e02bf626f404b5daec382a7b8a6a4456e49017e5", - "reference": "e02bf626f404b5daec382a7b8a6a4456e49017e5", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.6", - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-07-22T18:33:42+00:00" + "time": "2020-02-07T06:11:37+00:00" }, { "name": "sebastian/object-enumerator", @@ -4408,21 +4409,22 @@ }, { "name": "vimeo/psalm", - "version": "3.12.2", + "version": "3.13.1", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "7c7ebd068f8acaba211d4a2c707c4ba90874fa26" + "reference": "afd8874a9e4562eac42a02de90e42e430c3a1db1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/7c7ebd068f8acaba211d4a2c707c4ba90874fa26", - "reference": "7c7ebd068f8acaba211d4a2c707c4ba90874fa26", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/afd8874a9e4562eac42a02de90e42e430c3a1db1", + "reference": "afd8874a9e4562eac42a02de90e42e430c3a1db1", "shasum": "" }, "require": { "amphp/amp": "^2.1", "amphp/byte-stream": "^1.5", + "composer/package-versions-deprecated": "^1.8.0", "composer/semver": "^1.4 || ^2.0 || ^3.0", "composer/xdebug-handler": "^1.1", "ext-dom": "*", @@ -4432,9 +4434,8 @@ "ext-tokenizer": "*", "felixfbecker/advanced-json-rpc": "^3.0.3", "felixfbecker/language-server-protocol": "^1.4", - "netresearch/jsonmapper": "^1.0 || ^2.0", - "nikic/php-parser": "^4.3", - "ocramius/package-versions": "^1.2", + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0", + "nikic/php-parser": "4.3.* || 4.4.* || 4.5.* || 4.6.*", "openlss/lib-array2xml": "^1.0", "php": "^7.1.3|^8", "sebastian/diff": "^3.0 || ^4.0", @@ -4450,7 +4451,6 @@ "bamarni/composer-bin-plugin": "^1.2", "brianium/paratest": "^4.0.0", "ext-curl": "*", - "php-coveralls/php-coveralls": "^2.2", "phpmyadmin/sql-parser": "5.1.0", "phpspec/prophecy": ">=1.9.0", "phpunit/phpunit": "^7.5.16 || ^8.5 || ^9.0", @@ -4501,7 +4501,7 @@ "inspection", "php" ], - "time": "2020-07-03T16:59:07+00:00" + "time": "2020-07-30T19:42:34+00:00" }, { "name": "webmozart/assert", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 08b894e..662994b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -9,18 +9,17 @@ stopOnFailure="false" verbose="true" > - - - ./src - - - - - ./tests - + + + ./src + + + + + diff --git a/src/Message/ResponseFactory.php b/src/Message/ResponseFactory.php new file mode 100644 index 0000000..414d891 --- /dev/null +++ b/src/Message/ResponseFactory.php @@ -0,0 +1,27 @@ +withStatus($code, $reasonPhrase); + } +} diff --git a/src/Message/ServerRequest.php b/src/Message/ServerRequest.php index 6ec61aa..e61ffc8 100644 --- a/src/Message/ServerRequest.php +++ b/src/Message/ServerRequest.php @@ -76,7 +76,7 @@ class ServerRequest extends Request implements ServerRequestInterface array $headers = [], ?StreamInterface $body = null, array $serverParams = [] - ){ + ) { parent::__construct($method, $uri, $headers, $body); $this->serverParams = $serverParams; $this->cookieParams = []; diff --git a/src/Message/StreamFactory.php b/src/Message/StreamFactory.php new file mode 100644 index 0000000..0acda40 --- /dev/null +++ b/src/Message/StreamFactory.php @@ -0,0 +1,53 @@ +createResponse(); + + $this->assertEquals($statusCode, $response->getStatusCode()); + $this->assertEquals($reasonPhrase, $response->getReasonPhrase()); + } + + public function testCreateResponseWithStatusCode(): void + { + $statusCode = 201; + $reasonPhrase = 'Created'; + + $factory = new ResponseFactory(); + $response = $factory->createResponse($statusCode); + + $this->assertEquals($statusCode, $response->getStatusCode()); + $this->assertEquals($reasonPhrase, $response->getReasonPhrase()); + } + + public function testCreateResponseWithStatusCodeAndCustomReasonPhrase(): void + { + $statusCode = 512; + $reasonPhrase = 'Shortage of Chairs'; + + $factory = new ResponseFactory(); + $response = $factory->createResponse($statusCode, $reasonPhrase); + + $this->assertEquals($statusCode, $response->getStatusCode()); + $this->assertEquals($reasonPhrase, $response->getReasonPhrase()); + } +} diff --git a/tests/Message/StreamFactoryTest.php b/tests/Message/StreamFactoryTest.php new file mode 100644 index 0000000..2517d76 --- /dev/null +++ b/tests/Message/StreamFactoryTest.php @@ -0,0 +1,95 @@ +tempPath = tempnam(sys_get_temp_dir(), 'test'); + file_put_contents($this->tempPath, self::CONTENT); + } + + protected function tearDown(): void + { + parent::tearDown(); + unlink($this->tempPath); + } + + // ------------------------------------------------------------------------- + + public function testCreatesStreamFromString(): void + { + $factory = new StreamFactory(); + $stream = $factory->createStream(self::CONTENT); + + $this->assertEquals(self::CONTENT, (string) $stream); + } + + public function testCreatesStreamFromFile(): void + { + $factory = new StreamFactory(); + $stream = $factory->createStreamFromFile($this->tempPath); + + $this->assertEquals(self::CONTENT, (string) $stream); + } + + public function testCreatesStreamFromFileWithModeRByDefault(): void + { + $factory = new StreamFactory(); + $stream = $factory->createStreamFromFile($this->tempPath); + + $mode = $stream->getMetadata('mode'); + $this->assertEquals('r', $mode); + } + + /** + * @dataProvider modeProvider + * @param string $mode + */ + public function testCreatesStreamFromFileWithPassedMode(string $mode): void + { + $factory = new StreamFactory(); + $stream = $factory->createStreamFromFile($this->tempPath, $mode); + + $actual = $stream->getMetadata('mode'); + $this->assertEquals($mode, $actual); + } + + public function modeProvider(): array + { + return [ + ['r'], + ['r+'], + ['w'], + ['w+'] + ]; + } + + public function testCreateStreamFromFileThrowsRuntimeExceptionWhenUnableToOpenFile(): void + { + $this->expectException(RuntimeException::class); + + $factory = new StreamFactory(); + @$factory->createStreamFromFile('/dev/null/not-a-file', 'w'); + } + + public function testCreatesStreamFromResource(): void + { + $f = fopen($this->tempPath, 'r'); + + $factory = new StreamFactory(); + $stream = $factory->createStreamFromResource($f); + + $this->assertEquals(self::CONTENT, (string) $stream); + } +} From 8b467193d73aaa95dbc4c464e7b77678e0e8cde4 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 16 Aug 2020 11:54:28 -0400 Subject: [PATCH 50/53] Set minimum version to PHP 7.3 --- composer.json | 2 +- composer.lock | 4 ++-- docker-compose.yml | 5 ---- docker/nginx/site.conf | 2 +- docker/php/Dockerfile | 18 +++++++------- docker/php/entrypoint | 10 ++++++++ tests/Message/StreamTest.php | 46 ++++++++++++++++++++++++++++++++---- 7 files changed, 64 insertions(+), 23 deletions(-) create mode 100755 docker/php/entrypoint diff --git a/composer.json b/composer.json index 1a7446c..7e68dea 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "php": ">=7.2", + "php": ">=7.3", "psr/http-factory": "~1.0", "psr/http-message": "~1.0", "psr/http-server-handler": "~1.0", diff --git a/composer.lock b/composer.lock index 6f27dbc..6c47046 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "041c27e394aba3e5c3bf6cbe8751f845", + "content-hash": "bc05598d49e39b0082767d94ecb5bd4d", "packages": [ { "name": "psr/http-factory", @@ -4652,7 +4652,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.2" + "php": ">=7.3" }, "platform-dev": [], "plugin-api-version": "1.1.0" diff --git a/docker-compose.yml b/docker-compose.yml index 97e3292..7dabe4b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,8 +25,3 @@ services: volumes: - .:/usr/local/src/wellrested - ./docker/nginx/site.conf:/etc/nginx/conf.d/default.conf - - php-fpm: - image: php:7.4-fpm - volumes: - - .:/usr/local/src/wellrested diff --git a/docker/nginx/site.conf b/docker/nginx/site.conf index 453d502..ba76d7e 100644 --- a/docker/nginx/site.conf +++ b/docker/nginx/site.conf @@ -26,7 +26,7 @@ server { # PHP location ~ \.php$ { include fastcgi_params; - fastcgi_pass php-fpm:9000; + fastcgi_pass php:9000; fastcgi_index index.php; fastcgi_buffers 8 8k; fastcgi_buffer_size 16k; diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index aeae46a..9589150 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -1,4 +1,4 @@ -FROM php:7.4-cli +FROM php:7.3-fpm RUN DEBIAN_FRONTEND=noninteractive \ apt-get update && \ @@ -27,20 +27,18 @@ RUN mkdir /usr/local/src/wellrested && \ chown -R www-data:www-data /usr/local/src/wellrested && \ chown -R www-data:www-data /var/www -COPY ./src /usr/local/src/wellrested/src -COPY ./test /usr/local/src/wellrested/test -COPY ./composer.* /usr/local/src/wellrested/ -COPY ./phpunit.xml.dist /usr/local/src/wellrested/ +# Copy entrypoint script +COPY docker/php/entrypoint /usr/local/bin # Add symlinks for php-cs-fixer, phpunit, and psalm for easier running RUN ln -s /usr/local/src/wellrested/vendor/bin/php-cs-fixer /usr/local/bin/php-cs-fixer RUN ln -s /usr/local/src/wellrested/vendor/bin/phpunit /usr/local/bin/phpunit RUN ln -s /usr/local/src/wellrested/vendor/bin/psalm /usr/local/bin/psalm +ENTRYPOINT ["entrypoint"] + +CMD ["php-fpm"] + WORKDIR /usr/local/src/wellrested -USER www-data - -ENTRYPOINT ["dumb-init", "--"] - -RUN composer install +USER www-data \ No newline at end of file diff --git a/docker/php/entrypoint b/docker/php/entrypoint new file mode 100755 index 0000000..67bca32 --- /dev/null +++ b/docker/php/entrypoint @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# Run CLI commands with dumb-init to allow better signal handling. +# Run PHP-FPM as PID 1. +# https://engineeringblog.yelp.com/2016/01/dumb-init-an-init-for-docker.html +if [ "$1" == 'php-fpm' ] ; then + exec php-fpm +else + exec dumb-init -- "$@" +fi diff --git a/tests/Message/StreamTest.php b/tests/Message/StreamTest.php index b70b920..72ef2ef 100644 --- a/tests/Message/StreamTest.php +++ b/tests/Message/StreamTest.php @@ -15,8 +15,9 @@ class StreamTest extends TestCase protected function setUp(): void { $this->resource = fopen('php://memory', 'w+'); - $this->resourceDevNull = fopen('/dev/null', 'r'); + $this->resourceDevNull = fopen('/dev/zero', 'r'); fwrite($this->resource, $this->content); + StreamHelper::$fail = false; } protected function tearDown(): void @@ -105,7 +106,8 @@ class StreamTest extends TestCase public function testTellThrowsRuntimeExceptionWhenUnableToReadStreamPosition(): void { - $stream = new Stream($this->resourceDevNull); + StreamHelper::$fail = true; + $stream = new Stream($this->resource); $this->expectException(RuntimeException::class); $stream->tell(); } @@ -135,7 +137,8 @@ class StreamTest extends TestCase public function testSeekThrowsRuntimeExceptionWhenUnableToSeek(): void { - $stream = new Stream($this->resourceDevNull); + StreamHelper::$fail = true; + $stream = new Stream($this->resource); $this->expectException(RuntimeException::class); $stream->seek(10); } @@ -150,7 +153,8 @@ class StreamTest extends TestCase public function testRewindThrowsRuntimeExceptionWhenUnableToRewind(): void { - $stream = new Stream($this->resourceDevNull); + StreamHelper::$fail = true; + $stream = new Stream($this->resource); $this->expectException(RuntimeException::class); $stream->rewind(); } @@ -384,3 +388,37 @@ class StreamTest extends TestCase $this->assertNull($stream->getMetadata()); } } + +// ----------------------------------------------------------------------------- + +// Declare functions in this namespace so the class under test will use these +// instead of the internal global functions during testing. + +class StreamHelper +{ + public static $fail = false; +} + +function fseek($resource, $offset, $whence = SEEK_SET) +{ + if (StreamHelper::$fail) { + return -1; + } + return \fseek($resource, $offset, $whence); +} + +function ftell($resource) +{ + if (StreamHelper::$fail) { + return false; + } + return \ftell($resource); +} + +function rewind($resource) +{ + if (StreamHelper::$fail) { + return false; + } + return \rewind($resource); +} From 8f2206a65fefd2c9159521b652c3df3779870a28 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 16 Aug 2020 11:55:00 -0400 Subject: [PATCH 51/53] Set min verision for Travis to 7.3 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 161dea8..3d45ece 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: php php: - - "7.2" - "7.3" - "7.4" From bba06021226b36cf57e393857561192156a33d20 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 16 Aug 2020 17:39:41 -0400 Subject: [PATCH 52/53] Update README for v5 --- README.md | 37 ++++++++++++++++++++++++++++--------- public/index.php | 39 ++++++++------------------------------- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 2fe1888..34a6a2b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,19 @@ WellRESTed ========== -[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.0-8892BF.svg?style=flat-square)](https://php.net/) +[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.3-8892BF.svg?style=flat-square)](https://php.net/) [![Build Status](https://travis-ci.org/wellrestedphp/wellrested.svg?branch=master)](https://travis-ci.org/wellrestedphp/wellrested) [![Documentation Status](https://readthedocs.org/projects/wellrested/badge/?version=latest)](http://wellrested.readthedocs.org/en/latest/) -[![SensioLabsInsight](https://insight.sensiolabs.com/projects/b0a2efcb-49f8-4a90-a5bd-0c14e409f59e/mini.png)](https://insight.sensiolabs.com/projects/b0a2efcb-49f8-4a90-a5bd-0c14e409f59e) -WellRESTed is a library for creating RESTful Web services and websites in PHP. +WellRESTed is a library for creating RESTful APIs and websites in PHP that provides abstraction for HTTP messages, a powerful handler and middleware system, and a flexible router. + +### Features + +- Uses [PSR-7](https://www.php-fig.org/psr/psr-7/) interfaces for requests, responses, and streams. This lets you use other PSR-7 compatable libraries seamlessly with WellRESTed. +- Uses [PSR-15](https://www.php-fig.org/psr/psr-15/) interfaces for handlers and middleware to allow sharing and reusing code +- Router allows you to match paths with variables such as `/foo/{bar}/{baz}`. +- Middleware system provides a way to compose your application from discrete, modular components. +- Lazy-loaded handlers and middleware don't instantiate unless they're needed. Install ------- @@ -16,7 +23,7 @@ Add an entry for "wellrested/wellrested" to your composer.json file's `require` ```json { "require": { - "wellrested/wellrested": "^4" + "wellrested/wellrested": "^5" } } ``` @@ -55,14 +62,14 @@ class HomePageHandler implements RequestHandlerInterface // ----------------------------------------------------------------------------- -// Create a new server. +// Create a new Server instance. $server = new Server(); - // Add a router to the server to map methods and endpoints to handlers. $router = $server->createRouter(); -$router->register('GET', '/', new HomePageHandler()); +// Register the route GET / with an anonymous function that provides a handler. +$router->register("GET", "/", function () { return new HomePageHandler(); }); +// Add the router to the server. $server->add($router); - // Read the request from the client, dispatch a handler, and output. $server->respond(); ``` @@ -85,6 +92,18 @@ To run PHPUnit tests, use the `php` service: docker-compose run --rm php phpunit ``` +To run Psalm for static analysis: + +```bash +docker-compose run --rm php psalm +``` + +To run PHP Coding Standards Fixer: + +```bash +docker-compose run --rm php php-cs-fixer +``` + To generate documentation, use the `docs` service: ```bash @@ -104,5 +123,5 @@ The runs a site you can access at [http://localhost:8080](http://localhost:8080) Copyright and License --------------------- -Copyright © 2018 by PJ Dietz +Copyright © 202 by PJ Dietz Licensed under the [MIT license](http://opensource.org/licenses/MIT) diff --git a/public/index.php b/public/index.php index c19870d..98ae760 100644 --- a/public/index.php +++ b/public/index.php @@ -25,15 +25,15 @@ class HomePageHandler implements RequestHandlerInterface WellRESTed Development Site - +

WellRESTed Development Site

- +

To run unit tests, run:

docker-compose run --rm php phpunit

View the code coverage report.

- +

To generate documentation, run:

- docker-compose run --rm docs + docker-compose run --rm docs

View documentation.

@@ -47,36 +47,13 @@ HTML; // ----------------------------------------------------------------------------- +// Create a new Server instance. $server = new Server(); - // Add a router to the server to map methods and endpoints to handlers. $router = $server->createRouter(); -$router->register("GET", "/", new HomePageHandler()); +// Register the route GET / with an anonymous function that provides a handler. +$router->register("GET", "/", function () { return new HomePageHandler(); }); +// Add the router to the server. $server->add($router); - - -$server->add($server->createRouter() - ->register('GET, POST', '/cat', function ($rqst, $resp, $next) { - - $resp = $resp - ->withStatus(200) - ->withHeader('Content-type', 'text/html') - ->withBody(new Stream('Molly')); - return $next($rqst, $resp); - }) -); - -$server->add($server->createRouter() - ->register('GET', '/cat', function ($rqst, $resp) { - - $body = (string) $resp->getBody(); - - - return (new Response(200)) - ->withHeader('Content-type', 'text/html') - ->withBody(new Stream($body . ' Oscar')); - }) -); - // Read the request from the client, dispatch a handler, and output. $server->respond(); From c74a468f3e2d25a91ab75d35b9f8516b7153c056 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 16 Aug 2020 18:03:17 -0400 Subject: [PATCH 53/53] Update documentation for v5 --- README.md | 2 +- docs/source/changes-from-version-3.rst | 16 ---------------- docs/source/conf.py | 6 +++--- docs/source/extending.rst | 15 +++------------ docs/source/index.rst | 1 - docs/source/overview.rst | 4 ++-- 6 files changed, 9 insertions(+), 35 deletions(-) delete mode 100644 docs/source/changes-from-version-3.rst diff --git a/README.md b/README.md index 34a6a2b..928a49b 100644 --- a/README.md +++ b/README.md @@ -123,5 +123,5 @@ The runs a site you can access at [http://localhost:8080](http://localhost:8080) Copyright and License --------------------- -Copyright © 202 by PJ Dietz +Copyright © 2020 by PJ Dietz Licensed under the [MIT license](http://opensource.org/licenses/MIT) diff --git a/docs/source/changes-from-version-3.rst b/docs/source/changes-from-version-3.rst deleted file mode 100644 index 4ff8bc7..0000000 --- a/docs/source/changes-from-version-3.rst +++ /dev/null @@ -1,16 +0,0 @@ -Changes from Version 3 -====================== - -If your project uses WellRESTed version 3, you can most likely upgrade to to version 4 without making any changes to your code. However, there are a few changes that may affect some users, particularly users who have subclassed ``WellRESTed\Server`` or used custom implementations of other ``WellRESTed`` classes. - -Server Configuration -^^^^^^^^^^^^^^^^^^^^ - -Version 4 allows for easier customization of the server than version 3. Previously, to customize the Server, you would need to subclass Server and override protected methods that provided a default request, response, transmitter, etc. The Server in version 4 now provides the following setters for providing custom behavior: - -- ``setAttributes(array $attributes)`` -- ``setDispatcher(DispatcherInterface $dispatcher)`` -- ``setPathVariablesAttributeName(string $name)`` -- ``setRequest(ServerRequestInterface $request)`` -- ``setResponse(ResponseInterface $response)`` -- ``setTransmitter(TransmitterInterface $transmitter)`` diff --git a/docs/source/conf.py b/docs/source/conf.py index fe831cb..2c1ed94 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,9 +25,9 @@ master_doc = 'index' # General information about the project. project = u'WellRESTed' -copyright = u'2018, PJ Dietz' -version = '4.0.0' -release = '4.0.0' +copyright = u'202, PJ Dietz' +version = '5.0.0' +release = '5.0.0' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. diff --git a/docs/source/extending.rst b/docs/source/extending.rst index 8f3f180..7cc1d28 100644 --- a/docs/source/extending.rst +++ b/docs/source/extending.rst @@ -73,7 +73,7 @@ If you need the ability to dispatch other types of middleware, you can create yo $response = parent::dispatch($dispatchable, $request, $response, $next); } catch (\WellRESTed\Dispatching\DispatchException $e) { // If there's a problem, check if the handler or middleware - // (the "dispatchable") implements OtherHandlerInterface. + // (the "dispatchable") implements OtherHandlerInterface. // Dispatch it if it does. if ($dispatchable instanceof OtherHandlerInterface) { $response = $dispatchable->run($request); @@ -93,18 +93,9 @@ To use this dispatcher, create an instance implementing ``WellRESTed\Dispatching $server = new WellRESTed\Server(); $server->setDispatcher(new MyApi\CustomDispatcher()); -Message Customization ---------------------- +.. warning:: -In the example above, we passed a custom dispatcher to the server. You can also customize your server in other ways. For example, when the server reaches these end of its stack of middleware and has not had the response handled, it returns a blank 404 error response. You can customize this by passing a response to the server's ``setUnhandledResponse`` method. - -.. code-block:: php - - $unhandled = (new Response(404)) - ->withHeader('text/html') - ->withBody($fancy404message); - - $server->setUnhandledResponse($unhandled); + When you supply a custom Dispatcher, be sure to call ``Server::setDispatcher`` before you create any routers with ``Server::createRouter`` to allow the ``Server`` to pass you customer ``Dispatcher`` on to the newly created ``Router``. .. _PSR-7: https://www.php-fig.org/psr/psr-7/ .. _Handlers and Middleware: handlers-and-middleware.html diff --git a/docs/source/index.rst b/docs/source/index.rst index 6491e5d..81a84ac 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -138,7 +138,6 @@ Contents dependency-injection additional web-server-configuration - changes-from-version-3 .. _PSR-7: https://www.php-fig.org/psr/psr-7/ .. _PSR-15: https://www.php-fig.org/psr/psr-15/ diff --git a/docs/source/overview.rst b/docs/source/overview.rst index 7a570a1..6714ab4 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -10,14 +10,14 @@ The recommended method for installing WellRESTed is to use Composer_. Add an ent { "require": { - "wellrested/wellrested": "^4" + "wellrested/wellrested": "^5" } } Requirements ^^^^^^^^^^^^ -- PHP 7.0 +- PHP 7.3 License ^^^^^^^