hedgehoglab-engineering / php-declared-data
A set of data tools for PHP.
Installs: 545
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/hedgehoglab-engineering/php-declared-data
Requires
- php: ^8.2
- illuminate/support: ^9.1 || ^10.0
Requires (Dev)
- mockery/mockery: ^1.5
- netsells/code-standards-laravel: ^1.1
- phpunit/phpunit: ^10.0
README
This package provides attributes, contracts, and behaviors that simplify the creation and management of data classes in PHP applications.
In particular, it enables the use of sparse objects that can be hydrated from optional data submitted via PATCH requests in a RESTful API, allowing missing or nullable fields to be handled appropriately.
Table of Contents
Installation
Install the package via Composer:
composer require hedgehoglab-engineering/php-declared-data
Usage
Defining Data Classes
The easiest way to start to define a declared data object is to extend the AbstractDeclaredData class. Alternatively, you can compose your own using the provided contracts and traits. Then just define your properties in the constructor.
use HedgehoglabEngineering\DeclaredData\AbstractDeclaredData; class UserData extends AbstractDeclaredData { public function __construct( public string $name, public string $email, public int $age, ) { // } }
Interfaces
Interfaces define behaviors that can be implemented by data classes for different functionality.
ResolvableData
Implementing the ResolvableData interface allows a class to resolve its properties using the specified property type or a PHP 8 attribute.
use HedgehoglabEngineering\DeclaredData\Contracts\ResolvableData; class UserData extends AbstractDeclaredData implements ResolvableData { // ... }
LenientData
The LenientData interface allows the data object to ignore extra properties that are not defined in the class.
use HedgehoglabEngineering\DeclaredData\Contracts\LenientData; class UserData extends AbstractDeclaredData implements LenientData { // ... }
SparseData
The SparseData interface allows the data object to be instantiated without all required properties. The primary use case for this is transforming PATCH request data where missing properties without defaults may remain unset - i.e.: indicating that the field's value is not being modified.
use HedgehoglabEngineering\DeclaredData\Contracts\SparseData; class UserData extends AbstractDeclaredData implements SparseData { // ... }
Traits
Traits provide reusable functionality that can be applied to your data classes.
ArraysData
The ArraysData trait provides a toArray method to recursively convert a data instance into an array.
CollectsData
The CollectsData trait provides a static collect method which can convert an iterable value into a Illuminate\Support\Collection of instances of the defined class.
CreatesData
The CreatesData trait provides a static create method which can convert data into an instance of the defined class.
DeclaresData
The DeclaresData trait provides has, missing, only and except methods, which are useful for handling instances of declared data.
Attributes
The use of PHP attributes provides a mechanism for hinting how properties should be resolved.
CollectionOf
Transforms an array into an instance of Illuminate\Support\Collection containing instances of the specified class.
use HedgehoglabEngineering\DeclaredData\Attributes\CollectionOf; #[CollectionOf(class: PostData::class)] public readonly Collection $posts;
DateTimeFromFormat
Parses a date string into a DateTime object using a specified format and/or timezone.
use HedgehoglabEngineering\DeclaredData\Attributes\DateTimeFromFormat; #[DateTimeFromFormat(format: 'Y-m-d', timezone: 'UTC', toTimezone: 'America/New_York')] public readonly DateTimeInterface $publishedAt;
JsonDecode
Decodes a JSON string into a PHP array or object.
use HedgehoglabEngineering\DeclaredData\Attributes\JsonDecode; #[JsonDecode(associative: true)] public readonly array $settings;
MapArgumentName
Maps an input field name to a different property name in the data object.
use HedgehoglabEngineering\DeclaredData\Attributes\MapArgumentName; #[MapArgumentName(name: 'first_name')] public string $firstName;
Examples
Using Attributes in Data Classes
Here's an example of a data class using various attributes:
use HedgehoglabEngineering\DeclaredData\AbstractDeclaredData; use HedgehoglabEngineering\DeclaredData\Contracts\ResolvableData; use HedgehoglabEngineering\DeclaredData\Attributes\CollectionOf; use HedgehoglabEngineering\DeclaredData\Attributes\DateTimeFromFormat; use HedgehoglabEngineering\DeclaredData\Attributes\JsonDecode; use HedgehoglabEngineering\DeclaredData\Attributes\MapArgumentName; use Illuminate\Support\Collection; class PostData extends AbstractDeclaredData implements ResolvableData { public function __construct( #[MapArgumentName(name: 'post_title')] public string $title, #[DateTimeFromFormat('Y-m-d H:i:s')] public DateTimeInterface $createdAt, #[JsonDecode(associative: true)] public array $metadata, #[CollectionOf(class: CommentData::class)] public Collection $comments, ) { // } } $inputData = [ 'post_title' => 'Test Post', 'createdAt' => '2023-10-01 12:00:00', 'metadata' => '{"views": 100, "likes": 10}', 'comments' => [ ['content' => 'Great post!'], ], ]; $resolvedPostData = PostData::create($inputData);
Testing
composer test
Code Formatting
composer format
Code Analysing
composer analyse
Contributing
Contributions are welcome! Please submit a pull request or open an issue to discuss your ideas.