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-data
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 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.
use HedgehoglabEngineering\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.
use HedgehoglabEngineering\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.
use HedgehoglabEngineering\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.
use HedgehoglabEngineering\DeclaredData\Attributes\CollectionOf;
#[CollectionOf(class: PostData::class)]
public readonly Collection $posts;
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;
Decodes a JSON string into a PHP array or object.
use HedgehoglabEngineering\DeclaredData\Attributes\JsonDecode;
#[JsonDecode(associative: true)]
public readonly array $settings;
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;
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);
composer test
composer format
composer analyse
Contributions are welcome! Please submit a pull request or open an issue to discuss your ideas.