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.
Install the package via Composer:
composer require hedgehoglab-engineering/php-declared-dataThe 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.
useHedgehoglabEngineering\DeclaredData\AbstractDeclaredData;
class UserData extends AbstractDeclaredData
{
publicfunction__construct(
publicstring$name,
publicstring$email,
publicint$age,
) {
//
}
}Interfaces define behaviors that can be implemented by data classes for different functionality.
Implementing the ResolvableData interface allows a class to resolve its properties using the specified property type or a PHP 8 attribute.
useHedgehoglabEngineering\DeclaredData\Contracts\ResolvableData;
class UserData extends AbstractDeclaredData implements ResolvableData
{
// ...
}The LenientData interface allows the data object to ignore extra properties that are not defined in the class.
useHedgehoglabEngineering\DeclaredData\Contracts\LenientData;
class UserData extends AbstractDeclaredData implements LenientData
{
// ...
}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.
useHedgehoglabEngineering\DeclaredData\Contracts\SparseData;
class UserData extends AbstractDeclaredData implements SparseData
{
// ...
}Traits provide reusable functionality that can be applied to your data classes.
The ArraysData trait provides a toArray method to recursively convert a data instance into an array.
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.
The CreatesData trait provides a static create method which can convert data into an instance of the defined class.
The DeclaresData trait provides has, missing, only and except methods, which are useful for handling instances of declared data.
The use of PHP attributes provides a mechanism for hinting how properties should be resolved.
Transforms an array into an instance of Illuminate\Support\Collection containing instances of the specified class.
useHedgehoglabEngineering\DeclaredData\Attributes\CollectionOf;
#[CollectionOf(class: PostData::class)]
publicreadonly Collection $posts;Parses a date string into a DateTime object using a specified format and/or timezone.
useHedgehoglabEngineering\DeclaredData\Attributes\DateTimeFromFormat;
#[DateTimeFromFormat(format: 'Y-m-d', timezone: 'UTC', toTimezone: 'America/New_York')]
publicreadonly DateTimeInterface $publishedAt;Decodes a JSON string into a PHP array or object.
useHedgehoglabEngineering\DeclaredData\Attributes\JsonDecode;
#[JsonDecode(associative: true)]
publicreadonly array $settings;Maps an input field name to a different property name in the data object.
useHedgehoglabEngineering\DeclaredData\Attributes\MapArgumentName;
#[MapArgumentName(name: 'first_name')]
public string $firstName;Here's an example of a data class using various attributes:
useHedgehoglabEngineering\DeclaredData\AbstractDeclaredData;
useHedgehoglabEngineering\DeclaredData\Contracts\ResolvableData;
useHedgehoglabEngineering\DeclaredData\Attributes\CollectionOf;
useHedgehoglabEngineering\DeclaredData\Attributes\DateTimeFromFormat;
useHedgehoglabEngineering\DeclaredData\Attributes\JsonDecode;
useHedgehoglabEngineering\DeclaredData\Attributes\MapArgumentName;
useIlluminate\Support\Collection;
class PostData extends AbstractDeclaredData implements ResolvableData
{
publicfunction__construct(
#[MapArgumentName(name: 'post_title')]
publicstring$title,
#[DateTimeFromFormat('Y-m-d H:i:s')]
publicDateTimeInterface$createdAt,
#[JsonDecode(associative: true)]
publicarray$metadata,
#[CollectionOf(class: CommentData::class)]
publicCollection$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);composer testcomposer formatcomposer analyseContributions are welcome! Please submit a pull request or open an issue to discuss your ideas.