├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── DeepCopySerializer.php ├── JsonSerializer.php ├── Serializer.php ├── Serializer │ ├── HHVM │ │ ├── DatePeriodSerializer.php │ │ ├── DateTimeImmutableSerializer.php │ │ └── DateTimeSerializer.php │ └── InternalClasses │ │ ├── DateIntervalSerializer.php │ │ ├── DatePeriodSerializer.php │ │ ├── DateTimeZoneSerializer.php │ │ └── SplFixedArraySerializer.php ├── SerializerException.php ├── Strategy │ ├── JsonStrategy.php │ ├── NullStrategy.php │ ├── StrategyInterface.php │ ├── XmlStrategy.php │ └── YamlStrategy.php ├── Transformer │ ├── AbstractTransformer.php │ ├── ArrayTransformer.php │ ├── FlatArrayTransformer.php │ ├── JsonTransformer.php │ ├── XmlTransformer.php │ └── YamlTransformer.php ├── XmlSerializer.php └── YamlSerializer.php └── tests ├── DeepCopySerializerTest.php ├── Dummy ├── ComplexObject │ ├── Comment.php │ ├── Post.php │ ├── User.php │ └── ValueObject │ │ ├── CommentId.php │ │ ├── PostId.php │ │ └── UserId.php └── SimpleObject │ └── Post.php ├── JsonSerializerTest.php ├── SerializerTest.php ├── SupportClasses ├── AllVisibilities.php ├── ArrayAccessClass.php ├── ChildOfSplFixedArray.php ├── EmptyClass.php ├── MagicClass.php └── TraversableClass.php ├── Transformer ├── ArrayTransformerTest.php ├── FlatArrayTransformerTest.php ├── JsonTransformerTest.php ├── XmlTransformerTest.php └── YamlTransformerTest.php ├── XmlSerializerTest.php └── YamlSerializerTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | vendor/ 3 | composer.lock 4 | build/ 5 | .coveralls.yml 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - "5.6" 4 | - "7.0" 5 | - "7.1" 6 | 7 | before_script: 8 | - composer install 9 | 10 | script: 11 | - bin/phpunit --coverage-text 12 | 13 | branches: 14 | only: 15 | - master 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Nil Portugués Calderó 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Serializer for PHP 2 | ========================= 3 | 4 | [![Build Status](https://travis-ci.org/nilportugues/php-serializer.svg)](https://travis-ci.org/nilportugues/php-serializer) 5 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/nilportugues/serializer/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/nilportugues/serializer/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/7ae05bba-985d-4359-8a00-3209f85f1d77/mini.png?)](https://insight.sensiolabs.com/projects/7ae05bba-985d-4359-8a00-3209f85f1d77) 6 | [![Latest Stable Version](https://poser.pugx.org/nilportugues/serializer/v/stable)](https://packagist.org/packages/nilportugues/serializer) 7 | [![Total Downloads](https://poser.pugx.org/nilportugues/serializer/downloads)](https://packagist.org/packages/nilportugues/serializer) [![License](https://poser.pugx.org/nilportugues/serializer/license)](https://packagist.org/packages/nilportugues/serializer) 8 | [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://paypal.me/nilportugues) 9 | 10 | - [Installation](#installation) 11 | - [Introduction](#introduction) 12 | - [Features](#features) 13 | - [Serialization](#serialization) 14 | - [Serializers (JSON, XML, YAML)](#serializers-json-xml-yaml) 15 | - [Example](#example) 16 | - [Custom Serializers](#custom-serializers) 17 | - [Data Transformation](#data-transformation) 18 | - [Array Transformer](#array-transformer) 19 | - [Flat Array Transformer](#flat-array-transformer) 20 | - [XML Transformer](#xml-transformer) 21 | - [YAML Transformer](#yaml-transformer) 22 | - [JSON Transformer](#json-transformer) 23 | - [JSend Transformer](#jsend-transformer) 24 | - [JSON API Transformer](#json-api-transformer) 25 | - [HAL+JSON Transformer](#haljson-transformer) 26 | - [Quality](#quality) 27 | - [Contribute](#contribute) 28 | - [Author](#author) 29 | - [License](#license) 30 | 31 | ## Installation 32 | 33 | Use [Composer](https://getcomposer.org) to install the package: 34 | 35 | ```json 36 | $ composer require nilportugues/serializer 37 | ``` 38 | 39 | ## Introduction 40 | 41 | **What is serialization?** 42 | 43 | In the context of data storage, serialization is the process of translating data structures or object state into a format that can be stored (for example, in a file or memory buffer, or transmitted across a network connection link) and reconstructed later in the same or another computer environment. 44 | 45 | 46 | **Why not `serialize()` and `unserialize()`?** 47 | 48 | These native functions rely on having the serialized classes loaded and available at runtime and tie your unserialization process to a `PHP` platform. 49 | 50 | If the serialized string contains a reference to a class that cannot be instantiated (e.g. class was renamed, moved namespace, removed or changed to abstract) PHP will immediately die with a fatal error. 51 | 52 | Is this a problem? Yes it is. Serialized data is now **unusable**. 53 | 54 | ## Features 55 | 56 | - Serialize to **JSON**, **XML** and **YAML** formats. 57 | - Serializes **exact copies** of the object provided: 58 | - **All object properties**, public, protected and private are serialized. 59 | - All properties from the current object, and all the inherited properties are read and serialized. 60 | - Handles internal class serialization for objects such as SplFixedArray or classes implementing Traversable. 61 | - Basic **Data Transformers provided** to convert objects to different output formats. 62 | - **Production-ready**. 63 | - **Extensible:** easily write your out `Serializer` format or data `Transformers`. 64 | 65 | 66 | ## Serialization 67 | For the serializer to work, all you need to do is pass in a PHP Object to the serializer and a Strategy to implement its string representation. 68 | 69 | 70 | ### Serializers (JSON, XML, YAML) 71 | 72 | - [NilPortugues\Serializer\JsonSerializer](https://github.com/nilportugues/serializer/blob/master/src/JsonSerializer.php) 73 | - [NilPortugues\Serializer\XmlSerializer](https://github.com/nilportugues/serializer/blob/master/src/XmlSerializer.php) 74 | - [NilPortugues\Serializer\YamlSerializer](https://github.com/nilportugues/serializer/blob/master/src/YamlSerializer.php) 75 | 76 | ### Example 77 | 78 | In the following example a `$post` object is serialized into JSON. 79 | 80 | **Code** 81 | 82 | ```php 83 | use NilPortugues\Serializer\Serializer; 84 | use NilPortugues\Serializer\Strategy\JsonStrategy; 85 | 86 | //Example object 87 | $post = new Post( 88 | new PostId(9), 89 | 'Hello World', 90 | 'Your first post', 91 | new User( 92 | new UserId(1), 93 | 'Post Author' 94 | ), 95 | [ 96 | new Comment( 97 | new CommentId(1000), 98 | 'Have no fear, sers, your king is safe.', 99 | new User(new UserId(2), 'Barristan Selmy'), 100 | [ 101 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 102 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 103 | ] 104 | ), 105 | ] 106 | ); 107 | 108 | //Serialization 109 | $serializer = new JsonSerializer(); 110 | 111 | $serializedObject = $serializer->serialize($post); 112 | 113 | //Returns: true 114 | var_dump($post == $serializer->unserialize($serializedObject)); 115 | 116 | echo $serializedObject; 117 | ``` 118 | 119 | The object, before it's transformed into an output format, is an array with all the necessary data to be rebuild using unserialize method. 120 | 121 | **Output** 122 | 123 | ```json 124 | { 125 | "@type": "Acme\\\\Domain\\\\Dummy\\\\Post", 126 | "postId": { 127 | "@type": "Acme\\\\Domain\\\\Dummy\\\\ValueObject\\\\PostId", 128 | "postId": { 129 | "@scalar": "integer", 130 | "@value": 14 131 | } 132 | }, 133 | "title": { 134 | "@scalar": "string", 135 | "@value": "Hello World" 136 | }, 137 | "content": { 138 | "@scalar": "string", 139 | "@value": "Your first post" 140 | }, 141 | "author": { 142 | "@type": "Acme\\\\Domain\\\\Dummy\\\\User", 143 | "userId": { 144 | "@type": "Acme\\\\Domain\\\\Dummy\\\\ValueObject\\\\UserId", 145 | "userId": { 146 | "@scalar": "integer", 147 | "@value": 1 148 | } 149 | }, 150 | "name": { 151 | "@scalar": "string", 152 | "@value": "Post Author" 153 | } 154 | }, 155 | "comments": { 156 | "@map": "array", 157 | "@value": [ 158 | { 159 | "@type": "Acme\\\\Domain\\\\Dummy\\\\Comment", 160 | "commentId": { 161 | "@type": "Acme\\\\Domain\\\\Dummy\\\\ValueObject\\\\CommentId", 162 | "commentId": { 163 | "@scalar": "integer", 164 | "@value": 1000 165 | } 166 | }, 167 | "dates": { 168 | "@map": "array", 169 | "@value": { 170 | "created_at": { 171 | "@scalar": "string", 172 | "@value": "2015-07-18T12:13:00+00:00" 173 | }, 174 | "accepted_at": { 175 | "@scalar": "string", 176 | "@value": "2015-07-19T00:00:00+00:00" 177 | } 178 | } 179 | }, 180 | "comment": { 181 | "@scalar": "string", 182 | "@value": "Have no fear, sers, your king is safe." 183 | }, 184 | "user": { 185 | "@type": "Acme\\\\Domain\\\\Dummy\\\\User", 186 | "userId": { 187 | "@type": "Acme\\\\Domain\\\\Dummy\\\\ValueObject\\\\UserId", 188 | "userId": { 189 | "@scalar": "integer", 190 | "@value": 2 191 | } 192 | }, 193 | "name": { 194 | "@scalar": "string", 195 | "@value": "Barristan Selmy" 196 | } 197 | } 198 | } 199 | ] 200 | } 201 | }' 202 | ``` 203 | 204 | ### Custom Serializers 205 | 206 | If a custom serialization strategy is preferred, the `Serializer` class should be used instead. A `CustomStrategy` must implement the `StrategyInterface`. 207 | 208 | Usage is as follows: 209 | 210 | ```php 211 | use NilPortugues\Serializer\Serializer; 212 | use NilPortugues\Serializer\Strategy\CustomStrategy; 213 | 214 | $serializer = new Serializer(new CustomStrategy()); 215 | 216 | echo $serializer->serialize($post); 217 | ``` 218 | 219 | ---- 220 | 221 | 222 | ## Data Transformation 223 | 224 | Transformer classes **greatly differ** from a `Strategy` class because these cannot `unserialize()` as all class references are lost in the process of transformation. 225 | 226 | To obtain transformations instead of the `Serializer` class usage of `DeepCopySerializer` is required. 227 | 228 | The Serializer library comes with a set of defined Transformers that implement the `StrategyInterface`. 229 | Usage is as simple as before, pass a Transformer as a `$strategy`. 230 | 231 | **For instance:** 232 | 233 | ```php 234 | //...same as before ... 235 | 236 | $serializer = new DeepCopySerializer(new JsonTransformer()); 237 | echo $serializer->serialize($post); 238 | ``` 239 | 240 | Following, there are some examples and its output, given the `$post` object as data to be Transformed. 241 | 242 | ### Array Transformer 243 | 244 | - [`NilPortugues\Serializer\Transformer\ArrayTransformer`](https://github.com/nilportugues/serializer/blob/master/src/Transformer/ArrayTransformer.php) 245 | 246 | 247 | ```php 248 | array( 249 | 'postId' => 9, 250 | 'title' => 'Hello World', 251 | 'content' => 'Your first post', 252 | 'author' => array( 253 | 'userId' => 1, 254 | 'name' => 'Post Author', 255 | ), 256 | 'comments' => array( 257 | 0 => array( 258 | 'commentId' => 1000, 259 | 'dates' => array( 260 | 'created_at' => '2015-07-18T12:13:00+02:00', 261 | 'accepted_at' => '2015-07-19T00:00:00+02:00', 262 | ), 263 | 'comment' => 'Have no fear, sers, your king is safe.', 264 | 'user' => array( 265 | 'userId' => 2, 266 | 'name' => 'Barristan Selmy', 267 | ), 268 | ), 269 | ), 270 | ); 271 | ``` 272 | 273 | ### Flat Array Transformer 274 | 275 | - [`NilPortugues\Serializer\Transformer\FlatArrayTransformer`](https://github.com/nilportugues/serializer/blob/master/src/Transformer/FlatArrayTransformer.php) 276 | 277 | ```php 278 | array( 279 | 'postId' => 9, 280 | 'title' => 'Hello World', 281 | 'content' => 'Your first post', 282 | 'author.userId' => 1, 283 | 'author.name' => 'Post Author', 284 | 'comments.0.commentId' => 1000, 285 | 'comments.0.dates.created_at' => '2015-07-18T12:13:00+02:00', 286 | 'comments.0.dates.accepted_at' => '2015-07-19T00:00:00+02:00', 287 | 'comments.0.comment' => 'Have no fear, sers, your king is safe.', 288 | 'comments.0.user.userId' => 2, 289 | 'comments.0.user.name' => 'Barristan Selmy', 290 | ); 291 | ``` 292 | 293 | ### XML Transformer 294 | 295 | - [`NilPortugues\Serializer\Transformer\XmlTransformer`](https://github.com/nilportugues/serializer/blob/master/src/Transformer/XmlTransformer.php) 296 | 297 | ```xml 298 | 299 | 300 | 9 301 | Hello World 302 | Your first post 303 | 304 | 1 305 | Post Author 306 | 307 | 308 | 309 | 1000 310 | 311 | 2015-07-18T12:13:00+02:00 312 | 2015-07-19T00:00:00+02:00 313 | 314 | Have no fear, sers, your king is safe. 315 | 316 | 2 317 | Barristan Selmy 318 | 319 | 320 | 321 | 322 | ``` 323 | 324 | ### YAML Transformer 325 | 326 | - [`NilPortugues\Serializer\Transformer\YamlTransformer`](https://github.com/nilportugues/serializer/blob/master/src/Transformer/YamlTransformer.php) 327 | 328 | ```yml 329 | title: 'Hello World' 330 | content: 'Your first post' 331 | author: 332 | userId: 1 333 | name: 'Post Author' 334 | comments: 335 | - { commentId: 1000, dates: { created_at: '2015-07-18T12:13:00+02:00', accepted_at: '2015-07-19T00:00:00+02:00' }, comment: 'Have no fear, sers, your king is safe.', user: { userId: 2, name: 'Barristan Selmy' } } 336 | ``` 337 | 338 | 339 | ### Json Transformer 340 | 341 | JsonTransformer comes in 2 flavours. For object to JSON transformation the following transformer should be used: 342 | 343 | - [`NilPortugues\Serializer\Transformer\JsonTransformer`](https://github.com/nilportugues/serializer/blob/master/src/Transformer/JsonTransformer.php) 344 | 345 | **Output** 346 | 347 | ```json 348 | { 349 | "postId": 9, 350 | "title": "Hello World", 351 | "content": "Your first post", 352 | "author": { 353 | "userId": 1, 354 | "name": "Post Author" 355 | }, 356 | "comments": [ 357 | { 358 | "commentId": 1000, 359 | "dates": { 360 | "created_at": "2015-07-18T13:34:55+02:00", 361 | "accepted_at": "2015-07-18T14:09:55+02:00" 362 | }, 363 | "comment": "Have no fear, sers, your king is safe.", 364 | "user": { 365 | "userId": 2, 366 | "name": "Barristan Selmy" 367 | } 368 | } 369 | ] 370 | } 371 | ``` 372 | 373 | If your desired output is for **API consumption**, you may like to check out the JsonTransformer library, or require it using: 374 | 375 | ```json 376 | $ composer require nilportugues/json 377 | ``` 378 | 379 | 380 | ### JSend Transformer 381 | 382 | JSend Transformer has been built to transform data into valid **JSend** specification resources. 383 | 384 | Please check out the [JSend Transformer](https://github.com/nilportugues/jsend-transformer) or download it using: 385 | 386 | ```json 387 | $ composer require nilportugues/jsend 388 | ``` 389 | 390 | 391 | ### JSON API Transformer 392 | 393 | JSON API Transformer has been built to transform data into valid **JSON API** specification resources. 394 | 395 | Please check out the [JSON API Transformer](https://github.com/nilportugues/jsonapi-transformer) or download it using: 396 | 397 | ```json 398 | $ composer require nilportugues/json-api 399 | ``` 400 | 401 | 402 | ### HAL+JSON Transformer 403 | 404 | HAL+JSON Transformer has been built for **HAL+JSON API creation**. Given an object and a series of mappings a valid HAL+JSON resource representation is given as output. 405 | 406 | Please check out the [HAL+JSON API Transformer](https://github.com/nilportugues/hal-json-transformer) or download it using: 407 | 408 | ```json 409 | $ composer require nilportugues/haljson 410 | ``` 411 | 412 | ---- 413 | 414 | 415 | ## Quality 416 | 417 | To run the PHPUnit tests at the command line, go to the tests directory and issue `phpunit`. 418 | 419 | This library attempts to comply with [PSR-2](http://www.php-fig.org/psr/psr-2/) and [PSR-4](http://www.php-fig.org/psr/psr-4/). 420 | 421 | If you notice compliance oversights, please send a patch via pull request. 422 | 423 | ## Contribute 424 | 425 | Contributions to the package are always welcome! 426 | 427 | * Report any bugs or issues you find on the [issue tracker](https://github.com/nilportugues/serializer/issues/new). 428 | * You can grab the source code at the package's [Git repository](https://github.com/nilportugues/serializer). 429 | 430 | ## Authors 431 | 432 | * [Nil Portugués Calderó](http://nilportugues.com) 433 | * [The Community Contributors](https://github.com/nilportugues/serializer/graphs/contributors) 434 | 435 | ## License 436 | The code base is licensed under the MIT license. 437 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nilportugues/serializer", 3 | "type": "library", 4 | "description": "Serialize PHP variables, including objects, in any format. Support to unserialize it too.", 5 | "keywords": ["json", "serialize", "serializer"], 6 | "homepage": "http://nilportugues.com", 7 | "license": "MIT", 8 | "authors": [ 9 | 10 | { 11 | "name": "Nil Portugués Calderó", 12 | "email": "contact@nilportugues.com", 13 | "role": "Project Lead Developer" 14 | }, 15 | { 16 | "name": "Zumba Fitness, LLC", 17 | "email": "engineering@zumba.com", 18 | "role": "Author of the original idea: https://github.com/zumba/json-serializer" 19 | }, 20 | { 21 | "name": "Juan Basso", 22 | "email": "juan.basso@zumba.com", 23 | "role": "Author of the original idea: https://github.com/zumba/json-serializer" 24 | } 25 | ], 26 | "require": { 27 | "php": ">=5.6.0", 28 | "symfony/yaml": "2.*|3.*|4.*" 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "5.*", 32 | "nilportugues/php_backslasher": "~0.2", 33 | "fabpot/php-cs-fixer": "^1.9", 34 | "doctrine/collections": "^1.3" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "NilPortugues\\Serializer\\": "src/" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "NilPortugues\\Test\\Serializer\\": "tests/" 44 | } 45 | }, 46 | "config": { 47 | "bin-dir": "bin/" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ./tests 31 | 32 | 33 | 34 | 35 | 36 | ./src/ 37 | 38 | ./src/Mapping/ 39 | ./src/Serializer/ 40 | ./vendor/ 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/DeepCopySerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/28/15 6 | * Time: 1:44 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer; 13 | 14 | use ReflectionClass; 15 | 16 | class DeepCopySerializer extends Serializer 17 | { 18 | /** 19 | * Extract the data from an object. 20 | * 21 | * @param mixed $value 22 | * 23 | * @return array 24 | */ 25 | protected function serializeObject($value) 26 | { 27 | if (self::$objectStorage->contains($value)) { 28 | return self::$objectStorage[$value]; 29 | } 30 | 31 | $reflection = new ReflectionClass($value); 32 | $className = $reflection->getName(); 33 | 34 | $serialized = $this->serializeInternalClass($value, $className, $reflection); 35 | self::$objectStorage->attach($value, $serialized); 36 | 37 | return $serialized; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/JsonSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/29/15 6 | * Time: 12:42 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer; 13 | 14 | use NilPortugues\Serializer\Strategy\JsonStrategy; 15 | 16 | class JsonSerializer extends Serializer 17 | { 18 | /** 19 | * 20 | */ 21 | public function __construct() 22 | { 23 | parent::__construct(new JsonStrategy()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Serializer.php: -------------------------------------------------------------------------------- 1 | 'serializeArray', 59 | 'integer' => 'serializeScalar', 60 | 'double' => 'serializeScalar', 61 | 'boolean' => 'serializeScalar', 62 | 'string' => 'serializeScalar', 63 | ]; 64 | 65 | /** 66 | * Hack specific serialization classes. 67 | * 68 | * @var array 69 | */ 70 | protected $unserializationMapHHVM = []; 71 | 72 | /** 73 | * @param StrategyInterface $strategy 74 | */ 75 | public function __construct(StrategyInterface $strategy) 76 | { 77 | 78 | $this->serializationStrategy = $strategy; 79 | } 80 | 81 | /** 82 | * This is handly specially in order to add additional data before the 83 | * serialization process takes place using the transformer public methods, if any. 84 | * 85 | * @return StrategyInterface 86 | */ 87 | public function getTransformer() 88 | { 89 | return $this->serializationStrategy; 90 | } 91 | 92 | /** 93 | * Serialize the value in JSON. 94 | * 95 | * @param mixed $value 96 | * 97 | * @return string JSON encoded 98 | * 99 | * @throws SerializerException 100 | */ 101 | public function serialize($value) 102 | { 103 | $this->reset(); 104 | 105 | return $this->serializationStrategy->serialize($this->serializeData($value)); 106 | } 107 | 108 | /** 109 | * Reset variables. 110 | */ 111 | protected function reset() 112 | { 113 | self::$objectStorage = new SplObjectStorage(); 114 | self::$objectMapping = []; 115 | self::$objectMappingIndex = 0; 116 | } 117 | 118 | /** 119 | * Parse the data to be json encoded. 120 | * 121 | * @param mixed $value 122 | * 123 | * @return mixed 124 | * 125 | * @throws SerializerException 126 | */ 127 | protected function serializeData($value) 128 | { 129 | $this->guardForUnsupportedValues($value); 130 | 131 | if ($this->isInstanceOf($value, 'SplFixedArray')) { 132 | return SplFixedArraySerializer::serialize($this, $value); 133 | } 134 | 135 | if (\is_object($value)) { 136 | return $this->serializeObject($value); 137 | } 138 | 139 | $type = (\gettype($value) && $value !== null) ? \gettype($value) : 'string'; 140 | $func = $this->serializationMap[$type]; 141 | 142 | return $this->$func($value); 143 | } 144 | 145 | /** 146 | * Check if a class is instance or extends from the expected instance. 147 | * 148 | * @param mixed $value 149 | * @param string $classFQN 150 | * 151 | * @return bool 152 | */ 153 | private function isInstanceOf($value, $classFQN) 154 | { 155 | return is_object($value) 156 | && (strtolower(get_class($value)) === strtolower($classFQN) || \is_subclass_of($value, $classFQN, true)); 157 | } 158 | 159 | /** 160 | * @param mixed $value 161 | * 162 | * @throws SerializerException 163 | */ 164 | protected function guardForUnsupportedValues($value) 165 | { 166 | if ($value instanceof Closure) { 167 | throw new SerializerException('Closures are not supported in Serializer'); 168 | } 169 | 170 | if ($value instanceof \DatePeriod) { 171 | throw new SerializerException( 172 | 'DatePeriod is not supported in Serializer. Loop through it and serialize the output.' 173 | ); 174 | } 175 | 176 | if (\is_resource($value)) { 177 | throw new SerializerException('Resource is not supported in Serializer'); 178 | } 179 | } 180 | 181 | /** 182 | * Unserialize the value from string. 183 | * 184 | * @param mixed $value 185 | * 186 | * @return mixed 187 | */ 188 | public function unserialize($value) 189 | { 190 | if (\is_array($value) && isset($value[self::SCALAR_TYPE])) { 191 | return $this->unserializeData($value); 192 | } 193 | 194 | $this->reset(); 195 | 196 | return $this->unserializeData($this->serializationStrategy->unserialize($value)); 197 | } 198 | 199 | /** 200 | * Parse the json decode to convert to objects again. 201 | * 202 | * @param mixed $value 203 | * 204 | * @return mixed 205 | */ 206 | protected function unserializeData($value) 207 | { 208 | if ($value === null || !is_array($value)) { 209 | return $value; 210 | } 211 | 212 | if (isset($value[self::MAP_TYPE]) && !isset($value[self::CLASS_IDENTIFIER_KEY])) { 213 | $value = $value[self::SCALAR_VALUE]; 214 | 215 | return $this->unserializeData($value); 216 | } 217 | 218 | if (isset($value[self::SCALAR_TYPE])) { 219 | return $this->getScalarValue($value); 220 | } 221 | 222 | if (isset($value[self::CLASS_PARENT_KEY]) && 0 === strcmp($value[self::CLASS_PARENT_KEY], 'SplFixedArray')) { 223 | return SplFixedArraySerializer::unserialize($this, $value[self::CLASS_IDENTIFIER_KEY], $value); 224 | } 225 | 226 | if (isset($value[self::CLASS_IDENTIFIER_KEY])) { 227 | return $this->unserializeObject($value); 228 | } 229 | 230 | return \array_map([$this, __FUNCTION__], $value); 231 | } 232 | 233 | /** 234 | * @param $value 235 | * 236 | * @return float|int|null|bool 237 | */ 238 | protected function getScalarValue($value) 239 | { 240 | switch ($value[self::SCALAR_TYPE]) { 241 | case 'integer': 242 | return \intval($value[self::SCALAR_VALUE]); 243 | case 'float': 244 | return \floatval($value[self::SCALAR_VALUE]); 245 | case 'boolean': 246 | return $value[self::SCALAR_VALUE]; 247 | case 'NULL': 248 | return self::NULL_VAR; 249 | } 250 | 251 | return $value[self::SCALAR_VALUE]; 252 | } 253 | 254 | /** 255 | * Convert the serialized array into an object. 256 | * 257 | * @param array $value 258 | * 259 | * @return object 260 | * 261 | * @throws SerializerException 262 | */ 263 | protected function unserializeObject(array $value) 264 | { 265 | $className = $value[self::CLASS_IDENTIFIER_KEY]; 266 | unset($value[self::CLASS_IDENTIFIER_KEY]); 267 | 268 | if (isset($value[self::MAP_TYPE])) { 269 | unset($value[self::MAP_TYPE]); 270 | unset($value[self::SCALAR_VALUE]); 271 | } 272 | 273 | if ($className[0] === '@') { 274 | return self::$objectMapping[substr($className, 1)]; 275 | } 276 | 277 | if (!class_exists($className)) { 278 | throw new SerializerException('Unable to find class '.$className); 279 | } 280 | 281 | return (null === ($obj = $this->unserializeDateTimeFamilyObject($value, $className))) 282 | ? $this->unserializeUserDefinedObject($value, $className) : $obj; 283 | } 284 | 285 | /** 286 | * @param array $value 287 | * @param string $className 288 | * 289 | * @return mixed 290 | */ 291 | protected function unserializeDateTimeFamilyObject(array $value, $className) 292 | { 293 | $obj = null; 294 | 295 | if ($this->isDateTimeFamilyObject($className)) { 296 | $obj = $this->restoreUsingUnserialize($className, $value); 297 | self::$objectMapping[self::$objectMappingIndex++] = $obj; 298 | } 299 | 300 | return $obj; 301 | } 302 | 303 | /** 304 | * @param string $className 305 | * 306 | * @return bool 307 | */ 308 | protected function isDateTimeFamilyObject($className) 309 | { 310 | $isDateTime = false; 311 | 312 | foreach ($this->dateTimeClassType as $class) { 313 | $isDateTime = $isDateTime || \is_subclass_of($className, $class, true) || $class === $className; 314 | } 315 | 316 | return $isDateTime; 317 | } 318 | 319 | /** 320 | * @param string $className 321 | * @param array $attributes 322 | * 323 | * @return mixed 324 | */ 325 | protected function restoreUsingUnserialize($className, array $attributes) 326 | { 327 | foreach ($attributes as &$attribute) { 328 | $attribute = $this->unserializeData($attribute); 329 | } 330 | 331 | $obj = (object) $attributes; 332 | $serialized = \preg_replace( 333 | '|^O:\d+:"\w+":|', 334 | 'O:'.strlen($className).':"'.$className.'":', 335 | \serialize($obj) 336 | ); 337 | 338 | return \unserialize($serialized); 339 | } 340 | 341 | /** 342 | * @param array $value 343 | * @param string $className 344 | * 345 | * @return object 346 | */ 347 | protected function unserializeUserDefinedObject(array $value, $className) 348 | { 349 | $ref = new ReflectionClass($className); 350 | $obj = $ref->newInstanceWithoutConstructor(); 351 | 352 | self::$objectMapping[self::$objectMappingIndex++] = $obj; 353 | $this->setUnserializedObjectProperties($value, $ref, $obj); 354 | 355 | if (\method_exists($obj, '__wakeup')) { 356 | $obj->__wakeup(); 357 | } 358 | 359 | return $obj; 360 | } 361 | 362 | /** 363 | * @param array $value 364 | * @param ReflectionClass $ref 365 | * @param mixed $obj 366 | * 367 | * @return mixed 368 | */ 369 | protected function setUnserializedObjectProperties(array $value, ReflectionClass $ref, $obj) 370 | { 371 | foreach ($value as $property => $propertyValue) { 372 | try { 373 | $propRef = $ref->getProperty($property); 374 | $propRef->setAccessible(true); 375 | $propRef->setValue($obj, $this->unserializeData($propertyValue)); 376 | } catch (ReflectionException $e) { 377 | $obj->$property = $this->unserializeData($propertyValue); 378 | } 379 | } 380 | 381 | return $obj; 382 | } 383 | 384 | /** 385 | * @param $value 386 | * 387 | * @return string 388 | */ 389 | protected function serializeScalar($value) 390 | { 391 | $type = \gettype($value); 392 | if ($type === 'double') { 393 | $type = 'float'; 394 | } 395 | 396 | return [ 397 | self::SCALAR_TYPE => $type, 398 | self::SCALAR_VALUE => $value, 399 | ]; 400 | } 401 | 402 | /** 403 | * @param array $value 404 | * 405 | * @return array 406 | */ 407 | protected function serializeArray(array $value) 408 | { 409 | if (\array_key_exists(self::MAP_TYPE, $value)) { 410 | return $value; 411 | } 412 | 413 | $toArray = [self::MAP_TYPE => 'array', self::SCALAR_VALUE => []]; 414 | foreach ($value as $key => $field) { 415 | $toArray[self::SCALAR_VALUE][$key] = $this->serializeData($field); 416 | } 417 | 418 | return $this->serializeData($toArray); 419 | } 420 | 421 | /** 422 | * Extract the data from an object. 423 | * 424 | * @param mixed $value 425 | * 426 | * @return array 427 | */ 428 | protected function serializeObject($value) 429 | { 430 | if (self::$objectStorage->contains($value)) { 431 | return [self::CLASS_IDENTIFIER_KEY => '@'.self::$objectStorage[$value]]; 432 | } 433 | 434 | self::$objectStorage->attach($value, self::$objectMappingIndex++); 435 | 436 | $reflection = new ReflectionClass($value); 437 | $className = $reflection->getName(); 438 | 439 | return $this->serializeInternalClass($value, $className, $reflection); 440 | } 441 | 442 | /** 443 | * @param mixed $value 444 | * @param string $className 445 | * @param ReflectionClass $ref 446 | * 447 | * @return array 448 | */ 449 | protected function serializeInternalClass($value, $className, ReflectionClass $ref) 450 | { 451 | $paramsToSerialize = $this->getObjectProperties($ref, $value); 452 | $data = [self::CLASS_IDENTIFIER_KEY => $className]; 453 | $data += \array_map([$this, 'serializeData'], $this->extractObjectData($value, $ref, $paramsToSerialize)); 454 | 455 | return $data; 456 | } 457 | 458 | /** 459 | * Return the list of properties to be serialized. 460 | * 461 | * @param ReflectionClass $ref 462 | * @param $value 463 | * 464 | * @return array 465 | */ 466 | protected function getObjectProperties(ReflectionClass $ref, $value) 467 | { 468 | $props = []; 469 | foreach ($ref->getProperties() as $prop) { 470 | $props[] = $prop->getName(); 471 | } 472 | 473 | return \array_unique(\array_merge($props, \array_keys(\get_object_vars($value)))); 474 | } 475 | 476 | /** 477 | * Extract the object data. 478 | * 479 | * @param mixed $value 480 | * @param \ReflectionClass $rc 481 | * @param array $properties 482 | * 483 | * @return array 484 | */ 485 | protected function extractObjectData($value, ReflectionClass $rc, array $properties) 486 | { 487 | $data = []; 488 | 489 | $this->extractCurrentObjectProperties($value, $rc, $properties, $data); 490 | $this->extractAllInhertitedProperties($value, $rc, $data); 491 | 492 | return $data; 493 | } 494 | 495 | /** 496 | * @param mixed $value 497 | * @param ReflectionClass $rc 498 | * @param array $properties 499 | * @param array $data 500 | */ 501 | protected function extractCurrentObjectProperties($value, ReflectionClass $rc, array $properties, array &$data) 502 | { 503 | foreach ($properties as $propertyName) { 504 | try { 505 | $propRef = $rc->getProperty($propertyName); 506 | $propRef->setAccessible(true); 507 | $data[$propertyName] = $propRef->getValue($value); 508 | } catch (ReflectionException $e) { 509 | $data[$propertyName] = $value->$propertyName; 510 | } 511 | } 512 | } 513 | 514 | /** 515 | * @param mixed $value 516 | * @param ReflectionClass $rc 517 | * @param array $data 518 | */ 519 | protected function extractAllInhertitedProperties($value, ReflectionClass $rc, array &$data) 520 | { 521 | do { 522 | $rp = array(); 523 | /* @var $property \ReflectionProperty */ 524 | foreach ($rc->getProperties() as $property) { 525 | $property->setAccessible(true); 526 | $rp[$property->getName()] = $property->getValue($value); 527 | } 528 | $data = \array_merge($rp, $data); 529 | } while ($rc = $rc->getParentClass()); 530 | } 531 | } 532 | -------------------------------------------------------------------------------- /src/Serializer/HHVM/DatePeriodSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/4/15 6 | * Time: 12:41 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Serializer\HHVM; 13 | 14 | /** 15 | * Class DatePeriodSerializer. 16 | */ 17 | class DatePeriodSerializer 18 | { 19 | //HHVM's implementation is completely different 20 | /* 21 | [start:DatePeriod:private] => DateTime Object 22 | ( 23 | [date] => 2012-07-01 00:00:00.000000 24 | [timezone_type] => 3 25 | [timezone] => UTC 26 | ) 27 | 28 | [interval:DatePeriod:private] => DateInterval Object 29 | ( 30 | ) 31 | 32 | [end:DatePeriod:private] => DateTime Object 33 | ( 34 | [date] => 2012-08-05 00:00:00.000000 35 | [timezone_type] => 3 36 | [timezone] => UTC 37 | ) 38 | 39 | [options:DatePeriod:private] => 40 | [current:DatePeriod:private] => DateTime Object 41 | ( 42 | [date] => 2012-08-05 00:00:00.000000 43 | [timezone_type] => 3 44 | [timezone] => UTC 45 | ) 46 | 47 | [recurrances:DatePeriod:private] => 4 48 | [iterKey:DatePeriod:private] => 5 49 | 50 | */ 51 | } 52 | -------------------------------------------------------------------------------- /src/Serializer/HHVM/DateTimeImmutableSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/3/15 6 | * Time: 6:00 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Serializer\HHVM; 13 | 14 | use NilPortugues\Serializer\Serializer; 15 | use NilPortugues\Serializer\Serializer\InternalClasses\DateTimeZoneSerializer; 16 | use ReflectionClass; 17 | 18 | final class DateTimeImmutableSerializer 19 | { 20 | /** 21 | * @param Serializer $serializer 22 | * @param string $className 23 | * @param array $value 24 | * 25 | * @return object 26 | */ 27 | public static function unserialize(Serializer $serializer, $className, array $value) 28 | { 29 | $dateTimeZone = DateTimeZoneSerializer::unserialize( 30 | $serializer, 31 | 'DateTimeZone', 32 | array($serializer->unserialize($value['data']['timezone'])) 33 | ); 34 | 35 | $ref = new ReflectionClass($className); 36 | 37 | return $ref->newInstanceArgs( 38 | array($serializer->unserialize($value['data']['date']), $dateTimeZone) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Serializer/HHVM/DateTimeSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/3/15 6 | * Time: 6:00 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Serializer\HHVM; 13 | 14 | use NilPortugues\Serializer\Serializer; 15 | use NilPortugues\Serializer\Serializer\InternalClasses\DateTimeZoneSerializer; 16 | use ReflectionClass; 17 | 18 | final class DateTimeSerializer 19 | { 20 | /** 21 | * @param Serializer $serializer 22 | * @param string $className 23 | * @param array $value 24 | * 25 | * @return object 26 | */ 27 | public static function unserialize(Serializer $serializer, $className, array $value) 28 | { 29 | $dateTimeZone = DateTimeZoneSerializer::unserialize( 30 | $serializer, 31 | 'DateTimeZone', 32 | array($serializer->unserialize($value['timezone'])) 33 | ); 34 | 35 | $ref = new ReflectionClass($className); 36 | 37 | return $ref->newInstanceArgs( 38 | array($serializer->unserialize($value['date']), $dateTimeZone) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Serializer/InternalClasses/DateIntervalSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/3/15 6 | * Time: 6:00 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Serializer\InternalClasses; 13 | 14 | use DateInterval; 15 | use NilPortugues\Serializer\Serializer; 16 | use ReflectionClass; 17 | 18 | class DateIntervalSerializer 19 | { 20 | /** 21 | * @param Serializer $serializer 22 | * @param string $className 23 | * @param array $value 24 | * 25 | * @return object 26 | */ 27 | public static function unserialize(Serializer $serializer, $className, array $value) 28 | { 29 | $ref = new ReflectionClass($className); 30 | 31 | return self::fillObjectProperties(self::getTypedValue($serializer, $value), $ref); 32 | } 33 | 34 | /** 35 | * @param array $value 36 | * @param ReflectionClass $ref 37 | * 38 | * @return object 39 | */ 40 | protected static function fillObjectProperties(array $value, ReflectionClass $ref) 41 | { 42 | $obj = $ref->newInstanceArgs([$value['construct']]); 43 | unset($value['construct']); 44 | 45 | foreach ($value as $k => $v) { 46 | $obj->$k = $v; 47 | } 48 | 49 | return $obj; 50 | } 51 | 52 | /** 53 | * @param Serializer $serializer 54 | * @param array $value 55 | * 56 | * @return mixed 57 | */ 58 | protected static function getTypedValue(Serializer $serializer, array $value) 59 | { 60 | foreach ($value as &$v) { 61 | $v = $serializer->unserialize($v); 62 | } 63 | 64 | return $value; 65 | } 66 | 67 | /** 68 | * @param Serializer $serializer 69 | * @param DateInterval $dateInterval 70 | * 71 | * @return mixed 72 | */ 73 | public static function serialize(Serializer $serializer, DateInterval $dateInterval) 74 | { 75 | return array( 76 | Serializer::CLASS_IDENTIFIER_KEY => \get_class($dateInterval), 77 | 'construct' => array( 78 | Serializer::SCALAR_TYPE => 'string', 79 | Serializer::SCALAR_VALUE => \sprintf( 80 | 'P%sY%sM%sDT%sH%sM%sS', 81 | $dateInterval->y, 82 | $dateInterval->m, 83 | $dateInterval->d, 84 | $dateInterval->h, 85 | $dateInterval->i, 86 | $dateInterval->s 87 | ), 88 | ), 89 | 'invert' => array( 90 | Serializer::SCALAR_TYPE => 'integer', 91 | Serializer::SCALAR_VALUE => (empty($dateInterval->invert)) ? 0 : 1, 92 | ), 93 | 'days' => array( 94 | Serializer::SCALAR_TYPE => \gettype($dateInterval->days), 95 | Serializer::SCALAR_VALUE => $dateInterval->days, 96 | ), 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Serializer/InternalClasses/DatePeriodSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/4/15 6 | * Time: 12:43 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Serializer\InternalClasses; 13 | 14 | /** 15 | * Class DatePeriodSerializer. 16 | */ 17 | class DatePeriodSerializer 18 | { 19 | /* 20 | [start] => DateTime Object 21 | ( 22 | [date] => 2012-07-01 00:00:00 23 | [timezone_type] => 3 24 | [timezone] => Europe/Madrid 25 | ) 26 | 27 | [current] => DateTime Object 28 | ( 29 | [date] => 2012-08-05 00:00:00 30 | [timezone_type] => 3 31 | [timezone] => Europe/Madrid 32 | ) 33 | 34 | [end] => 35 | [interval] => DateInterval Object 36 | ( 37 | [y] => 0 38 | [m] => 0 39 | [d] => 7 40 | [h] => 0 41 | [i] => 0 42 | [s] => 0 43 | [weekday] => 0 44 | [weekday_behavior] => 0 45 | [first_last_day_of] => 0 46 | [invert] => 0 47 | [days] => 48 | [special_type] => 0 49 | [special_amount] => 0 50 | [have_weekday_relative] => 0 51 | [have_special_relative] => 0 52 | ) 53 | 54 | [recurrences] => 5 55 | [include_start_date] => 1 56 | 57 | */ 58 | } 59 | -------------------------------------------------------------------------------- /src/Serializer/InternalClasses/DateTimeZoneSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/3/15 6 | * Time: 6:00 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Serializer\InternalClasses; 13 | 14 | use DateTimeZone; 15 | use NilPortugues\Serializer\Serializer; 16 | use ReflectionClass; 17 | 18 | class DateTimeZoneSerializer 19 | { 20 | /** 21 | * @param Serializer $serializer 22 | * @param DateTimeZone $dateTimeZone 23 | * 24 | * @return mixed 25 | */ 26 | public static function serialize(Serializer $serializer, DateTimeZone $dateTimeZone) 27 | { 28 | return array( 29 | Serializer::CLASS_IDENTIFIER_KEY => 'DateTimeZone', 30 | 'timezone' => array( 31 | Serializer::SCALAR_TYPE => 'string', 32 | Serializer::SCALAR_VALUE => $dateTimeZone->getName(), 33 | ), 34 | ); 35 | } 36 | 37 | /** 38 | * @param Serializer $serializer 39 | * @param string $className 40 | * @param array $value 41 | * 42 | * @return object 43 | */ 44 | public static function unserialize(Serializer $serializer, $className, array $value) 45 | { 46 | $ref = new ReflectionClass($className); 47 | 48 | foreach ($value as &$v) { 49 | if (\is_array($v)) { 50 | $v = $serializer->unserialize($v); 51 | } 52 | } 53 | 54 | return $ref->newInstanceArgs($value); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Serializer/InternalClasses/SplFixedArraySerializer.php: -------------------------------------------------------------------------------- 1 | get_class($splFixedArray), 21 | Serializer::CLASS_PARENT_KEY => 'SplFixedArray', 22 | Serializer::SCALAR_VALUE => [], 23 | ]; 24 | foreach ($splFixedArray->toArray() as $key => $field) { 25 | $toArray[Serializer::SCALAR_VALUE][$key] = $serializer->serialize($field); 26 | } 27 | 28 | return $toArray; 29 | } 30 | 31 | /** 32 | * @param Serializer $serializer 33 | * @param string $className 34 | * @param array $value 35 | * 36 | * @return mixed 37 | */ 38 | public static function unserialize(Serializer $serializer, $className, array $value) 39 | { 40 | $data = $serializer->unserialize($value[Serializer::SCALAR_VALUE]); 41 | 42 | /* @var SplFixedArray $instance */ 43 | $ref = new ReflectionClass($className); 44 | $instance = $ref->newInstanceWithoutConstructor(); 45 | 46 | $instance->setSize(count($data)); 47 | foreach ($data as $k => $v) { 48 | $instance[$k] = $v; 49 | } 50 | 51 | return $instance; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/SerializerException.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/3/15 6 | * Time: 6:11 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Strategy; 13 | 14 | /** 15 | * Class JsonStrategy. 16 | */ 17 | class JsonStrategy implements StrategyInterface 18 | { 19 | /** 20 | * @param mixed $value 21 | * 22 | * @return string 23 | */ 24 | public function serialize($value) 25 | { 26 | return \json_encode($value, JSON_UNESCAPED_UNICODE); 27 | } 28 | 29 | /** 30 | * @param $value 31 | * 32 | * @return array 33 | */ 34 | public function unserialize($value) 35 | { 36 | return \json_decode($value, true); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Strategy/NullStrategy.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/29/15 6 | * Time: 12:44 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Strategy; 13 | 14 | /** 15 | * Class NullStrategy. 16 | */ 17 | class NullStrategy implements StrategyInterface 18 | { 19 | /** 20 | * @param mixed $value 21 | * 22 | * @return string 23 | */ 24 | public function serialize($value) 25 | { 26 | return $value; 27 | } 28 | 29 | /** 30 | * @param string $value 31 | * 32 | * @return array 33 | */ 34 | public function unserialize($value) 35 | { 36 | return $value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Strategy/StrategyInterface.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/4/15 6 | * Time: 2:56 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Strategy; 13 | 14 | interface StrategyInterface 15 | { 16 | /** 17 | * @param mixed $value 18 | * 19 | * @return string 20 | */ 21 | public function serialize($value); 22 | 23 | /** 24 | * @param $value 25 | * 26 | * @return array 27 | */ 28 | public function unserialize($value); 29 | } 30 | -------------------------------------------------------------------------------- /src/Strategy/XmlStrategy.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/29/15 6 | * Time: 12:46 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Strategy; 13 | 14 | use NilPortugues\Serializer\Serializer; 15 | use SimpleXMLElement; 16 | 17 | class XmlStrategy implements StrategyInterface 18 | { 19 | /** 20 | * @var array 21 | */ 22 | private $replacements = [ 23 | Serializer::CLASS_IDENTIFIER_KEY => 'np_serializer_type', 24 | Serializer::SCALAR_TYPE => 'np_serializer_scalar', 25 | Serializer::SCALAR_VALUE => 'np_serializer_value', 26 | Serializer::MAP_TYPE => 'np_serializer_map', 27 | ]; 28 | 29 | /** 30 | * @param mixed $value 31 | * 32 | * @return string 33 | */ 34 | public function serialize($value) 35 | { 36 | $value = self::replaceKeys($this->replacements, $value); 37 | $xml = new SimpleXMLElement(''); 38 | $this->arrayToXml($value, $xml); 39 | 40 | return $xml->asXML(); 41 | } 42 | 43 | /** 44 | * @param array $replacements 45 | * @param array $input 46 | * 47 | * @return array 48 | */ 49 | private static function replaceKeys(array &$replacements, array $input) 50 | { 51 | $return = []; 52 | foreach ($input as $key => $value) { 53 | $key = \str_replace(\array_keys($replacements), \array_values($replacements), $key); 54 | 55 | if (\is_array($value)) { 56 | $value = self::replaceKeys($replacements, $value); 57 | } 58 | 59 | $return[$key] = $value; 60 | } 61 | 62 | return $return; 63 | } 64 | 65 | /** 66 | * Converts an array to XML using SimpleXMLElement. 67 | * 68 | * @param array $data 69 | * @param SimpleXMLElement $xmlData 70 | */ 71 | private function arrayToXml(array &$data, SimpleXMLElement $xmlData) 72 | { 73 | foreach ($data as $key => $value) { 74 | if (\is_array($value)) { 75 | if (\is_numeric($key)) { 76 | $key = 'np_serializer_element_'.gettype($key).'_'.$key; 77 | } 78 | $subnode = $xmlData->addChild($key); 79 | $this->arrayToXml($value, $subnode); 80 | } else { 81 | $xmlData->addChild("$key", "$value"); 82 | } 83 | } 84 | } 85 | 86 | /** 87 | * @param $value 88 | * 89 | * @return array 90 | */ 91 | public function unserialize($value) 92 | { 93 | $array = (array) \simplexml_load_string($value); 94 | self::castToArray($array); 95 | self::recoverArrayNumericKeyValues($array); 96 | $replacements = \array_flip($this->replacements); 97 | $array = self::replaceKeys($replacements, $array); 98 | 99 | return $array; 100 | } 101 | 102 | /** 103 | * @param array $array 104 | */ 105 | private static function castToArray(array &$array) 106 | { 107 | foreach ($array as &$value) { 108 | if ($value instanceof SimpleXMLElement) { 109 | $value = (array) $value; 110 | } 111 | 112 | if (\is_array($value)) { 113 | self::castToArray($value); 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * @param array $array 120 | */ 121 | private static function recoverArrayNumericKeyValues(array &$array) 122 | { 123 | $newArray = []; 124 | foreach ($array as $key => &$value) { 125 | if (false !== \strpos($key, 'np_serializer_element_')) { 126 | $key = self::getNumericKeyValue($key); 127 | } 128 | 129 | $newArray[$key] = $value; 130 | 131 | if (\is_array($newArray[$key])) { 132 | self::recoverArrayNumericKeyValues($newArray[$key]); 133 | } 134 | } 135 | $array = $newArray; 136 | } 137 | 138 | /** 139 | * @param $key 140 | * 141 | * @return float|int 142 | */ 143 | private static function getNumericKeyValue($key) 144 | { 145 | $newKey = \str_replace('np_serializer_element_', '', $key); 146 | list($type, $index) = \explode('_', $newKey); 147 | 148 | if ('integer' === $type) { 149 | $index = (int) $index; 150 | } 151 | 152 | return $index; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/Strategy/YamlStrategy.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/27/15 6 | * Time: 11:58 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Strategy; 13 | 14 | use Symfony\Component\Yaml\Yaml; 15 | 16 | class YamlStrategy implements StrategyInterface 17 | { 18 | /** 19 | * @param mixed $value 20 | * 21 | * @return string 22 | */ 23 | public function serialize($value) 24 | { 25 | return Yaml::dump($value); 26 | } 27 | 28 | /** 29 | * @param $value 30 | * 31 | * @return array 32 | */ 33 | public function unserialize($value) 34 | { 35 | return Yaml::parse($value); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Transformer/AbstractTransformer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/17/15 6 | * Time: 11:40 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Transformer; 13 | 14 | use InvalidArgumentException; 15 | use NilPortugues\Serializer\Serializer; 16 | use NilPortugues\Serializer\Strategy\StrategyInterface; 17 | 18 | abstract class AbstractTransformer implements StrategyInterface 19 | { 20 | /** 21 | * @param array $array 22 | * @param array $unwantedKey 23 | */ 24 | protected function recursiveUnset(array &$array, array $unwantedKey) 25 | { 26 | foreach ($unwantedKey as $key) { 27 | if (\array_key_exists($key, $array)) { 28 | unset($array[$key]); 29 | } 30 | } 31 | 32 | foreach ($array as &$value) { 33 | if (\is_array($value)) { 34 | $this->recursiveUnset($value, $unwantedKey); 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * @param array $array 41 | */ 42 | protected function recursiveSetValues(array &$array) 43 | { 44 | if (\array_key_exists(Serializer::SCALAR_VALUE, $array)) { 45 | $array = $array[Serializer::SCALAR_VALUE]; 46 | } 47 | 48 | if (\is_array($array) && !array_key_exists(Serializer::SCALAR_VALUE, $array)) { 49 | foreach ($array as &$value) { 50 | if (\is_array($value)) { 51 | $this->recursiveSetValues($value); 52 | } 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * @param array $array 59 | * @param null $parentKey 60 | * @param null $currentKey 61 | */ 62 | protected function recursiveFlattenOneElementObjectsToScalarType(array &$array, $parentKey = null, $currentKey = null) 63 | { 64 | if (1 === \count($array) && \is_scalar(\end($array))) { 65 | if ($parentKey == $currentKey) { 66 | $array = \array_pop($array); 67 | } 68 | } 69 | 70 | if (\is_array($array)) { 71 | foreach ($array as $parentKey => &$value) { 72 | 73 | if (\is_array($value)) { 74 | $key = null; 75 | foreach($value as $key => $v) { 76 | if (is_array($v)) { 77 | $this->recursiveFlattenOneElementObjectsToScalarType($v, $parentKey, $key); 78 | } 79 | } 80 | $this->recursiveFlattenOneElementObjectsToScalarType($value, $parentKey, $key); 81 | } 82 | } 83 | } 84 | } 85 | 86 | /** 87 | * @param $value 88 | * 89 | * @throws \InvalidArgumentException 90 | * 91 | * @return array 92 | */ 93 | public function unserialize($value) 94 | { 95 | throw new InvalidArgumentException(\sprintf('%s does not perform unserializations.', __CLASS__)); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Transformer/ArrayTransformer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/29/15 6 | * Time: 2:48 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Transformer; 13 | 14 | use NilPortugues\Serializer\Serializer; 15 | 16 | class ArrayTransformer extends AbstractTransformer 17 | { 18 | public function __construct() 19 | { 20 | //overwriting default constructor. 21 | } 22 | 23 | /** 24 | * @param mixed $value 25 | * 26 | * @return string 27 | */ 28 | public function serialize($value) 29 | { 30 | $this->recursiveSetValues($value); 31 | $this->recursiveUnset($value, [Serializer::CLASS_IDENTIFIER_KEY]); 32 | $this->recursiveFlattenOneElementObjectsToScalarType($value); 33 | 34 | return $value; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Transformer/FlatArrayTransformer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/29/15 6 | * Time: 2:48 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Transformer; 13 | 14 | class FlatArrayTransformer extends ArrayTransformer 15 | { 16 | /** 17 | * @param mixed $value 18 | * 19 | * @return string 20 | */ 21 | public function serialize($value) 22 | { 23 | return $this->flatten(parent::serialize($value)); 24 | } 25 | 26 | /** 27 | * @param array $array 28 | * @param string $prefix 29 | * 30 | * @return array 31 | */ 32 | private function flatten(array $array, $prefix = '') 33 | { 34 | $result = []; 35 | foreach ($array as $key => $value) { 36 | if (\is_array($value)) { 37 | $result = $result + $this->flatten($value, $prefix.$key.'.'); 38 | } else { 39 | $result[$prefix.$key] = $value; 40 | } 41 | } 42 | 43 | return $result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Transformer/JsonTransformer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/31/15 6 | * Time: 9:33 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Transformer; 13 | 14 | use DOMDocument; 15 | use SimpleXMLElement; 16 | 17 | /** 18 | * Class XmlTransformer. 19 | */ 20 | class XmlTransformer extends ArrayTransformer 21 | { 22 | /** 23 | * @param mixed $value 24 | * 25 | * @return string 26 | */ 27 | public function serialize($value) 28 | { 29 | $array = parent::serialize($value); 30 | 31 | $xmlData = new SimpleXMLElement(''); 32 | $this->arrayToXml($array, $xmlData); 33 | $xml = $xmlData->asXML(); 34 | 35 | $xmlDoc = new DOMDocument(); 36 | $xmlDoc->loadXML($xml); 37 | $xmlDoc->preserveWhiteSpace = false; 38 | $xmlDoc->formatOutput = true; 39 | 40 | return $xmlDoc->saveXML(); 41 | } 42 | 43 | /** 44 | * Converts an array to XML using SimpleXMLElement. 45 | * 46 | * @param array $data 47 | * @param SimpleXMLElement $xmlData 48 | */ 49 | private function arrayToXml(array &$data, SimpleXMLElement $xmlData) 50 | { 51 | foreach ($data as $key => $value) { 52 | if (\is_array($value)) { 53 | if (\is_numeric($key)) { 54 | $key = 'sequential-item'; 55 | } 56 | $subnode = $xmlData->addChild($key); 57 | 58 | $this->arrayToXml($value, $subnode); 59 | } else { 60 | $subnode = $xmlData->addChild("$key", "$value"); 61 | 62 | $type = \gettype($value); 63 | if ('array' !== $type) { 64 | $subnode->addAttribute('type', $type); 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Transformer/YamlTransformer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/31/15 6 | * Time: 9:11 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer\Transformer; 13 | 14 | use Symfony\Component\Yaml\Yaml; 15 | 16 | class YamlTransformer extends ArrayTransformer 17 | { 18 | /** 19 | * @param mixed $value 20 | * 21 | * @return string 22 | */ 23 | public function serialize($value) 24 | { 25 | return Yaml::dump(parent::serialize($value)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/XmlSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/29/15 6 | * Time: 12:47 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer; 13 | 14 | use NilPortugues\Serializer\Strategy\XmlStrategy; 15 | 16 | class XmlSerializer extends Serializer 17 | { 18 | /** 19 | * 20 | */ 21 | public function __construct() 22 | { 23 | parent::__construct(new XmlStrategy()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/YamlSerializer.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/29/15 6 | * Time: 12:41 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Serializer; 13 | 14 | use NilPortugues\Serializer\Strategy\YamlStrategy; 15 | 16 | class YamlSerializer extends Serializer 17 | { 18 | /** 19 | * 20 | */ 21 | public function __construct() 22 | { 23 | parent::__construct(new YamlStrategy()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/DeepCopySerializerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 12:33 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\DeepCopySerializer; 16 | use NilPortugues\Serializer\Strategy\NullStrategy; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 22 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 23 | use NilPortugues\Test\Serializer\SupportClasses\ChildOfSplFixedArray; 24 | use SplFixedArray; 25 | 26 | class DeepCopySerializerTest extends \PHPUnit_Framework_TestCase 27 | { 28 | public function testSerialization() 29 | { 30 | $object = $this->getObject(); 31 | $serializer = new DeepCopySerializer(new NullStrategy()); 32 | $serializedObject = $serializer->serialize($object); 33 | 34 | $this->assertEquals($object, $serializer->unserialize($serializedObject)); 35 | } 36 | 37 | private function getObject() 38 | { 39 | return new Post( 40 | new PostId(9), 41 | 'Hello World', 42 | 'Your first post', 43 | new User( 44 | new UserId(1), 45 | 'Post Author' 46 | ), 47 | [ 48 | new Comment( 49 | new CommentId(1000), 50 | 'Have no fear, sers, your king is safe.', 51 | new User(new UserId(2), 'Barristan Selmy'), 52 | [ 53 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 54 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 55 | ] 56 | ), 57 | ] 58 | ); 59 | } 60 | 61 | public function testArraySerialization() 62 | { 63 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 64 | $serializer = new DeepCopySerializer(new NullStrategy()); 65 | $serializedObject = $serializer->serialize($arrayOfObjects); 66 | 67 | $this->assertEquals($arrayOfObjects, $serializer->unserialize($serializedObject)); 68 | } 69 | 70 | public function testObjectStorageCopyDuringSerialization() 71 | { 72 | $post = $this->getObject(); 73 | 74 | $stdClass = new \stdClass(); 75 | $stdClass->first = $post; 76 | $stdClass->second = $post; 77 | 78 | $serializer = new DeepCopySerializer(new NullStrategy()); 79 | $serializedObject = $serializer->serialize($stdClass); 80 | 81 | $this->assertEquals($stdClass, $serializer->unserialize($serializedObject)); 82 | } 83 | 84 | public function testSplFixedArraySerialization() 85 | { 86 | $splFixedArray = new SplFixedArray(3); 87 | $splFixedArray[0] = 1; 88 | $splFixedArray[1] = 2; 89 | $splFixedArray[2] = 3; 90 | 91 | $serializer = new DeepCopySerializer(new NullStrategy()); 92 | $serializedObject = $serializer->serialize($splFixedArray); 93 | 94 | $this->assertEquals($splFixedArray, $serializer->unserialize($serializedObject)); 95 | } 96 | 97 | public function testSplFixedArrayChildSerialization() 98 | { 99 | $splFixedArray = new ChildOfSplFixedArray(3); 100 | $splFixedArray[0] = 1; 101 | $splFixedArray[1] = 2; 102 | $splFixedArray[2] = 3; 103 | 104 | $serializer = new DeepCopySerializer(new NullStrategy()); 105 | $serializedObject = $serializer->serialize($splFixedArray); 106 | 107 | $this->assertEquals($splFixedArray, $serializer->unserialize($serializedObject)); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tests/Dummy/ComplexObject/Comment.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/18/15 6 | * Time: 10:42 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Dummy\ComplexObject; 13 | 14 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 15 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 16 | 17 | class Comment 18 | { 19 | /** 20 | * @var 21 | */ 22 | private $commentId; 23 | /** 24 | * @var array 25 | */ 26 | private $dates; 27 | /** 28 | * @var string 29 | */ 30 | private $comment; 31 | 32 | /** 33 | * @param CommentId $id 34 | * @param $comment 35 | * @param User $user 36 | * @param array $dates 37 | */ 38 | public function __construct(CommentId $id, $comment, User $user, array $dates) 39 | { 40 | $this->commentId = $id; 41 | $this->comment = $comment; 42 | $this->user = $user; 43 | $this->dates = $dates; 44 | } 45 | 46 | /** 47 | * @return mixed 48 | */ 49 | public function getCommentId() 50 | { 51 | return $this->commentId; 52 | } 53 | 54 | /** 55 | * @return mixed 56 | */ 57 | public function getComment() 58 | { 59 | return $this->comment; 60 | } 61 | 62 | /** 63 | * @return UserId 64 | */ 65 | public function getUser() 66 | { 67 | return $this->user; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/Dummy/ComplexObject/Post.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/18/15 6 | * Time: 10:42 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Dummy\ComplexObject; 13 | 14 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 15 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 16 | 17 | class Post 18 | { 19 | /** 20 | * @param PostId $id 21 | * @param $title 22 | * @param $content 23 | * @param User $user 24 | * @param array $comments 25 | */ 26 | public function __construct(PostId $id, $title, $content, User $user, array $comments) 27 | { 28 | $this->postId = $id; 29 | $this->title = $title; 30 | $this->content = $content; 31 | $this->author = $user; 32 | $this->comments = $comments; 33 | } 34 | 35 | /** 36 | * @return array 37 | */ 38 | public function getComments() 39 | { 40 | return $this->comments; 41 | } 42 | 43 | /** 44 | * @return mixed 45 | */ 46 | public function getContent() 47 | { 48 | return $this->content; 49 | } 50 | 51 | /** 52 | * @return PostId 53 | */ 54 | public function getPostId() 55 | { 56 | return $this->postId; 57 | } 58 | 59 | /** 60 | * @return mixed 61 | */ 62 | public function getTitle() 63 | { 64 | return $this->title; 65 | } 66 | 67 | /** 68 | * @return UserId 69 | */ 70 | public function getUserId() 71 | { 72 | return $this->author; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/Dummy/ComplexObject/User.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/18/15 6 | * Time: 10:41 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Dummy\ComplexObject; 13 | 14 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 15 | 16 | class User 17 | { 18 | /** 19 | * @var UserId 20 | */ 21 | private $userId; 22 | /** 23 | * @var 24 | */ 25 | private $name; 26 | 27 | /** 28 | * @param UserId $id 29 | * @param $name 30 | */ 31 | public function __construct(UserId $id, $name) 32 | { 33 | $this->userId = $id; 34 | $this->name = $name; 35 | } 36 | 37 | /** 38 | * @return mixed 39 | */ 40 | public function getUserId() 41 | { 42 | return $this->userId; 43 | } 44 | 45 | /** 46 | * @return mixed 47 | */ 48 | public function getName() 49 | { 50 | return $this->name; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Dummy/ComplexObject/ValueObject/CommentId.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/18/15 6 | * Time: 10:42 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject; 13 | 14 | class CommentId 15 | { 16 | /** 17 | * @param $id 18 | */ 19 | public function __construct($id) 20 | { 21 | $this->commentId = $id; 22 | } 23 | 24 | /** 25 | * @return mixed 26 | */ 27 | public function getCommentId() 28 | { 29 | return $this->commentId; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Dummy/ComplexObject/ValueObject/PostId.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/18/15 6 | * Time: 10:42 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject; 13 | 14 | class PostId 15 | { 16 | /** 17 | * @param $id 18 | */ 19 | public function __construct($id) 20 | { 21 | $this->postId = $id; 22 | } 23 | 24 | /** 25 | * @return mixed 26 | */ 27 | public function getPostId() 28 | { 29 | return $this->postId; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Dummy/ComplexObject/ValueObject/UserId.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/18/15 6 | * Time: 10:41 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject; 13 | 14 | class UserId 15 | { 16 | /** 17 | * @param $id 18 | */ 19 | public function __construct($id) 20 | { 21 | $this->userId = $id; 22 | } 23 | 24 | /** 25 | * @return mixed 26 | */ 27 | public function getUserId() 28 | { 29 | return $this->userId; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Dummy/SimpleObject/Post.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 7/18/15 6 | * Time: 11:21 AM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Dummy\SimpleObject; 13 | 14 | class Post 15 | { 16 | /** 17 | * @var 18 | */ 19 | private $postId; 20 | /** 21 | * @var 22 | */ 23 | private $title; 24 | /** 25 | * @var 26 | */ 27 | private $body; 28 | /** 29 | * @var 30 | */ 31 | private $authorId; 32 | /** 33 | * @var array 34 | */ 35 | private $comments = []; 36 | 37 | /** 38 | * @param $postId 39 | * @param $title 40 | * @param $body 41 | * @param $authorId 42 | */ 43 | public function __construct($postId, $title, $body, $authorId) 44 | { 45 | $this->postId = $postId; 46 | $this->title = $title; 47 | $this->body = $body; 48 | $this->authorId = $authorId; 49 | } 50 | 51 | /** 52 | * @param $commentId 53 | * @param $user 54 | * @param $comment 55 | * @param $created_at 56 | */ 57 | public function addComment($commentId, $user, $comment, $created_at) 58 | { 59 | $this->comments[] = [ 60 | 'comment_id' => $commentId, 61 | 'comment' => $comment, 62 | 'user_id' => $user, 63 | 'created_at' => $created_at, 64 | ]; 65 | } 66 | 67 | /** 68 | * @param mixed $authorId 69 | * 70 | * @return $this 71 | */ 72 | public function setAuthorId($authorId) 73 | { 74 | $this->authorId = $authorId; 75 | 76 | return $this; 77 | } 78 | 79 | /** 80 | * @return mixed 81 | */ 82 | public function getAuthorId() 83 | { 84 | return $this->authorId; 85 | } 86 | 87 | /** 88 | * @param mixed $body 89 | * 90 | * @return $this 91 | */ 92 | public function setBody($body) 93 | { 94 | $this->body = $body; 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * @return mixed 101 | */ 102 | public function getBody() 103 | { 104 | return $this->body; 105 | } 106 | 107 | /** 108 | * @param mixed $commentId 109 | * 110 | * @return $this 111 | */ 112 | public function setPostId($commentId) 113 | { 114 | $this->postId = $commentId; 115 | 116 | return $this; 117 | } 118 | 119 | /** 120 | * @return mixed 121 | */ 122 | public function getPostId() 123 | { 124 | return $this->postId; 125 | } 126 | 127 | /** 128 | * @param mixed $title 129 | * 130 | * @return $this 131 | */ 132 | public function setTitle($title) 133 | { 134 | $this->title = $title; 135 | 136 | return $this; 137 | } 138 | 139 | /** 140 | * @return mixed 141 | */ 142 | public function getTitle() 143 | { 144 | return $this->title; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /tests/JsonSerializerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 12:33 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\JsonSerializer; 16 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 22 | 23 | class JsonSerializerTest extends \PHPUnit_Framework_TestCase 24 | { 25 | public function testSerialization() 26 | { 27 | $object = $this->getObject(); 28 | $serializer = new JsonSerializer(); 29 | $serializedObject = $serializer->serialize($object); 30 | 31 | $this->assertEquals($object, $serializer->unserialize($serializedObject)); 32 | } 33 | 34 | private function getObject() 35 | { 36 | return new Post( 37 | new PostId(9), 38 | 'Hello World', 39 | 'Your first post', 40 | new User( 41 | new UserId(1), 42 | 'Post Author' 43 | ), 44 | [ 45 | new Comment( 46 | new CommentId(1000), 47 | 'Have no fear, sers, your king is safe.', 48 | new User(new UserId(2), 'Barristan Selmy'), 49 | [ 50 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 51 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 52 | ] 53 | ), 54 | ] 55 | ); 56 | } 57 | 58 | public function testArraySerialization() 59 | { 60 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 61 | $serializer = new JsonSerializer(); 62 | $serializedObject = $serializer->serialize($arrayOfObjects); 63 | 64 | $this->assertEquals($arrayOfObjects, $serializer->unserialize($serializedObject)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/SerializerTest.php: -------------------------------------------------------------------------------- 1 | serializer = new Serializer(new JsonStrategy()); 29 | } 30 | 31 | /** 32 | * Test serialization of DateTime classes. 33 | * 34 | * Some interal classes, such as DateTime, cannot be initialized with 35 | * ReflectionClass::newInstanceWithoutConstructor() 36 | */ 37 | public function testSerializationOfDateTime() 38 | { 39 | $date = new \DateTime('2014-06-15 12:00:00', new \DateTimeZone('UTC')); 40 | 41 | $obj = $this->serializer->unserialize($this->serializer->serialize($date)); 42 | $this->assertSame($date->getTimestamp(), $obj->getTimestamp()); 43 | $this->assertEquals($date, $obj); 44 | } 45 | 46 | /** 47 | * Test serialization of scalar values. 48 | * 49 | * @dataProvider scalarDataToJson 50 | * 51 | * @param mixed $scalar 52 | * @param string $jsoned 53 | */ 54 | public function testSerializeScalar($scalar, $jsoned) 55 | { 56 | $this->assertSame($jsoned, $this->serializer->serialize($scalar)); 57 | } 58 | 59 | /** 60 | * Test unserialization of scalar values. 61 | * 62 | * @dataProvider scalarDataToJson 63 | * 64 | * @param mixed $scalar 65 | * @param string $jsoned 66 | */ 67 | public function testUnserializeScalar($scalar, $jsoned) 68 | { 69 | $this->assertSame($scalar, $this->serializer->unserialize($jsoned)); 70 | } 71 | 72 | /** 73 | * List of scalar data. 74 | * 75 | * @return array 76 | */ 77 | public function scalarDataToJson() 78 | { 79 | return [ 80 | ['testing', '{"@scalar":"string","@value":"testing"}'], 81 | [123, '{"@scalar":"integer","@value":123}'], 82 | [0, '{"@scalar":"integer","@value":0}'], 83 | [0.0, '{"@scalar":"float","@value":0}'], 84 | [17.0, '{"@scalar":"float","@value":17}'], 85 | [17e1, '{"@scalar":"float","@value":170}'], 86 | [17.2, '{"@scalar":"float","@value":17.2}'], 87 | [true, '{"@scalar":"boolean","@value":true}'], 88 | [false, '{"@scalar":"boolean","@value":false}'], 89 | [null, '{"@scalar":"NULL","@value":null}'], 90 | // Non UTF8 91 | ['ßåö', '{"@scalar":"string","@value":"ßåö"}'], 92 | ]; 93 | } 94 | 95 | /** 96 | * Test the serialization of resources. 97 | */ 98 | public function testSerializeResource() 99 | { 100 | $this->setExpectedException(SerializerException::class); 101 | $this->serializer->serialize(\fopen(__FILE__, 'r')); 102 | } 103 | 104 | /** 105 | * Test the serialization of closures. 106 | */ 107 | public function testSerializeClosure() 108 | { 109 | $this->setExpectedException(SerializerException::class); 110 | $this->serializer->serialize(['func' => function () { 111 | echo 'whoops'; 112 | }]); 113 | } 114 | 115 | /** 116 | * Test serialization of array without objects. 117 | * 118 | * @dataProvider arrayNoObjectData 119 | * 120 | * @param array $array 121 | * @param string $jsoned 122 | */ 123 | public function testSerializeArrayNoObject($array, $jsoned) 124 | { 125 | $this->assertSame($jsoned, $this->serializer->serialize($array)); 126 | } 127 | 128 | /** 129 | * Test unserialization of array without objects. 130 | * 131 | * @dataProvider arrayNoObjectData 132 | * 133 | * @param array $array 134 | * @param string $jsoned 135 | */ 136 | public function testUnserializeArrayNoObject($array, $jsoned) 137 | { 138 | $this->assertSame($array, $this->serializer->unserialize($jsoned)); 139 | } 140 | 141 | /** 142 | * List of array data. 143 | * 144 | * @return array 145 | */ 146 | public function arrayNoObjectData() 147 | { 148 | return [ 149 | [[1, 2, 3], '{"@map":"array","@value":[{"@scalar":"integer","@value":1},{"@scalar":"integer","@value":2},{"@scalar":"integer","@value":3}]}'], 150 | [[1, 'abc', false], '{"@map":"array","@value":[{"@scalar":"integer","@value":1},{"@scalar":"string","@value":"abc"},{"@scalar":"boolean","@value":false}]}'], 151 | [['a' => 1, 'b' => 2, 'c' => 3], '{"@map":"array","@value":{"a":{"@scalar":"integer","@value":1},"b":{"@scalar":"integer","@value":2},"c":{"@scalar":"integer","@value":3}}}'], 152 | [['integer' => 1, 'string' => 'abc', 'bool' => false], '{"@map":"array","@value":{"integer":{"@scalar":"integer","@value":1},"string":{"@scalar":"string","@value":"abc"},"bool":{"@scalar":"boolean","@value":false}}}'], 153 | [[1, ['nested']], '{"@map":"array","@value":[{"@scalar":"integer","@value":1},{"@map":"array","@value":[{"@scalar":"string","@value":"nested"}]}]}'], 154 | [['integer' => 1, 'array' => ['nested']], '{"@map":"array","@value":{"integer":{"@scalar":"integer","@value":1},"array":{"@map":"array","@value":[{"@scalar":"string","@value":"nested"}]}}}'], 155 | [['integer' => 1, 'array' => ['nested' => 'object']], '{"@map":"array","@value":{"integer":{"@scalar":"integer","@value":1},"array":{"@map":"array","@value":{"nested":{"@scalar":"string","@value":"object"}}}}}'], 156 | [[1.0, 2, 3e1], '{"@map":"array","@value":[{"@scalar":"float","@value":1},{"@scalar":"integer","@value":2},{"@scalar":"float","@value":30}]}'], 157 | ]; 158 | } 159 | 160 | /** 161 | * Test serialization of objects. 162 | */ 163 | public function testSerializeObject() 164 | { 165 | $obj = new stdClass(); 166 | $this->assertSame('{"@type":"stdClass"}', $this->serializer->serialize($obj)); 167 | 168 | $obj = $empty = new SupportClasses\EmptyClass(); 169 | $this->assertSame('{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}', $this->serializer->serialize($obj)); 170 | 171 | $obj = new SupportClasses\AllVisibilities(); 172 | $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"}}'; 173 | $this->assertSame($expected, $this->serializer->serialize($obj)); 174 | 175 | $obj->pub = 'new value'; 176 | $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"}}'; 177 | $this->assertSame($expected, $this->serializer->serialize($obj)); 178 | 179 | $obj->pub = $empty; 180 | $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"}}'; 181 | $this->assertSame($expected, $this->serializer->serialize($obj)); 182 | 183 | $array = ['instance' => $empty]; 184 | $expected = '{"@map":"array","@value":{"instance":{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}}}'; 185 | $this->assertSame($expected, $this->serializer->serialize($array)); 186 | 187 | $obj = new stdClass(); 188 | $obj->total = 10.0; 189 | $obj->discount = 0.0; 190 | $expected = '{"@type":"stdClass","total":{"@scalar":"float","@value":10},"discount":{"@scalar":"float","@value":0}}'; 191 | $this->assertSame($expected, $this->serializer->serialize($obj)); 192 | } 193 | 194 | /** 195 | * Test unserialization of objects. 196 | */ 197 | public function testUnserializeObjects() 198 | { 199 | $serialized = '{"@type":"stdClass"}'; 200 | $obj = $this->serializer->unserialize($serialized); 201 | $this->assertInstanceOf('stdClass', $obj); 202 | 203 | $serialized = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}'; 204 | $obj = $this->serializer->unserialize($serialized); 205 | $this->assertInstanceOf(EmptyClass::class, $obj); 206 | 207 | $serialized = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\AllVisibilities","pub":{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"},"prot":"protected","priv":"dont tell anyone"}'; 208 | $obj = $this->serializer->unserialize($serialized); 209 | $this->assertInstanceOf(AllVisibilities::class, $obj); 210 | $this->assertInstanceOf(EmptyClass::class, $obj->pub); 211 | $this->assertAttributeSame('protected', 'prot', $obj); 212 | $this->assertAttributeSame('dont tell anyone', 'priv', $obj); 213 | 214 | $serialized = '{"instance":{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\EmptyClass"}}'; 215 | $array = $this->serializer->unserialize($serialized); 216 | $this->assertTrue(\is_array($array)); 217 | $this->assertInstanceOf(EmptyClass::class, $array['instance']); 218 | } 219 | 220 | /** 221 | * Test magic serialization methods. 222 | */ 223 | public function testSerializationMagicMethods() 224 | { 225 | $obj = new SupportClasses\MagicClass(); 226 | $serialized = '{"@type":"NilPortugues\\\\Test\\\\Serializer\\\\SupportClasses\\\\MagicClass","show":{"@scalar":"boolean","@value":true},"hide":{"@scalar":"boolean","@value":true},"woke":{"@scalar":"boolean","@value":false}}'; 227 | $this->assertSame($serialized, $this->serializer->serialize($obj)); 228 | $this->assertFalse($obj->woke); 229 | 230 | $obj = $this->serializer->unserialize($serialized); 231 | $this->assertTrue($obj->woke); 232 | } 233 | 234 | /** 235 | * TraversableSerializer serialization. 236 | 237 | public function testSerializationOfTraversableClasses() 238 | { 239 | $traversable = new TraversableClass(); 240 | $traversable->next(); 241 | 242 | $serialized = $this->serializer->serialize($traversable); 243 | $unserializedCollection = $this->serializer->unserialize($serialized); 244 | 245 | 246 | $this->assertEquals($traversable, $unserializedCollection); 247 | } 248 | 249 | /** 250 | * TraversableSerializer serialization. 251 | } */ 252 | 253 | /** 254 | * ArrayAccess serialization. 255 | */ 256 | public function testSerializationOfArrayAccessClasses() 257 | { 258 | $arrayAccess = new ArrayAccessClass(); 259 | $arrayAccess[] = 'Append 1'; 260 | $arrayAccess[] = 'Append 2'; 261 | $arrayAccess[] = 'Append 3'; 262 | 263 | $unserializedCollection = $this->serializer->unserialize($this->serializer->serialize($arrayAccess)); 264 | 265 | $this->assertEquals($arrayAccess, $unserializedCollection); 266 | } 267 | 268 | /** 269 | * Test serialization of DateTimeImmutable classes. 270 | * 271 | * Some interal classes, such as DateTimeImmutable, cannot be initialized with 272 | * ReflectionClass::newInstanceWithoutConstructor() 273 | */ 274 | public function testSerializationOfDateTimeImmutable() 275 | { 276 | if (\version_compare(PHP_VERSION, '5.5.0', '<')) { 277 | $this->markTestSkipped('Supported for PHP 5.5.0 and above'); 278 | } 279 | 280 | $date = new \DateTimeImmutable('2014-06-15 12:00:00', new \DateTimeZone('UTC')); 281 | $obj = $this->serializer->unserialize($this->serializer->serialize($date)); 282 | 283 | $this->assertSame($date->getTimestamp(), $obj->getTimestamp()); 284 | $this->assertEquals($date, $obj); 285 | } 286 | 287 | /** 288 | * Test serialization of DateTimeZone classes. 289 | * 290 | * Some interal classes, such as DateTimeZone, cannot be initialized with 291 | * ReflectionClass::newInstanceWithoutConstructor() 292 | */ 293 | public function testSerializationOfDateTimeZone() 294 | { 295 | $date = new \DateTimeZone('UTC'); 296 | 297 | $obj = $this->serializer->unserialize($this->serializer->serialize($date)); 298 | $this->assertEquals($date, $obj); 299 | } 300 | 301 | /** 302 | * Test serialization of DateInterval classes. 303 | * 304 | * Some interal classes, such as DateInterval, cannot be initialized with 305 | * ReflectionClass::newInstanceWithoutConstructor() 306 | */ 307 | public function testSerializationOfDateInterval() 308 | { 309 | $date = new \DateInterval('P2Y4DT6H8M'); 310 | $obj = $this->serializer->unserialize($this->serializer->serialize($date)); 311 | $this->assertEquals($date, $obj); 312 | $this->assertSame($date->d, $obj->d); 313 | } 314 | 315 | /** 316 | * Test serialization of DatePeriod classes. 317 | * 318 | * Some interal classes, such as DatePeriod, cannot be initialized with 319 | * ReflectionClass::newInstanceWithoutConstructor() 320 | */ 321 | public function testSerializationOfDatePeriodException() 322 | { 323 | $this->setExpectedException( 324 | SerializerException::class, 325 | 'DatePeriod is not supported in Serializer. Loop through it and serialize the output.' 326 | ); 327 | 328 | $period = new \DatePeriod(new \DateTime('2012-07-01'), new \DateInterval('P7D'), 4); 329 | $this->serializer->serialize($period); 330 | } 331 | 332 | /** 333 | * Test serialization of DatePeriod output. 334 | */ 335 | public function testSerializationOfDatePeriodOutputIsSerializable() 336 | { 337 | $period = new \DatePeriod(new \DateTime('2012-07-01'), new \DateInterval('P7D'), 4); 338 | $dates = []; 339 | foreach ($period as $p) { 340 | $dates[] = $p; 341 | } 342 | 343 | $serialized = $this->serializer->serialize($dates); 344 | $objs = $this->serializer->unserialize($serialized); 345 | 346 | foreach ($objs as $key => $obj) { 347 | $this->assertSame($dates[$key]->getTimestamp(), $obj->getTimestamp()); 348 | $this->assertEquals($dates[$key], $obj); 349 | } 350 | } 351 | 352 | /** 353 | * Test unserialize of unknown class. 354 | */ 355 | public function testUnserializeUnknownClass() 356 | { 357 | $this->setExpectedException(SerializerException::class); 358 | $serialized = '{"@type":"UnknownClass"}'; 359 | $this->serializer->unserialize($serialized); 360 | } 361 | 362 | /** 363 | * Test serialization of undeclared properties. 364 | */ 365 | public function testSerializationUndeclaredProperties() 366 | { 367 | $obj = new stdClass(); 368 | $obj->param1 = true; 369 | $obj->param2 = 'store me, please'; 370 | $serialized = '{"@type":"stdClass","param1":{"@scalar":"boolean","@value":true},"param2":{"@scalar":"string","@value":"store me, please"}}'; 371 | $this->assertSame($serialized, $this->serializer->serialize($obj)); 372 | 373 | $obj2 = $this->serializer->unserialize($serialized); 374 | $this->assertInstanceOf('stdClass', $obj2); 375 | $this->assertTrue($obj2->param1); 376 | $this->assertSame('store me, please', $obj2->param2); 377 | 378 | $serialized = '{"@type":"stdClass","sub":{"@type":"stdClass","key":"value"}}'; 379 | $obj = $this->serializer->unserialize($serialized); 380 | $this->assertInstanceOf('stdClass', $obj->sub); 381 | $this->assertSame('value', $obj->sub->key); 382 | } 383 | 384 | /** 385 | * Test serialize with recursion. 386 | */ 387 | public function testSerializeRecursion() 388 | { 389 | $c1 = new stdClass(); 390 | $c1->c2 = new stdClass(); 391 | $c1->c2->c3 = new stdClass(); 392 | $c1->c2->c3->c1 = $c1; 393 | $c1->something = 'ok'; 394 | $c1->c2->c3->ok = true; 395 | 396 | $expected = '{"@type":"stdClass","c2":{"@type":"stdClass","c3":{"@type":"stdClass","c1":{"@type":"@0"},"ok":{"@scalar":"boolean","@value":true}}},"something":{"@scalar":"string","@value":"ok"}}'; 397 | $this->assertSame($expected, $this->serializer->serialize($c1)); 398 | 399 | $c1 = new stdClass(); 400 | $c1->mirror = $c1; 401 | $expected = '{"@type":"stdClass","mirror":{"@type":"@0"}}'; 402 | $this->assertSame($expected, $this->serializer->serialize($c1)); 403 | } 404 | 405 | /** 406 | * Test unserialize with recursion. 407 | */ 408 | public function testUnserializeRecursion() 409 | { 410 | $serialized = '{"@type":"stdClass","c2":{"@type":"stdClass","c3":{"@type":"stdClass","c1":{"@type":"@0"},"ok":{"@scalar":"boolean","@value":true}}},"something":{"@scalar":"string","@value":"ok"}}'; 411 | $obj = $this->serializer->unserialize($serialized); 412 | $this->assertTrue($obj->c2->c3->ok); 413 | $this->assertSame($obj, $obj->c2->c3->c1); 414 | $this->assertNotSame($obj, $obj->c2); 415 | 416 | $serialized = '{"@type":"stdClass","c2":{"@type":"stdClass","c3":{"@type":"stdClass","c1":{"@type":"@0"},"c2":{"@type":"@1"},"c3":{"@type":"@2"}},"c3_copy":{"@type":"@2"}}}'; 417 | $obj = $this->serializer->unserialize($serialized); 418 | $this->assertSame($obj, $obj->c2->c3->c1); 419 | $this->assertSame($obj->c2, $obj->c2->c3->c2); 420 | $this->assertSame($obj->c2->c3, $obj->c2->c3->c3); 421 | $this->assertSame($obj->c2->c3_copy, $obj->c2->c3); 422 | } 423 | 424 | public function testItCanSerializeAndUnserializeTraversableClass() 425 | { 426 | $elements = [new \DateTime('now')]; 427 | $collection = new \Doctrine\Common\Collections\ArrayCollection($elements); 428 | $serializer = new Serializer(new \NilPortugues\Serializer\Strategy\JsonStrategy()); 429 | $serialized = $serializer->serialize($collection); 430 | 431 | $this->assertEquals($collection, $serializer->unserialize($serialized)); 432 | } 433 | 434 | public function testItCanGetTransformer() 435 | { 436 | $strategy = new \NilPortugues\Serializer\Strategy\JsonStrategy(); 437 | $serializer = new Serializer($strategy); 438 | 439 | $this->assertSame($strategy, $serializer->getTransformer()); 440 | } 441 | 442 | public function testSerializationOfAnArrayOfScalars() 443 | { 444 | $scalar = 'a string'; 445 | 446 | $serializer = new Serializer(new \NilPortugues\Serializer\Strategy\JsonStrategy()); 447 | $serialized = $serializer->serialize($scalar); 448 | 449 | $this->assertEquals($scalar, $serializer->unserialize($serialized)); 450 | } 451 | } 452 | -------------------------------------------------------------------------------- /tests/SupportClasses/AllVisibilities.php: -------------------------------------------------------------------------------- 1 | container = ['one' => 1, 'two' => 2, 'three' => 3]; 18 | } 19 | 20 | /** 21 | * @param mixed $offset 22 | * @param mixed $value 23 | */ 24 | public function offsetSet($offset, $value) 25 | { 26 | if (\is_null($offset)) { 27 | $this->container[] = $value; 28 | } else { 29 | $this->container[$offset] = $value; 30 | } 31 | } 32 | 33 | /** 34 | * @param mixed $offset 35 | * 36 | * @return bool 37 | */ 38 | public function offsetExists($offset) 39 | { 40 | return isset($this->container[$offset]); 41 | } 42 | 43 | /** 44 | * @param mixed $offset 45 | */ 46 | public function offsetUnset($offset) 47 | { 48 | unset($this->container[$offset]); 49 | } 50 | 51 | /** 52 | * @param mixed $offset 53 | * 54 | * @return mixed|null 55 | */ 56 | public function offsetGet($offset) 57 | { 58 | return isset($this->container[$offset]) ? $this->container[$offset] : null; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/SupportClasses/ChildOfSplFixedArray.php: -------------------------------------------------------------------------------- 1 | woke = true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/SupportClasses/TraversableClass.php: -------------------------------------------------------------------------------- 1 | position = 0; 23 | } 24 | 25 | /** 26 | * 27 | */ 28 | public function rewind() 29 | { 30 | $this->position = 0; 31 | } 32 | 33 | /** 34 | * @return mixed 35 | */ 36 | public function current() 37 | { 38 | return $this->array[$this->position]; 39 | } 40 | 41 | /** 42 | * @return int 43 | */ 44 | public function key() 45 | { 46 | return $this->position; 47 | } 48 | 49 | /** 50 | * 51 | */ 52 | public function next() 53 | { 54 | ++$this->position; 55 | } 56 | 57 | /** 58 | * @return bool 59 | */ 60 | public function valid() 61 | { 62 | return isset($this->array[$this->position]); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/Transformer/ArrayTransformerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 1:24 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Transformer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\DeepCopySerializer; 16 | use NilPortugues\Serializer\Transformer\ArrayTransformer; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 22 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 23 | 24 | class ArrayTransformerTest extends \PHPUnit_Framework_TestCase 25 | { 26 | public function testSerialization() 27 | { 28 | $object = $this->getObject(); 29 | $serializer = new DeepCopySerializer(new ArrayTransformer()); 30 | 31 | $expected = array( 32 | 'postId' => 9, 33 | 'title' => 'Hello World', 34 | 'content' => 'Your first post', 35 | 'author' => array( 36 | 'userId' => 1, 37 | 'name' => 'Post Author', 38 | ), 39 | 'comments' => array( 40 | 0 => array( 41 | 'commentId' => 1000, 42 | 'dates' => array( 43 | 'created_at' => '2015-07-18T12:13:00+02:00', 44 | 'accepted_at' => '2015-07-19T00:00:00+02:00', 45 | ), 46 | 'comment' => 'Have no fear, sers, your king is safe.', 47 | 'user' => array( 48 | 'userId' => 2, 49 | 'name' => 'Barristan Selmy', 50 | ), 51 | ), 52 | ), 53 | ); 54 | 55 | $this->assertEquals($expected, $serializer->serialize($object)); 56 | } 57 | 58 | /** 59 | * @return Post 60 | */ 61 | private function getObject() 62 | { 63 | return new Post( 64 | new PostId(9), 65 | 'Hello World', 66 | 'Your first post', 67 | new User( 68 | new UserId(1), 69 | 'Post Author' 70 | ), 71 | [ 72 | new Comment( 73 | new CommentId(1000), 74 | 'Have no fear, sers, your king is safe.', 75 | new User(new UserId(2), 'Barristan Selmy'), 76 | [ 77 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 78 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 79 | ] 80 | ), 81 | ] 82 | ); 83 | } 84 | 85 | public function testArraySerialization() 86 | { 87 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 88 | $serializer = new DeepCopySerializer(new ArrayTransformer()); 89 | 90 | $expected = array( 91 | 0 => array( 92 | 'postId' => 9, 93 | 'title' => 'Hello World', 94 | 'content' => 'Your first post', 95 | 'author' => array( 96 | 'userId' => 1, 97 | 'name' => 'Post Author', 98 | ), 99 | 'comments' => array( 100 | 0 => array( 101 | 'commentId' => 1000, 102 | 'dates' => array( 103 | 'created_at' => '2015-07-18T12:13:00+02:00', 104 | 'accepted_at' => '2015-07-19T00:00:00+02:00', 105 | ), 106 | 'comment' => 'Have no fear, sers, your king is safe.', 107 | 'user' => array( 108 | 'userId' => 2, 109 | 'name' => 'Barristan Selmy', 110 | ), 111 | ), 112 | ), 113 | ), 114 | 1 => array( 115 | 'postId' => 9, 116 | 'title' => 'Hello World', 117 | 'content' => 'Your first post', 118 | 'author' => array( 119 | 'userId' => 1, 120 | 'name' => 'Post Author', 121 | ), 122 | 'comments' => array( 123 | 0 => array( 124 | 'commentId' => 1000, 125 | 'dates' => array( 126 | 'created_at' => '2015-07-18T12:13:00+02:00', 127 | 'accepted_at' => '2015-07-19T00:00:00+02:00', 128 | ), 129 | 'comment' => 'Have no fear, sers, your king is safe.', 130 | 'user' => array( 131 | 'userId' => 2, 132 | 'name' => 'Barristan Selmy', 133 | ), 134 | ), 135 | ), 136 | ), 137 | ); 138 | 139 | $this->assertEquals($expected, $serializer->serialize($arrayOfObjects)); 140 | } 141 | 142 | public function testUnserializeWillThrowException() 143 | { 144 | $serialize = new DeepCopySerializer(new ArrayTransformer()); 145 | 146 | $this->setExpectedException(\InvalidArgumentException::class); 147 | $serialize->unserialize($serialize->serialize($this->getObject())); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /tests/Transformer/FlatArrayTransformerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 1:24 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Transformer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\DeepCopySerializer; 16 | use NilPortugues\Serializer\Transformer\FlatArrayTransformer; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 22 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 23 | 24 | class FlatArrayTransformerTest extends \PHPUnit_Framework_TestCase 25 | { 26 | public function testSerialization() 27 | { 28 | $object = $this->getObject(); 29 | $serializer = new DeepCopySerializer(new FlatArrayTransformer()); 30 | 31 | $expected = [ 32 | 'postId' => 9, 33 | 'title' => 'Hello World', 34 | 'content' => 'Your first post', 35 | 'author.userId' => 1, 36 | 'author.name' => 'Post Author', 37 | 'comments.0.commentId' => 1000, 38 | 'comments.0.dates.created_at' => '2015-07-18T12:13:00+02:00', 39 | 'comments.0.dates.accepted_at' => '2015-07-19T00:00:00+02:00', 40 | 'comments.0.comment' => 'Have no fear, sers, your king is safe.', 41 | 'comments.0.user.userId' => 2, 42 | 'comments.0.user.name' => 'Barristan Selmy', 43 | 44 | ]; 45 | 46 | $this->assertEquals($expected, $serializer->serialize($object)); 47 | } 48 | 49 | /** 50 | * @return Post 51 | */ 52 | private function getObject() 53 | { 54 | return new Post( 55 | new PostId(9), 56 | 'Hello World', 57 | 'Your first post', 58 | new User( 59 | new UserId(1), 60 | 'Post Author' 61 | ), 62 | [ 63 | new Comment( 64 | new CommentId(1000), 65 | 'Have no fear, sers, your king is safe.', 66 | new User(new UserId(2), 'Barristan Selmy'), 67 | [ 68 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 69 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 70 | ] 71 | ), 72 | ] 73 | ); 74 | } 75 | 76 | public function testArraySerialization() 77 | { 78 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 79 | $serializer = new DeepCopySerializer(new FlatArrayTransformer()); 80 | 81 | $expected = [ 82 | '0.postId' => 9, 83 | '0.title' => 'Hello World', 84 | '0.content' => 'Your first post', 85 | '0.author.userId' => 1, 86 | '0.author.name' => 'Post Author', 87 | '0.comments.0.commentId' => 1000, 88 | '0.comments.0.dates.created_at' => '2015-07-18T12:13:00+02:00', 89 | '0.comments.0.dates.accepted_at' => '2015-07-19T00:00:00+02:00', 90 | '0.comments.0.comment' => 'Have no fear, sers, your king is safe.', 91 | '0.comments.0.user.userId' => 2, 92 | '0.comments.0.user.name' => 'Barristan Selmy', 93 | '1.postId' => 9, 94 | '1.title' => 'Hello World', 95 | '1.content' => 'Your first post', 96 | '1.author.userId' => 1, 97 | '1.author.name' => 'Post Author', 98 | '1.comments.0.commentId' => 1000, 99 | '1.comments.0.dates.created_at' => '2015-07-18T12:13:00+02:00', 100 | '1.comments.0.dates.accepted_at' => '2015-07-19T00:00:00+02:00', 101 | '1.comments.0.comment' => 'Have no fear, sers, your king is safe.', 102 | '1.comments.0.user.userId' => 2, 103 | '1.comments.0.user.name' => 'Barristan Selmy', 104 | ]; 105 | 106 | $this->assertEquals($expected, $serializer->serialize($arrayOfObjects)); 107 | } 108 | 109 | public function testUnserializeWillThrowException() 110 | { 111 | $serialize = new DeepCopySerializer(new FlatArrayTransformer()); 112 | 113 | $this->setExpectedException(\InvalidArgumentException::class); 114 | $serialize->unserialize($serialize->serialize($this->getObject())); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /tests/Transformer/JsonTransformerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 1:03 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Transformer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\DeepCopySerializer; 16 | use NilPortugues\Serializer\Transformer\JsonTransformer; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 22 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 23 | 24 | class JsonTransformerTest extends \PHPUnit_Framework_TestCase 25 | { 26 | 27 | public function testSerializationObjectWithArrayOfOneAttribute() 28 | { 29 | $object = new \stdClass(); 30 | $object->payload = ['userId' => 1]; 31 | 32 | $serializer = new DeepCopySerializer(new JsonTransformer()); 33 | 34 | $expected = <<assertEquals($expected, $serializer->serialize($object)); 43 | } 44 | 45 | public function testSerializationObjectWithObjectOfOneAttribute() 46 | { 47 | $internal = new \stdClass(); 48 | $internal->userId = 1; 49 | 50 | $object = new \stdClass(); 51 | $object->payload = $internal; 52 | 53 | $serializer = new DeepCopySerializer(new JsonTransformer()); 54 | 55 | $expected = <<assertEquals($expected, $serializer->serialize($object)); 64 | } 65 | 66 | public function testSerialization() 67 | { 68 | $object = $this->getObject(); 69 | $serializer = new DeepCopySerializer(new JsonTransformer()); 70 | 71 | $expected = <<assertEquals($expected, $serializer->serialize($object)); 98 | } 99 | 100 | /** 101 | * @return Post 102 | */ 103 | private function getObject() 104 | { 105 | return new Post( 106 | new PostId(9), 107 | 'Hello World', 108 | 'Your first post', 109 | new User( 110 | new UserId(1), 111 | 'Post Author' 112 | ), 113 | [ 114 | new Comment( 115 | new CommentId(1000), 116 | 'Have no fear, sers, your king is safe.', 117 | new User(new UserId(2), 'Barristan Selmy'), 118 | [ 119 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 120 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 121 | ] 122 | ), 123 | ] 124 | ); 125 | } 126 | 127 | public function testArraySerialization() 128 | { 129 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 130 | $serializer = new DeepCopySerializer(new JsonTransformer()); 131 | 132 | $expected = <<assertEquals($expected, $serializer->serialize($arrayOfObjects)); 184 | } 185 | 186 | public function testUnserializeWillThrowException() 187 | { 188 | $serialize = new DeepCopySerializer(new JsonTransformer()); 189 | 190 | $this->setExpectedException(\InvalidArgumentException::class); 191 | $serialize->unserialize($serialize->serialize($this->getObject())); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /tests/Transformer/XmlTransformerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 1:03 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Transformer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\DeepCopySerializer; 16 | use NilPortugues\Serializer\Transformer\XmlTransformer; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 22 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 23 | 24 | class XmlTransformerTest extends \PHPUnit_Framework_TestCase 25 | { 26 | public function testSerialization() 27 | { 28 | $object = $this->getObject(); 29 | $serializer = new DeepCopySerializer(new XmlTransformer()); 30 | $xml = $serializer->serialize($object); 31 | 32 | $expected = << 34 | 35 | 9 36 | Hello World 37 | Your first post 38 | 39 | 1 40 | Post Author 41 | 42 | 43 | 44 | 1000 45 | 46 | 2015-07-18T12:13:00+02:00 47 | 2015-07-19T00:00:00+02:00 48 | 49 | Have no fear, sers, your king is safe. 50 | 51 | 2 52 | Barristan Selmy 53 | 54 | 55 | 56 | 57 | 58 | STRING; 59 | 60 | $this->assertEquals($expected, $xml); 61 | } 62 | 63 | /** 64 | * @return Post 65 | */ 66 | private function getObject() 67 | { 68 | return new Post( 69 | new PostId(9), 70 | 'Hello World', 71 | 'Your first post', 72 | new User( 73 | new UserId(1), 74 | 'Post Author' 75 | ), 76 | [ 77 | new Comment( 78 | new CommentId(1000), 79 | 'Have no fear, sers, your king is safe.', 80 | new User(new UserId(2), 'Barristan Selmy'), 81 | [ 82 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 83 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 84 | ] 85 | ), 86 | ] 87 | ); 88 | } 89 | 90 | public function testArraySerialization() 91 | { 92 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 93 | $serializer = new DeepCopySerializer(new XmlTransformer()); 94 | 95 | $expected = << 97 | 98 | 99 | 9 100 | Hello World 101 | Your first post 102 | 103 | 1 104 | Post Author 105 | 106 | 107 | 108 | 1000 109 | 110 | 2015-07-18T12:13:00+02:00 111 | 2015-07-19T00:00:00+02:00 112 | 113 | Have no fear, sers, your king is safe. 114 | 115 | 2 116 | Barristan Selmy 117 | 118 | 119 | 120 | 121 | 122 | 9 123 | Hello World 124 | Your first post 125 | 126 | 1 127 | Post Author 128 | 129 | 130 | 131 | 1000 132 | 133 | 2015-07-18T12:13:00+02:00 134 | 2015-07-19T00:00:00+02:00 135 | 136 | Have no fear, sers, your king is safe. 137 | 138 | 2 139 | Barristan Selmy 140 | 141 | 142 | 143 | 144 | 145 | 146 | STRING; 147 | 148 | $this->assertEquals($expected, $serializer->serialize($arrayOfObjects)); 149 | } 150 | 151 | public function testUnserializeWillThrowException() 152 | { 153 | $serialize = new DeepCopySerializer(new XmlTransformer()); 154 | 155 | $this->setExpectedException(\InvalidArgumentException::class); 156 | $serialize->unserialize($serialize->serialize($this->getObject())); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /tests/Transformer/YamlTransformerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 1:03 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer\Transformer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\DeepCopySerializer; 16 | use NilPortugues\Serializer\Transformer\YamlTransformer; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 22 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 23 | 24 | class YamlTransformerTest extends \PHPUnit_Framework_TestCase 25 | { 26 | public function testSerialization() 27 | { 28 | $object = $this->getObject(); 29 | $serializer = new DeepCopySerializer(new YamlTransformer()); 30 | 31 | $expected = "postId: 9 32 | title: 'Hello World' 33 | content: 'Your first post' 34 | author: 35 | userId: 1 36 | name: 'Post Author' 37 | comments: 38 | - { commentId: 1000, dates: { created_at: '2015-07-18T12:13:00+02:00', accepted_at: '2015-07-19T00:00:00+02:00' }, comment: 'Have no fear, sers, your king is safe.', user: { userId: 2, name: 'Barristan Selmy' } } 39 | "; 40 | 41 | $this->assertEquals($expected, $serializer->serialize($object)); 42 | } 43 | 44 | /** 45 | * @return Post 46 | */ 47 | private function getObject() 48 | { 49 | return new Post( 50 | new PostId(9), 51 | 'Hello World', 52 | 'Your first post', 53 | new User( 54 | new UserId(1), 55 | 'Post Author' 56 | ), 57 | [ 58 | new Comment( 59 | new CommentId(1000), 60 | 'Have no fear, sers, your king is safe.', 61 | new User(new UserId(2), 'Barristan Selmy'), 62 | [ 63 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 64 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 65 | ] 66 | ), 67 | ] 68 | ); 69 | } 70 | 71 | public function testArraySerialization() 72 | { 73 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 74 | $serializer = new DeepCopySerializer(new YamlTransformer()); 75 | 76 | $expected = "- 77 | postId: 9 78 | title: 'Hello World' 79 | content: 'Your first post' 80 | author: { userId: 1, name: 'Post Author' } 81 | comments: [{ commentId: 1000, dates: { created_at: '2015-07-18T12:13:00+02:00', accepted_at: '2015-07-19T00:00:00+02:00' }, comment: 'Have no fear, sers, your king is safe.', user: { userId: 2, name: 'Barristan Selmy' } }] 82 | - 83 | postId: 9 84 | title: 'Hello World' 85 | content: 'Your first post' 86 | author: { userId: 1, name: 'Post Author' } 87 | comments: [{ commentId: 1000, dates: { created_at: '2015-07-18T12:13:00+02:00', accepted_at: '2015-07-19T00:00:00+02:00' }, comment: 'Have no fear, sers, your king is safe.', user: { userId: 2, name: 'Barristan Selmy' } }] 88 | "; 89 | 90 | $this->assertEquals($expected, $serializer->serialize($arrayOfObjects)); 91 | } 92 | 93 | public function testUnserializeWillThrowException() 94 | { 95 | $serialize = new DeepCopySerializer(new YamlTransformer()); 96 | 97 | $this->setExpectedException(\InvalidArgumentException::class); 98 | $serialize->unserialize($serialize->serialize($this->getObject())); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/XmlSerializerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 12:33 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\XmlSerializer; 16 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 22 | 23 | class XmlSerializerTest extends \PHPUnit_Framework_TestCase 24 | { 25 | public function testSerialization() 26 | { 27 | $object = $this->getObject(); 28 | $serializer = new XmlSerializer(); 29 | $serializedObject = $serializer->serialize($object); 30 | 31 | $this->assertEquals($object, $serializer->unserialize($serializedObject)); 32 | } 33 | 34 | private function getObject() 35 | { 36 | return new Post( 37 | new PostId(9), 38 | 'Hello World', 39 | 'Your first post', 40 | new User( 41 | new UserId(1), 42 | 'Post Author' 43 | ), 44 | [ 45 | new Comment( 46 | new CommentId(1000), 47 | 'Have no fear, sers, your king is safe.', 48 | new User(new UserId(2), 'Barristan Selmy'), 49 | [ 50 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 51 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 52 | ] 53 | ), 54 | ] 55 | ); 56 | } 57 | 58 | public function testArraySerialization() 59 | { 60 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 61 | $serializer = new XmlSerializer(); 62 | $serializedObject = $serializer->serialize($arrayOfObjects); 63 | 64 | $this->assertEquals($arrayOfObjects, $serializer->unserialize($serializedObject)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/YamlSerializerTest.php: -------------------------------------------------------------------------------- 1 | 5 | * Date: 8/30/15 6 | * Time: 12:33 PM. 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace NilPortugues\Test\Serializer; 13 | 14 | use DateTime; 15 | use NilPortugues\Serializer\YamlSerializer; 16 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Comment; 17 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\Post; 18 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\User; 19 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\CommentId; 20 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\PostId; 21 | use NilPortugues\Test\Serializer\Dummy\ComplexObject\ValueObject\UserId; 22 | 23 | class YamlSerializerTest extends \PHPUnit_Framework_TestCase 24 | { 25 | public function testSerialization() 26 | { 27 | $object = $this->getObject(); 28 | $serializer = new YamlSerializer(); 29 | $serializedObject = $serializer->serialize($object); 30 | 31 | $this->assertEquals($object, $serializer->unserialize($serializedObject)); 32 | } 33 | 34 | private function getObject() 35 | { 36 | return new Post( 37 | new PostId(9), 38 | 'Hello World', 39 | 'Your first post', 40 | new User( 41 | new UserId(1), 42 | 'Post Author' 43 | ), 44 | [ 45 | new Comment( 46 | new CommentId(1000), 47 | 'Have no fear, sers, your king is safe.', 48 | new User(new UserId(2), 'Barristan Selmy'), 49 | [ 50 | 'created_at' => (new DateTime('2015/07/18 12:13:00'))->format('c'), 51 | 'accepted_at' => (new DateTime('2015/07/19 00:00:00'))->format('c'), 52 | ] 53 | ), 54 | ] 55 | ); 56 | } 57 | 58 | public function testArraySerialization() 59 | { 60 | $arrayOfObjects = [$this->getObject(), $this->getObject()]; 61 | $serializer = new YamlSerializer(); 62 | $serializedObject = $serializer->serialize($arrayOfObjects); 63 | 64 | $this->assertEquals($arrayOfObjects, $serializer->unserialize($serializedObject)); 65 | } 66 | } 67 | --------------------------------------------------------------------------------