├── .editorconfig ├── .github └── FUNDING.yml ├── Hydrator.php ├── LICENSE.md ├── composer.json ├── phpbench.json └── readme.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | indent_style = space 10 | indent_size = 4 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: samdark 4 | patreon: samdark 5 | -------------------------------------------------------------------------------- /Hydrator.php: -------------------------------------------------------------------------------- 1 | map = $map; 31 | } 32 | 33 | /** 34 | * Creates an instance of a class filled with data according to map 35 | * 36 | * @param array $data 37 | * @param string $className 38 | * @return object 39 | * 40 | * @since 1.0.2 41 | */ 42 | public function hydrate($data, $className) 43 | { 44 | $reflection = $this->getReflectionClass($className); 45 | $object = $reflection->newInstanceWithoutConstructor(); 46 | 47 | foreach ($this->map as $dataKey => $propertyName) { 48 | try { 49 | $property = $reflection->getProperty($propertyName); 50 | } catch (\ReflectionException $e) { 51 | throw new \InvalidArgumentException("There's no $propertyName property in $className."); 52 | } 53 | 54 | if (isset($data[$dataKey])) { 55 | $property->setAccessible(true); 56 | $property->setValue($object, $data[$dataKey]); 57 | } 58 | } 59 | 60 | return $object; 61 | } 62 | 63 | /** 64 | * Fills an object passed with data according to map 65 | * 66 | * @param array $data 67 | * @param object $object 68 | * @return object 69 | * 70 | * @since 1.0.2 71 | */ 72 | public function hydrateInto($data, $object) 73 | { 74 | $className = get_class($object); 75 | $reflection = $this->getReflectionClass($className); 76 | 77 | foreach ($this->map as $dataKey => $propertyName) { 78 | if (!$reflection->hasProperty($propertyName)) { 79 | throw new \InvalidArgumentException("There's no $propertyName property in $className."); 80 | } 81 | 82 | if (isset($data[$dataKey])) { 83 | $property = $reflection->getProperty($propertyName); 84 | $property->setAccessible(true); 85 | $property->setValue($object, $data[$dataKey]); 86 | } 87 | } 88 | 89 | return $object; 90 | } 91 | 92 | /** 93 | * Extracts data from an object according to map 94 | * 95 | * @param object $object 96 | * @return array 97 | */ 98 | public function extract($object) 99 | { 100 | $data = []; 101 | 102 | $className = get_class($object); 103 | $reflection = $this->getReflectionClass($className); 104 | 105 | foreach ($this->map as $dataKey => $propertyName) { 106 | if ($reflection->hasProperty($propertyName)) { 107 | $property = $reflection->getProperty($propertyName); 108 | $property->setAccessible(true); 109 | $data[$dataKey] = $property->getValue($object); 110 | } 111 | } 112 | 113 | return $data; 114 | } 115 | 116 | /** 117 | * Returns instance of reflection class for class name passed 118 | * 119 | * @param string $className 120 | * @return \ReflectionClass 121 | * @throws \ReflectionException 122 | */ 123 | protected function getReflectionClass($className) 124 | { 125 | if (!isset($this->reflectionClassMap[$className])) { 126 | $this->reflectionClassMap[$className] = new \ReflectionClass($className); 127 | } 128 | return $this->reflectionClassMap[$className]; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Alexander Makarov 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 7 | to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of 10 | the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 14 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 15 | OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "samdark/hydrator", 3 | "type": "library", 4 | "description": "Allows to extract data from an object or create a new object based on data for the purpose of persisting state. Works with private and protected properties.", 5 | "keywords": ["hydrator", "extract", "hydrate"], 6 | "require-dev": { 7 | "phpunit/phpunit": "^4.8", 8 | "phpbench/phpbench": "^0.17.1" 9 | }, 10 | "license": "MIT", 11 | "support": { 12 | "issues": "https://github.com/samdark/hydrator/issues", 13 | "source": "https://github.com/samdark/hydrator" 14 | }, 15 | "authors": [ 16 | { 17 | "name": "Alexander Makarov", 18 | "email": "sam@rmcreative.ru" 19 | } 20 | ], 21 | "autoload": { 22 | "psr-4": { 23 | "samdark\\hydrator\\": "" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /phpbench.json: -------------------------------------------------------------------------------- 1 | { 2 | "bootstrap": "vendor/autoload.php", 3 | "path": "tests/Benchmark", 4 | "retry_threshold": 3, 5 | "outputs": { 6 | "html_file": { 7 | "extends": "html", 8 | "file": "benchmarks.html", 9 | "title": "Hydrator benchmark report" 10 | }, 11 | "md_file": { 12 | "extends": "markdown", 13 | "file": "benchmarks.md", 14 | "title": "Hydrator benchmark report" 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Hydrator 2 | ======== 3 | 4 | Hydrator can be used for two purposes: 5 | 6 | - To extract data from a class to be further stored in a persistent storage. 7 | - To fill an object with data or create a new instance of a class filled with data. 8 | 9 | In both cases it is saving and filling protected and private properties without calling 10 | any methods which leads to ability to persist state of an object with properly encapsulated 11 | data. 12 | 13 | [![Latest Stable Version](https://poser.pugx.org/samdark/hydrator/v/stable.png)](https://packagist.org/packages/samdark/hydrator) 14 | [![Total Downloads](https://poser.pugx.org/samdark/hydrator/downloads.png)](https://packagist.org/packages/samdark/hydrator) 15 | [![Build Status](https://travis-ci.org/samdark/hydrator.svg?branch=master)](https://travis-ci.org/samdark/hydrator) 16 | 17 | 18 | ## Installation 19 | 20 | The preferred way to install this package is through [composer](http://getcomposer.org/download/). 21 | 22 | ``` 23 | composer require --prefer-dist samdark/hydrator 24 | ``` 25 | 26 | ## Usage 27 | 28 | Consider we have a `Post` entity which represents a blog post. It has a title and a text. A unique id is generated to 29 | identify it. 30 | 31 | ```php 32 | class Post 33 | { 34 | private $id; 35 | protected $title; 36 | protected $text; 37 | 38 | public function __construct($title, $text) 39 | { 40 | $this->id = uniqid('post_', true); 41 | $this->title = $title; 42 | $this->text = $text; 43 | } 44 | 45 | public function getId() 46 | { 47 | return $this->id; 48 | } 49 | 50 | public function getTitle() 51 | { 52 | return $this->title; 53 | } 54 | 55 | public function setTitle($title) 56 | { 57 | $this->title = $title; 58 | } 59 | 60 | public function getText() 61 | { 62 | return $this->text; 63 | } 64 | 65 | public function setText() 66 | { 67 | return $this->text; 68 | } 69 | } 70 | ``` 71 | 72 | Saving a post to database: 73 | 74 | ```php 75 | $post = new Post('First post', 'Hell, it is a first post.'); 76 | 77 | $postHydrator = new \samdark\hydrator\Hydrator([ 78 | 'id' => 'id', 79 | 'title' => 'title', 80 | 'text' => 'text', 81 | ]); 82 | 83 | $data = $postHydrator->extract($post); 84 | save_to_database($data); 85 | ``` 86 | 87 | Loading post from database: 88 | 89 | ```php 90 | 'id', 95 | 'title' => 'title', 96 | 'text' => 'text', 97 | ]); 98 | 99 | $post = $postHydrator->hydrate($data, Post::class); 100 | echo $post->getId(); 101 | ``` 102 | 103 | Filling existing post object with data: 104 | 105 | ```php 106 | $data = load_from_database(); 107 | 108 | $postHydrator = new \samdark\hydrator\Hydrator([ 109 | 'title' => 'title', 110 | 'text' => 'text', 111 | ]); 112 | 113 | $post = get_post(); 114 | $post = $postHydrator->hydrateInto($data, $post); 115 | echo $post->getTitle(); 116 | ``` 117 | --------------------------------------------------------------------------------