├── src ├── Makes.php ├── Mappers │ ├── CannotMap.php │ ├── ObjectMapper.php │ ├── MakesMapper.php │ ├── ArrayMapper.php │ ├── FileMapper.php │ ├── JsonMapper.php │ └── XmlMapper.php ├── functions.php ├── Serializer.php └── Factory.php ├── CHANGELOG.md ├── LICENSE.md ├── composer.json └── README.md /src/Makes.php: -------------------------------------------------------------------------------- 1 | $className 11 | * @return \Brendt\Make\Factory 12 | */ 13 | function make(string $className): Factory 14 | { 15 | return Factory::make($className); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Mappers/ObjectMapper.php: -------------------------------------------------------------------------------- 1 | factory->from((array) $input); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Mappers/MakesMapper.php: -------------------------------------------------------------------------------- 1 | factory->from($input->data()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Mappers/ArrayMapper.php: -------------------------------------------------------------------------------- 1 | serializer->denormalize($input, $this->className); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Mappers/FileMapper.php: -------------------------------------------------------------------------------- 1 | factory->from(file_get_contents($input)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Mappers/JsonMapper.php: -------------------------------------------------------------------------------- 1 | serializer->deserialize($input, $this->className, 'json'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Mappers/XmlMapper.php: -------------------------------------------------------------------------------- 1 | ') 22 | ) { 23 | throw new CannotMap("Not a valid XML string"); 24 | } 25 | 26 | return $this->serializer->deserialize($input, $this->className, 'xml'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) stitcher.io 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brendt/php-make-object", 3 | "description": "Simple wrapper for symfony/serializer for the 90% use-case", 4 | "keywords": [ 5 | "brendt", 6 | "php-make-object" 7 | ], 8 | "homepage": "https://github.com/brendt/php-make-object", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Brent Roose", 13 | "email": "brendt@stitcher.io", 14 | "role": "Developer" 15 | } 16 | ], 17 | "require": { 18 | "php": "^8.1", 19 | "illuminate/collections": "^9.42", 20 | "phpdocumentor/reflection-docblock": "^5.3", 21 | "symfony/property-access": "^6.0", 22 | "symfony/serializer": "^6.0", 23 | "symfony/validator": "^6.2" 24 | }, 25 | "require-dev": { 26 | "friendsofphp/php-cs-fixer": "^3.0", 27 | "larapack/dd": "^1.1", 28 | "phpunit/phpunit": "^9.5" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Brendt\\Make\\": "src" 33 | }, 34 | "files" : [ 35 | "src/functions.php" 36 | ] 37 | }, 38 | "autoload-dev": { 39 | "psr-4": { 40 | "Brendt\\Make\\Tests\\": "tests" 41 | } 42 | }, 43 | "scripts": { 44 | "test": "vendor/bin/pest", 45 | "test-coverage": "vendor/bin/pest --coverage", 46 | "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes" 47 | }, 48 | "config": { 49 | "sort-packages": true 50 | }, 51 | "minimum-stability": "dev", 52 | "prefer-stable": true 53 | } 54 | -------------------------------------------------------------------------------- /src/Serializer.php: -------------------------------------------------------------------------------- 1 | className = $className; 34 | 35 | $this->serializer = Serializer::make(); 36 | 37 | $this 38 | ->addMapper(new MakesMapper($this)) 39 | ->addMapper(new FileMapper($this)) 40 | ->addMapper(new ArrayMapper($this->serializer, $this->className)) 41 | ->addMapper(new JsonMapper($this->serializer, $this->className)) 42 | ->addMapper(new XmlMapper($this->serializer, $this->className)) 43 | ->addMapper(new ObjectMapper($this)); 44 | } 45 | 46 | /** 47 | * @param class-string $className 48 | * 49 | * @return self 50 | */ 51 | public static function make(string $className): self 52 | { 53 | return new self($className); 54 | } 55 | 56 | /** 57 | * @return ClassType 58 | */ 59 | public function from(mixed $input): object 60 | { 61 | foreach ($this->mappers as $mapper) { 62 | try { 63 | return $mapper($input); 64 | } catch (TypeError|CannotMap) { 65 | continue; 66 | } 67 | } 68 | 69 | throw new Exception("No mapper found for {$input}"); 70 | } 71 | 72 | /** 73 | * @param array $input 74 | * @return \Illuminate\Support\Collection 75 | */ 76 | public function fromCollection(array $input): Collection 77 | { 78 | return collect($input)->map(fn (mixed $input) => $this->from($input)); 79 | } 80 | 81 | public function addMapper(callable $mapper): self 82 | { 83 | $this->mappers[] = $mapper; 84 | 85 | return $this; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple wrapper for symfony/serializer for the 90% use-case 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/brendt/php-make-object.svg?style=flat-square)](https://packagist.org/packages/brendt/php-make-object) 4 | [![Tests](https://github.com/brendt/php-make-object/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/brendt/php-make-object/actions/workflows/run-tests.yml) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/brendt/php-make-object.svg?style=flat-square)](https://packagist.org/packages/brendt/php-make-object) 6 | 7 | Write this: 8 | 9 | ```php 10 | $post = make(Post::class)->from($postData); 11 | ``` 12 | 13 | instead of this: 14 | 15 | ```php 16 | $reflectionExtractor = new ReflectionExtractor(); 17 | 18 | $phpDocExtractor = new PhpDocExtractor(); 19 | 20 | $propertyTypeExtractor = new PropertyInfoExtractor( 21 | listExtractors: [$reflectionExtractor], 22 | typeExtractors: [$phpDocExtractor, $reflectionExtractor], 23 | descriptionExtractors: [$phpDocExtractor], 24 | accessExtractors: [$reflectionExtractor], 25 | initializableExtractors: [$reflectionExtractor] 26 | ); 27 | 28 | $normalizer = new ObjectNormalizer( 29 | propertyTypeExtractor: $propertyTypeExtractor 30 | ); 31 | 32 | $arrayNormalizer = new ArrayDenormalizer(); 33 | 34 | $serializer = new SymfonySerializer( 35 | normalizers: [ 36 | $arrayNormalizer, 37 | $normalizer, 38 | ], 39 | encoders: [ 40 | new XmlEncoder(), 41 | new JsonEncoder(), 42 | ], 43 | ); 44 | 45 | $post = $serializer->denormalize($postData, Post::class) 46 | ``` 47 | 48 | ## Installation 49 | 50 | You can install the package via composer: 51 | 52 | ```bash 53 | composer require brendt/php-make-object 54 | ``` 55 | 56 | ## Usage 57 | 58 | This package abstracts away all configuration needed for complex deserialization with [symfony/serializer](https://symfony.com/doc/current/components/serializer.html). All you need to do is say which class you want to make, provide it some input (arrays, JSON, XML, files or objects), and this package will take care of the rest. 59 | 60 | Added bonus: proper static analysis, so you'll know what kind of object was created. 61 | 62 | ```php 63 | $post = make(Post::class)->from($postData); 64 | ``` 65 | 66 | ### Input types 67 | 68 | #### Arrays 69 | 70 | ```php 71 | $post = make(Post::class)->from([ 72 | 'title' => 'test', 73 | ]); 74 | ``` 75 | 76 | #### JSON 77 | 78 | ```php 79 | $post = make(Post::class)->from(<<from(<< 91 | test 92 | 93 | XML); 94 | ``` 95 | 96 | #### Files 97 | 98 | ```php 99 | $post = make(Post::class)->from(__DIR__ . '/post.json'); 100 | ``` 101 | 102 | #### The `Make` interface 103 | 104 | The `Make` interface can be added on any class, allowing that class to provide data that can be used to create an object. 105 | 106 | ```php 107 | $post = make(Post::class)->from(new PostRequest()); 108 | ``` 109 | 110 | ```php 111 | final class PostRequest implements Makes 112 | { 113 | public function data(): array 114 | { 115 | return [ 116 | 'title' => 'test', 117 | ]; 118 | } 119 | } 120 | ``` 121 | 122 | #### Collections 123 | 124 | ```php 125 | $posts = make(Post::class)->fromCollection([ 126 | ['title' => 'a'], 127 | ['title' => 'b'], 128 | ['title' => 'c'], 129 | ]); 130 | ``` 131 | 132 | ## Changelog 133 | 134 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 135 | 136 | ## Contributing 137 | 138 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 139 | 140 | ## Credits 141 | 142 | - [Brent Roose](https://github.com/brendt) 143 | 144 | ## License 145 | 146 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 147 | --------------------------------------------------------------------------------