diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..876e230 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin +.idea +vendor diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cb98a2b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: php +php: + - "5.5" + - "5.6" + - "7.0" + - "hhvm" + +before_script: + - composer install --dev + +script: ./bin/phpunit --coverage-text + +matrix: + allow_failures: + - php: "hhvm" diff --git a/README.md b/README.md new file mode 100644 index 0000000..33d5f1a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Serializer for PHP diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..1af8db4 --- /dev/null +++ b/composer.json @@ -0,0 +1,48 @@ +{ + "name": "nilportugues/serializer", + "type": "library", + "description": "Serialize PHP variables, including objects, in any format. Support to unserialize it too.", + "keywords": ["json", "serialize", "serializer"], + "homepage": "http://nilportugues.com", + "license": "MIT", + "authors": [ + + { + "name": "Nil Portugués Calderó", + "email": "contact@nilportugues.com", + "role": "Project Lead Developer" + + }, + { + "name": "Zumba Fitness, LLC", + "email": "engineering@zumba.com", + "role": "Author of the original repository: https://github.com/zumba/json-serializer" + }, + { + "name": "Juan Basso", + "email": "juan.basso@zumba.com", + "role": "Author of the original repository: https://github.com/zumba/json-serializer" + } + ], + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "4.4.*", + "fabpot/php-cs-fixer": "^1.9", + "mmoreram/php-formatter": "dev-master" + }, + "autoload": { + "psr-4": { + "NilPortugues\\Serializer\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "NilPortugues\\Test\\Serializer\\": "tests/" + } + }, + "config": { + "bin-dir": "bin/" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..32f5c97 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1345 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "0f71b7378b6b82aed2ca7f9e2b2d7441", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "fabpot/php-cs-fixer", + "version": "v1.9", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "ef528b9d3f1dd66197baabf8f77c8402c62bb9fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/ef528b9d3f1dd66197baabf8f77c8402c62bb9fc", + "reference": "ef528b9d3f1dd66197baabf8f77c8402c62bb9fc", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.6", + "sebastian/diff": "~1.1", + "symfony/console": "~2.3", + "symfony/event-dispatcher": "~2.1", + "symfony/filesystem": "~2.1", + "symfony/finder": "~2.1", + "symfony/process": "~2.3", + "symfony/stopwatch": "~2.5" + }, + "require-dev": { + "satooshi/php-coveralls": "0.7.*@dev" + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "Symfony\\CS\\": "Symfony/CS/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "time": "2015-06-13 09:30:19" + }, + { + "name": "mmoreram/php-formatter", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/mmoreram/php-formatter.git", + "reference": "8513e35b4fc9170cd4468e95a4eaacd0296e88cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mmoreram/php-formatter/zipball/8513e35b4fc9170cd4468e95a4eaacd0296e88cf", + "reference": "8513e35b4fc9170cd4468e95a4eaacd0296e88cf", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "symfony/console": "~2.2", + "symfony/event-dispatcher": "~2.2", + "symfony/filesystem": "~2.2", + "symfony/finder": "~2.2", + "symfony/process": "~2.2", + "symfony/property-access": "~2.2", + "symfony/yaml": "~2.2" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.4.2", + "phpunit/phpunit": "4.5.0" + }, + "bin": [ + "bin/php-formatter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Mmoreram\\PHPFormatter\\": "src/PHPFormatter" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marc Morera", + "email": "yuhu@mmoreram.com" + } + ], + "description": "PHP custom formatter", + "keywords": [ + "formatter", + "php" + ], + "time": "2015-05-03 15:53:11" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.1.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "07e27765596d72c378a6103e80da5d84e802f1e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/07e27765596d72c378a6103e80da5d84e802f1e4", + "reference": "07e27765596d72c378a6103e80da5d84e802f1e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "~1.0", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-06-30 06:52:35" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/83fe1bdc5d47658b727595c14da140da92b3d66d", + "reference": "83fe1bdc5d47658b727595c14da140da92b3d66d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2015-06-13 07:35:30" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "7a9b0969488c3c54fd62b4d504b3ec758fd005d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/7a9b0969488c3c54fd62b4d504b3ec758fd005d9", + "reference": "7a9b0969488c3c54fd62b4d504b3ec758fd005d9", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-06-19 03:43:16" + }, + { + "name": "phpunit/phpunit", + "version": "4.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "2e8580deebb7d1ac92ac878595e6bffe01069c2a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2e8580deebb7d1ac92ac878595e6bffe01069c2a", + "reference": "2e8580deebb7d1ac92ac878595e6bffe01069c2a", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": "~2.0", + "phpunit/php-file-iterator": "~1.3.2", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.0", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.1", + "sebastian/exporter": "~1.1", + "sebastian/global-state": "~1.0", + "sebastian/recursion-context": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-01-27 16:06:15" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "92408bb1968a81b3217a6fdf6c1a198da83caa35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/92408bb1968a81b3217a6fdf6c1a198da83caa35", + "reference": "92408bb1968a81b3217a6fdf6c1a198da83caa35", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-06-11 15:55:48" + }, + { + "name": "sebastian/comparator", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-01-29 16:28:08" + }, + { + "name": "sebastian/diff", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-02-22 15:13:53" + }, + { + "name": "sebastian/environment", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2015-01-01 10:01:08" + }, + { + "name": "sebastian/exporter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "84839970d05254c73cde183a721c7af13aede943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-01-27 07:23:06" + }, + { + "name": "sebastian/global-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2014-10-06 09:23:50" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-01-24 09:48:32" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21 13:59:46" + }, + { + "name": "symfony/console", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console.git", + "reference": "564398bc1f33faf92fc2ec86859983d30eb81806" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/564398bc1f33faf92fc2ec86859983d30eb81806", + "reference": "564398bc1f33faf92fc2ec86859983d30eb81806", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/phpunit-bridge": "~2.7", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2015-06-10 15:30:22" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "be3c5ff8d503c46768aeb78ce6333051aa6f26d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/be3c5ff8d503c46768aeb78ce6333051aa6f26d9", + "reference": "be3c5ff8d503c46768aeb78ce6333051aa6f26d9", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/phpunit-bridge": "~2.7", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2015-06-08 09:37:21" + }, + { + "name": "symfony/filesystem", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "a0d43eb3e17d4f4c6990289805a488a0482a07f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/a0d43eb3e17d4f4c6990289805a488a0482a07f3", + "reference": "a0d43eb3e17d4f4c6990289805a488a0482a07f3", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2015-06-08 09:37:21" + }, + { + "name": "symfony/finder", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder.git", + "reference": "c13a40d638aeede1e8400f8c956c7f9246c05f75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Finder/zipball/c13a40d638aeede1e8400f8c956c7f9246c05f75", + "reference": "c13a40d638aeede1e8400f8c956c7f9246c05f75", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2015-06-04 20:11:48" + }, + { + "name": "symfony/process", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process.git", + "reference": "552d8efdc80980cbcca50b28d626ac8e36e3cdd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Process/zipball/552d8efdc80980cbcca50b28d626ac8e36e3cdd1", + "reference": "552d8efdc80980cbcca50b28d626ac8e36e3cdd1", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2015-06-08 09:37:21" + }, + { + "name": "symfony/property-access", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/PropertyAccess.git", + "reference": "c30871f355c311b33bd0b9be7d07514f920f2f8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/c30871f355c311b33bd0b9be7d07514f920f2f8d", + "reference": "c30871f355c311b33bd0b9be7d07514f920f2f8d", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony PropertyAccess Component", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property path", + "reflection" + ], + "time": "2015-06-08 09:37:21" + }, + { + "name": "symfony/stopwatch", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Stopwatch.git", + "reference": "c653f1985f6c2b7dbffd04d48b9c0a96aaef814b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/c653f1985f6c2b7dbffd04d48b9c0a96aaef814b", + "reference": "c653f1985f6c2b7dbffd04d48b9c0a96aaef814b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "time": "2015-06-04 20:11:48" + }, + { + "name": "symfony/yaml", + "version": "v2.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "9808e75c609a14f6db02f70fccf4ca4aab53c160" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/9808e75c609a14f6db02f70fccf4ca4aab53c160", + "reference": "9808e75c609a14f6db02f70fccf4ca4aab53c160", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2015-06-10 15:30:22" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "mmoreram/php-formatter": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.5.0" + }, + "platform-dev": [] +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..b4bb637 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,22 @@ + + + + + ./tests/ + + + + + ./src/ + + + \ No newline at end of file diff --git a/src/Serializer.php b/src/Serializer.php new file mode 100644 index 0000000..8a32d0a --- /dev/null +++ b/src/Serializer.php @@ -0,0 +1,477 @@ + 'serializeObject', + 'array' => 'serializeArray', + 'integer' => 'serializeScalar', + 'double' => 'serializeScalar', + 'boolean' => 'serializeScalar', + 'string' => 'serializeScalar', + 'Traversable' => 'serializeArrayLikeObject', + //Hack specific serialization classes + 'DateInterval' => '\NilPortugues\Serializer\Serializer\InternalClasses\DateIntervalSerializer::serialize', + 'DateTimeZone' => '\NilPortugues\Serializer\Serializer\InternalClasses\DateTimeZoneSerializer::serialize', + 'DateTimeImmutable' => '\NilPortugues\Serializer\Serializer\HHVM\DateTimeImmutableSerializer::serialize', + ); + + /** + * @var bool + */ + private $isHHVM; + + /** + * Hack specific serialization classes. + * + * @var array + */ + private $unserializationMapHHVM = [ + 'DateInterval' => '\NilPortugues\Serializer\Serializer\InternalClasses\DateIntervalSerializer::unserialize', + 'DateTimeZone' => '\NilPortugues\Serializer\Serializer\InternalClasses\DateTimeZoneSerializer::unserialize', + 'DateTimeImmutable' => '\NilPortugues\Serializer\Serializer\HHVM\DateTimeImmutableSerializer::unserialize', + 'DateTime' => '\NilPortugues\Serializer\Serializer\HHVM\DateTimeSerializer::unserialize', + ]; + + /** + * Constructor. + */ + public function __construct() + { + $this->isHHVM = defined('HHVM_VERSION'); + $this->serializationStrategy = new JsonStrategy(); + } + + /** + * Serialize the value in JSON. + * + * @param mixed $value + * + * @return string JSON encoded + * + * @throws SerializerException + */ + public function serialize($value) + { + $this->reset(); + + return $this->serializationStrategy->serialize($this->serializeData($value)); + } + + /** + * Reset variables. + */ + protected function reset() + { + $this->objectStorage = new SplObjectStorage(); + $this->objectMapping = array(); + $this->objectMappingIndex = 0; + } + + /** + * Parse the data to be json encoded. + * + * @param mixed $value + * + * @return mixed + * + * @throws SerializerException + */ + protected function serializeData($value) + { + $this->guardForUnsupportedValues($value); + + if ($this->isHHVM && ($value instanceof \DateTimeZone || $value instanceof \DateInterval)) { + return call_user_func_array($this->serializationMap[get_class($value)], [$this, $value]); + } + + $type = (gettype($value) && $value !== null) ? gettype($value) : 'string'; + $type = (class_implements('Traversable')) ? get_class($value) : $type; + + $func = $this->serializationMap[$type]; + + return $this->$func($value); + } + + /** + * @param mixed $value + * + * @throws SerializerException + */ + protected function guardForUnsupportedValues($value) + { + if ($value instanceof \Closure) { + throw new SerializerException('Closures are not supported in Serializer'); + } + + if ($value instanceof \DatePeriod) { + throw new SerializerException( + 'DatePeriod is not supported in Serializer. Loop through it and serialize the output.' + ); + } + + if (is_resource($value)) { + throw new SerializerException('Resource is not supported in Serializer'); + } + } + + /** + * Unserialize the value from string. + * + * @param mixed $value + * + * @return mixed + */ + public function unserialize($value) + { + if (is_array($value) && isset($value[self::SCALAR_TYPE])) { + return $this->unserializeData($value); + } + + $this->reset(); + + return $this->unserializeData($this->serializationStrategy->unserialize($value)); + } + + /** + * Parse the json decode to convert to objects again. + * + * @param mixed $value + * + * @return mixed + */ + protected function unserializeData($value) + { + if ($value === null || !is_array($value)) { + return $value; + } + + if (isset($value[self::SCALAR_TYPE])) { + return $this->getScalarValue($value); + } + + if (isset($value[self::CLASS_IDENTIFIER_KEY])) { + return $this->unserializeObject($value); + } + + return array_map(array($this, __FUNCTION__), $value); + } + + /** + * @param $value + * + * @return float|int|null|bool + */ + protected function getScalarValue($value) + { + switch ($value[self::SCALAR_TYPE]) { + case 'integer': + return intval($value[self::SCALAR_VALUE]); + break; + case 'float': + return floatval($value[self::SCALAR_VALUE]); + break; + case 'boolean': + return $value[self::SCALAR_VALUE]; + break; + case 'NULL': + return self::NULL_VAR; + break; + } + + return $value[self::SCALAR_VALUE]; + } + + /** + * Convert the serialized array into an object. + * + * @param array $value + * + * @return object + * + * @throws SerializerException + */ + protected function unserializeObject(array $value) + { + $className = $value[self::CLASS_IDENTIFIER_KEY]; + unset($value[self::CLASS_IDENTIFIER_KEY]); + + if ($className[0] === '@') { + return $this->objectMapping[substr($className, 1)]; + } + + if (!class_exists($className)) { + throw new SerializerException('Unable to find class '.$className); + } + + return (null === ($obj = $this->unserializeDateTimeFamilyObject($value, $className))) + ? $this->unserializeUserDefinedObject($value, $className) : $obj; + } + + /** + * @param array $value + * @param string $className + * + * @return mixed + */ + protected function unserializeDateTimeFamilyObject(array $value, $className) + { + $obj = null; + + if ($this->isDateTimeFamilyObject($className)) { + if ($this->isHHVM) { + return call_user_func_array( + $this->unserializationMapHHVM[$className], + [$this, $className, $value] + ); + } + + $obj = $this->restoreUsingUnserialize($className, $value); + $this->objectMapping[$this->objectMappingIndex++] = $obj; + } + + return $obj; + } + + /** + * @param string $className + * + * @return bool + */ + protected function isDateTimeFamilyObject($className) + { + $isDateTime = false; + + foreach ($this->dateTimeClassType as $class) { + $isDateTime = $isDateTime || is_subclass_of($className, $class, true) || $class === $className; + } + + return $isDateTime; + } + + /** + * @param string $className + * @param array $attributes + * + * @return mixed + */ + protected function restoreUsingUnserialize($className, array $attributes) + { + foreach ($attributes as &$attribute) { + $attribute = $this->unserializeData($attribute); + } + + $obj = (object) $attributes; + $serialized = preg_replace( + '|^O:\d+:"\w+":|', + 'O:'.strlen($className).':"'.$className.'":', + serialize($obj) + ); + + return unserialize($serialized); + } + + /** + * @param array $value + * @param string $className + * + * @return object + */ + protected function unserializeUserDefinedObject(array $value, $className) + { + $ref = new ReflectionClass($className); + $obj = $ref->newInstanceWithoutConstructor(); + + $this->objectMapping[$this->objectMappingIndex++] = $obj; + $this->setUnserializedObjectProperties($value, $ref, $obj); + + if (method_exists($obj, '__wakeup')) { + $obj->__wakeup(); + } + + return $obj; + } + + /** + * @param array $value + * @param ReflectionClass $ref + * @param mixed $obj + * + * @return mixed + */ + protected function setUnserializedObjectProperties(array $value, ReflectionClass $ref, $obj) + { + foreach ($value as $property => $propertyValue) { + try { + $propRef = $ref->getProperty($property); + $propRef->setAccessible(true); + $propRef->setValue($obj, $this->unserializeData($propertyValue)); + } catch (ReflectionException $e) { + $obj->$property = $this->unserializeData($propertyValue); + } + } + + return $obj; + } + + /** + * @param $value + * + * @return string + */ + protected function serializeScalar($value) + { + $type = gettype($value); + if ($type === 'double') { + $type = 'float'; + } + + return [ + self::SCALAR_TYPE => $type, + self::SCALAR_VALUE => $value, + ]; + } + + /** + * @param \Traversable|\ArrayAccess $value + * + * @return mixed + */ + protected function serializeArrayLikeObject($value) + { + $toArray = array(self::CLASS_IDENTIFIER_KEY => get_class($value)); + foreach ($value as $field) { + $toArray[] = $field; + } + + return $this->serializeData($toArray); + } + + /** + * @param array $value + * + * @return array + */ + protected function serializeArray(array $value) + { + return array_map(array($this, 'serializeData'), $value); + } + + /** + * Extract the data from an object. + * + * @param string $value + * + * @return array + */ + protected function serializeObject($value) + { + $ref = new ReflectionClass($value); + if ($this->objectStorage->contains($value)) { + return array(self::CLASS_IDENTIFIER_KEY => '@'.$this->objectStorage[$value]); + } + + $this->objectStorage->attach($value, $this->objectMappingIndex++); + $paramsToSerialize = $this->getObjectProperties($ref, $value); + + $data = array(self::CLASS_IDENTIFIER_KEY => $ref->getName()); + $data += array_map(array($this, 'serializeData'), $this->extractObjectData($value, $ref, $paramsToSerialize)); + + return $data; + } + + /** + * Return the list of properties to be serialized. + * + * @param ReflectionClass $ref + * @param object $value + * + * @return array + */ + protected function getObjectProperties(ReflectionClass $ref, $value) + { + if (method_exists($value, '__sleep')) { + return $value->__sleep(); + } + + $props = array(); + foreach ($ref->getProperties() as $prop) { + $props[] = $prop->getName(); + } + + return array_unique(array_merge($props, array_keys(get_object_vars($value)))); + } + + /** + * Extract the object data. + * + * @param object $value + * @param ReflectionClass $ref + * @param array $properties + * + * @return array + */ + protected function extractObjectData($value, $ref, $properties) + { + $data = array(); + foreach ($properties as $property) { + try { + $propRef = $ref->getProperty($property); + $propRef->setAccessible(true); + $data[$property] = $propRef->getValue($value); + } catch (ReflectionException $e) { + $data[$property] = $value->$property; + } + } + + return $data; + } +} diff --git a/src/Serializer/AbstractSerializerProvider.php b/src/Serializer/AbstractSerializerProvider.php new file mode 100644 index 0000000..2388af6 --- /dev/null +++ b/src/Serializer/AbstractSerializerProvider.php @@ -0,0 +1,30 @@ + + * Date: 7/3/15 + * Time: 6:21 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer; + +/** + * Class AbstractSerializerProvider. + */ +abstract class AbstractSerializerProvider +{ + /** + * @var array + */ + protected $serializers = array(); + + /** + * @return array + */ + public function getSerializers() + { + return $this->serializers; + } +} diff --git a/src/Serializer/HHVM/DatePeriodSerializer.php b/src/Serializer/HHVM/DatePeriodSerializer.php new file mode 100644 index 0000000..23bd366 --- /dev/null +++ b/src/Serializer/HHVM/DatePeriodSerializer.php @@ -0,0 +1,50 @@ + + * Date: 7/4/15 + * Time: 12:41 AM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\HHVM; + +/** + * Class DatePeriodSerializer. + */ +class DatePeriodSerializer +{ + //@todo: HHVM's implementation is completely different + /* + [start:DatePeriod:private] => DateTime Object + ( + [date] => 2012-07-01 00:00:00.000000 + [timezone_type] => 3 + [timezone] => UTC + ) + + [interval:DatePeriod:private] => DateInterval Object + ( + ) + + [end:DatePeriod:private] => DateTime Object + ( + [date] => 2012-08-05 00:00:00.000000 + [timezone_type] => 3 + [timezone] => UTC + ) + + [options:DatePeriod:private] => + [current:DatePeriod:private] => DateTime Object + ( + [date] => 2012-08-05 00:00:00.000000 + [timezone_type] => 3 + [timezone] => UTC + ) + + [recurrances:DatePeriod:private] => 4 + [iterKey:DatePeriod:private] => 5 + + */ +} diff --git a/src/Serializer/HHVM/DateTimeImmutableSerializer.php b/src/Serializer/HHVM/DateTimeImmutableSerializer.php new file mode 100644 index 0000000..0700412 --- /dev/null +++ b/src/Serializer/HHVM/DateTimeImmutableSerializer.php @@ -0,0 +1,40 @@ + + * Date: 7/3/15 + * Time: 6:00 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\HHVM; + +use NilPortugues\Serializer\Serializer; +use NilPortugues\Serializer\Serializer\InternalClasses\DateTimeZoneSerializer; +use ReflectionClass; + +final class DateTimeImmutableSerializer +{ + /** + * @param Serializer $serializer + * @param string $className + * @param array $value + * + * @return object + */ + public static function unserialize(Serializer $serializer, $className, array $value) + { + $dateTimeZone = DateTimeZoneSerializer::unserialize( + $serializer, + 'DateTimeZone', + array($serializer->unserialize($value['data']['timezone'])) + ); + + $ref = new ReflectionClass($className); + + return $ref->newInstanceArgs( + array($serializer->unserialize($value['data']['date']), $dateTimeZone) + ); + } +} diff --git a/src/Serializer/HHVM/DateTimeSerializer.php b/src/Serializer/HHVM/DateTimeSerializer.php new file mode 100644 index 0000000..0192bab --- /dev/null +++ b/src/Serializer/HHVM/DateTimeSerializer.php @@ -0,0 +1,40 @@ + + * Date: 7/3/15 + * Time: 6:00 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\HHVM; + +use NilPortugues\Serializer\Serializer; +use NilPortugues\Serializer\Serializer\InternalClasses\DateTimeZoneSerializer; +use ReflectionClass; + +final class DateTimeSerializer +{ + /** + * @param Serializer $serializer + * @param string $className + * @param array $value + * + * @return object + */ + public static function unserialize(Serializer $serializer, $className, array $value) + { + $dateTimeZone = DateTimeZoneSerializer::unserialize( + $serializer, + 'DateTimeZone', + array($serializer->unserialize($value['timezone'])) + ); + + $ref = new ReflectionClass($className); + + return $ref->newInstanceArgs( + array($serializer->unserialize($value['date']), $dateTimeZone) + ); + } +} diff --git a/src/Serializer/HHVMSerializerProvider.php b/src/Serializer/HHVMSerializerProvider.php new file mode 100644 index 0000000..4b00303 --- /dev/null +++ b/src/Serializer/HHVMSerializerProvider.php @@ -0,0 +1,26 @@ + + * Date: 7/3/15 + * Time: 6:19 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer; + +/** + * Class SerializerProvider. + */ +class HHVMSerializerProvider extends AbstractSerializerProvider +{ + /** + * @var array + */ + protected $serializers = array( + 'DateInterval' => '\NilPortugues\Serializer\Serializer\HHVM\DateIntervalSerializer', + 'DateTimeImmutable' => '\NilPortugues\Serializer\Serializer\HHVM\DateTimeImmutableSerializer', + 'DateTimeZone' => '\NilPortugues\Serializer\Serializer\HHVM\DateTimeZoneSerializer', + ); +} diff --git a/src/Serializer/InternalClasses/DateIntervalSerializer.php b/src/Serializer/InternalClasses/DateIntervalSerializer.php new file mode 100644 index 0000000..a6c8860 --- /dev/null +++ b/src/Serializer/InternalClasses/DateIntervalSerializer.php @@ -0,0 +1,98 @@ + + * Date: 7/3/15 + * Time: 6:00 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\InternalClasses; + +use DateInterval; +use NilPortugues\Serializer\Serializer; +use ReflectionClass; + +class DateIntervalSerializer +{ + /** + * @param Serializer $serializer + * @param string $className + * @param array $value + * + * @return object + */ + public static function unserialize(Serializer $serializer, $className, array $value) + { + $ref = new ReflectionClass($className); + + return self::fillObjectProperties(self::getTypedValue($serializer, $value), $ref); + } + + /** + * @param array $value + * @param ReflectionClass $ref + * + * @return object + */ + protected static function fillObjectProperties(array $value, ReflectionClass $ref) + { + $obj = $ref->newInstanceArgs([$value['construct']]); + unset($value['construct']); + + foreach ($value as $k => $v) { + $obj->$k = $v; + } + + return $obj; + } + + /** + * @param Serializer $serializer + * @param array $value + * + * @return mixed + */ + protected static function getTypedValue(Serializer $serializer, array $value) + { + foreach ($value as &$v) { + $v = $serializer->unserialize($v); + } + + return $value; + } + + /** + * @param Serializer $serializer + * @param DateInterval $dateInterval + * + * @return mixed + */ + public static function serialize(Serializer $serializer, DateInterval $dateInterval) + { + return array( + Serializer::CLASS_IDENTIFIER_KEY => get_class($dateInterval), + 'construct' => array( + Serializer::SCALAR_TYPE => 'string', + Serializer::SCALAR_VALUE => sprintf( + 'P%sY%sM%sDT%sH%sM%sS', + $dateInterval->y, + $dateInterval->m, + $dateInterval->d, + $dateInterval->h, + $dateInterval->i, + $dateInterval->s + ), + ), + 'invert' => array( + Serializer::SCALAR_TYPE => 'integer', + Serializer::SCALAR_VALUE => (empty($dateInterval->invert)) ? 0 : 1, + ), + 'days' => array( + Serializer::SCALAR_TYPE => gettype($dateInterval->days), + Serializer::SCALAR_VALUE => $dateInterval->days, + ), + ); + } +} diff --git a/src/Serializer/InternalClasses/DatePeriodSerializer.php b/src/Serializer/InternalClasses/DatePeriodSerializer.php new file mode 100644 index 0000000..ed11c60 --- /dev/null +++ b/src/Serializer/InternalClasses/DatePeriodSerializer.php @@ -0,0 +1,57 @@ + + * Date: 7/4/15 + * Time: 12:43 AM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\InternalClasses; + +/** + * Class DatePeriodSerializer. + */ +class DatePeriodSerializer +{ + /* + [start] => DateTime Object + ( + [date] => 2012-07-01 00:00:00 + [timezone_type] => 3 + [timezone] => Europe/Madrid + ) + + [current] => DateTime Object + ( + [date] => 2012-08-05 00:00:00 + [timezone_type] => 3 + [timezone] => Europe/Madrid + ) + + [end] => + [interval] => DateInterval Object + ( + [y] => 0 + [m] => 0 + [d] => 7 + [h] => 0 + [i] => 0 + [s] => 0 + [weekday] => 0 + [weekday_behavior] => 0 + [first_last_day_of] => 0 + [invert] => 0 + [days] => + [special_type] => 0 + [special_amount] => 0 + [have_weekday_relative] => 0 + [have_special_relative] => 0 + ) + + [recurrences] => 5 + [include_start_date] => 1 + + */ +} diff --git a/src/Serializer/InternalClasses/DateTimeZoneSerializer.php b/src/Serializer/InternalClasses/DateTimeZoneSerializer.php new file mode 100644 index 0000000..612a397 --- /dev/null +++ b/src/Serializer/InternalClasses/DateTimeZoneSerializer.php @@ -0,0 +1,55 @@ + + * Date: 7/3/15 + * Time: 6:00 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\InternalClasses; + +use DateTimeZone; +use NilPortugues\Serializer\Serializer; +use ReflectionClass; + +class DateTimeZoneSerializer +{ + /** + * @param Serializer $serializer + * @param DateTimeZone $dateTimeZone + * + * @return mixed + */ + public static function serialize(Serializer $serializer, DateTimeZone $dateTimeZone) + { + return array( + Serializer::CLASS_IDENTIFIER_KEY => 'DateTimeZone', + 'timezone' => array( + Serializer::SCALAR_TYPE => 'string', + Serializer::SCALAR_VALUE => $dateTimeZone->getName(), + ), + ); + } + + /** + * @param Serializer $serializer + * @param string $className + * @param array $value + * + * @return object + */ + public static function unserialize(Serializer $serializer, $className, array $value) + { + $ref = new ReflectionClass($className); + + foreach ($value as &$v) { + if (is_array($v)) { + $v = $serializer->unserialize($v); + } + } + + return $ref->newInstanceArgs($value); + } +} diff --git a/src/Serializer/InternalClasses/TraversableSerializer.php b/src/Serializer/InternalClasses/TraversableSerializer.php new file mode 100644 index 0000000..a6dac1a --- /dev/null +++ b/src/Serializer/InternalClasses/TraversableSerializer.php @@ -0,0 +1,18 @@ + + * Date: 7/3/15 + * Time: 6:05 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\InternalClasses; + +/** + * Class TraversableSerializer. + */ +class TraversableSerializer +{ +} diff --git a/src/Serializer/InternalClassesSerializerProvider.php b/src/Serializer/InternalClassesSerializerProvider.php new file mode 100644 index 0000000..ca17273 --- /dev/null +++ b/src/Serializer/InternalClassesSerializerProvider.php @@ -0,0 +1,18 @@ + + * Date: 7/3/15 + * Time: 6:20 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer; + +/** + * Class InternalClassesSerializerProvider. + */ +class InternalClassesSerializerProvider extends AbstractSerializerProvider +{ +} diff --git a/src/Serializer/SerializerProvider.php b/src/Serializer/SerializerProvider.php new file mode 100644 index 0000000..7146682 --- /dev/null +++ b/src/Serializer/SerializerProvider.php @@ -0,0 +1,58 @@ + + * Date: 7/3/15 + * Time: 6:20 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer; + +use NilPortugues\Serializer\Serializer; + +/** + * Class SerializerProvider. + */ +class SerializerProvider +{ + /** + * @var array + */ + private $providers = array(); + + /** + * @var \NilPortugues\Serializer\Serializer + */ + private $serializer; + + /** + * @param Serializer $serializer + */ + public function __construct(Serializer $serializer) + { + $this->serializer = $serializer; + } + + /** + * @param string $alias + * @param AbstractSerializerProvider $provider + */ + public function addProvider($alias, AbstractSerializerProvider $provider) + { + $this->providers = array_merge( + $this->providers, + array($alias => $provider->getSerializers()) + ); + } + + /** + * @param string $type + * @param bool $isInternal + * @param bool $isHHVM + */ + public function get($type, $isInternal, $isHHVM = false) + { + } +} diff --git a/src/Serializer/UserDefined/ArraySerializer.php b/src/Serializer/UserDefined/ArraySerializer.php new file mode 100644 index 0000000..e3e4349 --- /dev/null +++ b/src/Serializer/UserDefined/ArraySerializer.php @@ -0,0 +1,18 @@ + + * Date: 7/3/15 + * Time: 6:17 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\UserDefined; + +/** + * Class ArraySerializer. + */ +class ArraySerializer +{ +} diff --git a/src/Serializer/UserDefined/ObjectSerializer.php b/src/Serializer/UserDefined/ObjectSerializer.php new file mode 100644 index 0000000..19995d8 --- /dev/null +++ b/src/Serializer/UserDefined/ObjectSerializer.php @@ -0,0 +1,18 @@ + + * Date: 7/3/15 + * Time: 6:17 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\UserDefined; + +/** + * Class ObjectSerializer. + */ +class ObjectSerializer +{ +} diff --git a/src/Serializer/UserDefined/ScalarSerializer.php b/src/Serializer/UserDefined/ScalarSerializer.php new file mode 100644 index 0000000..41c6a93 --- /dev/null +++ b/src/Serializer/UserDefined/ScalarSerializer.php @@ -0,0 +1,27 @@ + + * Date: 7/3/15 + * Time: 6:16 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\UserDefined; + +/** + * Class ScalarSerializer. + */ +class ScalarSerializer +{ + /** + * @param mixed $value + * + * @return mixed + */ + protected function serialize($value) + { + return $value; + } +} diff --git a/src/Serializer/UserDefined/TraversableSerializer.php b/src/Serializer/UserDefined/TraversableSerializer.php new file mode 100644 index 0000000..68b1a5b --- /dev/null +++ b/src/Serializer/UserDefined/TraversableSerializer.php @@ -0,0 +1,18 @@ + + * Date: 7/3/15 + * Time: 6:17 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer\UserDefined; + +/** + * Class TraversableSerializer. + */ +class TraversableSerializer +{ +} diff --git a/src/Serializer/UserDefinedSerializerProvider.php b/src/Serializer/UserDefinedSerializerProvider.php new file mode 100644 index 0000000..aa1d137 --- /dev/null +++ b/src/Serializer/UserDefinedSerializerProvider.php @@ -0,0 +1,18 @@ + + * Date: 7/3/15 + * Time: 6:20 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Serializer; + +/** + * Class UserDefinedSerializerProvider. + */ +class UserDefinedSerializerProvider extends AbstractSerializerProvider +{ +} diff --git a/src/SerializerException.php b/src/SerializerException.php new file mode 100644 index 0000000..f9ea1f1 --- /dev/null +++ b/src/SerializerException.php @@ -0,0 +1,9 @@ + + * Date: 7/3/15 + * Time: 6:11 PM. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace NilPortugues\Serializer\Strategy; + +/** + * Class JsonStrategy. + */ +class JsonStrategy +{ + /** + * @param mixed $value + * + * @return string + */ + public function serialize($value) + { + return json_encode($value, JSON_UNESCAPED_UNICODE); + } + + /** + * @param $value + * + * @return array + */ + public function unserialize($value) + { + return json_decode($value, true); + } +} diff --git a/tests/JsonSerializerTest.php b/tests/JsonSerializerTest.php new file mode 100644 index 0000000..b9753c3 --- /dev/null +++ b/tests/JsonSerializerTest.php @@ -0,0 +1,415 @@ +serializer = new Serializer(); + } + + /** + * Test serialization of scalar values. + * + * @dataProvider scalarDataToJson + * + * @param mixed $scalar + * @param string $jsoned + */ + public function testSerializeScalar($scalar, $jsoned) + { + $this->assertSame($jsoned, $this->serializer->serialize($scalar)); + } + + /** + * Test unserialization of scalar values. + * + * @dataProvider scalarDataToJson + * + * @param mixed $scalar + * @param string $jsoned + */ + public function testUnserializeScalar($scalar, $jsoned) + { + $this->assertSame($scalar, $this->serializer->unserialize($jsoned)); + } + + /** + * List of scalar data. + * + * @return array + */ + public function scalarDataToJson() + { + return array( + array('testing', '{"@scalar":"string","@value":"testing"}'), + array(123, '{"@scalar":"integer","@value":123}'), + array(0, '{"@scalar":"integer","@value":0}'), + array(0.0, '{"@scalar":"float","@value":0}'), + array(17.0, '{"@scalar":"float","@value":17}'), + array(17e1, '{"@scalar":"float","@value":170}'), + array(17.2, '{"@scalar":"float","@value":17.2}'), + array(true, '{"@scalar":"boolean","@value":true}'), + array(false, '{"@scalar":"boolean","@value":false}'), + array(null, '{"@scalar":"NULL","@value":null}'), + // Non UTF8 + array('ßåö', '{"@scalar":"string","@value":"ßåö"}'), + ); + } + + /** + * Test the serialization of resources. + */ + public function testSerializeResource() + { + $this->setExpectedException(SerializerException::class); + $this->serializer->serialize(fopen(__FILE__, 'r')); + } + + /** + * Test the serialization of closures. + */ + public function testSerializeClosure() + { + $this->setExpectedException(SerializerException::class); + $this->serializer->serialize(array('func' => function () { + echo 'whoops'; + })); + } + + /** + * Test serialization of array without objects. + * + * @dataProvider arrayNoObjectData + * + * @param array $array + * @param string $jsoned + */ + public function testSerializeArrayNoObject($array, $jsoned) + { + $this->assertSame($jsoned, $this->serializer->serialize($array)); + } + + /** + * Test unserialization of array without objects. + * + * @dataProvider arrayNoObjectData + * + * @param array $array + * @param string $jsoned + */ + public function testUnserializeArrayNoObject($array, $jsoned) + { + $this->assertSame($array, $this->serializer->unserialize($jsoned)); + } + + /** + * List of array data. + * + * @return array + */ + public function arrayNoObjectData() + { + return array( + array(array(1, 2, 3), '[{"@scalar":"integer","@value":1},{"@scalar":"integer","@value":2},{"@scalar":"integer","@value":3}]'), + array(array(1, 'abc', false), '[{"@scalar":"integer","@value":1},{"@scalar":"string","@value":"abc"},{"@scalar":"boolean","@value":false}]'), + array(array('a' => 1, 'b' => 2, 'c' => 3), '{"a":{"@scalar":"integer","@value":1},"b":{"@scalar":"integer","@value":2},"c":{"@scalar":"integer","@value":3}}'), + array(array('integer' => 1, 'string' => 'abc', 'bool' => false), '{"integer":{"@scalar":"integer","@value":1},"string":{"@scalar":"string","@value":"abc"},"bool":{"@scalar":"boolean","@value":false}}'), + array(array(1, array('nested')), '[{"@scalar":"integer","@value":1},[{"@scalar":"string","@value":"nested"}]]'), + array(array('integer' => 1, 'array' => array('nested')), '{"integer":{"@scalar":"integer","@value":1},"array":[{"@scalar":"string","@value":"nested"}]}'), + array(array('integer' => 1, 'array' => array('nested' => 'object')), '{"integer":{"@scalar":"integer","@value":1},"array":{"nested":{"@scalar":"string","@value":"object"}}}'), + array(array(1.0, 2, 3e1), '[{"@scalar":"float","@value":1},{"@scalar":"integer","@value":2},{"@scalar":"float","@value":30}]'), + ); + } + + /** + * Test serialization of objects. + */ + public function testSerializeObject() + { + $obj = new stdClass(); + $this->assertSame('{"@type":"stdClass"}', $this->serializer->serialize($obj)); + + $obj = $empty = new SupportClasses\EmptyClass(); + $this->assertSame('{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}', $this->serializer->serialize($obj)); + + $obj = new SupportClasses\AllVisibilities(); + $expected = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\AllVisibilities","pub":{"@scalar":"string","@value":"this is public"},"prot":{"@scalar":"string","@value":"protected"},"priv":{"@scalar":"string","@value":"dont tell anyone"}}'; + $this->assertSame($expected, $this->serializer->serialize($obj)); + + $obj->pub = 'new value'; + $expected = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\AllVisibilities","pub":{"@scalar":"string","@value":"new value"},"prot":{"@scalar":"string","@value":"protected"},"priv":{"@scalar":"string","@value":"dont tell anyone"}}'; + $this->assertSame($expected, $this->serializer->serialize($obj)); + + $obj->pub = $empty; + $expected = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\AllVisibilities","pub":{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"},"prot":{"@scalar":"string","@value":"protected"},"priv":{"@scalar":"string","@value":"dont tell anyone"}}'; + $this->assertSame($expected, $this->serializer->serialize($obj)); + + $array = array('instance' => $empty); + $expected = '{"instance":{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}}'; + $this->assertSame($expected, $this->serializer->serialize($array)); + + $obj = new stdClass(); + $obj->total = 10.0; + $obj->discount = 0.0; + $expected = '{"@type":"stdClass","total":{"@scalar":"float","@value":10},"discount":{"@scalar":"float","@value":0}}'; + $this->assertSame($expected, $this->serializer->serialize($obj)); + } + + /** + * Test unserialization of objects. + */ + public function testUnserializeObjects() + { + $serialized = '{"@type":"stdClass"}'; + $obj = $this->serializer->unserialize($serialized); + $this->assertInstanceOf('stdClass', $obj); + + $serialized = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}'; + $obj = $this->serializer->unserialize($serialized); + $this->assertInstanceOf(EmptyClass::class, $obj); + + $serialized = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\AllVisibilities","pub":{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"},"prot":"protected","priv":"dont tell anyone"}'; + $obj = $this->serializer->unserialize($serialized); + $this->assertInstanceOf(AllVisibilities::class, $obj); + $this->assertInstanceOf(EmptyClass::class, $obj->pub); + $this->assertAttributeSame('protected', 'prot', $obj); + $this->assertAttributeSame('dont tell anyone', 'priv', $obj); + + $serialized = '{"instance":{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}}'; + $array = $this->serializer->unserialize($serialized); + $this->assertTrue(is_array($array)); + $this->assertInstanceOf(EmptyClass::class, $array['instance']); + } + + /** + * Test magic serialization methods. + */ + public function testSerializationMagicMethods() + { + $obj = new SupportClasses\MagicClass(); + $serialized = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\MagicClass","show":{"@scalar":"boolean","@value":true}}'; + $this->assertSame($serialized, $this->serializer->serialize($obj)); + $this->assertFalse($obj->woke); + + $obj = $this->serializer->unserialize($serialized); + $this->assertTrue($obj->woke); + } + + /** + * TraversableSerializer serialization. + */ + public function testSerializationOfTraversableClasses() + { + $traversable = new TraversableClass(); + $traversable->next(); + $unserializedCollection = $this->serializer->unserialize($this->serializer->serialize($traversable)); + + $this->assertEquals($traversable, $unserializedCollection); + } + + /** + * ArrayAccess serialization. + */ + public function testSerializationOfArrayAccessClasses() + { + $arrayAccess = new ArrayAccessClass(); + $arrayAccess[] = 'Append 1'; + $arrayAccess[] = 'Append 2'; + $arrayAccess[] = 'Append 3'; + + $unserializedCollection = $this->serializer->unserialize($this->serializer->serialize($arrayAccess)); + + $this->assertEquals($arrayAccess, $unserializedCollection); + } + + /** + * Test serialization of DateTime classes. + * + * Some interal classes, such as DateTime, cannot be initialized with + * ReflectionClass::newInstanceWithoutConstructor() + */ + public function testSerializationOfDateTime() + { + $date = new \DateTime('2014-06-15 12:00:00', new \DateTimeZone('UTC')); + $obj = $this->serializer->unserialize($this->serializer->serialize($date)); + $this->assertSame($date->getTimestamp(), $obj->getTimestamp()); + $this->assertEquals($date, $obj); + } + + /** + * Test serialization of DateTimeImmutable classes. + * + * Some interal classes, such as DateTimeImmutable, cannot be initialized with + * ReflectionClass::newInstanceWithoutConstructor() + */ + public function testSerializationOfDateTimeImmutable() + { + if (version_compare(PHP_VERSION, '5.5.0', '<')) { + $this->markTestSkipped('Supported for PHP 5.5.0 and above'); + } + + $date = new \DateTimeImmutable('2014-06-15 12:00:00', new \DateTimeZone('UTC')); + $obj = $this->serializer->unserialize($this->serializer->serialize($date)); + + $this->assertSame($date->getTimestamp(), $obj->getTimestamp()); + $this->assertEquals($date, $obj); + } + + /** + * Test serialization of DateTimeZone classes. + * + * Some interal classes, such as DateTimeZone, cannot be initialized with + * ReflectionClass::newInstanceWithoutConstructor() + */ + public function testSerializationOfDateTimeZone() + { + $date = new \DateTimeZone('UTC'); + + $obj = $this->serializer->unserialize($this->serializer->serialize($date)); + $this->assertEquals($date, $obj); + } + + /** + * Test serialization of DateInterval classes. + * + * Some interal classes, such as DateInterval, cannot be initialized with + * ReflectionClass::newInstanceWithoutConstructor() + */ + public function testSerializationOfDateInterval() + { + $date = new \DateInterval('P2Y4DT6H8M'); + $obj = $this->serializer->unserialize($this->serializer->serialize($date)); + $this->assertEquals($date, $obj); + $this->assertSame($date->d, $obj->d); + } + + /** + * Test serialization of DatePeriod classes. + * + * Some interal classes, such as DatePeriod, cannot be initialized with + * ReflectionClass::newInstanceWithoutConstructor() + */ + public function testSerializationOfDatePeriodException() + { + $this->setExpectedException( + SerializerException::class, + 'DatePeriod is not supported in Serializer. Loop through it and serialize the output.' + ); + + $period = new \DatePeriod(new \DateTime('2012-07-01'), new \DateInterval('P7D'), 4); + $this->serializer->serialize($period); + } + + /** + * Test serialization of DatePeriod output. + */ + public function testSerializationOfDatePeriodOutputIsSerializable() + { + $period = new \DatePeriod(new \DateTime('2012-07-01'), new \DateInterval('P7D'), 4); + $dates = array(); + foreach ($period as $p) { + $dates[] = $p; + } + + $serialized = $this->serializer->serialize($dates); + $objs = $this->serializer->unserialize($serialized); + + foreach ($objs as $key => $obj) { + $this->assertSame($dates[$key]->getTimestamp(), $obj->getTimestamp()); + $this->assertEquals($dates[$key], $obj); + } + } + + /** + * Test unserialize of unknown class. + */ + public function testUnserializeUnknownClass() + { + $this->setExpectedException(SerializerException::class); + $serialized = '{"@type":"UnknownClass"}'; + $this->serializer->unserialize($serialized); + } + + /** + * Test serialization of undeclared properties. + */ + public function testSerializationUndeclaredProperties() + { + $obj = new stdClass(); + $obj->param1 = true; + $obj->param2 = 'store me, please'; + $serialized = '{"@type":"stdClass","param1":{"@scalar":"boolean","@value":true},"param2":{"@scalar":"string","@value":"store me, please"}}'; + $this->assertSame($serialized, $this->serializer->serialize($obj)); + + $obj2 = $this->serializer->unserialize($serialized); + $this->assertInstanceOf('stdClass', $obj2); + $this->assertTrue($obj2->param1); + $this->assertSame('store me, please', $obj2->param2); + + $serialized = '{"@type":"stdClass","sub":{"@type":"stdClass","key":"value"}}'; + $obj = $this->serializer->unserialize($serialized); + $this->assertInstanceOf('stdClass', $obj->sub); + $this->assertSame('value', $obj->sub->key); + } + + /** + * Test serialize with recursion. + */ + public function testSerializeRecursion() + { + $c1 = new stdClass(); + $c1->c2 = new stdClass(); + $c1->c2->c3 = new stdClass(); + $c1->c2->c3->c1 = $c1; + $c1->something = 'ok'; + $c1->c2->c3->ok = true; + + $expected = '{"@type":"stdClass","c2":{"@type":"stdClass","c3":{"@type":"stdClass","c1":{"@type":"@0"},"ok":{"@scalar":"boolean","@value":true}}},"something":{"@scalar":"string","@value":"ok"}}'; + $this->assertSame($expected, $this->serializer->serialize($c1)); + + $c1 = new stdClass(); + $c1->mirror = $c1; + $expected = '{"@type":"stdClass","mirror":{"@type":"@0"}}'; + $this->assertSame($expected, $this->serializer->serialize($c1)); + } + + /** + * Test unserialize with recursion. + */ + public function testUnserializeRecursion() + { + $serialized = '{"@type":"stdClass","c2":{"@type":"stdClass","c3":{"@type":"stdClass","c1":{"@type":"@0"},"ok":{"@scalar":"boolean","@value":true}}},"something":{"@scalar":"string","@value":"ok"}}'; + $obj = $this->serializer->unserialize($serialized); + $this->assertTrue($obj->c2->c3->ok); + $this->assertSame($obj, $obj->c2->c3->c1); + $this->assertNotSame($obj, $obj->c2); + + $serialized = '{"@type":"stdClass","c2":{"@type":"stdClass","c3":{"@type":"stdClass","c1":{"@type":"@0"},"c2":{"@type":"@1"},"c3":{"@type":"@2"}},"c3_copy":{"@type":"@2"}}}'; + $obj = $this->serializer->unserialize($serialized); + $this->assertSame($obj, $obj->c2->c3->c1); + $this->assertSame($obj->c2, $obj->c2->c3->c2); + $this->assertSame($obj->c2->c3, $obj->c2->c3->c3); + $this->assertSame($obj->c2->c3_copy, $obj->c2->c3); + } +} diff --git a/tests/SupportClasses/AllVisibilities.php b/tests/SupportClasses/AllVisibilities.php new file mode 100644 index 0000000..c65d7cb --- /dev/null +++ b/tests/SupportClasses/AllVisibilities.php @@ -0,0 +1,10 @@ +container = array( + 'one' => 1, + 'two' => 2, + 'three' => 3, + ); + } + + /** + * @param mixed $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + if (is_null($offset)) { + $this->container[] = $value; + } else { + $this->container[$offset] = $value; + } + } + + /** + * @param mixed $offset + * + * @return bool + */ + public function offsetExists($offset) + { + return isset($this->container[$offset]); + } + + /** + * @param mixed $offset + */ + public function offsetUnset($offset) + { + unset($this->container[$offset]); + } + + /** + * @param mixed $offset + */ + public function offsetGet($offset) + { + return isset($this->container[$offset]) ? $this->container[$offset] : null; + } +} diff --git a/tests/SupportClasses/EmptyClass.php b/tests/SupportClasses/EmptyClass.php new file mode 100644 index 0000000..5ee8804 --- /dev/null +++ b/tests/SupportClasses/EmptyClass.php @@ -0,0 +1,7 @@ +woke = true; + } +} diff --git a/tests/SupportClasses/TraversableClass.php b/tests/SupportClasses/TraversableClass.php new file mode 100644 index 0000000..e93721e --- /dev/null +++ b/tests/SupportClasses/TraversableClass.php @@ -0,0 +1,67 @@ +position = 0; + } + + /** + * + */ + public function rewind() + { + $this->position = 0; + } + + /** + * @return mixed + */ + public function current() + { + return $this->array[$this->position]; + } + + /** + * @return int + */ + public function key() + { + return $this->position; + } + + /** + * + */ + public function next() + { + ++$this->position; + } + + /** + * @return bool + */ + public function valid() + { + return isset($this->array[$this->position]); + } +}