├── LICENSE ├── README.md ├── composer.json ├── phpstan.neon ├── pint.json ├── src ├── Console │ └── Commands │ │ └── DataTransferObjectMakeCommand.php ├── Contracts │ ├── DataObjectContract.php │ └── HydratorContract.php ├── Facades │ └── Hydrator.php ├── Hydrator │ └── Hydrate.php └── Providers │ └── PackageServiceProvider.php └── stubs ├── dto-82.stub └── dto.stub /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Steve McDougall 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Data Object Tools 2 | 3 | 4 | [![Latest Version][badge-release]][packagist] 5 | [![PHP Version][badge-php]][php] 6 | [![Tests][badge-tests]][tests] 7 | [![Total Downloads][badge-downloads]][downloads] 8 | 9 | [badge-tests]: https://github.com/juststeveking/laravel-data-object-tools/actions/workflows/test.yml/badge.svg 10 | [badge-release]: https://img.shields.io/packagist/v/juststeveking/laravel-data-object-tools.svg?style=flat-square&label=release 11 | [badge-php]: https://img.shields.io/packagist/php-v/juststeveking/laravel-data-object-tools.svg?style=flat-square 12 | [badge-downloads]: https://img.shields.io/packagist/dt/juststeveking/laravel-data-object-tools.svg?style=flat-square&colorB=mediumvioletred 13 | 14 | [packagist]: https://packagist.org/packages/juststeveking/laravel-data-object-tools 15 | [php]: https://php.net 16 | [downloads]: https://packagist.org/packages/juststeveking/laravel-data-object-tools 17 | [tests]: https://github.com/juststeveking/laravel-data-object-tools/actions/workflows/test.yml 18 | 19 | 20 | This package is aimed to be a suite of tools to help working with DTOs even easier. 21 | It includes an artisan command to generate DTOs as well as a facade to help you hydrate them. 22 | 23 | ## Installation 24 | 25 | ```bash 26 | composer require juststeveking/laravel-data-object-tools 27 | ``` 28 | 29 | ## Usage 30 | 31 | To generate a new DTO all you need to do is run the following artisan command: 32 | 33 | ```bash 34 | php artisan make:dto MyDto 35 | ``` 36 | 37 | This will generate the following class: `app/DataObjects/MyDto.php`. By default this class 38 | will be a `final` class that implements a `DataObjectContract` which enforces a method `toArray` so that you can 39 | easily cast your DTOs to arrays. 40 | 41 | If you are using PHP 8.2 however, you will by default get a `readonly` class generated, so that you do not have 42 | to declare each property as readonly. 43 | 44 | To work with the hydration functionality you can either use Laravels DI container, or the ready made facade. 45 | 46 | Using the container: 47 | 48 | ```php 49 | class StoreController 50 | { 51 | public function __construct( 52 | private readonly HydratorContract $hydrator, 53 | ) {} 54 | 55 | public function __invoke(StoreRequest $request) 56 | { 57 | $model = Model::query()->create( 58 | attributes: $this->hydrator->fill( 59 | class: ModelObject::class, 60 | parameters: $request->validated(), 61 | )->toArray(), 62 | ); 63 | } 64 | } 65 | ``` 66 | 67 | To work with the facade, you can do something very similar: 68 | 69 | ```php 70 | class StoreController 71 | { 72 | public function __invoke(StoreRequest $request) 73 | { 74 | $model = Model::query()->create( 75 | attributes: Hydrator::fill( 76 | class: ModelObject::class, 77 | parameters: $request->validated(), 78 | )->toArray(), 79 | ); 80 | } 81 | } 82 | ``` 83 | 84 | ## Object Hydration 85 | 86 | Under the hood this package uses an [EventSauce](https://eventsauce.io) package, created by [Frank de Jonge](https://twitter.com/frankdejonge). It is possibly the 87 | best package I have found to hydrate objects nicely in PHP. You can find the [documentation here](https://github.com/EventSaucePHP/ObjectHydrator) 88 | if you would like to see what else you are able to do with the package to suit your needs. 89 | 90 | ## Testing 91 | 92 | To run the test suite: 93 | 94 | ```bash 95 | composer run test 96 | ``` 97 | 98 | ## Credits 99 | 100 | - [Steve McDougall](https://github.com/JustSteveKing) 101 | - [All Contributors](../../contributors) 102 | 103 | ## LICENSE 104 | 105 | The MIT License (MIT). Please see [License File](./LICENSE) for more information. 106 | 107 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "juststeveking/laravel-data-object-tools", 3 | "description": "A set of tools to make working with Data Transfer Objects easier in Laravel", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "role": "Developer", 9 | "name": "Steve McDougall", 10 | "email": "juststevemcd@gmail.com", 11 | "homepage": "https://www.juststeveking.uk/" 12 | } 13 | ], 14 | "autoload": { 15 | "psr-4": { 16 | "JustSteveKing\\DataObjects\\": "src/" 17 | } 18 | }, 19 | "autoload-dev": { 20 | "psr-4": { 21 | "JustSteveKing\\DataObjects\\Tests\\": "tests/" 22 | } 23 | }, 24 | "require": { 25 | "php": "^8.1", 26 | "eventsauce/object-hydrator": "^0.4.3", 27 | "illuminate/contracts": "^9.22|^10.0|^11.0", 28 | "illuminate/support": "^9.22|^10.0|^11.0" 29 | }, 30 | "scripts": { 31 | "test": "./vendor/bin/pest", 32 | "fix": "./vendor/bin/pint", 33 | "check": "./vendor/bin/pint --test -v", 34 | "static": "./vendor/bin/phpstan analyse", 35 | "all": [ 36 | "@test", 37 | "@fix", 38 | "@check", 39 | "@static" 40 | ] 41 | }, 42 | "extra": { 43 | "laravel": { 44 | "providers": [ 45 | "JustSteveKing\\DataObjects\\Providers\\PackageServiceProvider" 46 | ], 47 | "aliases": [ 48 | "JustSteveKing\\DataObjects\\Facades\\Hydrator" 49 | ] 50 | } 51 | }, 52 | "minimum-stability": "dev", 53 | "prefer-stable": true, 54 | "config": { 55 | "sort-packages": true, 56 | "preferred-install": "dist", 57 | "optimize-autoloader": true, 58 | "allow-plugins": { 59 | "pestphp/pest-plugin": true 60 | } 61 | }, 62 | "require-dev": { 63 | "laravel/pint": "^1.1", 64 | "orchestra/testbench": "^7.6", 65 | "pestphp/pest": "^1.21", 66 | "phpstan/phpstan": "^1.8" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 9 3 | 4 | paths: 5 | - src 6 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "psr12" 3 | } 4 | -------------------------------------------------------------------------------- /src/Console/Commands/DataTransferObjectMakeCommand.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | public function toArray(): array; 13 | } 14 | -------------------------------------------------------------------------------- /src/Contracts/HydratorContract.php: -------------------------------------------------------------------------------- 1 | $class 11 | * @param array $properties 12 | * @return DataObjectContract 13 | */ 14 | public function fill(string $class, array $properties): DataObjectContract; 15 | } 16 | -------------------------------------------------------------------------------- /src/Facades/Hydrator.php: -------------------------------------------------------------------------------- 1 | $class 23 | * @param array $properties 24 | * @return DataObjectContract 25 | */ 26 | public function fill(string $class, array $properties): DataObjectContract 27 | { 28 | return $this->mapper->hydrateObject( 29 | className: $class, 30 | payload: $properties, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Providers/PackageServiceProvider.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | public array $bindings = [ 18 | HydratorContract::class => Hydrate::class, 19 | ]; 20 | 21 | /** 22 | * @return void 23 | */ 24 | public function boot(): void 25 | { 26 | if ($this->app->runningInConsole()) { 27 | $this->commands( 28 | commands: [ 29 | DataTransferObjectMakeCommand::class, 30 | ], 31 | ); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /stubs/dto-82.stub: -------------------------------------------------------------------------------- 1 |