diff --git a/composer.json b/composer.json index b276c7d..ecf2616 100644 --- a/composer.json +++ b/composer.json @@ -31,11 +31,13 @@ } }, "require": { - "php": "^7.3 || ~8.0.0 || ~8.1.0", + "php": "^7.4 || ~8.0.0 || ~8.1.0", "ext-dom": "*", "ext-json": "*", + "psr/http-factory": "^1.0", "psr/http-message": "^1.0.1", "psr/link": "^1.0", + "webmozart/assert": "^1.10", "willdurand/negotiation": "^3.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index d5cb070..6cbb5a6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,63 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "85f8e1cb2192c4c01f94b2b744cf60b5", + "content-hash": "dfac9153c74306ea8f4d7eda11a78ab2", "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" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -111,6 +166,143 @@ }, "time": "2016-10-28T16:06:13+00:00" }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + }, + "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": "2021-02-19T12:13:01+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + }, { "name": "willdurand/negotiation", "version": "3.0.0", @@ -171,27 +363,27 @@ "packages-dev": [ { "name": "amphp/amp", - "version": "v2.5.2", + "version": "v2.6.1", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9" + "reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/efca2b32a7580087adb8aabbff6be1dc1bb924a9", - "reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9", + "url": "https://api.github.com/repos/amphp/amp/zipball/c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae", + "reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae", "shasum": "" }, "require": { - "php": ">=7" + "php": ">=7.1" }, "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", + "phpunit/phpunit": "^7 | ^8 | ^9", "psalm/phar": "^3.11@dev", "react/promise": "^2" }, @@ -248,7 +440,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.5.2" + "source": "https://github.com/amphp/amp/tree/v2.6.1" }, "funding": [ { @@ -256,7 +448,7 @@ "type": "github" } ], - "time": "2021-01-10T17:06:37+00:00" + "time": "2021-09-23T18:43:08+00:00" }, { "name": "amphp/byte-stream", @@ -410,16 +602,16 @@ }, { "name": "composer/semver", - "version": "3.2.4", + "version": "3.2.6", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" + "reference": "83e511e247de329283478496f7a1e114c9517506" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "url": "https://api.github.com/repos/composer/semver/zipball/83e511e247de329283478496f7a1e114c9517506", + "reference": "83e511e247de329283478496f7a1e114c9517506", "shasum": "" }, "require": { @@ -471,7 +663,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.4" + "source": "https://github.com/composer/semver/tree/3.2.6" }, "funding": [ { @@ -487,25 +679,25 @@ "type": "tidelift" } ], - "time": "2020-11-13T08:59:24+00:00" + "time": "2021-10-25T11:34:17+00:00" }, { "name": "composer/xdebug-handler", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496" + "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", - "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339", + "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0" + "psr/log": "^1 || ^2 || ^3" }, "require-dev": { "phpstan/phpstan": "^0.12.55", @@ -535,7 +727,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.1" + "source": "https://github.com/composer/xdebug-handler/tree/2.0.2" }, "funding": [ { @@ -551,7 +743,7 @@ "type": "tidelift" } ], - "time": "2021-05-05T19:37:51+00:00" + "time": "2021-07-31T17:03:58+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", @@ -1480,16 +1672,16 @@ }, { "name": "doctrine/orm", - "version": "2.10.2", + "version": "2.10.3", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "81d472f6f96b8b571cafefe8d2fef89ed9446a62" + "reference": "7b242753466508e1dd10f67c1baee95785f845c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/81d472f6f96b8b571cafefe8d2fef89ed9446a62", - "reference": "81d472f6f96b8b571cafefe8d2fef89ed9446a62", + "url": "https://api.github.com/repos/doctrine/orm/zipball/7b242753466508e1dd10f67c1baee95785f845c1", + "reference": "7b242753466508e1dd10f67c1baee95785f845c1", "shasum": "" }, "require": { @@ -1519,12 +1711,12 @@ "doctrine/annotations": "^1.13", "doctrine/coding-standard": "^9.0", "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/phpstan": "0.12.99", + "phpstan/phpstan": "1.2.0", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4", "squizlabs/php_codesniffer": "3.6.1", "symfony/cache": "^4.4 || ^5.2", "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "vimeo/psalm": "4.10.0" + "vimeo/psalm": "4.13.1" }, "suggest": { "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", @@ -1573,9 +1765,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.10.2" + "source": "https://github.com/doctrine/orm/tree/2.10.3" }, - "time": "2021-10-21T17:57:02+00:00" + "time": "2021-12-03T12:27:05+00:00" }, { "name": "doctrine/persistence", @@ -1666,20 +1858,20 @@ }, { "name": "felixfbecker/advanced-json-rpc", - "version": "v3.2.0", + "version": "v3.2.1", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", - "reference": "06f0b06043c7438959dbdeed8bb3f699a19be22e" + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/06f0b06043c7438959dbdeed8bb3f699a19be22e", - "reference": "06f0b06043c7438959dbdeed8bb3f699a19be22e", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", "shasum": "" }, "require": { - "netresearch/jsonmapper": "^1.0 || ^2.0", + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", "php": "^7.1 || ^8.0", "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" }, @@ -1705,9 +1897,9 @@ "description": "A more advanced JSONRPC implementation", "support": { "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", - "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.0" + "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" }, - "time": "2021-01-10T17:48:47+00:00" + "time": "2021-06-11T22:34:44+00:00" }, { "name": "felixfbecker/language-server-protocol", @@ -2088,68 +2280,6 @@ ], "time": "2021-11-10T11:33:52+00:00" }, - { - "name": "laminas/laminas-zendframework-bridge", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "bf180a382393e7db5c1e8d0f2ec0c4af9c724baf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/bf180a382393e7db5c1e8d0f2ec0c4af9c724baf", - "reference": "bf180a382393e7db5c1e8d0f2ec0c4af9c724baf", - "shasum": "" - }, - "require": { - "php": "^7.3 || ~8.0.0 || ~8.1.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "psalm/plugin-phpunit": "^0.15.1", - "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^4.6" - }, - "type": "library", - "extra": { - "laminas": { - "module": "Laminas\\ZendFrameworkBridge" - } - }, - "autoload": { - "files": [ - "src/autoload.php" - ], - "psr-4": { - "Laminas\\ZendFrameworkBridge\\": "src//" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Alias legacy ZF class names to Laminas Project equivalents.", - "keywords": [ - "ZendFramework", - "autoloading", - "laminas", - "zf" - ], - "support": { - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", - "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", - "source": "https://github.com/laminas/laminas-zendframework-bridge" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2021-09-03T17:53:30+00:00" - }, { "name": "mezzio/mezzio-helpers", "version": "5.7.0", @@ -2371,16 +2501,16 @@ }, { "name": "netresearch/jsonmapper", - "version": "v2.1.0", + "version": "v4.0.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e" + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e", - "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", "shasum": "" }, "require": { @@ -2388,10 +2518,10 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", - "php": ">=5.6" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0", + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", "squizlabs/php_codesniffer": "~3.5" }, "type": "library", @@ -2416,9 +2546,9 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/master" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0" }, - "time": "2020-04-16T18:48:43+00:00" + "time": "2020-12-01T19:48:11+00:00" }, { "name": "nikic/php-parser", @@ -2970,16 +3100,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.9", + "version": "9.2.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b" + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687", + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687", "shasum": "" }, "require": { @@ -3035,7 +3165,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10" }, "funding": [ { @@ -3043,7 +3173,7 @@ "type": "github" } ], - "time": "2021-11-19T15:21:02+00:00" + "time": "2021-12-05T09:12:13+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3391,16 +3521,16 @@ }, { "name": "psalm/plugin-phpunit", - "version": "0.15.1", + "version": "0.15.2", "source": { "type": "git", "url": "https://github.com/psalm/psalm-plugin-phpunit.git", - "reference": "30ca25ce069bf4943c36e59b7df6954f6af05e64" + "reference": "31d15bbc0169a3c454e495e03fd8a6ccb663661b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/psalm-plugin-phpunit/zipball/30ca25ce069bf4943c36e59b7df6954f6af05e64", - "reference": "30ca25ce069bf4943c36e59b7df6954f6af05e64", + "url": "https://api.github.com/repos/psalm/psalm-plugin-phpunit/zipball/31d15bbc0169a3c454e495e03fd8a6ccb663661b", + "reference": "31d15bbc0169a3c454e495e03fd8a6ccb663661b", "shasum": "" }, "require": { @@ -3445,9 +3575,9 @@ "description": "Psalm plugin for PHPUnit", "support": { "issues": "https://github.com/psalm/psalm-plugin-phpunit/issues", - "source": "https://github.com/psalm/psalm-plugin-phpunit/tree/0.15.1" + "source": "https://github.com/psalm/psalm-plugin-phpunit/tree/0.15.2" }, - "time": "2021-01-23T00:19:07+00:00" + "time": "2021-05-29T19:11:38+00:00" }, { "name": "psr/cache", @@ -3500,20 +3630,20 @@ }, { "name": "psr/container", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=7.2.0" + "php": ">=7.4.0" }, "type": "library", "autoload": { @@ -3542,64 +3672,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" - }, - "time": "2021-03-05T17:36:06+00:00" - }, - { - "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/" - } + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "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" - ], - "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" - }, - "time": "2019-04-30T12:38:16+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { "name": "psr/http-server-handler", @@ -5012,85 +5087,6 @@ ], "time": "2021-07-12T14:48:14+00:00" }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" - }, - "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": "2021-02-19T12:13:01+00:00" - }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.23.1", @@ -5795,16 +5791,16 @@ }, { "name": "vimeo/psalm", - "version": "4.7.2", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "83a0325c0a95c0ab531d6b90c877068b464377b5" + "reference": "14dcbc908ab2625cd7a74258ee6c740cbecc6140" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/83a0325c0a95c0ab531d6b90c877068b464377b5", - "reference": "83a0325c0a95c0ab531d6b90c877068b464377b5", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/14dcbc908ab2625cd7a74258ee6c740cbecc6140", + "reference": "14dcbc908ab2625cd7a74258ee6c740cbecc6140", "shasum": "" }, "require": { @@ -5814,6 +5810,7 @@ "composer/semver": "^1.4 || ^2.0 || ^3.0", "composer/xdebug-handler": "^1.1 || ^2.0", "dnoegel/php-xdg-base-dir": "^0.1.1", + "ext-ctype": "*", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -5823,11 +5820,11 @@ "felixfbecker/advanced-json-rpc": "^3.0.3", "felixfbecker/language-server-protocol": "^1.5", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.10.1", + "nikic/php-parser": "^4.13", "openlss/lib-array2xml": "^1.0", "php": "^7.1|^8", "sebastian/diff": "^3.0 || ^4.0", - "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0", "webmozart/path-util": "^2.3" }, "provide": { @@ -5842,15 +5839,15 @@ "phpmyadmin/sql-parser": "5.1.0||dev-master", "phpspec/prophecy": ">=1.9.0", "phpunit/phpunit": "^9.0", - "psalm/plugin-phpunit": "^0.13", - "slevomat/coding-standard": "^6.3.11", + "psalm/plugin-phpunit": "^0.16", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.3", - "weirdan/phpunit-appveyor-reporter": "^1.0.0", + "symfony/process": "^4.3 || ^5.0 || ^6.0", "weirdan/prophecy-shim": "^1.0 || ^2.0" }, "suggest": { - "ext-igbinary": "^2.0.5" + "ext-curl": "In order to send data to shepherd", + "ext-igbinary": "^2.0.5 is required, used to serialize caching data" }, "bin": [ "psalm", @@ -5894,9 +5891,9 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.7.2" + "source": "https://github.com/vimeo/psalm/tree/v4.14.0" }, - "time": "2021-05-01T20:56:25+00:00" + "time": "2021-12-04T17:49:24+00:00" }, { "name": "webimpress/coding-standard", @@ -5953,64 +5950,6 @@ ], "time": "2021-10-28T21:18:17+00:00" }, - { - "name": "webmozart/assert", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" - }, - "time": "2021-03-09T10:59:23+00:00" - }, { "name": "webmozart/path-util", "version": "2.3.0", @@ -6069,7 +6008,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3 || ~8.0.0 || ~8.1.0", + "php": "^7.4 || ~8.0.0 || ~8.1.0", "ext-dom": "*", "ext-json": "*" }, diff --git a/psalm-baseline.xml b/psalm-baseline.xml index d8820ce..49a131c 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,21 +1,9 @@ - - - - \Zend\Expressive\Hal\RouteBasedCollectionStrategy - \Zend\Expressive\Hal\RouteBasedResourceStrategy - \Zend\Expressive\Hal\UrlBasedCollectionStrategy - \Zend\Expressive\Hal\UrlBasedResourceStrategy - - + - - $this->embedded[$name] + is_object($resource) - - $new->embedded - $containsNonLinkItem $isResource @@ -36,7 +24,7 @@ function ($item) { function (array $byRelation, LinkInterface $link) { - + $item $links $links @@ -45,7 +33,6 @@ $relations $resource $resource - $this->embedded[$name] $value $value $value @@ -58,11 +45,10 @@ $byRelation[$rel] $relations[$key] - + $byRelation[$rel] $embedded[$name] $relations[$key] - $resource $byRelation[$rel] @@ -72,8 +58,7 @@ $relations[$key] $relations[$key] - - $collection + $relations $relations[$key] $value @@ -97,15 +82,10 @@ $this->aggregateEmbeddedCollection($name, $resource, $context) HalResource|HalResource[] - + $resource - $this->firstResource($collection) - $this->firstResource($original) - $this->firstResource($this->embedded[$name]) - - $this->embedded[$name] instanceof self - $this->embedded[$name] instanceof self + gettype($resource) @@ -113,29 +93,12 @@ $matchedType->getValue() - - $response - - - ResponseInterface - ResponseInterface - - - getBody - withHeader - write - - - $response->withHeader('Content-Type', $mediaType) - $responseFactory() - getValue - - $container->get(ResponseInterface::class) + $jsonRenderer $xmlRenderer @@ -307,9 +270,6 @@ $value $value - - $resource['_links'] - $element @@ -326,10 +286,9 @@ - + $item $item - $metadata $links @@ -348,17 +307,11 @@ $perPage - - $metadata instanceof AbstractCollectionMetadata - count - - ContainerExceptionInterface - $metadata->getExtractor() @@ -395,8 +348,7 @@ $request->getQueryParams() - - $resourceGenerator + protected function generateSelfLink( @@ -429,8 +381,7 @@ $queryStringArgs !== null - - $resourceGenerator + protected function generateSelfLink( @@ -442,21 +393,19 @@ HydratorPluginManager - + $container->get($strategy) $container->get($this->linkGeneratorServiceName) $container->get(HydratorPluginManager::class) $container->get(Metadata\MetadataMap::class) $data['linkGeneratorServiceName'] ?? LinkGenerator::class - $metadataType $strategy HydratorPluginManager::class $config['mezzio-hal']['resource-generator'] - - $metadataType + $strategy @@ -487,9 +436,6 @@ - - ExceptionInterface::class - Generator @@ -525,200 +471,22 @@ self::assertAttributeSame($xmlRenderer, 'xmlRenderer', $instance) self::assertAttributeSame($xmlRenderer, 'xmlRenderer', $instance) - - $responseFactory - - - $responseFactory() - StreamInterface StreamInterface - - - $response - $response - $response - $response - - - createResponse - createResponse - createResponse - createResponse - getBody - getBody - getBody - getBody - getHeaderLine - getHeaderLine - getHeaderLine - getHeaderLine - render - render - render - render - render - render - render - render - render - render - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - will - will - will - will - will - will - will - will - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - withHeader - withHeader - withHeader - withHeader - - - $this->factory - $this->jsonRenderer - $this->request - $this->response - $this->xmlRenderer - - - $this->factory - $this->factory - $this->factory - $this->factory - $this->jsonRenderer - $this->jsonRenderer - $this->jsonRenderer - $this->jsonRenderer - $this->jsonRenderer - $this->request - $this->request - $this->request - $this->request - $this->response - $this->response - $this->response - $this->response - $this->xmlRenderer - $this->xmlRenderer - $this->xmlRenderer - $this->xmlRenderer - $this->xmlRenderer - - - - assertAttributeEmpty - assertAttributeSame - assertAttributeSame - assertAttributeSame - assertAttributeSame - assertAttributeSame - - - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() + CustomUrlHelper::class - - get - get - get - get - get - get - get - get - has - has - has - has - has - has - has - has - has - has - has - has - reveal - reveal - reveal - reveal - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - - + CustomUrlHelper CustomUrlHelper CustomUrlHelper CustomUrlHelper CustomUrlHelper - - $this->container - - - $this->container - $this->container - $this->container - $this->container - - - - - assertAttributeEmpty - - - $fragment - @@ -757,9 +525,6 @@ - - ExceptionInterface::class - Generator @@ -768,108 +533,9 @@ - - assertAttributeSame - assertAttributeSame - - - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - $this->container->reveal() - Generator - - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - - - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - - - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - - - - - $class - - - testCanAggregateAnyMetadataType - - - add - add - add - add - get - get - get - has - has - - - $this->map - - - $this->map - $this->map - $this->map - $this->map - @@ -884,10 +550,6 @@ is_object($object) - - $stack[1]['class'] - $stack[1]['function'] - $value @@ -897,189 +559,16 @@ is_object($classOrObject) - - ! $attribute - setMethods - - - MockObject&MockedType - iterable - - count - count - count - count - createResource - createResource - createResource - createResource - fromObject - fromObject - fromObject - fromRoute - getAttribute - getAttribute - getAttribute - getCollectionRelation - getCollectionRelation - getCollectionRelation - getIterator - getIterator - getIterator - getLinkGenerator - getLinkGenerator - getLinkGenerator - getPaginationParam - getPaginationParam - getPaginationParam - getPaginationParam - getPaginationParamType - getPaginationParamType - getPaginationParamType - getPaginationParamType - getQuery - getQuery - getQuery - getQuery - getQueryParams - getQueryParams - getQueryParams - getQueryParams - getQueryStringArguments - getQueryStringArguments - getQueryStringArguments - getRoute - getRoute - getRoute - getRouteParams - getRouteParams - getRouteParams - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - reveal - shouldBeCalledTimes - shouldBeCalledTimes - shouldBeCalledTimes - shouldBeCalledTimes - shouldBeCalledTimes - shouldBeCalledTimes - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - shouldNotBeCalled - will - will - will - will - will - will - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - willReturn - - - $query - $query - $query - $query - $query - $query - MockObject&MockedType - - - $this->generator - $this->linkGenerator - $this->metadata - $this->paginator - $this->request - $this->strategy - - - $this->generator - $this->generator - $this->generator - $this->generator - $this->linkGenerator - $this->linkGenerator - $this->linkGenerator - $this->linkGenerator - $this->metadata - $this->metadata - $this->metadata - $this->metadata - $this->paginator - $this->paginator - $this->paginator - $this->paginator - $this->request - $this->request - $this->request - $this->request - $this->request - $this->strategy - $this->strategy - $this->strategy - $this->strategy - - - ExceptionInterface::class - Generator diff --git a/psalm.xml.dist b/psalm.xml.dist index b8b808e..7d0e5fc 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -15,17 +15,55 @@ - + - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + diff --git a/src/HalResource.php b/src/HalResource.php index efe9926..78b5a20 100644 --- a/src/HalResource.php +++ b/src/HalResource.php @@ -10,6 +10,7 @@ use Psr\Link\EvolvableLinkProviderInterface; use Psr\Link\LinkInterface; use RuntimeException; +use Webmozart\Assert\Assert; use function array_key_exists; use function array_keys; @@ -42,7 +43,7 @@ class HalResource implements EvolvableLinkProviderInterface, JsonSerializable /** @var array All data to represent. */ private $data = []; - /** @var self[] */ + /** @var array */ private $embedded = []; /** @@ -336,14 +337,26 @@ private function aggregateEmbeddedResource(string $name, $resource, string $cont return [$this->embedded[$name], $resource]; } + $collection = $this->embedded[$name]; + Assert::allIsInstanceOf($collection, self::class); + + $collectionFirstResource = $this->firstResource($collection); + if (null === $collectionFirstResource) { + throw new InvalidArgumentException(sprintf( + '%s detected structurally inequivalent resources for element %s', + $context, + $name + )); + } + // $resource is a HalResource; existing collection present $this->compareResources( - $this->firstResource($this->embedded[$name]), + $collectionFirstResource, $resource, $name, $context ); - $collection = $this->embedded[$name]; + array_push($collection, $resource); return $collection; @@ -355,9 +368,25 @@ private function aggregateEmbeddedResource(string $name, $resource, string $cont private function aggregateEmbeddedCollection(string $name, array $collection, string $context): array { $original = $this->embedded[$name] instanceof self ? [$this->embedded[$name]] : $this->embedded[$name]; + + $originalFirstResource = $this->firstResource($original); + $collectionFirstResource = $this->firstResource($collection); + + if (null === $originalFirstResource && null === $collectionFirstResource) { + return []; + } + + if (null === $originalFirstResource || null === $collectionFirstResource) { + throw new InvalidArgumentException(sprintf( + '%s detected structurally inequivalent resources for element %s', + $context, + $name + )); + } + $this->compareResources( - $this->firstResource($original), - $this->firstResource($collection), + $originalFirstResource, + $collectionFirstResource, $name, $context ); diff --git a/src/HalResponseFactory.php b/src/HalResponseFactory.php index e9d34c2..f773619 100644 --- a/src/HalResponseFactory.php +++ b/src/HalResponseFactory.php @@ -4,10 +4,13 @@ namespace Mezzio\Hal; +use Mezzio\Hal\Response\CallableResponseFactoryDecorator; use Negotiation\Negotiator; +use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use function is_callable; use function strstr; class HalResponseFactory @@ -33,22 +36,31 @@ class HalResponseFactory /** * A callable capable of producing an empty ResponseInterface instance. * - * @var callable + * @var ResponseFactoryInterface */ private $responseFactory; /** @var Renderer\XmlRenderer */ private $xmlRenderer; + /** + * @param (callable():ResponseInterface)|ResponseFactoryInterface $responseFactory + */ public function __construct( - callable $responseFactory, + $responseFactory, ?Renderer\JsonRenderer $jsonRenderer = null, ?Renderer\XmlRenderer $xmlRenderer = null ) { - // Ensures type safety of the composed factory - $this->responseFactory = function () use ($responseFactory): ResponseInterface { - return $responseFactory(); - }; + if (is_callable($responseFactory)) { + // Ensures type safety of the composed factory + $responseFactory = new CallableResponseFactoryDecorator( + static function () use ($responseFactory): ResponseInterface { + return $responseFactory(); + } + ); + } + + $this->responseFactory = $responseFactory; $this->jsonRenderer = $jsonRenderer ?: new Renderer\JsonRenderer(); $this->xmlRenderer = $xmlRenderer ?: new Renderer\XmlRenderer(); } @@ -74,7 +86,7 @@ public function createResponse( break; } - $response = ($this->responseFactory)(); + $response = $this->responseFactory->createResponse(); $response->getBody()->write($renderer->render($resource)); return $response->withHeader('Content-Type', $mediaType); } diff --git a/src/HalResponseFactoryFactory.php b/src/HalResponseFactoryFactory.php index 317e4e0..0e88079 100644 --- a/src/HalResponseFactoryFactory.php +++ b/src/HalResponseFactoryFactory.php @@ -5,7 +5,6 @@ namespace Mezzio\Hal; use Psr\Container\ContainerInterface; -use Psr\Http\Message\ResponseInterface; use Zend\Expressive\Hal\Renderer\JsonRenderer; use Zend\Expressive\Hal\Renderer\XmlRenderer; @@ -21,6 +20,8 @@ */ class HalResponseFactoryFactory { + use Psr17ResponseFactoryTrait; + /** * @throws RuntimeException If neither a ResponseInterface service is * present nor laminas-diactoros is installed. @@ -40,7 +41,7 @@ public function __invoke(ContainerInterface $container): HalResponseFactory : new Renderer\XmlRenderer()); return new HalResponseFactory( - $container->get(ResponseInterface::class), + $this->detectResponseFactory($container), $jsonRenderer, $xmlRenderer ); diff --git a/src/LinkGenerator/MezzioUrlGenerator.php b/src/LinkGenerator/MezzioUrlGenerator.php index 77feb98..8924407 100644 --- a/src/LinkGenerator/MezzioUrlGenerator.php +++ b/src/LinkGenerator/MezzioUrlGenerator.php @@ -38,4 +38,20 @@ public function generate( $serverUrlHelper->setUri($request->getUri()); return $serverUrlHelper($path); } + + /** + * @internal This should only be used in unit tests. + */ + public function getServerUrlHelper(): ?ServerUrlHelper + { + return $this->serverUrlHelper; + } + + /** + * @internal This should only be used in unit tests. + */ + public function getUrlHelper(): UrlHelper + { + return $this->urlHelper; + } } diff --git a/src/LinkGenerator/MezzioUrlGeneratorFactory.php b/src/LinkGenerator/MezzioUrlGeneratorFactory.php index c31afcf..72ee015 100644 --- a/src/LinkGenerator/MezzioUrlGeneratorFactory.php +++ b/src/LinkGenerator/MezzioUrlGeneratorFactory.php @@ -54,4 +54,12 @@ public function __invoke(ContainerInterface $container): MezzioUrlGenerator : null) ); } + + /** + * @internal This should only be used in unit tests. + */ + public function getUrlHelperServiceName(): string + { + return $this->urlHelperServiceName; + } } diff --git a/src/Metadata/Exception/InvalidConfigException.php b/src/Metadata/Exception/InvalidConfigException.php index 26a9e7e..dc2da1b 100644 --- a/src/Metadata/Exception/InvalidConfigException.php +++ b/src/Metadata/Exception/InvalidConfigException.php @@ -91,6 +91,7 @@ public static function dueToUnrecognizedMetadataClass(string $class): self )); } + /** @psalm-param string[] $requiredKeys */ public static function dueToMissingMetadata(string $type, array $requiredKeys): self { return new self(sprintf( diff --git a/src/Metadata/MetadataMap.php b/src/Metadata/MetadataMap.php index b999799..e7bdc1b 100644 --- a/src/Metadata/MetadataMap.php +++ b/src/Metadata/MetadataMap.php @@ -51,4 +51,12 @@ public function get(string $class): AbstractMetadata return $this->map[$class]; } + + /** + * @internal This should only be used in unit tests. + */ + public function getMap(): array + { + return $this->map; + } } diff --git a/src/Psr17ResponseFactoryTrait.php b/src/Psr17ResponseFactoryTrait.php new file mode 100644 index 0000000..e1b2a85 --- /dev/null +++ b/src/Psr17ResponseFactoryTrait.php @@ -0,0 +1,73 @@ +has(ResponseFactoryInterface::class); + + if (! $psr17FactoryAvailable) { + return $this->createResponseFactoryFromDeprecatedCallable($container); + } + + if ($this->doesConfigurationProvidesDedicatedResponseFactory($container)) { + return $this->createResponseFactoryFromDeprecatedCallable($container); + } + + $responseFactory = $container->get(ResponseFactoryInterface::class); + Assert::isInstanceOf($responseFactory, ResponseFactoryInterface::class); + return $responseFactory; + } + + private function createResponseFactoryFromDeprecatedCallable( + ContainerInterface $container + ): ResponseFactoryInterface { + /** @var callable():ResponseInterface $responseFactory */ + $responseFactory = $container->get(ResponseInterface::class); + + return new CallableResponseFactoryDecorator($responseFactory); + } + + private function doesConfigurationProvidesDedicatedResponseFactory(ContainerInterface $container): bool + { + if (! $container->has('config')) { + return false; + } + + $config = $container->get('config'); + Assert::isArrayAccessible($config); + $dependencies = $config['dependencies'] ?? []; + Assert::isMap($dependencies); + + $delegators = $dependencies['delegators'] ?? []; + $aliases = $dependencies['aliases'] ?? []; + Assert::isArrayAccessible($delegators); + Assert::isArrayAccessible($aliases); + + if (isset($delegators[ResponseInterface::class]) || isset($aliases[ResponseInterface::class])) { + // Even tho, aliases could point to a different service, we assume that there is a dedicated factory + // available. The alias resolving is not worth it. + return true; + } + + /** @psalm-suppress MixedAssignment */ + $deprecatedResponseFactory = $dependencies['factories'][ResponseInterface::class] ?? null; + + return $deprecatedResponseFactory !== null && $deprecatedResponseFactory !== ResponseFactoryFactory::class; + } +} diff --git a/src/ResourceGeneratorFactory.php b/src/ResourceGeneratorFactory.php index c8d2dab..a1687c6 100644 --- a/src/ResourceGeneratorFactory.php +++ b/src/ResourceGeneratorFactory.php @@ -11,6 +11,7 @@ use Traversable; use function is_array; +use function is_string; class ResourceGeneratorFactory { @@ -77,6 +78,10 @@ private function injectStrategies(ContainerInterface $container, ResourceGenerat } foreach ($strategies as $metadataType => $strategy) { + if (! is_string($metadataType) || empty($metadataType)) { + continue; + } + $generator->addStrategy( $metadataType, $container->get($strategy) diff --git a/src/Response/CallableResponseFactoryDecorator.php b/src/Response/CallableResponseFactoryDecorator.php new file mode 100644 index 0000000..e495519 --- /dev/null +++ b/src/Response/CallableResponseFactoryDecorator.php @@ -0,0 +1,36 @@ +responseFactory = $responseFactory; + } + + public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface + { + return $this->getResponseFromCallable()->withStatus($code, $reasonPhrase); + } + + public function getResponseFromCallable(): ResponseInterface + { + return ($this->responseFactory)(); + } +} diff --git a/test/HalResponseFactoryFactoryTest.php b/test/HalResponseFactoryFactoryTest.php index a6efbfb..da30ff5 100644 --- a/test/HalResponseFactoryFactoryTest.php +++ b/test/HalResponseFactoryFactoryTest.php @@ -7,10 +7,11 @@ use Mezzio\Hal\HalResponseFactory; use Mezzio\Hal\HalResponseFactoryFactory; use Mezzio\Hal\Renderer; -use PHPUnit\Framework\Assert; +use Mezzio\Hal\Response\CallableResponseFactoryDecorator; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use Psr\Container\ContainerInterface; +use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use ReflectionProperty; use Zend\Expressive\Hal\Renderer\JsonRenderer; @@ -27,19 +28,22 @@ public static function assertResponseFactoryReturns(ResponseInterface $expected, $r = new ReflectionProperty($factory, 'responseFactory'); $r->setAccessible(true); $responseFactory = $r->getValue($factory); - Assert::assertSame($expected, $responseFactory()); + + self::assertInstanceOf(CallableResponseFactoryDecorator::class, $responseFactory); + self::assertSame($expected, $responseFactory->getResponseFromCallable()); } public function testReturnsHalResponseFactoryInstance(): void { - $jsonRenderer = $this->prophesize(Renderer\JsonRenderer::class)->reveal(); - $xmlRenderer = $this->prophesize(Renderer\XmlRenderer::class)->reveal(); - $response = $this->prophesize(ResponseInterface::class)->reveal(); + $jsonRenderer = $this->createMock(Renderer\JsonRenderer::class); + $xmlRenderer = $this->createMock(Renderer\XmlRenderer::class); + $response = $this->createMock(ResponseInterface::class); $responseFactory = function () use ($response): ResponseInterface { return $response; }; $container = $this->prophesize(ContainerInterface::class); + $container->has(ResponseFactoryInterface::class)->willReturn(false); $container->get(ResponseInterface::class)->willReturn($responseFactory); $container->has(Renderer\JsonRenderer::class)->willReturn(true); $container->get(Renderer\JsonRenderer::class)->willReturn($jsonRenderer); @@ -47,7 +51,6 @@ public function testReturnsHalResponseFactoryInstance(): void $container->get(Renderer\XmlRenderer::class)->willReturn($xmlRenderer); $instance = (new HalResponseFactoryFactory())($container->reveal()); - self::assertInstanceOf(HalResponseFactory::class, $instance); self::assertAttributeSame($jsonRenderer, 'jsonRenderer', $instance); self::assertAttributeSame($xmlRenderer, 'xmlRenderer', $instance); self::assertResponseFactoryReturns($response, $instance); @@ -55,11 +58,12 @@ public function testReturnsHalResponseFactoryInstance(): void public function testReturnsHalResponseFactoryInstanceWithoutConfiguredDependencies(): void { - $response = $this->prophesize(ResponseInterface::class)->reveal(); + $response = $this->createMock(ResponseInterface::class); $responseFactory = function () use ($response): ResponseInterface { return $response; }; $container = $this->prophesize(ContainerInterface::class); + $container->has(ResponseFactoryInterface::class)->willReturn(false); $container->get(ResponseInterface::class)->willReturn($responseFactory); $container->has(Renderer\JsonRenderer::class)->willReturn(false); $container->has(JsonRenderer::class)->willReturn(false); @@ -67,7 +71,6 @@ public function testReturnsHalResponseFactoryInstanceWithoutConfiguredDependenci $container->has(XmlRenderer::class)->willReturn(false); $instance = (new HalResponseFactoryFactory())($container->reveal()); - self::assertInstanceOf(HalResponseFactory::class, $instance); self::assertAttributeInstanceOf(Renderer\JsonRenderer::class, 'jsonRenderer', $instance); self::assertAttributeInstanceOf(Renderer\XmlRenderer::class, 'xmlRenderer', $instance); self::assertResponseFactoryReturns($response, $instance); @@ -75,9 +78,9 @@ public function testReturnsHalResponseFactoryInstanceWithoutConfiguredDependenci public function testReturnsHalResponseFactoryInstanceWhenResponseInterfaceReturnsFactory(): void { - $jsonRenderer = $this->prophesize(Renderer\JsonRenderer::class)->reveal(); - $xmlRenderer = $this->prophesize(Renderer\XmlRenderer::class)->reveal(); - $response = $this->prophesize(ResponseInterface::class)->reveal(); + $jsonRenderer = $this->createMock(Renderer\JsonRenderer::class); + $xmlRenderer = $this->createMock(Renderer\XmlRenderer::class); + $response = $this->createMock(ResponseInterface::class); $responseFactory = function () use ($response): ResponseInterface { return $response; }; @@ -89,6 +92,7 @@ public function __invoke() }; $container = $this->prophesize(ContainerInterface::class); + $container->has(ResponseFactoryInterface::class)->willReturn(false); $container->has(Renderer\JsonRenderer::class)->willReturn(true); $container->get(Renderer\JsonRenderer::class)->willReturn($jsonRenderer); $container->has(Renderer\XmlRenderer::class)->willReturn(true); @@ -99,7 +103,6 @@ public function __invoke() $container->get(StreamInterface::class)->willReturn($stream); $instance = (new HalResponseFactoryFactory())($container->reveal()); - self::assertInstanceOf(HalResponseFactory::class, $instance); self::assertAttributeSame($jsonRenderer, 'jsonRenderer', $instance); self::assertAttributeSame($xmlRenderer, 'xmlRenderer', $instance); } diff --git a/test/HalResponseFactoryTest.php b/test/HalResponseFactoryTest.php index 6fc755f..e814c64 100644 --- a/test/HalResponseFactoryTest.php +++ b/test/HalResponseFactoryTest.php @@ -7,8 +7,8 @@ use Mezzio\Hal\HalResponseFactory; use Mezzio\Hal\Renderer; use MezzioTest\Hal\Renderer\TestAsset; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\StreamInterface; @@ -17,41 +17,78 @@ class HalResponseFactoryTest extends TestCase { - use ProphecyTrait; use TestAsset; + /** @var ServerRequestInterface&MockObject */ + private $request; + + /** @var ResponseInterface&MockObject */ + private $response; + + /** @var Renderer\JsonRenderer&MockObject */ + private $jsonRenderer; + + /** @var Renderer\XmlRenderer&MockObject */ + private $xmlRenderer; + + /** @var HalResponseFactory */ + private $factory; + public function setUp(): void { - $this->request = $this->prophesize(ServerRequestInterface::class); - $this->response = $this->prophesize(ResponseInterface::class); - $this->jsonRenderer = $this->prophesize(Renderer\JsonRenderer::class); - $this->xmlRenderer = $this->prophesize(Renderer\XmlRenderer::class); + $this->request = $this->createMock(ServerRequestInterface::class); + $this->response = $this->createMock(ResponseInterface::class); + $this->response->method('withStatus')->willReturnSelf(); + $this->jsonRenderer = $this->createMock(Renderer\JsonRenderer::class); + $this->xmlRenderer = $this->createMock(Renderer\XmlRenderer::class); $this->factory = new HalResponseFactory( - function () { - return $this->response->reveal(); + function (): ResponseInterface { + return $this->response; }, - $this->jsonRenderer->reveal(), - $this->xmlRenderer->reveal() + $this->jsonRenderer, + $this->xmlRenderer ); } public function testReturnsJsonResponseIfNoAcceptHeaderPresent(): void { $resource = $this->createExampleResource(); - $this->jsonRenderer->render($resource)->willReturn('{}'); - $this->xmlRenderer->render($resource)->shouldNotBeCalled(); - $this->request->getHeaderLine('Accept')->willReturn(''); + $this->jsonRenderer + ->method('render') + ->with($resource) + ->willReturn('{}'); - $stream = $this->prophesize(StreamInterface::class); - $stream->write('{}')->shouldBeCalled(); - $this->response->getBody()->will([$stream, 'reveal']); - $this->response->withHeader('Content-Type', 'application/hal+json')->will([$this->response, 'reveal']); + $this->xmlRenderer + ->expects(self::never()) + ->method('render'); + + $this->request + ->method('getHeaderLine') + ->with('Accept') + ->willReturn(''); + + $stream = $this->createMock(StreamInterface::class); + $stream + ->expects(self::once()) + ->method('write') + ->with('{}') + ->willReturnSelf(); + + $this->response + ->method('getBody') + ->willReturn($stream); + + $this->response + ->method('withHeader') + ->with('Content-Type', 'application/hal+json') + ->willReturnSelf(); $response = $this->factory->createResponse( - $this->request->reveal(), + $this->request, $resource ); - $this->assertSame($this->response->reveal(), $response); + + self::assertSame($this->response, $response); } /** @@ -72,20 +109,42 @@ public function jsonAcceptHeaders(): array public function testReturnsJsonResponseIfAcceptHeaderMatchesJson(string $header): void { $resource = $this->createExampleResource(); - $this->jsonRenderer->render($resource)->willReturn('{}'); - $this->xmlRenderer->render($resource)->shouldNotBeCalled(); - $this->request->getHeaderLine('Accept')->willReturn($header); + $this->jsonRenderer + ->method('render') + ->with($resource) + ->willReturn('{}'); - $stream = $this->prophesize(StreamInterface::class); - $stream->write('{}')->shouldBeCalled(); - $this->response->getBody()->will([$stream, 'reveal']); - $this->response->withHeader('Content-Type', 'application/hal+json')->will([$this->response, 'reveal']); + $this->xmlRenderer + ->expects(self::never()) + ->method('render'); + + $this->request + ->method('getHeaderLine') + ->with('Accept') + ->willReturn($header); + + $stream = $this->createMock(StreamInterface::class); + $stream + ->expects(self::once()) + ->method('write') + ->with('{}') + ->willReturnSelf(); + + $this->response + ->method('getBody') + ->willReturn($stream); + + $this->response + ->expects(self::once()) + ->method('withHeader') + ->with('Content-Type', 'application/hal+json') + ->willReturnSelf(); $response = $this->factory->createResponse( - $this->request->reveal(), + $this->request, $resource ); - $this->assertSame($this->response->reveal(), $response); + self::assertSame($this->response, $response); } /** @@ -107,20 +166,42 @@ public function xmlAcceptHeaders(): array public function testReturnsXmlResponseIfAcceptHeaderMatchesXml(string $header): void { $resource = $this->createExampleResource(); - $this->xmlRenderer->render($resource)->willReturn(''); - $this->jsonRenderer->render($resource)->shouldNotBeCalled(); - $this->request->getHeaderLine('Accept')->willReturn($header); + $this->xmlRenderer + ->method('render') + ->with($resource) + ->willReturn(''); + + $this->jsonRenderer + ->expects(self::never()) + ->method('render'); - $stream = $this->prophesize(StreamInterface::class); - $stream->write('')->shouldBeCalled(); - $this->response->getBody()->will([$stream, 'reveal']); - $this->response->withHeader('Content-Type', 'application/hal+xml')->will([$this->response, 'reveal']); + $this->request + ->method('getHeaderLine') + ->with('Accept') + ->willReturn($header); + + $stream = $this->createMock(StreamInterface::class); + $stream + ->expects(self::once()) + ->method('write') + ->with('') + ->willReturnSelf(); + + $this->response + ->method('getBody') + ->wilLReturn($stream); + + $this->response + ->expects(self::once()) + ->method('withHeader') + ->with('Content-Type', 'application/hal+xml') + ->willReturnSelf(); $response = $this->factory->createResponse( - $this->request->reveal(), + $this->request, $resource ); - $this->assertSame($this->response->reveal(), $response); + self::assertSame($this->response, $response); } /** @@ -148,28 +229,55 @@ public function testUsesProvidedMediaTypeInReturnedResponseWithMatchedFormatAppe $resource = $this->createExampleResource(); switch (true) { case strstr($header, 'json'): - $this->jsonRenderer->render($resource)->willReturn($responseBody); - $this->xmlRenderer->render($resource)->shouldNotBeCalled(); + $this->jsonRenderer + ->expects(self::once()) + ->method('render') + ->with($resource) + ->willReturn($responseBody); + $this->xmlRenderer + ->expects(self::never()) + ->method('render'); break; case strstr($header, 'xml'): - $this->xmlRenderer->render($resource)->willReturn($responseBody); - $this->jsonRenderer->render($resource)->shouldNotBeCalled(); + $this->xmlRenderer + ->expects(self::once()) + ->method('render') + ->with($resource) + ->willReturn($responseBody); + $this->jsonRenderer + ->expects(self::never()) + ->method('render'); // fall-through default: break; } - $this->request->getHeaderLine('Accept')->willReturn($header); + $this->request + ->method('getHeaderLine') + ->with('Accept') + ->willReturn($header); + + $stream = $this->createMock(StreamInterface::class); + $stream + ->expects(self::once()) + ->method('write') + ->with($responseBody) + ->willReturnSelf(); + + $this->response + ->method('getBody') + ->willReturn($stream); - $stream = $this->prophesize(StreamInterface::class); - $stream->write($responseBody)->shouldBeCalled(); - $this->response->getBody()->will([$stream, 'reveal']); - $this->response->withHeader('Content-Type', $expectedMediaType)->will([$this->response, 'reveal']); + $this->response + ->expects(self::once()) + ->method('withHeader') + ->with('Content-Type', $expectedMediaType) + ->willReturnSelf(); $response = $this->factory->createResponse( - $this->request->reveal(), + $this->request, $resource, $mediaType ); - $this->assertSame($this->response->reveal(), $response); + self::assertSame($this->response, $response); } } diff --git a/test/InMemoryContainer.php b/test/InMemoryContainer.php new file mode 100644 index 0000000..be24edc --- /dev/null +++ b/test/InMemoryContainer.php @@ -0,0 +1,51 @@ + */ + private $services = []; + + /** + * @param string $id + * @return mixed + */ + public function get($id) + { + if (! $this->has($id)) { + throw new class ($id . ' was not found') extends RuntimeException implements NotFoundExceptionInterface { + }; + } + + return $this->services[$id]; + } + + /** + * @param string $id + * @return bool + */ + public function has($id) + { + return array_key_exists($id, $this->services); + } + + /** @param mixed $item */ + public function set(string $id, $item): void + { + $this->services[$id] = $item; + } + + public function reset(): void + { + $this->services = []; + } +} diff --git a/test/LinkGenerator/MezzioUrlGeneratorFactoryTest.php b/test/LinkGenerator/MezzioUrlGeneratorFactoryTest.php index cd2a576..7cbd64b 100644 --- a/test/LinkGenerator/MezzioUrlGeneratorFactoryTest.php +++ b/test/LinkGenerator/MezzioUrlGeneratorFactoryTest.php @@ -4,102 +4,127 @@ namespace MezzioTest\Hal\LinkGenerator; -use Mezzio\Hal\LinkGenerator\MezzioUrlGenerator; use Mezzio\Hal\LinkGenerator\MezzioUrlGeneratorFactory; use Mezzio\Helper\ServerUrlHelper; use Mezzio\Helper\UrlHelper; -use MezzioTest\Hal\PHPUnitDeprecatedAssertions; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; use Psr\Container\ContainerInterface; use RuntimeException; class MezzioUrlGeneratorFactoryTest extends TestCase { - use PHPUnitDeprecatedAssertions; - - use ProphecyTrait; + /** @var ContainerInterface&MockObject */ + private $container; public function setUp(): void { - $this->container = $this->prophesize(ContainerInterface::class); + $this->container = $this->createMock(ContainerInterface::class); } public function testFactoryRaisesExceptionIfUrlHelperIsMissingFromContainer(): void { - $this->container->has(UrlHelper::class)->willReturn(false); - $this->container->has(\Zend\Expressive\Helper\UrlHelper::class)->willReturn(false); - $this->container->get(UrlHelper::class)->shouldNotBeCalled(); - $this->container->get(\Zend\Expressive\Helper\UrlHelper::class)->shouldNotBeCalled(); - $this->container->has(ServerUrlHelper::class)->shouldNotBeCalled(); - $this->container->has(\Zend\Expressive\Helper\ServerUrlHelper::class)->shouldNotBeCalled(); + $this->container + ->expects(self::once()) + ->method('has') + ->withConsecutive([UrlHelper::class]) + ->willReturn(false); + + $this->container + ->expects(self::never()) + ->method('get'); $factory = new MezzioUrlGeneratorFactory(); $this->expectException(RuntimeException::class); $this->expectExceptionMessage(UrlHelper::class); - $factory($this->container->reveal()); + $factory($this->container); } public function testFactoryCanCreateUrlGeneratorWithOnlyUrlHelperPresentInContainer(): void { - $urlHelper = $this->prophesize(UrlHelper::class)->reveal(); - - $this->container->has(UrlHelper::class)->willReturn(true); - $this->container->get(UrlHelper::class)->willReturn($urlHelper); - $this->container->has(ServerUrlHelper::class)->willReturn(false); - $this->container->has(\Zend\Expressive\Helper\ServerUrlHelper::class)->willReturn(false); - $this->container->get(ServerUrlHelper::class)->shouldNotBeCalled(); - $this->container->get(\Zend\Expressive\Helper\ServerUrlHelper::class)->shouldNotBeCalled(); + $urlHelper = $this->createMock(UrlHelper::class); + + $this->container + ->expects(self::exactly(3)) + ->method('has') + ->withConsecutive( + [UrlHelper::class], + [ServerUrlHelper::class], + [\Zend\Expressive\Helper\ServerUrlHelper::class] + ) + ->willReturnOnConsecutiveCalls(true, false, false); + $this->container + ->expects(self::once()) + ->method('get') + ->with(UrlHelper::class) + ->willReturn($urlHelper); $factory = new MezzioUrlGeneratorFactory(); - $generator = $factory($this->container->reveal()); + $generator = $factory($this->container); - $this->assertInstanceOf(MezzioUrlGenerator::class, $generator); - $this->assertAttributeSame($urlHelper, 'urlHelper', $generator); + self::assertSame($urlHelper, $generator->getUrlHelper()); } public function testFactoryCanCreateUrlGeneratorWithBothUrlHelperAndServerUrlHelper(): void { - $urlHelper = $this->prophesize(UrlHelper::class)->reveal(); - $serverUrlHelper = $this->prophesize(ServerUrlHelper::class)->reveal(); - - $this->container->has(UrlHelper::class)->willReturn(true); - $this->container->get(UrlHelper::class)->willReturn($urlHelper); - $this->container->has(ServerUrlHelper::class)->willReturn(true); - $this->container->get(ServerUrlHelper::class)->willReturn($serverUrlHelper); + $urlHelper = $this->createMock(UrlHelper::class); + $serverUrlHelper = $this->createMock(ServerUrlHelper::class); + + $this->container + ->expects(self::exactly(2)) + ->method('has') + ->withConsecutive( + [UrlHelper::class], + [ServerUrlHelper::class] + )->willReturn(true); + + $this->container + ->expects(self::exactly(2)) + ->method('get') + ->withConsecutive( + [UrlHelper::class], + [ServerUrlHelper::class] + )->willReturnOnConsecutiveCalls($urlHelper, $serverUrlHelper); $factory = new MezzioUrlGeneratorFactory(); - $generator = $factory($this->container->reveal()); + $generator = $factory($this->container); - $this->assertInstanceOf(MezzioUrlGenerator::class, $generator); - $this->assertAttributeSame($urlHelper, 'urlHelper', $generator); - $this->assertAttributeSame($serverUrlHelper, 'serverUrlHelper', $generator); + self::assertSame($urlHelper, $generator->getUrlHelper()); + self::assertSame($serverUrlHelper, $generator->getServerUrlHelper()); } public function testFactoryCanAcceptUrlHelperServiceNameToConstructor(): void { - $urlHelper = $this->prophesize(UrlHelper::class)->reveal(); - - $this->container->has(CustomUrlHelper::class)->willReturn(true); - $this->container->get(CustomUrlHelper::class)->willReturn($urlHelper); - $this->container->has(ServerUrlHelper::class)->willReturn(false); - $this->container->has(\Zend\Expressive\Helper\ServerUrlHelper::class)->willReturn(false); + $urlHelper = $this->createMock(UrlHelper::class); + + $this->container + ->expects(self::exactly(3)) + ->method('has') + ->withConsecutive( + [CustomUrlHelper::class], + [ServerUrlHelper::class], + [\Zend\Expressive\Helper\ServerUrlHelper::class] + )->willReturnOnConsecutiveCalls(true, false, false); + + $this->container + ->expects(self::once()) + ->method('get') + ->with(CustomUrlHelper::class) + ->willReturn($urlHelper); $factory = new MezzioUrlGeneratorFactory(CustomUrlHelper::class); - $generator = $factory($this->container->reveal()); + $generator = $factory($this->container); - $this->assertInstanceOf(MezzioUrlGenerator::class, $generator); - $this->assertAttributeSame($urlHelper, 'urlHelper', $generator); - $this->assertAttributeEmpty('serverUrlHelper', $generator); + self::assertSame($urlHelper, $generator->getUrlHelper()); + self::assertNull($generator->getServerUrlHelper()); } public function testFactoryIsSerializable(): void { $factory = MezzioUrlGeneratorFactory::__set_state([ - 'urlHelperServiceName' => CustomUrlHelper::class, + 'urlHelperServiceName' => 'customUrlHelper', ]); - $this->assertInstanceOf(MezzioUrlGeneratorFactory::class, $factory); - $this->assertAttributeSame(CustomUrlHelper::class, 'urlHelperServiceName', $factory); + self::assertSame('customUrlHelper', $factory->getUrlHelperServiceName()); } } diff --git a/test/LinkGenerator/MezzioUrlGeneratorTest.php b/test/LinkGenerator/MezzioUrlGeneratorTest.php index 2b4a40b..629d181 100644 --- a/test/LinkGenerator/MezzioUrlGeneratorTest.php +++ b/test/LinkGenerator/MezzioUrlGeneratorTest.php @@ -7,31 +7,30 @@ use Mezzio\Hal\LinkGenerator\MezzioUrlGenerator; use Mezzio\Helper\ServerUrlHelper; use Mezzio\Helper\UrlHelper; -use MezzioTest\Hal\PHPUnitDeprecatedAssertions; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\UriInterface; +use ReflectionProperty; class MezzioUrlGeneratorTest extends TestCase { - use PHPUnitDeprecatedAssertions; - - use ProphecyTrait; - public function testCanGenerateUrlWithOnlyUrlHelper(): void { - $urlHelper = $this->prophesize(UrlHelper::class); - $urlHelper->generate('test', ['foo' => 'bar'], ['baz' => 'bat'])->willReturn('/test/bar?baz=bat'); + $urlHelper = $this->createMock(UrlHelper::class); + $urlHelper + ->method('generate') + ->with('test', ['foo' => 'bar'], ['baz' => 'bat']) + ->willReturn('/test/bar?baz=bat'); - $request = $this->prophesize(ServerRequestInterface::class); - $request->getUri()->shouldNotBeCalled(); + $request = $this->createMock(ServerRequestInterface::class); + $request + ->expects(self::never()) + ->method('getUri'); - $generator = new MezzioUrlGenerator($urlHelper->reveal()); + $generator = new MezzioUrlGenerator($urlHelper); - $this->assertSame('/test/bar?baz=bat', $generator->generate( - $request->reveal(), + self::assertSame('/test/bar?baz=bat', $generator->generate( + $request, 'test', ['foo' => 'bar'], ['baz' => 'bat'] @@ -40,33 +39,51 @@ public function testCanGenerateUrlWithOnlyUrlHelper(): void public function testCanGenerateFullyQualifiedURIWhenServerUrlHelperIsComposed(): void { - $uri = $this->prophesize(UriInterface::class); - $uri->withQuery('')->will([$uri, 'reveal']); - $uri->withFragment('')->will([$uri, 'reveal'])->shouldBeCalledTimes(1); - $uri->getPath()->willReturn('/some/path'); - $uri->withPath('/test/bar')->will([$uri, 'reveal']); - $uri->withQuery('baz=bat')->will([$uri, 'reveal']); + $uri = $this->createMock(UriInterface::class); + + $uri + ->expects(self::once()) + ->method('withFragment') + ->with('') + ->willReturnSelf(); + + $uri + ->method('getPath') + ->willReturn('/some/path'); + + $uri + ->method('withPath') + ->with('/test/bar') + ->willReturnSelf(); + + $uri + ->expects(self::exactly(2)) + ->method('withQuery') + ->withConsecutive([''], ['baz=bat']) + ->willReturnSelf(); $uri - ->withFragment(Argument::that(function ($fragment) { - return ! empty($fragment); - })) - ->shouldNotBeCalled(); + ->method('__toString') + ->willReturn('https://api.example.com/test/bar?baz=bat'); - $uri->__toString()->willReturn('https://api.example.com/test/bar?baz=bat'); + $request = $this->createMock(ServerRequestInterface::class); + $request + ->method('getUri') + ->willReturn($uri); - $request = $this->prophesize(ServerRequestInterface::class); - $request->getUri()->will([$uri, 'reveal']); + $urlHelper = $this->createMock(UrlHelper::class); - $urlHelper = $this->prophesize(UrlHelper::class); - $urlHelper->generate('test', ['foo' => 'bar'], ['baz' => 'bat'])->willReturn('/test/bar?baz=bat'); + $urlHelper + ->method('generate') + ->with('test', ['foo' => 'bar'], ['baz' => 'bat']) + ->willReturn('/test/bar?baz=bat'); $serverUrlHelper = new ServerUrlHelper(); - $generator = new MezzioUrlGenerator($urlHelper->reveal(), $serverUrlHelper); + $generator = new MezzioUrlGenerator($urlHelper, $serverUrlHelper); - $this->assertSame('https://api.example.com/test/bar?baz=bat', $generator->generate( - $request->reveal(), + self::assertSame('https://api.example.com/test/bar?baz=bat', $generator->generate( + $request, 'test', ['foo' => 'bar'], ['baz' => 'bat'] @@ -74,6 +91,8 @@ public function testCanGenerateFullyQualifiedURIWhenServerUrlHelperIsComposed(): // The helper should be cloned on each invocation, ensuring that the URI // is not persisted. - $this->assertAttributeEmpty('uri', $serverUrlHelper); + $reflectionProperty = new ReflectionProperty($serverUrlHelper, 'uri'); + $reflectionProperty->setAccessible(true); + self::assertNull($reflectionProperty->getValue($serverUrlHelper)); } } diff --git a/test/LinkGeneratorFactoryTest.php b/test/LinkGeneratorFactoryTest.php index b95bce7..909627b 100644 --- a/test/LinkGeneratorFactoryTest.php +++ b/test/LinkGeneratorFactoryTest.php @@ -18,7 +18,7 @@ class LinkGeneratorFactoryTest extends TestCase public function testReturnsLinkGeneratorInstance(): void { - $urlGenerator = $this->prophesize(LinkGenerator\UrlGeneratorInterface::class)->reveal(); + $urlGenerator = $this->createMock(LinkGenerator\UrlGeneratorInterface::class); $container = $this->prophesize(ContainerInterface::class); $container->get(LinkGenerator\UrlGeneratorInterface::class)->willReturn($urlGenerator); @@ -30,7 +30,7 @@ public function testReturnsLinkGeneratorInstance(): void public function testConstructorAllowsSpecifyingUrlGeneratorServiceName(): void { - $urlGenerator = $this->prophesize(LinkGenerator\UrlGeneratorInterface::class)->reveal(); + $urlGenerator = $this->createMock(LinkGenerator\UrlGeneratorInterface::class); $container = $this->prophesize(ContainerInterface::class); $container->get(UrlGenerator::class)->willReturn($urlGenerator); diff --git a/test/LinkGeneratorTest.php b/test/LinkGeneratorTest.php index 23d2a39..009cc14 100644 --- a/test/LinkGeneratorTest.php +++ b/test/LinkGeneratorTest.php @@ -16,7 +16,7 @@ class LinkGeneratorTest extends TestCase public function testUsesComposedUrlGeneratorToGenerateHrefForLink(): void { - $request = $this->prophesize(ServerRequestInterface::class)->reveal(); + $request = $this->createMock(ServerRequestInterface::class); $urlGenerator = $this->prophesize(LinkGenerator\UrlGeneratorInterface::class); $urlGenerator->generate( @@ -46,7 +46,7 @@ public function testUsesComposedUrlGeneratorToGenerateHrefForLink(): void public function testUsesComposedUrlGeneratorToGenerateHrefForTemplatedLink(): void { - $request = $this->prophesize(ServerRequestInterface::class)->reveal(); + $request = $this->createMock(ServerRequestInterface::class); $urlGenerator = $this->prophesize(LinkGenerator\UrlGeneratorInterface::class); $urlGenerator->generate( diff --git a/test/Metadata/MetadataMapFactoryTest.php b/test/Metadata/MetadataMapFactoryTest.php index 396e732..1948360 100644 --- a/test/Metadata/MetadataMapFactoryTest.php +++ b/test/Metadata/MetadataMapFactoryTest.php @@ -17,80 +17,60 @@ use Mezzio\Hal\Metadata\UrlBasedCollectionMetadataFactory; use Mezzio\Hal\Metadata\UrlBasedResourceMetadata; use Mezzio\Hal\Metadata\UrlBasedResourceMetadataFactory; -use MezzioTest\Hal\PHPUnitDeprecatedAssertions; use MezzioTest\Hal\TestAsset; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; -use Prophecy\Prophecy\ObjectProphecy; use Psr\Container\ContainerInterface; use stdClass; class MetadataMapFactoryTest extends TestCase { - use PHPUnitDeprecatedAssertions; - - use ProphecyTrait; - /** @var MetadataMapFactory */ private $factory; - /** @var ObjectProphecy|ContainerInterface */ + /** @var ContainerInterface&MockObject */ private $container; public function setUp(): void { - $this->container = $this->prophesize(ContainerInterface::class); + $this->container = $this->createMock(ContainerInterface::class); $this->factory = new MetadataMapFactory(); } public function testFactoryReturnsEmptyMetadataMapWhenNoConfigServicePresent(): void { - $this->container->has('config')->willReturn(false); - $metadataMap = ($this->factory)($this->container->reveal()); - $this->assertInstanceOf(MetadataMap::class, $metadataMap); - $this->assertAttributeSame([], 'map', $metadataMap); + $metadataMap = ($this->factory)($this->container); + self::assertSame([], $metadataMap->getMap()); } public function testFactoryReturnsEmptyMetadataMapWhenConfigServiceHasNoMetadataMapEntries(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn([]); - $metadataMap = ($this->factory)($this->container->reveal()); - $this->assertInstanceOf(MetadataMap::class, $metadataMap); - $this->assertAttributeSame([], 'map', $metadataMap); + $this->populateConfiguration($this->container, []); + + $metadataMap = ($this->factory)($this->container); + self::assertSame([], $metadataMap->getMap()); } public function testFactoryRaisesExceptionIfMetadataMapConfigIsNotAnArray(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn([MetadataMap::class => 'nope']); - $this->expectException(InvalidConfigException::class); - $this->expectExceptionMessage('expected an array'); - ($this->factory)($this->container->reveal()); - } + $this->populateConfiguration($this->container, [MetadataMap::class => 'nope']); - public function testFactoryRaisesExceptionIfMetadataMapItemIsNotAnArray(): void - { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn([MetadataMap::class => ['nope']]); $this->expectException(InvalidConfigException::class); - $this->expectExceptionMessage('metadata item configuration'); - ($this->factory)($this->container->reveal()); + $this->expectExceptionMessage('expected an array'); + ($this->factory)($this->container); } public function testFactoryRaisesExceptionIfAnyMetadataIsMissingAClassEntry(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn([MetadataMap::class => [['nope']]]); + $this->populateConfiguration($this->container, [MetadataMap::class => [['nope']]]); $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage('missing "__class__"'); - ($this->factory)($this->container->reveal()); + ($this->factory)($this->container); } public function testFactoryRaisesExceptionIfTheMetadataClassDoesNotExist(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn([ + $this->populateConfiguration($this->container, [ MetadataMap::class => [ [ '__class__' => 'not-a-class', @@ -99,13 +79,12 @@ public function testFactoryRaisesExceptionIfTheMetadataClassDoesNotExist(): void ]); $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage('Invalid metadata class provided'); - ($this->factory)($this->container->reveal()); + ($this->factory)($this->container); } public function testFactoryRaisesExceptionIfTheMetadataClassIsNotAnAbstractMetadataType(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn([ + $this->populateConfiguration($this->container, [ MetadataMap::class => [ [ '__class__' => self::class, @@ -114,13 +93,12 @@ public function testFactoryRaisesExceptionIfTheMetadataClassIsNotAnAbstractMetad ]); $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage('does not extend ' . Metadata\AbstractMetadata::class); - ($this->factory)($this->container->reveal()); + ($this->factory)($this->container); } public function testFactoryRaisesExceptionIfMetadataClassDoesNotHaveACreationMethodInTheFactory(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn([ + $this->populateConfiguration($this->container, [ MetadataMap::class => [ [ '__class__' => TestAsset\TestMetadata::class, @@ -129,27 +107,25 @@ public function testFactoryRaisesExceptionIfMetadataClassDoesNotHaveACreationMet ]); $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage('please provide a factory in your configuration'); - ($this->factory)($this->container->reveal()); + ($this->factory)($this->container); } public function testFactoryRaisesExceptionIfMetadataFactoryDoesNotImplementFactoryInterface(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn( - [ - MetadataMap::class => [ - ['__class__' => TestAsset\TestMetadata::class], - ], - 'mezzio-hal' => [ - 'metadata-factories' => [ - TestAsset\TestMetadata::class => stdClass::class, - ], + $this->populateConfiguration($this->container, [ + MetadataMap::class => [ + ['__class__' => TestAsset\TestMetadata::class], + ], + 'mezzio-hal' => [ + 'metadata-factories' => [ + TestAsset\TestMetadata::class => stdClass::class, ], - ] - ); + ], + ]); + $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage('is not a valid metadata factory class; does not implement'); - ($this->factory)($this->container->reveal()); + ($this->factory)($this->container); } public function invalidMetadata(): Generator @@ -173,132 +149,117 @@ public function testFactoryRaisesExceptionIfMetadataIsMissingRequiredElements( array $metadata, string $expectExceptionString ): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn( - [ - MetadataMap::class => [$metadata], - 'mezzio-hal' => [ - 'metadata-factories' => [ - RouteBasedCollectionMetadata::class => RouteBasedCollectionMetadataFactory::class, - RouteBasedResourceMetadata::class => RouteBasedResourceMetadataFactory::class, - UrlBasedCollectionMetadata::class => UrlBasedCollectionMetadataFactory::class, - UrlBasedResourceMetadata::class => UrlBasedResourceMetadataFactory::class, - ], + $this->populateConfiguration($this->container, [ + MetadataMap::class => [$metadata], + 'mezzio-hal' => [ + 'metadata-factories' => [ + RouteBasedCollectionMetadata::class => RouteBasedCollectionMetadataFactory::class, + RouteBasedResourceMetadata::class => RouteBasedResourceMetadataFactory::class, + UrlBasedCollectionMetadata::class => UrlBasedCollectionMetadataFactory::class, + UrlBasedResourceMetadata::class => UrlBasedResourceMetadataFactory::class, ], - ] - ); + ], + ]); $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage($expectExceptionString); - ($this->factory)($this->container->reveal()); + ($this->factory)($this->container); } public function testFactoryCanMapUrlBasedResourceMetadata(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn( - [ - MetadataMap::class => [ - [ - '__class__' => UrlBasedResourceMetadata::class, - 'resource_class' => stdClass::class, - 'url' => '/test/foo', - 'extractor' => 'ObjectProperty', - ], + $this->populateConfiguration($this->container, [ + MetadataMap::class => [ + [ + '__class__' => UrlBasedResourceMetadata::class, + 'resource_class' => stdClass::class, + 'url' => '/test/foo', + 'extractor' => 'ObjectProperty', ], - 'mezzio-hal' => [ - 'metadata-factories' => [ - UrlBasedResourceMetadata::class => UrlBasedResourceMetadataFactory::class, - ], + ], + 'mezzio-hal' => [ + 'metadata-factories' => [ + UrlBasedResourceMetadata::class => UrlBasedResourceMetadataFactory::class, ], - ] - ); + ], + ]); - $metadataMap = ($this->factory)($this->container->reveal()); - $this->assertInstanceOf(MetadataMap::class, $metadataMap); - $this->assertTrue($metadataMap->has(stdClass::class)); + $metadataMap = ($this->factory)($this->container); + self::assertTrue($metadataMap->has(stdClass::class)); $metadata = $metadataMap->get(stdClass::class); - $this->assertInstanceOf(UrlBasedResourceMetadata::class, $metadata); - $this->assertSame(stdClass::class, $metadata->getClass()); - $this->assertSame('ObjectProperty', $metadata->getExtractor()); - $this->assertSame('/test/foo', $metadata->getUrl()); + self::assertInstanceOf(UrlBasedResourceMetadata::class, $metadata); + self::assertSame(stdClass::class, $metadata->getClass()); + self::assertSame('ObjectProperty', $metadata->getExtractor()); + self::assertSame('/test/foo', $metadata->getUrl()); } public function testFactoryCanMapUrlBasedCollectionMetadata(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn( - [ - MetadataMap::class => [ - [ - '__class__' => UrlBasedCollectionMetadata::class, - 'collection_class' => stdClass::class, - 'collection_relation' => 'foo', - 'url' => '/test/foo', - 'pagination_param' => 'p', - 'pagination_param_type' => Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, - ], + $this->populateConfiguration($this->container, [ + MetadataMap::class => [ + [ + '__class__' => UrlBasedCollectionMetadata::class, + 'collection_class' => stdClass::class, + 'collection_relation' => 'foo', + 'url' => '/test/foo', + 'pagination_param' => 'p', + 'pagination_param_type' => Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, ], - 'mezzio-hal' => [ - 'metadata-factories' => [ - UrlBasedCollectionMetadata::class => UrlBasedCollectionMetadataFactory::class, - ], + ], + 'mezzio-hal' => [ + 'metadata-factories' => [ + UrlBasedCollectionMetadata::class => UrlBasedCollectionMetadataFactory::class, ], - ] - ); + ], + ]); - $metadataMap = ($this->factory)($this->container->reveal()); - $this->assertInstanceOf(MetadataMap::class, $metadataMap); - $this->assertTrue($metadataMap->has(stdClass::class)); + $metadataMap = ($this->factory)($this->container); + self::assertTrue($metadataMap->has(stdClass::class)); $metadata = $metadataMap->get(stdClass::class); - $this->assertInstanceOf(UrlBasedCollectionMetadata::class, $metadata); - $this->assertSame(stdClass::class, $metadata->getClass()); - $this->assertSame('foo', $metadata->getCollectionRelation()); - $this->assertSame('/test/foo', $metadata->getUrl()); - $this->assertSame('p', $metadata->getPaginationParam()); - $this->assertSame(Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, $metadata->getPaginationParamType()); + self::assertInstanceOf(UrlBasedCollectionMetadata::class, $metadata); + self::assertSame(stdClass::class, $metadata->getClass()); + self::assertSame('foo', $metadata->getCollectionRelation()); + self::assertSame('/test/foo', $metadata->getUrl()); + self::assertSame('p', $metadata->getPaginationParam()); + self::assertSame(Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, $metadata->getPaginationParamType()); } public function testFactoryCanMapRouteBasedResourceMetadata(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn( - [ - MetadataMap::class => [ - [ - '__class__' => RouteBasedResourceMetadata::class, - 'resource_class' => stdClass::class, - 'route' => 'foo', - 'extractor' => 'ObjectProperty', - 'resource_identifier' => 'foo_id', - 'route_params' => ['foo' => 'bar'], - 'identifiers_to_placeholders_mapping' => [ - 'bar' => 'bar_value', - 'baz' => 'baz_value', - ], + $this->populateConfiguration($this->container, [ + MetadataMap::class => [ + [ + '__class__' => RouteBasedResourceMetadata::class, + 'resource_class' => stdClass::class, + 'route' => 'foo', + 'extractor' => 'ObjectProperty', + 'resource_identifier' => 'foo_id', + 'route_params' => ['foo' => 'bar'], + 'identifiers_to_placeholders_mapping' => [ + 'bar' => 'bar_value', + 'baz' => 'baz_value', ], ], - 'mezzio-hal' => [ - 'metadata-factories' => [ - RouteBasedResourceMetadata::class => RouteBasedResourceMetadataFactory::class, - ], + ], + 'mezzio-hal' => [ + 'metadata-factories' => [ + RouteBasedResourceMetadata::class => RouteBasedResourceMetadataFactory::class, ], - ] - ); + ], + ]); - $metadataMap = ($this->factory)($this->container->reveal()); - $this->assertInstanceOf(MetadataMap::class, $metadataMap); - $this->assertTrue($metadataMap->has(stdClass::class)); + $metadataMap = ($this->factory)($this->container); + self::assertTrue($metadataMap->has(stdClass::class)); $metadata = $metadataMap->get(stdClass::class); - $this->assertInstanceOf(RouteBasedResourceMetadata::class, $metadata); - $this->assertSame(stdClass::class, $metadata->getClass()); - $this->assertSame('ObjectProperty', $metadata->getExtractor()); - $this->assertSame('foo', $metadata->getRoute()); - $this->assertSame('foo_id', $metadata->getResourceIdentifier()); - $this->assertSame(['foo' => 'bar'], $metadata->getRouteParams()); - $this->assertSame([ + self::assertInstanceOf(RouteBasedResourceMetadata::class, $metadata); + self::assertSame(stdClass::class, $metadata->getClass()); + self::assertSame('ObjectProperty', $metadata->getExtractor()); + self::assertSame('foo', $metadata->getRoute()); + self::assertSame('foo_id', $metadata->getResourceIdentifier()); + self::assertSame(['foo' => 'bar'], $metadata->getRouteParams()); + self::assertSame([ 'bar' => 'bar_value', 'baz' => 'baz_value', ], $metadata->getIdentifiersToPlaceholdersMapping()); @@ -306,62 +267,70 @@ public function testFactoryCanMapRouteBasedResourceMetadata(): void public function testFactoryCanMapRouteBasedCollectionMetadata(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn( - [ - MetadataMap::class => [ - [ - '__class__' => RouteBasedCollectionMetadata::class, - 'collection_class' => stdClass::class, - 'collection_relation' => 'foo', - 'route' => 'foo', - 'pagination_param' => 'p', - 'pagination_param_type' => Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, - 'route_params' => ['foo' => 'bar'], - 'query_string_arguments' => ['baz' => 'bat'], - ], + $this->populateConfiguration($this->container, [ + MetadataMap::class => [ + [ + '__class__' => RouteBasedCollectionMetadata::class, + 'collection_class' => stdClass::class, + 'collection_relation' => 'foo', + 'route' => 'foo', + 'pagination_param' => 'p', + 'pagination_param_type' => Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, + 'route_params' => ['foo' => 'bar'], + 'query_string_arguments' => ['baz' => 'bat'], ], - 'mezzio-hal' => [ - 'metadata-factories' => [ - RouteBasedCollectionMetadata::class => RouteBasedCollectionMetadataFactory::class, - ], + ], + 'mezzio-hal' => [ + 'metadata-factories' => [ + RouteBasedCollectionMetadata::class => RouteBasedCollectionMetadataFactory::class, ], - ] - ); + ], + ]); - $metadataMap = ($this->factory)($this->container->reveal()); - $this->assertInstanceOf(MetadataMap::class, $metadataMap); - $this->assertTrue($metadataMap->has(stdClass::class)); + $metadataMap = ($this->factory)($this->container); + self::assertTrue($metadataMap->has(stdClass::class)); $metadata = $metadataMap->get(stdClass::class); - $this->assertInstanceOf(RouteBasedCollectionMetadata::class, $metadata); - $this->assertSame(stdClass::class, $metadata->getClass()); - $this->assertSame('foo', $metadata->getCollectionRelation()); - $this->assertSame('foo', $metadata->getRoute()); - $this->assertSame('p', $metadata->getPaginationParam()); - $this->assertSame(Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, $metadata->getPaginationParamType()); - $this->assertSame(['foo' => 'bar'], $metadata->getRouteParams()); - $this->assertSame(['baz' => 'bat'], $metadata->getQueryStringArguments()); + self::assertInstanceOf(RouteBasedCollectionMetadata::class, $metadata); + self::assertSame(stdClass::class, $metadata->getClass()); + self::assertSame('foo', $metadata->getCollectionRelation()); + self::assertSame('foo', $metadata->getRoute()); + self::assertSame('p', $metadata->getPaginationParam()); + self::assertSame(Metadata\AbstractCollectionMetadata::TYPE_PLACEHOLDER, $metadata->getPaginationParamType()); + self::assertSame(['foo' => 'bar'], $metadata->getRouteParams()); + self::assertSame(['baz' => 'bat'], $metadata->getQueryStringArguments()); } public function testFactoryCanCreateMetadataViaFactoryMethod(): void { - $this->container->has('config')->willReturn(true); - $this->container->get('config')->willReturn( - [ - MetadataMap::class => [ - ['__class__' => TestAsset\TestMetadata::class], - ], - ] - ); + $this->populateConfiguration($this->container, [ + MetadataMap::class => [ + ['__class__' => TestAsset\TestMetadata::class], + ], + ]); $this->factory = new TestAsset\TestMetadataMapFactory(); - $metadataMap = ($this->factory)($this->container->reveal()); - $this->assertInstanceOf(MetadataMap::class, $metadataMap); - $this->assertTrue($metadataMap->has(stdClass::class)); + $metadataMap = ($this->factory)($this->container); + self::assertTrue($metadataMap->has(stdClass::class)); $metadata = $metadataMap->get(stdClass::class); - $this->assertInstanceOf(TestAsset\TestMetadata::class, $metadata); + self::assertInstanceOf(TestAsset\TestMetadata::class, $metadata); + } + + /** + * @param ContainerInterface&MockObject $container + */ + private function populateConfiguration(ContainerInterface $container, array $config): void + { + $container + ->method('has') + ->with('config') + ->willReturn(true); + + $container + ->method('get') + ->with('config') + ->willReturn($config); } } diff --git a/test/Metadata/MetadataMapTest.php b/test/Metadata/MetadataMapTest.php index 842c7d4..e16cd77 100644 --- a/test/Metadata/MetadataMapTest.php +++ b/test/Metadata/MetadataMapTest.php @@ -6,14 +6,15 @@ use Generator; use Mezzio\Hal\Metadata; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\PhpUnit\ProphecyTrait; +/** + * @see MockObject + */ class MetadataMapTest extends TestCase { - use ProphecyTrait; - - /** @psalm-var string[] */ + /** @psalm-var non-empty-list> */ private $metadataClasses = [ Metadata\AbstractMetadata::class, Metadata\AbstractCollectionMetadata::class, @@ -24,20 +25,29 @@ class MetadataMapTest extends TestCase Metadata\UrlBasedResourceMetadata::class, ]; + /** @var Metadata\MetadataMap */ + private $map; + public function setUp(): void { $this->map = new Metadata\MetadataMap(); } /** - * @psalm-return Generator + * @psalm-return Generator, array{ + * 0: class-string, + * 1: Metadata\AbstractMetadata&MockObject + * }> */ public function validMetadataTypes(): Generator { foreach ($this->metadataClasses as $class) { - $metadata = $this->prophesize($class); - $metadata->getClass()->willReturn($class); - yield $class => [$class, $metadata->reveal()]; + $metadata = $this->createMock($class); + $metadata + ->method('getClass') + ->willReturn($class); + + yield $class => [$class, $metadata]; } } @@ -46,36 +56,42 @@ public function validMetadataTypes(): Generator */ public function testCanAggregateAnyMetadataType(string $class, Metadata\AbstractMetadata $metadata): void { - $this->assertFalse($this->map->has($class)); + self::assertFalse($this->map->has($class)); $this->map->add($metadata); - $this->assertTrue($this->map->has($class)); - $this->assertSame($metadata, $this->map->get($class)); + self::assertTrue($this->map->has($class)); + self::assertSame($metadata, $this->map->get($class)); } public function testAddWillRaiseUndefinedClassExceptionIfClassDoesNotExist(): void { - $metadata = $this->prophesize(Metadata\AbstractMetadata::class); - $metadata->getClass()->willReturn('undefined-class'); + $metadata = $this->createMock(Metadata\AbstractMetadata::class); + $metadata + ->method('getClass') + ->willReturn('undefined-class'); $this->expectException(Metadata\Exception\UndefinedClassException::class); $this->expectExceptionMessage('undefined-class'); - $this->map->add($metadata->reveal()); + $this->map->add($metadata); } public function testAddWillRaiseDuplicateMetadataExceptionWhenDuplicateMetadataEncountered(): void { - $first = $this->prophesize(Metadata\AbstractMetadata::class); - $first->getClass()->willReturn(self::class); + $first = $this->createMock(Metadata\AbstractMetadata::class); + $first + ->method('getClass') + ->willReturn(self::class); - $this->map->add($first->reveal()); - $this->assertSame($first->reveal(), $this->map->get(self::class)); + $this->map->add($first); + self::assertSame($first, $this->map->get(self::class)); - $second = $this->prophesize(Metadata\AbstractMetadata::class); - $second->getClass()->willReturn(self::class); + $second = $this->createMock(Metadata\AbstractMetadata::class); + $second + ->method('getClass') + ->willReturn(self::class); $this->expectException(Metadata\Exception\DuplicateMetadataException::class); $this->expectExceptionMessage(self::class); - $this->map->add($second->reveal()); + $this->map->add($second); } public function testGetWilRaiseUndefinedMetadataExceptionIfClassNotPresentInMap(): void diff --git a/test/PHPUnitDeprecatedAssertions.php b/test/PHPUnitDeprecatedAssertions.php index ae6b257..9cb9cf8 100644 --- a/test/PHPUnitDeprecatedAssertions.php +++ b/test/PHPUnitDeprecatedAssertions.php @@ -216,10 +216,14 @@ public static function getObjectAttribute($object, string $attributeName) $reflector = new ReflectionObject($object); do { + if (! $reflector->hasProperty($attributeName)) { + continue; + } + try { $attribute = $reflector->getProperty($attributeName); - if (! $attribute || $attribute->isPublic()) { + if ($attribute->isPublic()) { return $object->$attributeName; } @@ -262,7 +266,7 @@ private static function invalidArgument(int $argument, string $type, $value = nu 'Argument #%d%sof %s::%s() must be a %s', $argument, $value !== null ? ' (' . gettype($value) . '#' . $value . ')' : ' (No Value) ', - $stack[1]['class'], + $stack[1]['class'] ?? '', $stack[1]['function'], $type ) diff --git a/test/Psr17ResponseFactoryTraitTest.php b/test/Psr17ResponseFactoryTraitTest.php new file mode 100644 index 0000000..152c0f2 --- /dev/null +++ b/test/Psr17ResponseFactoryTraitTest.php @@ -0,0 +1,105 @@ +factory = new Psr17ResponseFactoryTraitImplementation(); + } + + /** + * @psalm-return Generator}> + */ + public function configurationsWithOverriddenResponseInterfaceFactory(): Generator + { + yield 'default' => [ + [ + 'dependencies' => [ + 'factories' => [ + ResponseInterface::class => function (): ResponseInterface { + return $this->createMock(ResponseInterface::class); + }, + ], + ], + ], + ]; + + yield 'aliased' => [ + [ + 'dependencies' => [ + 'aliases' => [ + ResponseInterface::class => 'CustomResponseInterface', + ], + ], + ], + ]; + + yield 'delegated' => [ + [ + 'dependencies' => [ + 'delegators' => [ + ResponseInterface::class => [ + function (): ResponseInterface { + return $this->createMock(ResponseInterface::class); + }, + ], + ], + ], + ], + ]; + } + + public function testWillUseResponseFactoryInterfaceFromContainerWhenApplicationFactoryIsNotOverridden(): void + { + $responseFactory = $this->createMock(ResponseFactoryInterface::class); + $container = new InMemoryContainer(); + $container->set('config', [ + 'dependencies' => [ + 'factories' => [ + ResponseInterface::class => ResponseFactoryFactory::class, + ], + ], + ]); + $container->set(ResponseFactoryInterface::class, $responseFactory); + $detectedResponseFactory = ($this->factory)($container); + self::assertSame($responseFactory, $detectedResponseFactory); + } + + /** + * @param array $config + * @dataProvider configurationsWithOverriddenResponseInterfaceFactory + */ + public function testWontUseResponseFactoryInterfaceFromContainerWhenApplicationFactoryIsOverriden( + array $config + ): void { + $responseFactory = $this->createMock(ResponseFactoryInterface::class); + $container = new InMemoryContainer(); + $container->set('config', $config); + $container->set(ResponseFactoryInterface::class, $responseFactory); + $response = $this->createMock(ResponseInterface::class); + $container->set(ResponseInterface::class, function () use ($response): ResponseInterface { + return $response; + }); + + $detectedResponseFactory = ($this->factory)($container); + self::assertNotSame($responseFactory, $detectedResponseFactory); + self::assertInstanceOf(CallableResponseFactoryDecorator::class, $detectedResponseFactory); + self::assertEquals($response, $detectedResponseFactory->getResponseFromCallable()); + } +} diff --git a/test/ResourceGenerator/DoctrinePaginatorTest.php b/test/ResourceGenerator/DoctrinePaginatorTest.php index 34d2128..3352acf 100644 --- a/test/ResourceGenerator/DoctrinePaginatorTest.php +++ b/test/ResourceGenerator/DoctrinePaginatorTest.php @@ -16,56 +16,56 @@ use Mezzio\Hal\ResourceGenerator\RouteBasedCollectionStrategy; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; -use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\ServerRequestInterface; use function array_map; +use function assert; +use function count; use function range; class DoctrinePaginatorTest extends TestCase { - use ProphecyTrait; + /** @var RouteBasedCollectionMetadata&MockObject */ + private $metadata; + + /** @var LinkGenerator&MockObject */ + private $linkGenerator; + + /** @var ResourceGenerator&MockObject */ + private $generator; + + /** @var ServerRequestInterface&MockObject */ + private $request; + + /** @var Paginator&MockObject */ + private $paginator; + + /** @var RouteBasedCollectionStrategy */ + private $strategy; public function setUp(): void { - $this->metadata = $this->prophesize(RouteBasedCollectionMetadata::class); - $this->linkGenerator = $this->prophesize(LinkGenerator::class); - $this->generator = $this->prophesize(ResourceGenerator::class); - $this->request = $this->prophesize(ServerRequestInterface::class); - $this->paginator = $this->prophesize(Paginator::class); + $this->metadata = $this->createMock(RouteBasedCollectionMetadata::class); + $this->linkGenerator = $this->createMock(LinkGenerator::class); + $this->generator = $this->createMock(ResourceGenerator::class); + $this->request = $this->createMock(ServerRequestInterface::class); + $this->paginator = $this->createMock(Paginator::class); $this->strategy = new RouteBasedCollectionStrategy(); } /** - * @return MockObject&mixed - * @psalm-return MockObject&MockedType + * @psalm-return AbstractQuery&MockObject */ - public function mockQuery() + public function mockQuery(): AbstractQuery { - return $this->getMockBuilder(AbstractQuery::class) + $mock = $this->getMockBuilder(AbstractQuery::class) ->disableOriginalConstructor() ->setMethods(['getMaxResults', 'setFirstResult']) ->getMockForAbstractClass(); - } - public function mockLinkGeneration( - string $relation, - string $route, - array $routeParams, - array $queryStringArgs - ): void { - $link = $this->prophesize(Link::class)->reveal(); - $this->linkGenerator - ->fromRoute( - $relation, - $this->request->reveal(), - $route, - $routeParams, - $queryStringArgs - ) - ->willReturn($link); + assert($mock instanceof AbstractQuery && $mock instanceof MockObject); + return $mock; } public function invalidPageCombinations(): iterable @@ -81,23 +81,38 @@ public function invalidPageCombinations(): iterable public function testThrowsOutOfBoundsExceptionForInvalidPage(int $page, int $numPages): void { $query = $this->mockQuery(); - $query->expects($this->once()) + $query + ->expects($this->once()) ->method('getMaxResults') ->with() ->willReturn(15); - $this->paginator->getQuery()->willReturn($query); - $this->paginator->count()->willReturn($numPages); - $this->metadata->getPaginationParamType()->willReturn(RouteBasedCollectionMetadata::TYPE_QUERY); - $this->metadata->getPaginationParam()->willReturn('page_num'); - $this->request->getQueryParams()->willReturn(['page_num' => $page]); + $this->paginator + ->method('getQuery') + ->willReturn($query); + + $this->paginator + ->method('count') + ->willReturn($numPages); + + $this->metadata + ->method('getPaginationParamType') + ->willReturn(RouteBasedCollectionMetadata::TYPE_QUERY); + + $this->metadata + ->method('getPaginationParam') + ->willReturn('page_num'); + + $this->request + ->method('getQueryParams') + ->willReturn(['page_num' => $page]); $this->expectException(OutOfBoundsException::class); $this->strategy->createResource( - $this->paginator->reveal(), - $this->metadata->reveal(), - $this->generator->reveal(), - $this->request->reveal() + $this->paginator, + $this->metadata, + $this->generator, + $this->request ); } @@ -108,103 +123,189 @@ public function testDoesNotCreateLinksForUnknownPaginationParamType(): void ->method('getMaxResults') ->with() ->willReturn(15); - $this->paginator->getQuery()->willReturn($query); - $this->paginator->count()->willReturn(100); + $this->paginator + ->method('getQuery') + ->willReturn($query); + + $this->paginator + ->method('count') + ->willReturn(100); + + $this->metadata + ->method('getPaginationParamType') + ->willReturn('unknown'); - $this->metadata->getPaginationParamType()->willReturn('unknown'); - $this->metadata->getPaginationParam()->shouldNotBeCalled(); - $this->metadata->getRouteParams()->willReturn([]); - $this->metadata->getQueryStringArguments()->willReturn([]); - $this->metadata->getRoute()->willReturn('test'); - $this->metadata->getCollectionRelation()->willReturn('test'); + $this->metadata + ->expects(self::never()) + ->method('getPaginationParam'); + + $this->metadata + ->method('getRouteParams') + ->willReturn([]); + + $this->metadata + ->method('getQueryStringArguments') + ->willReturn([]); + + $this->metadata + ->method('getRoute') + ->willReturn('test'); + + $this->metadata + ->method('getCollectionRelation') + ->willReturn('test'); + + $this->request + ->expects(self::once()) + ->method('getQueryParams') + ->willReturn(['page' => 3]); $this->request - ->getQueryParams() - ->willReturn(['page' => 3]) - ->shouldBeCalledTimes(1); - $this->request->getAttribute(Argument::any(), Argument::any())->shouldNotBeCalled(); + ->expects(self::never()) + ->method('getAttribute'); $values = array_map(function ($value) { return (object) ['value' => $value]; }, range(46, 60)); - $this->paginator->getIterator()->willReturn(new ArrayIterator($values)); + $this->paginator + ->method('getIterator') + ->willReturn(new ArrayIterator($values)); - $testCase = $this; + $consecutiveGeneratorArguments = []; foreach (range(46, 60) as $value) { - $this->generator - ->fromObject( - (object) ['value' => $value], - Argument::that([$this->request, 'reveal']), - 1 - ) - ->will(function () use ($testCase) { - $resource = $testCase->prophesize(HalResource::class); - $resource->getElements()->willReturn(['test' => true]); - return $resource->reveal(); - }) - ->shouldBeCalledTimes(1); + $consecutiveGeneratorArguments[] = [ + (object) ['value' => $value], + $this->request, + 1, + ]; } - $this->generator->getLinkGenerator()->will([$this->linkGenerator, 'reveal']); - $this->mockLinkGeneration('self', 'test', [], ['page' => 3]); + $this->generator + ->expects(self::exactly(count($consecutiveGeneratorArguments))) + ->method('fromObject') + ->withConsecutive( + ...$consecutiveGeneratorArguments + ) + ->willReturnCallback(function (): HalResource { + $resource = $this->createMock(HalResource::class); + $resource + ->method('getElements') + ->willReturn(['test' => true]); - $resource = $this->strategy->createResource( - $this->paginator->reveal(), - $this->metadata->reveal(), - $this->generator->reveal(), - $this->request->reveal() - ); + return $resource; + }); - $this->assertInstanceOf(HalResource::class, $resource); + $this->generator + ->method('getLinkGenerator') + ->willReturn($this->linkGenerator); + + $link = $this->createMock(Link::class); + $this->linkGenerator + ->method('fromRoute') + ->with( + 'self', + $this->request, + 'test', + [], + ['page' => 3] + ) + ->willReturn($link); + + $this->strategy->createResource( + $this->paginator, + $this->metadata, + $this->generator, + $this->request + ); } public function testCreatesLinksForQueryBasedPagination(): void { $query = $this->mockQuery(); - $query->expects($this->once()) + $query + ->expects($this->once()) ->method('getMaxResults') ->with() ->willReturn(15); - $query->expects($this->once()) + $query + ->expects($this->once()) ->method('setFirstResult') ->with(30); - $this->paginator->getQuery()->willReturn($query); - $this->paginator->count()->willReturn(100); - $this->metadata->getPaginationParamType()->willReturn(RouteBasedCollectionMetadata::TYPE_QUERY); - $this->metadata->getPaginationParam()->willReturn('page_num'); - $this->metadata->getRouteParams()->willReturn([]); - $this->metadata->getQueryStringArguments()->willReturn([]); - $this->metadata->getRoute()->willReturn('test'); - $this->metadata->getCollectionRelation()->willReturn('test'); + $this->paginator + ->method('getQuery') + ->willReturn($query); + + $this->paginator + ->method('count') + ->willReturn(100); + + $this->metadata + ->method('getPaginationParamType') + ->willReturn(RouteBasedCollectionMetadata::TYPE_QUERY); + + $this->metadata + ->method('getPaginationParam') + ->willReturn('page_num'); + + $this->metadata + ->method('getRouteParams') + ->willReturn([]); + + $this->metadata + ->method('getQueryStringArguments') + ->willReturn([]); + + $this->metadata + ->method('getRoute') + ->willReturn('test'); + + $this->metadata + ->method('getCollectionRelation') + ->willReturn('test'); $this->request - ->getQueryParams() - ->willReturn(['page_num' => 3]) - ->shouldBeCalledTimes(1); - $this->request->getAttribute(Argument::any(), Argument::any())->shouldNotBeCalled(); + ->expects(self::once()) + ->method('getQueryParams') + ->willReturn(['page_num' => 3]); + + $this->request + ->expects(self::never()) + ->method('getAttribute'); $values = array_map(function ($value) { return (object) ['value' => $value]; }, range(46, 60)); - $this->paginator->getIterator()->willReturn(new ArrayIterator($values)); - $testCase = $this; + $this->paginator + ->method('getIterator') + ->willReturn(new ArrayIterator($values)); + + $testCase = $this; + $consecutiveGeneratorArguments = []; foreach (range(46, 60) as $value) { - $this->generator - ->fromObject( - (object) ['value' => $value], - Argument::that([$this->request, 'reveal']), - 1 - ) - ->will(function () use ($testCase) { - $resource = $testCase->prophesize(HalResource::class); - $resource->getElements()->willReturn(['test' => true]); - return $resource->reveal(); - }) - ->shouldBeCalledTimes(1); + $consecutiveGeneratorArguments[] = [ + (object) ['value' => $value], + $this->request, + 1, + ]; } - $this->generator->getLinkGenerator()->will([$this->linkGenerator, 'reveal']); + + $this->generator + ->expects(self::exactly(count($consecutiveGeneratorArguments))) + ->method('fromObject') + ->withConsecutive( + ...$consecutiveGeneratorArguments + ) + ->willReturnCallback(function () use ($testCase): HalResource { + $resource = $testCase->createMock(HalResource::class); + $resource->method('getElements')->willReturn(['test' => true]); + return $resource; + }); + + $this->generator + ->method('getLinkGenerator') + ->willReturn($this->linkGenerator); $paginationLinks = [ 'self' => ['page_num' => 3], @@ -213,67 +314,118 @@ public function testCreatesLinksForQueryBasedPagination(): void 'next' => ['page_num' => 4], 'last' => ['page_num' => 7], ]; + + $consecutiveLinkGenerationArguments = []; foreach ($paginationLinks as $relation => $queryStringArgs) { - $this->mockLinkGeneration($relation, 'test', [], $queryStringArgs); + $consecutiveLinkGenerationArguments[] = [ + $relation, + $this->request, + 'test', + [], + $queryStringArgs, + ]; } + $link = $this->createMock(Link::class); + $this->linkGenerator + ->expects(self::exactly(count($consecutiveLinkGenerationArguments))) + ->method('fromRoute') + ->withConsecutive(...$consecutiveLinkGenerationArguments) + ->willReturn($link); + $resource = $this->strategy->createResource( - $this->paginator->reveal(), - $this->metadata->reveal(), - $this->generator->reveal(), - $this->request->reveal() + $this->paginator, + $this->metadata, + $this->generator, + $this->request ); - $this->assertInstanceOf(HalResource::class, $resource); + self::assertInstanceOf(HalResource::class, $resource); } public function testCreatesLinksForRouteBasedPagination(): void { $query = $this->mockQuery(); - $query->expects($this->once()) + $query + ->expects($this->once()) ->method('getMaxResults') ->with() ->willReturn(15); - $query->expects($this->once()) + + $query + ->expects($this->once()) ->method('setFirstResult') ->with(30); - $this->paginator->getQuery()->willReturn($query); - $this->paginator->count()->willReturn(100); + $this->paginator + ->method('getQuery') + ->willReturn($query); + $this->paginator->method('count')->willReturn(100); + + $this->metadata + ->method('getPaginationParamType') + ->willReturn(RouteBasedCollectionMetadata::TYPE_PLACEHOLDER); + + $this->metadata + ->method('getPaginationParam') + ->willReturn('page_num'); - $this->metadata->getPaginationParamType()->willReturn(RouteBasedCollectionMetadata::TYPE_PLACEHOLDER); - $this->metadata->getPaginationParam()->willReturn('page_num'); - $this->metadata->getRouteParams()->willReturn([]); - $this->metadata->getQueryStringArguments()->willReturn([]); - $this->metadata->getRoute()->willReturn('test'); - $this->metadata->getCollectionRelation()->willReturn('test'); + $this->metadata + ->method('getRouteParams') + ->willReturn([]); + + $this->metadata + ->method('getQueryStringArguments') + ->willReturn([]); + + $this->metadata + ->method('getRoute') + ->willReturn('test'); + + $this->metadata + ->method('getCollectionRelation') + ->willReturn('test'); + + $this->request + ->expects(self::never()) + ->method('getQueryParams'); - $this->request->getQueryParams()->shouldNotBeCalled(); $this->request - ->getAttribute('page_num', 1) - ->willReturn(3) - ->shouldBeCalledTimes(1); + ->expects(self::once()) + ->method('getAttribute') + ->with('page_num', 1) + ->willReturn(3); $values = array_map(function ($value) { return (object) ['value' => $value]; }, range(46, 60)); - $this->paginator->getIterator()->willReturn(new ArrayIterator($values)); + + $this->paginator + ->method('getIterator') + ->willReturn(new ArrayIterator($values)); $testCase = $this; + + $consecutiveGeneratorArguments = []; foreach (range(46, 60) as $value) { - $this->generator - ->fromObject( - (object) ['value' => $value], - Argument::that([$this->request, 'reveal']), - 1 - ) - ->will(function () use ($testCase) { - $resource = $testCase->prophesize(HalResource::class); - $resource->getElements()->willReturn(['test' => true]); - return $resource->reveal(); - }) - ->shouldBeCalledTimes(1); + $consecutiveGeneratorArguments[] = [ + (object) ['value' => $value], + $this->request, + 1, + ]; } - $this->generator->getLinkGenerator()->will([$this->linkGenerator, 'reveal']); + $this->generator + ->expects(self::exactly(count($consecutiveGeneratorArguments))) + ->method('fromObject') + ->withConsecutive(...$consecutiveGeneratorArguments) + ->willReturnCallback(function () use ($testCase): HalResource { + $resource = $testCase->createMock(HalResource::class); + $resource->method('getElements')->willReturn(['test' => true]); + return $resource; + }); + + $this->generator + ->method('getLinkGenerator') + ->willReturn($this->linkGenerator); $paginationLinks = [ 'self' => ['page_num' => 3], @@ -282,17 +434,33 @@ public function testCreatesLinksForRouteBasedPagination(): void 'next' => ['page_num' => 4], 'last' => ['page_num' => 7], ]; + + $consecutiveLinkGenerationArguments = []; foreach ($paginationLinks as $relation => $routeParams) { - $this->mockLinkGeneration($relation, 'test', $routeParams, []); + $consecutiveLinkGenerationArguments[] = [ + $relation, + $this->request, + 'test', + $routeParams, + [], + ]; } + $link = $this->createMock(Link::class); + $this->linkGenerator + ->method('fromRoute') + ->withConsecutive( + ...$consecutiveLinkGenerationArguments + ) + ->willReturn($link); + $resource = $this->strategy->createResource( - $this->paginator->reveal(), - $this->metadata->reveal(), - $this->generator->reveal(), - $this->request->reveal() + $this->paginator, + $this->metadata, + $this->generator, + $this->request ); - $this->assertInstanceOf(HalResource::class, $resource); + self::assertInstanceOf(HalResource::class, $resource); } } diff --git a/test/ResourceGeneratorFactoryTest.php b/test/ResourceGeneratorFactoryTest.php index f22794c..8907e83 100644 --- a/test/ResourceGeneratorFactoryTest.php +++ b/test/ResourceGeneratorFactoryTest.php @@ -193,7 +193,7 @@ public function testConstructorAllowsSpecifyingLinkGeneratorServiceName(): void ->get(HydratorPluginManager::class) ->willReturn($this->prophesize(ContainerInterface::class)->reveal()); - $linkGenerator = $this->prophesize(LinkGenerator::class)->reveal(); + $linkGenerator = $this->createMock(LinkGenerator::class); $container ->get(CustomLinkGenerator::class) ->willReturn($linkGenerator); diff --git a/test/TestAsset/Psr17ResponseFactoryTraitImplementation.php b/test/TestAsset/Psr17ResponseFactoryTraitImplementation.php new file mode 100644 index 0000000..e65e833 --- /dev/null +++ b/test/TestAsset/Psr17ResponseFactoryTraitImplementation.php @@ -0,0 +1,19 @@ +detectResponseFactory($container); + } +}