thoemo/dto (2.2.1)
Installation
{
"repositories": [{
"type": "composer",
"url": " "
}
]
}composer config repositories.thoemo composer composer require thoemo/dto:2.2.1About this package
thoemo/dto
Building blocks for data transfer objects that keep their state in a single array and read and
write it by dot path ("address.city"), using jasny/dotkey.
Requirements
- PHP >= 8.2
jasny/dotkey^2.2.0(installed with the package)
Installation
The package is served by the Forgejo Composer registry (no credentials needed). Add the repository
to your composer.json:
"repositories": {
"packages.link.thoemo.net/thoemo": {
"type": "composer",
"url": "https://packages.link.thoemo.net/api/packages/thoemo/composer"
}
}
Then:
composer require thoemo/dto
The namespace is Thoemo\DTO. Before 2.1 it was elnebuloso\DTO; update your use statements when upgrading.
Overview
| Type | Purpose |
|---|---|
AbstractReadDTO (class) |
Read-only DTO. Constructor takes the data array and merges it over getDefaults(). Implements ToArray and JsonSerializable. |
DTOReadTrait (trait) |
Adds protected array $data, protected fetchValue(string $path, mixed $default = null) and a public jsonSerialize() returning $data. |
DTOWriteTrait (trait) |
Includes DTOReadTrait and adds protected methods to change $data (below). |
ToArray (interface) |
toArray(): array. |
fetchValue() returns the value at the dot path, or $default if the path does not exist.
DTOWriteTrait methods, all protected and returning void:
| Method | Effect |
|---|---|
storeValue(string $path, mixed $value) |
Sets the value at $path, creating intermediate arrays. |
storeValues(string $path, array $values) |
Replaces the list at $path with $values. |
pushValue(string $path, mixed $value) |
Appends to the list at $path and re-indexes it. |
pushValues(string $path, array $values) |
Appends each value. |
incrementValue(string $path, int $number = 1) |
Adds $number (a missing value counts as 0). |
decrementValue(string $path, int $number = 1) |
Subtracts $number (a missing value counts as 0). |
removeValue(string $path) |
Removes the key at $path. |
copyValue(string $from, string $to, bool $allowEmpty = false) |
Copies the value. Does nothing if the source is empty(), unless $allowEmpty. |
moveValue(string $from, string $to, bool $moveEmpty = false) |
Copies, then removes the source. Does nothing if the source is empty(), unless $moveEmpty. |
Usage
Read DTO with defaults
use Thoemo\DTO\AbstractReadDTO;
final class UserDTO extends AbstractReadDTO
{
public function getId(): string
{
return $this->fetchValue("id");
}
public function getRole(): string
{
return $this->fetchValue("role");
}
public function getCity(): ?string
{
return $this->fetchValue("address.city");
}
protected function getDefaults(): array
{
return ["role" => "user"];
}
}
$user = new UserDTO(["id" => "42", "address" => ["city" => "Bonn"]]);
$user->getRole(); // "user"
$user->getCity(); // "Bonn"
$user->toArray(); // ["role" => "user", "id" => "42", "address" => ["city" => "Bonn"]]
json_encode($user); // same data as JSON
Defaults and data are combined with array_replace_recursive(): nested arrays are merged key by
key, and that includes numeric keys. A default list ["a", "b"] given the data ["c"] becomes
["c", "b"], not ["c"].
Writable entity
There is no abstract writable class; use DTOWriteTrait in your own class and fill $data
yourself:
use Thoemo\DTO\DTOWriteTrait;
use Thoemo\DTO\ToArray;
final class Article implements ToArray, JsonSerializable
{
use DTOWriteTrait;
public function __construct(array $data = [])
{
$this->data = $data;
}
public function rename(string $title): void
{
$this->storeValue("title", $title);
}
public function addTag(string $tag): void
{
$this->pushValue("tags", $tag);
}
public function registerView(): void
{
$this->incrementValue("stats.views");
}
public function toArray(): array
{
return $this->data;
}
public function jsonSerialize(): array
{
return $this->toArray();
}
}
Upgrading from 1.x
Version 1.x was published as elnebuloso/dto and contained AbstractDTO and
AbstractDTOBuilder. Both are gone in 2.0.
AbstractDTO → AbstractReadDTO:
- The public
getValue()is now the protectedfetchValue(). Expose values through your own getters. - The
protected array $defaultsproperty is now theprotected function getDefaults(): arraymethod. - Defaults are merged with
array_replace_recursive()instead ofarray_merge(), so nested arrays are merged instead of replaced. getValue()fell back to the value in$defaultsat the same path;fetchValue()only looks at$data(defaults reach it through the constructor).- New
toArray();jsonSerialize()returns the same array.
AbstractDTOBuilder → DTOWriteTrait in your own class (see above). The methods are now
protected, return void instead of $this, and some were renamed:
1.x AbstractDTOBuilder |
2.x DTOWriteTrait |
|---|---|
getValue() |
fetchValue() |
setValue() |
storeValue() |
setValues() |
storeValues() |
addValue() |
pushValue() |
addValues() |
pushValues() |
delValue() |
removeValue() |
copyValue() |
copyValue() |
moveValue() |
moveValue() |
The builder took a JsonSerializable in its constructor; with the trait you set $this->data
yourself.
Coming from thoemo/traits
thoemo/traits up to 1.4.x had its own DTOReadTrait and DTOWriteTrait (namespace
elnebuloso\Traits). The versions here differ:
- Namespace
elnebuloso\Traits→Thoemo\DTO. DTOReadTrait(and with itDTOWriteTrait) providesjsonSerialize()returning the raw data, as before; since 2.2. In 2.0 and 2.1 it was missing.incrementValue()anddecrementValue()take an optional$number(default1).copyValue()andmoveValue()are new.
Development
Tests and tools run in Docker through redo; build.yml holds the project's redo properties.
redo composer:install phpunit # tests on PHP 8.2 (php_version in build.yml)
redo composer:install phpunit -Dphp_version=8.4 # tests on another PHP version
redo commit # clean:dist, prettier:fix, phplint, phpunit, composer:validate:require
Releases
Every push to main runs the GitLab pipeline: phplint, composer:validate:require and phpunit
on PHP 8.2 to 8.5. It then raises the patch version in VERSION and uploads that version to the
Forgejo registry. Only README.md, composer.json and src/ are part of the released archive.
Dependencies
Dependencies
| ID | Version |
|---|---|
| jasny/dotkey | ^2.2.0 |
| php | >=8.2 |