diff --git a/.travis.yml b/.travis.yml index 9ca5a87..25be1cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,7 @@ matrix: - php: 5.6 env: - DEPS=locked - - LEGACY_DEPS="phpunit/phpunit" - - TEST_COVERAGE=true + - LEGACY_DEPS="phpunit/phpunit zendframework/zend-hydrator" - php: 5.6 env: - DEPS=latest @@ -31,7 +30,7 @@ matrix: - php: 7 env: - DEPS=locked - - LEGACY_DEPS="phpunit/phpunit" + - LEGACY_DEPS="phpunit/phpunit zendframework/zend-hydrator" - CS_CHECK=true - php: 7 env: @@ -42,6 +41,8 @@ matrix: - php: 7.1 env: - DEPS=locked + - LEGACY_DEPS="zendframework/zend-hydrator" + - TEST_COVERAGE=true - php: 7.1 env: - DEPS=latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a8953b..e7f2803 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,11 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.5.1 - TBD +## 1.6.0 - 2018-12-11 ### Added -- Nothing. +- [#172](https://github.com/zfcampus/zf-hal/pull/172) adds support for zend-hydrator v3 releases (while retaining support for v1 and v2). ### Changed diff --git a/composer.json b/composer.json index 3dd8baf..32aac0a 100644 --- a/composer.json +++ b/composer.json @@ -21,8 +21,8 @@ }, "extra": { "branch-alias": { - "dev-master": "1.5-dev", - "dev-develop": "1.6-dev" + "dev-master": "1.6.x-dev", + "dev-develop": "1.7.x-dev" }, "zf": { "module": "ZF\\Hal" @@ -34,7 +34,7 @@ "zendframework/zend-eventmanager": "^2.6.3 || ^3.0.1", "zendframework/zend-filter": "^2.7.1", "zendframework/zend-http": "^2.5.4", - "zendframework/zend-hydrator": "^1.1 || ^2.2.1", + "zendframework/zend-hydrator": "^1.1 || ^2.2.1 || ^3.0", "zendframework/zend-mvc": "^2.7.15 || ^3.0.2", "zendframework/zend-paginator": "^2.7", "zendframework/zend-uri": "^2.5.2", @@ -47,6 +47,9 @@ "zendframework/zend-coding-standard": "~1.0.0" }, "autoload": { + "files": [ + "src/_autoload.php" + ], "psr-4": { "ZF\\Hal\\": "src/" } diff --git a/composer.lock b/composer.lock index 7c41595..04811e7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4347c4e5265477a824aed4fb79ba55ec", + "content-hash": "cc3fb02778e5217b3c85f26b303f8820", "packages": [ { "name": "container-interop/container-interop", @@ -359,16 +359,16 @@ }, { "name": "zendframework/zend-http", - "version": "2.8.0", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/zendframework/zend-http.git", - "reference": "f48b276ffa11b48dd1ae3c6bc306d6ed7958ef51" + "reference": "2c8aed3d25522618573194e7cc51351f8cd4a45b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-http/zipball/f48b276ffa11b48dd1ae3c6bc306d6ed7958ef51", - "reference": "f48b276ffa11b48dd1ae3c6bc306d6ed7958ef51", + "url": "https://api.github.com/repos/zendframework/zend-http/zipball/2c8aed3d25522618573194e7cc51351f8cd4a45b", + "reference": "2c8aed3d25522618573194e7cc51351f8cd4a45b", "shasum": "" }, "require": { @@ -410,48 +410,47 @@ "zend", "zf" ], - "time": "2018-04-26T21:04:50+00:00" + "time": "2018-08-13T18:47:03+00:00" }, { "name": "zendframework/zend-hydrator", - "version": "2.4.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-hydrator.git", - "reference": "bd48bc3bc046df007a94125f868dd1aa1b73a813" + "reference": "baa10aaafe92559d2579d3dc8417b7b690f260bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-hydrator/zipball/bd48bc3bc046df007a94125f868dd1aa1b73a813", - "reference": "bd48bc3bc046df007a94125f868dd1aa1b73a813", + "url": "https://api.github.com/repos/zendframework/zend-hydrator/zipball/baa10aaafe92559d2579d3dc8417b7b690f260bc", + "reference": "baa10aaafe92559d2579d3dc8417b7b690f260bc", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0", - "zendframework/zend-stdlib": "^3.0" + "php": "^7.2", + "zendframework/zend-stdlib": "^3.2.1" }, "require-dev": { - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", + "phpspec/prophecy": "^1.7.5", + "phpstan/phpstan": "^0.10.5", + "phpunit/phpunit": "^7.5", "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", - "zendframework/zend-filter": "^2.6", - "zendframework/zend-inputfilter": "^2.6", - "zendframework/zend-serializer": "^2.6.1", - "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" + "zendframework/zend-eventmanager": "^3.2.1", + "zendframework/zend-modulemanager": "^2.8", + "zendframework/zend-serializer": "^2.9", + "zendframework/zend-servicemanager": "^3.3.2" }, "suggest": { - "zendframework/zend-eventmanager": "^2.6.2 || ^3.0, to support aggregate hydrator usage", - "zendframework/zend-filter": "^2.6, to support naming strategy hydrator usage", - "zendframework/zend-serializer": "^2.6.1, to use the SerializableStrategy", - "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3, to support hydrator plugin manager usage" + "zendframework/zend-eventmanager": "^3.2, to support aggregate hydrator usage", + "zendframework/zend-serializer": "^2.9, to use the SerializableStrategy", + "zendframework/zend-servicemanager": "^3.3, to support hydrator plugin manager usage" }, "type": "library", "extra": { "branch-alias": { - "dev-release-1.0": "1.0.x-dev", - "dev-release-1.1": "1.1.x-dev", - "dev-master": "2.4.x-dev", - "dev-develop": "2.5.x-dev" + "dev-release-2.4": "2.4.x-dev", + "dev-master": "3.0.x-dev", + "dev-develop": "3.1.x-dev" }, "zf": { "component": "Zend\\Hydrator", @@ -473,7 +472,7 @@ "hydrator", "zf" ], - "time": "2018-04-30T21:22:14+00:00" + "time": "2018-12-10T17:48:39+00:00" }, { "name": "zendframework/zend-json", @@ -769,42 +768,41 @@ }, { "name": "zendframework/zend-router", - "version": "3.0.2", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-router.git", - "reference": "03763610632a9022aff22a0e8f340852e68392a1" + "reference": "a80a7427afb8f736b9aeeb341a78dae855849291" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-router/zipball/03763610632a9022aff22a0e8f340852e68392a1", - "reference": "03763610632a9022aff22a0e8f340852e68392a1", + "url": "https://api.github.com/repos/zendframework/zend-router/zipball/a80a7427afb8f736b9aeeb341a78dae855849291", + "reference": "a80a7427afb8f736b9aeeb341a78dae855849291", "shasum": "" }, "require": { - "container-interop/container-interop": "^1.1", - "php": "^5.5 || ^7.0", - "zendframework/zend-http": "^2.5", - "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", - "zendframework/zend-stdlib": "^2.7.5 || ^3.0" + "container-interop/container-interop": "^1.2", + "php": "^5.6 || ^7.0", + "zendframework/zend-http": "^2.8.1", + "zendframework/zend-servicemanager": "^2.7.8 || ^3.3", + "zendframework/zend-stdlib": "^2.7.7 || ^3.1" }, "conflict": { "zendframework/zend-mvc": "<3.0.0" }, "require-dev": { - "phpunit/phpunit": "^4.5", - "sebastian/version": "^1.0.4", - "squizlabs/php_codesniffer": "^2.3", - "zendframework/zend-i18n": "^2.6" + "phpunit/phpunit": "^5.7.22 || ^6.4.1", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-i18n": "^2.7.4" }, "suggest": { - "zendframework/zend-i18n": "^2.6, if defining translatable HTTP path segments" + "zendframework/zend-i18n": "^2.7.4, if defining translatable HTTP path segments" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev", - "dev-develop": "3.1-dev" + "dev-master": "3.2.x-dev", + "dev-develop": "3.3.x-dev" }, "zf": { "component": "Zend\\Router", @@ -820,13 +818,15 @@ "license": [ "BSD-3-Clause" ], - "homepage": "https://github.com/zendframework/zend-router", + "description": "Flexible routing system for HTTP and console applications", "keywords": [ + "ZendFramework", "mvc", "routing", - "zf2" + "zend", + "zf" ], - "time": "2016-05-31T20:47:48+00:00" + "time": "2018-08-01T22:24:35+00:00" }, { "name": "zendframework/zend-servicemanager", @@ -898,16 +898,16 @@ }, { "name": "zendframework/zend-stdlib", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-stdlib.git", - "reference": "cd164b4a18b5d1aeb69be2c26db035b5ed6925ae" + "reference": "66536006722aff9e62d1b331025089b7ec71c065" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/cd164b4a18b5d1aeb69be2c26db035b5ed6925ae", - "reference": "cd164b4a18b5d1aeb69be2c26db035b5ed6925ae", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/66536006722aff9e62d1b331025089b7ec71c065", + "reference": "66536006722aff9e62d1b331025089b7ec71c065", "shasum": "" }, "require": { @@ -940,7 +940,7 @@ "stdlib", "zf" ], - "time": "2018-04-30T13:50:40+00:00" + "time": "2018-08-28T21:34:05+00:00" }, { "name": "zendframework/zend-uri", @@ -1062,21 +1062,22 @@ }, { "name": "zendframework/zend-view", - "version": "2.10.0", + "version": "2.11.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-view.git", - "reference": "4478cc5dd960e2339d88b363ef99fa278700e80e" + "reference": "0428d6b2a67c7058451394921c90c5576ac5b373" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-view/zipball/4478cc5dd960e2339d88b363ef99fa278700e80e", - "reference": "4478cc5dd960e2339d88b363ef99fa278700e80e", + "url": "https://api.github.com/repos/zendframework/zend-view/zipball/0428d6b2a67c7058451394921c90c5576ac5b373", + "reference": "0428d6b2a67c7058451394921c90c5576ac5b373", "shasum": "" }, "require": { "php": "^5.6 || ^7.0", "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", + "zendframework/zend-json": "^2.6.1 || ^3.0", "zendframework/zend-loader": "^2.5", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, @@ -1092,10 +1093,9 @@ "zendframework/zend-filter": "^2.6.1", "zendframework/zend-http": "^2.5.4", "zendframework/zend-i18n": "^2.6", - "zendframework/zend-json": "^2.6.1", "zendframework/zend-log": "^2.7", "zendframework/zend-modulemanager": "^2.7.1", - "zendframework/zend-mvc": "^2.7 || ^3.0", + "zendframework/zend-mvc": "^2.7.14 || ^3.0", "zendframework/zend-navigation": "^2.5", "zendframework/zend-paginator": "^2.5", "zendframework/zend-permissions-acl": "^2.6", @@ -1112,8 +1112,8 @@ "zendframework/zend-filter": "Zend\\Filter component", "zendframework/zend-http": "Zend\\Http component", "zendframework/zend-i18n": "Zend\\I18n component", - "zendframework/zend-json": "Zend\\Json component", "zendframework/zend-mvc": "Zend\\Mvc component", + "zendframework/zend-mvc-plugin-flashmessenger": "zend-mvc-plugin-flashmessenger component, if you want to use the FlashMessenger view helper with zend-mvc versions 3 and up", "zendframework/zend-navigation": "Zend\\Navigation component", "zendframework/zend-paginator": "Zend\\Paginator component", "zendframework/zend-permissions-acl": "Zend\\Permissions\\Acl component", @@ -1126,8 +1126,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.10.x-dev", - "dev-develop": "2.11.x-dev" + "dev-master": "2.11.x-dev", + "dev-develop": "2.12.x-dev" } }, "autoload": { @@ -1145,20 +1145,20 @@ "view", "zf2" ], - "time": "2018-01-17T22:21:50+00:00" + "time": "2018-12-10T16:37:55+00:00" }, { "name": "zfcampus/zf-api-problem", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/zfcampus/zf-api-problem.git", - "reference": "8227f2116835db3835b9f362806a2a7336f72559" + "reference": "4f8ce00a3971cdfbea65e83b64f0774424b54ffb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zfcampus/zf-api-problem/zipball/8227f2116835db3835b9f362806a2a7336f72559", - "reference": "8227f2116835db3835b9f362806a2a7336f72559", + "url": "https://api.github.com/repos/zfcampus/zf-api-problem/zipball/4f8ce00a3971cdfbea65e83b64f0774424b54ffb", + "reference": "4f8ce00a3971cdfbea65e83b64f0774424b54ffb", "shasum": "" }, "require": { @@ -1167,18 +1167,18 @@ "zendframework/zend-eventmanager": "^2.6.3 || ^3.0.1", "zendframework/zend-http": "^2.5.4", "zendframework/zend-json": "^2.6.1 || ^3.0", - "zendframework/zend-mvc": "^2.7.9 || ^3.0.2", + "zendframework/zend-mvc": "^2.7.15 || ^3.0.4", "zendframework/zend-view": "^2.8.1" }, "require-dev": { - "phpunit/phpunit": "^4.8", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.5", "zendframework/zend-coding-standard": "~1.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev", - "dev-develop": "1.3-dev" + "dev-master": "1.3.x-dev", + "dev-develop": "1.4.x-dev" }, "zf": { "module": "ZF\\ApiProblem" @@ -1194,15 +1194,14 @@ "BSD-3-Clause" ], "description": "ZF2 Module providing API-Problem assets and rendering", - "homepage": "http://apigility.org/", "keywords": [ + "ZendFramework", "api-problem", "module", "rest", - "zend", - "zf2" + "zf" ], - "time": "2017-07-24T13:48:49+00:00" + "time": "2018-05-08T13:57:58+00:00" } ], "packages-dev": [ @@ -1262,25 +1261,28 @@ }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -1303,7 +1305,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2018-06-11T23:09:50+00:00" }, { "name": "phar-io/manifest", @@ -1561,16 +1563,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.6", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "shasum": "" }, "require": { @@ -1582,12 +1584,12 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { @@ -1620,7 +1622,7 @@ "spy", "stub" ], - "time": "2018-04-18T13:57:24+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1873,16 +1875,16 @@ }, { "name": "phpunit/phpunit", - "version": "6.5.8", + "version": "6.5.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b" + "reference": "0973426fb012359b2f18d3bd1e90ef1172839693" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0973426fb012359b2f18d3bd1e90ef1172839693", + "reference": "0973426fb012359b2f18d3bd1e90ef1172839693", "shasum": "" }, "require": { @@ -1900,7 +1902,7 @@ "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.5", + "phpunit/phpunit-mock-objects": "^5.0.9", "sebastian/comparator": "^2.1", "sebastian/diff": "^2.0", "sebastian/environment": "^3.1", @@ -1953,20 +1955,20 @@ "testing", "xunit" ], - "time": "2018-04-10T11:38:34+00:00" + "time": "2018-09-08T15:10:43+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.6", + "version": "5.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf" + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", "shasum": "" }, "require": { @@ -1979,7 +1981,7 @@ "phpunit/phpunit": "<6.0" }, "require-dev": { - "phpunit/phpunit": "^6.5" + "phpunit/phpunit": "^6.5.11" }, "suggest": { "ext-soap": "*" @@ -2012,7 +2014,7 @@ "mock", "xunit" ], - "time": "2018-01-06T05:45:45+00:00" + "time": "2018-08-09T05:50:03+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -2575,16 +2577,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "2.9.1", + "version": "2.9.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62" + "reference": "2acf168de78487db620ab4bc524135a13cfe6745" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62", - "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745", + "reference": "2acf168de78487db620ab4bc524135a13cfe6745", "shasum": "" }, "require": { @@ -2649,7 +2651,7 @@ "phpcs", "standards" ], - "time": "2017-05-22T02:43:20+00:00" + "time": "2018-11-07T22:31:41+00:00" }, { "name": "theseer/tokenizer", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 91bbff9..66128c6 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -8,6 +8,9 @@ src + + ./src/Extractor/EntityExtractorHydratorV3.php + diff --git a/src/EntityHydratorManager.php b/src/EntityHydratorManager.php index 20216c0..d707e06 100644 --- a/src/EntityHydratorManager.php +++ b/src/EntityHydratorManager.php @@ -8,12 +8,13 @@ use Zend\Hydrator\ExtractionInterface; use Zend\Hydrator\HydratorPluginManager; +use Zend\Hydrator\HydratorPluginManagerInterface; use ZF\Hal\Metadata\MetadataMap; class EntityHydratorManager { /** - * @var HydratorPluginManager + * @var HydratorPluginManager|HydratorPluginManagerInterface */ protected $hydrators; @@ -37,17 +38,31 @@ class EntityHydratorManager protected $defaultHydrator; /** - * @param HydratorPluginManager $hydrators + * @param HydratorPluginManager|HydratorPluginManagerInterface $hydrators * @param MetadataMap $map + * @throws Exception\InvalidArgumentException if $hydrators is of invalid type. */ - public function __construct(HydratorPluginManager $hydrators, MetadataMap $map) + public function __construct($hydrators, MetadataMap $map) { + if ($hydrators instanceof HydratorPluginManagerInterface) { + $this->hydrators = $hydrators; + } elseif ($hydrators instanceof HydratorPluginManager) { + $this->hydrators = $hydrators; + } else { + throw new Exception\InvalidArgumentException(sprintf( + '$hydrators argument to %s must be an instance of either %s or %s; received %s', + __CLASS__, + HydratorPluginManagerInterface::class, + HydratorPluginManager::class, + is_object($hydrators) ? get_class($hydrators) : gettype($hydrators) + )); + } $this->hydrators = $hydrators; $this->metadataMap = $map; } /** - * @return HydratorPluginManager + * @return HydratorPluginManager|HydratorPluginManagerInterface */ public function getHydratorManager() { diff --git a/src/Extractor/EntityExtractor.php b/src/Extractor/EntityExtractorHydratorV2.php similarity index 86% rename from src/Extractor/EntityExtractor.php rename to src/Extractor/EntityExtractorHydratorV2.php index 069ef77..8dfabd4 100644 --- a/src/Extractor/EntityExtractor.php +++ b/src/Extractor/EntityExtractorHydratorV2.php @@ -11,7 +11,13 @@ use Zend\Hydrator\ExtractionInterface; use ZF\Hal\EntityHydratorManager; -class EntityExtractor implements ExtractionInterface +/** + * Extract entities. + * + * This version targets zend-hydrator v1 and v2, and will be aliased to + * ZF\Hal\Extractor\EntityExtractor when one of those versions is in use. + */ +class EntityExtractorHydratorV2 implements ExtractionInterface { /** * @var EntityHydratorManager diff --git a/src/Extractor/EntityExtractorHydratorV3.php b/src/Extractor/EntityExtractorHydratorV3.php new file mode 100644 index 0000000..cd75f01 --- /dev/null +++ b/src/Extractor/EntityExtractorHydratorV3.php @@ -0,0 +1,71 @@ +entityHydratorManager = $entityHydratorManager; + $this->serializedEntities = new SplObjectStorage(); + } + + /** + * @inheritDoc + */ + public function extract(object $entity) : array + { + if (isset($this->serializedEntities[$entity])) { + return $this->serializedEntities[$entity]; + } + + $this->serializedEntities[$entity] = $this->extractEntity($entity); + + return $this->serializedEntities[$entity]; + } + + private function extractEntity(object $entity) : array + { + $hydrator = $this->entityHydratorManager->getHydratorForEntity($entity); + + if ($hydrator) { + return $hydrator->extract($entity); + } + + if ($entity instanceof JsonSerializable) { + return $entity->jsonSerialize(); + } + + return get_object_vars($entity); + } +} diff --git a/src/Metadata/Metadata.php b/src/Metadata/Metadata.php index 141712e..edc87d8 100644 --- a/src/Metadata/Metadata.php +++ b/src/Metadata/Metadata.php @@ -9,6 +9,7 @@ use Zend\Filter\FilterChain; use Zend\Hydrator\ExtractionInterface; use Zend\Hydrator\HydratorPluginManager; +use Zend\Hydrator\HydratorPluginManagerInterface; use ZF\Hal\Exception; class Metadata @@ -35,7 +36,7 @@ class Metadata protected $hydrator; /** - * @var HydratorPluginManager + * @var HydratorPluginManager|HydratorPluginManagerInterface */ protected $hydrators; @@ -128,10 +129,10 @@ class Metadata * * @param string $class * @param array $options - * @param HydratorPluginManager $hydrators + * @param null|HydratorPluginManager|HydratorPluginManagerInterface $hydrators * @throws Exception\InvalidArgumentException */ - public function __construct($class, array $options = [], HydratorPluginManager $hydrators = null) + public function __construct($class, array $options = [], $hydrators = null) { $filter = new FilterChain(); $filter->attachByName('WordUnderscoreToCamelCase') @@ -147,7 +148,7 @@ public function __construct($class, array $options = [], HydratorPluginManager $ $this->class = $class; if (null !== $hydrators) { - $this->hydrators = $hydrators; + $this->setHydrators($hydrators); } $legacyIdentifierName = false; @@ -602,4 +603,25 @@ public function setForceSelfLink($forceSelfLink) $this->forceSelfLink = $forceSelfLink; return $this; } + + /** + * @param HydratorPluginManager|HydratorPluginManagerInterface $hydrators + * @throws Exception\InvalidArgumentException if $hydrators is an invaild type. + */ + private function setHydrators($hydrators) + { + if ($hydrators instanceof HydratorPluginManagerInterface) { + $this->hydrators = $hydrators; + } elseif ($hydrators instanceof HydratorPluginManager) { + $this->hydrators = $hydrators; + } else { + throw new Exception\InvalidArgumentException(sprintf( + '$hydrators argument to %s must be an instance of either %s or %s; received %s', + __CLASS__, + HydratorPluginManagerInterface::class, + HydratorPluginManager::class, + is_object($hydrators) ? get_class($hydrators) : gettype($hydrators) + )); + } + } } diff --git a/src/Metadata/MetadataMap.php b/src/Metadata/MetadataMap.php index fd8bf59..01d65bf 100644 --- a/src/Metadata/MetadataMap.php +++ b/src/Metadata/MetadataMap.php @@ -7,13 +7,14 @@ namespace ZF\Hal\Metadata; use Zend\Hydrator\HydratorPluginManager; +use Zend\Hydrator\HydratorPluginManagerInterface; use Zend\ServiceManager\ServiceManager; use ZF\Hal\Exception; class MetadataMap { /** - * @var HydratorPluginManager + * @var HydratorPluginManager|HydratorPluginManagerInterface */ protected $hydrators; @@ -29,9 +30,9 @@ class MetadataMap * If provided, will pass $hydrators to setHydratorManager(). * * @param null|array $map - * @param null|HydratorPluginManager $hydrators + * @param null|HydratorPluginManager|HydratorPluginManagerInterface $hydrators */ - public function __construct(array $map = null, HydratorPluginManager $hydrators = null) + public function __construct(array $map = null, $hydrators = null) { if (null !== $hydrators) { $this->setHydratorManager($hydrators); @@ -43,17 +44,30 @@ public function __construct(array $map = null, HydratorPluginManager $hydrators } /** - * @param HydratorPluginManager $hydrators + * @param HydratorPluginManager|HydratorPluginManagerInterface $hydrators * @return self */ - public function setHydratorManager(HydratorPluginManager $hydrators) + public function setHydratorManager($hydrators) { - $this->hydrators = $hydrators; + if ($hydrators instanceof HydratorPluginManagerInterface) { + $this->hydrators = $hydrators; + } elseif ($hydrators instanceof HydratorPluginManager) { + $this->hydrators = $hydrators; + } else { + throw new Exception\InvalidArgumentException(sprintf( + '$hydrators argument to %s must be an instance of either %s or %s; received %s', + __CLASS__, + HydratorPluginManagerInterface::class, + HydratorPluginManager::class, + is_object($hydrators) ? get_class($hydrators) : gettype($hydrators) + )); + } + return $this; } /** - * @return HydratorPluginManager + * @return HydratorPluginManager|HydratorPluginManagerInterface */ public function getHydratorManager() { diff --git a/src/Plugin/Hal.php b/src/Plugin/Hal.php index e110f15..dd059a3 100644 --- a/src/Plugin/Hal.php +++ b/src/Plugin/Hal.php @@ -16,6 +16,7 @@ use Zend\EventManager\EventManagerInterface; use Zend\Hydrator\ExtractionInterface; use Zend\Hydrator\HydratorPluginManager; +use Zend\Hydrator\HydratorPluginManagerInterface; use Zend\Mvc\Controller\Plugin\PluginInterface as ControllerPluginInterface; use Zend\Paginator\Paginator; use Zend\ServiceManager\ServiceManager; @@ -122,14 +123,26 @@ class Hal extends AbstractHelper implements protected $entityHashStack = []; /** - * @param null|HydratorPluginManager $hydrators + * @param null|HydratorPluginManager|HydratorPluginManagerInterface $hydrators + * @throws Exception\InvalidArgumentException if $hydrators is of invalid type. */ - public function __construct(HydratorPluginManager $hydrators = null) + public function __construct($hydrators = null) { if (null === $hydrators) { - $hydrators = new HydratorPluginManager(new ServiceManager()); + $this->hydrators = new HydratorPluginManager(new ServiceManager()); + } elseif ($hydrators instanceof HydratorPluginManagerInterface) { + $this->hydrators = $hydrators; + } elseif ($hydrators instanceof HydratorPluginManager) { + $this->hydrators = $hydrators; + } else { + throw new Exception\InvalidArgumentException(sprintf( + '$hydrators argument to %s must be an instance of either %s or %s; received %s', + __CLASS__, + HydratorPluginManagerInterface::class, + HydratorPluginManager::class, + is_object($hydrators) ? get_class($hydrators) : gettype($hydrators) + )); } - $this->hydrators = $hydrators; } /** diff --git a/src/_autoload.php b/src/_autoload.php new file mode 100644 index 0000000..dc89c2d --- /dev/null +++ b/src/_autoload.php @@ -0,0 +1,21 @@ +hydratorClass = interface_exists(HydratorPluginManagerInterface::class) + ? TestAsset\DummyV3Hydrator::class + : TestAsset\DummyHydrator::class; + } + public function testAddHydratorGivenEntityClassAndHydratorInstanceShouldAssociateThem() { $entity = new TestAsset\Entity('foo', 'Foo Bar'); - $hydratorClass = TestAsset\DummyHydrator::class; + $hydratorClass = $this->hydratorClass; $hydrator = new $hydratorClass(); $metadataMap = new MetadataMap(); @@ -40,7 +52,7 @@ public function testAddHydratorGivenEntityClassAndHydratorInstanceShouldAssociat public function testAddHydratorGivenEntityAndHydratorClassesShouldAssociateThem() { $entity = new TestAsset\Entity('foo', 'Foo Bar'); - $hydratorClass = TestAsset\DummyHydrator::class; + $hydratorClass = $this->hydratorClass; $metadataMap = new MetadataMap(); $metadataMap->setHydratorManager(new HydratorPluginManager(new ServiceManager())); @@ -58,24 +70,24 @@ public function testAddHydratorGivenEntityAndHydratorClassesShouldAssociateThem( public function testAddHydratorDoesntFailWithAutoInvokables() { - $metadataMap = new MetadataMap(); + $metadataMap = new MetadataMap(); $metadataMap->setHydratorManager(new HydratorPluginManager(new ServiceManager())); $hydratorPluginManager = new HydratorPluginManager(new ServiceManager()); $entityHydratorManager = new EntityHydratorManager($hydratorPluginManager, $metadataMap); - $entityHydratorManager->addHydrator('stdClass', TestAsset\DummyHydrator::class); + $entityHydratorManager->addHydrator(stdClass::class, $this->hydratorClass); $this->assertInstanceOf( - TestAsset\DummyHydrator::class, - $entityHydratorManager->getHydratorForEntity(new \stdClass) + $this->hydratorClass, + $entityHydratorManager->getHydratorForEntity(new stdClass()) ); } public function testGetHydratorForEntityGivenEntityDefinedInMetadataMapShouldReturnDefaultHydrator() { $entity = new TestAsset\Entity('foo', 'Foo Bar'); - $hydratorClass = TestAsset\DummyHydrator::class; + $hydratorClass = $this->hydratorClass; $metadataMap = new MetadataMap([ TestAsset\Entity::class => [ @@ -96,10 +108,11 @@ public function testGetHydratorForEntityGivenEntityDefinedInMetadataMapShouldRet public function testGetHydratorForEntityGivenUnkownEntityShouldReturnDefaultHydrator() { - $entity = new TestAsset\Entity('foo', 'Foo Bar'); - $defaultHydrator = new TestAsset\DummyHydrator(); + $entity = new TestAsset\Entity('foo', 'Foo Bar'); + $hydratorClass = $this->hydratorClass; + $defaultHydrator = new $hydratorClass(); - $metadataMap = new MetadataMap(); + $metadataMap = new MetadataMap(); $metadataMap->setHydratorManager(new HydratorPluginManager(new ServiceManager())); $hydratorPluginManager = new HydratorPluginManager(new ServiceManager()); diff --git a/test/Extractor/EntityExtractorTest.php b/test/Extractor/EntityExtractorTest.php index 10e5cb7..ae3224c 100644 --- a/test/Extractor/EntityExtractorTest.php +++ b/test/Extractor/EntityExtractorTest.php @@ -8,6 +8,7 @@ use PHPUnit\Framework\TestCase; use Zend\Hydrator\ObjectProperty; +use Zend\Hydrator\ObjectPropertyHydrator; use ZF\Hal\EntityHydratorManager; use ZF\Hal\Extractor\EntityExtractor; use ZFTest\Hal\Plugin\TestAsset; @@ -17,9 +18,19 @@ */ class EntityExtractorTest extends TestCase { + /** @var string */ + private $hydratorClass; + + public function setUp() + { + $this->hydratorClass = class_exists(ObjectPropertyHydrator::class) + ? ObjectPropertyHydrator::class + : ObjectProperty::class; + } + public function testExtractGivenEntityWithAssociateHydratorShouldExtractData() { - $hydrator = new ObjectProperty(); + $hydrator = new $this->hydratorClass(); $entity = new TestAsset\Entity('foo', 'Foo Bar'); $entityHydratorManager = $this->prophesize(EntityHydratorManager::class); diff --git a/test/Plugin/HalTest.php b/test/Plugin/HalTest.php index 3fa3938..c7fc30d 100644 --- a/test/Plugin/HalTest.php +++ b/test/Plugin/HalTest.php @@ -10,7 +10,6 @@ use PHPUnit\Framework\TestCase; use ReflectionObject; use Zend\Hydrator; -use Zend\Hydrator\ObjectProperty; use Zend\Mvc\Controller\AbstractRestfulController; use Zend\Mvc\MvcEvent; use Zend\Mvc\Router\Exception as V2RouterException; @@ -44,6 +43,11 @@ */ class HalTest extends TestCase { + /** + * @var MvcEvent + */ + protected $event; + /** * @var HalHelper */ @@ -54,11 +58,6 @@ class HalTest extends TestCase */ protected $router; - /** - * @var MvcEvent - */ - protected $event; - /** * @var ServerUrlHelper */ @@ -152,6 +151,26 @@ public function setUp() $plugin->setLinkCollectionExtractor($linkCollectionExtractor); } + /** + * @return string + */ + public function getArraySerializableHydratorClass() + { + return class_exists(Hydrator\ArraySerializableHydrator::class) + ? Hydrator\ArraySerializableHydrator::class + : Hydrator\ArraySerializable::class; + } + + /** + * @return string + */ + public function getObjectPropertyHydratorClass() + { + return class_exists(Hydrator\ObjectPropertyHydrator::class) + ? Hydrator\ObjectPropertyHydrator::class + : Hydrator\ObjectProperty::class; + } + public function assertRelationalLinkContains($match, $relation, $entity) { $this->assertInternalType('array', $entity); @@ -258,19 +277,19 @@ public function testRendersEmbeddedEntitiesInsideEntitiesBasedOnMetadataMap() $metadata = new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', ], TestAsset\EmbeddedEntity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', ], TestAsset\EmbeddedEntityWithCustomIdentifier::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded_custom', 'route_identifier_name' => 'custom_id', 'entity_identifier_name' => 'custom_id', @@ -311,19 +330,19 @@ public function testMetadataMapLooksForParentClasses() $metadata = new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', ], TestAsset\EmbeddedEntity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', ], TestAsset\EmbeddedEntityWithCustomIdentifier::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded_custom', 'route_identifier_name' => 'custom_id', 'entity_identifier_name' => 'custom_id', @@ -434,7 +453,7 @@ public function testRendersEmbeddedCollectionsInsideCollectionsBasedOnMetadataMa 'entity_identifier_name' => 'id', ], TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', @@ -485,11 +504,11 @@ public function testDoesNotRenderEmbeddedEntitiesInsideCollectionsBasedOnMetadat $metadata = new MetadataMap([ TestAsset\EmbeddedEntity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded', ], TestAsset\EmbeddedEntityWithCustomIdentifier::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded_custom', 'route_identifier_name' => 'custom_id', 'entity_identifier_name' => 'custom_id', @@ -500,7 +519,7 @@ public function testDoesNotRenderEmbeddedEntitiesInsideCollectionsBasedOnMetadat 'entity_route' => 'hostname/embedded', ], TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', ], ]); @@ -751,7 +770,7 @@ public function testRetainsLinksInjectedViaMetadataDuringCreateEntity() $metadata = new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'links' => [ [ @@ -948,7 +967,7 @@ public function testRenderingCollectionUsesCollectionNameFromMetadataMap() $metadata = new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', @@ -1062,7 +1081,7 @@ public function testCreateEntityShouldNotSerializeEntity() { $metadata = new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', @@ -1238,14 +1257,14 @@ protected function createNestedMetadataMap($maxDepth = null) { return new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', 'max_depth' => $maxDepth, ], TestAsset\EmbeddedEntityWithBackReference::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', @@ -1504,13 +1523,13 @@ protected function createNestedCollectionMetadataMap($maxDepth = null) 'max_depth' => $maxDepth, ], TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', ], TestAsset\EmbeddedEntityWithBackReference::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', @@ -1569,7 +1588,7 @@ public function testCreateEntityFromMetadataWithoutForcedSelfLinks() $object = new TestAsset\Entity('foo', 'Foo'); $metadata = new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'links' => [], 'force_self_link' => false, @@ -1592,7 +1611,7 @@ public function testCreateEntityWithoutForcedSelfLinks() $metadata = new MetadataMap([ TestAsset\Entity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route_name' => 'hostname/resource', 'links' => [], 'force_self_link' => false, @@ -1749,9 +1768,10 @@ public function testCanRenderStdclassEntity() public function testCanSerializeHydratableEntity() { + $hydratorClass = $this->getArraySerializableHydratorClass(); $this->plugin->addHydrator( HalTestAsset\ArraySerializable::class, - new Hydrator\ArraySerializable() + new $hydratorClass() ); $item = new Entity(new HalTestAsset\ArraySerializable(), 'identifier'); @@ -1769,8 +1789,9 @@ public function testCanSerializeHydratableEntity() public function testUsesDefaultHydratorIfAvailable() { + $hydratorClass = $this->getArraySerializableHydratorClass(); $this->plugin->setDefaultHydrator( - new Hydrator\ArraySerializable() + new $hydratorClass() ); $item = new Entity(new HalTestAsset\ArraySerializable(), 'identifier'); @@ -2233,7 +2254,7 @@ public function testNotExistingRouteInMetadataLinks() $metadata = new MetadataMap([ TestAsset\EmbeddedEntity::class => [ - 'hydrator' => ObjectProperty::class, + 'hydrator' => $this->getObjectPropertyHydratorClass(), 'route' => 'hostname/embedded', 'route_identifier_name' => 'id', 'entity_identifier_name' => 'id', diff --git a/test/Plugin/TestAsset/DummyV3Hydrator.php b/test/Plugin/TestAsset/DummyV3Hydrator.php new file mode 100644 index 0000000..6c44cab --- /dev/null +++ b/test/Plugin/TestAsset/DummyV3Hydrator.php @@ -0,0 +1,14 @@ +