dldash / data-transfer-object
Data transfer objects.
Requires
- php: ^8.0
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^9.0
README
⚡️ Requirements
- 🐘 PHP >= 8.0
💥 Installation
composer require dldash/data-transfer-object
✨ Usage
- 👉 Simple DTO
- 👉 Value Objects
- 👉 Nested DTO classes
- 👉 Typed DTO arrays and collections
- 👉 Partial update
- 👉 Serialized name
Simple DTO
If extra fields are passed that are not described in the DTO class, they will be ignored.
DTO class:
use Dldash\DataTransferObject\Models\DataTransferObject; class UserDto extends DataTransferObject { public function __construct( public int $userId, public string|null $username ) {} }
Usage:
$request = [ 'userId' => 100, 'username' => 'admin', 'emailAddress' => 'admin@test.com' ]; $dto = UserDto::create($request);
Value Objects
You can also use value objects in DTO classes.
All you need is to implement the ValueObjectContract
interface.
Value object class:
use Dldash\DataTransferObject\Contracts\ValueObjectContract; class EmailAddress implements ValueObjectContract, JsonSerializable { public function __construct(private string $value) { if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException("Email address [${value}] is not valid."); } $this->value = strtolower($value); } public function value(): string { return $this->value; } public function jsonSerialize(): string { return $this->value; } }
DTO class:
use Dldash\DataTransferObject\Models\DataTransferObject; class OrderDto extends DataTransferObject { public function __construct( public int $orderId, public EmailAddress $emailAddress ) {} }
Usage:
$request = [ 'orderId' => 100, 'emailAddress' => 'admin@test.com' ]; $dto = OrderDto::create($request);
Nested DTO classes
DTO class:
use Dldash\DataTransferObject\Models\DataTransferObject; class OrderDto extends DataTransferObject { public function __construct( public int $orderId, public UserDto $user ) {} }
Usage:
$request = [ 'orderId' => 100, 'user' => [ 'userId' => 100, 'username' => 'admin' ] ]; $dto = OrderDto::create($request);
Typed DTO arrays and collections
You can use arrays of DTO objects.
To do this, you need to inherit the abstract DataTransferObjectCollection
class.
Collection class:
use Dldash\DataTransferObject\Objects\DataTransferObjectCollection; /** @method ArrayIterator|UserDto[] getIterator() */ class UserDtoCollection extends DataTransferObjectCollection { protected function create(mixed $item): object { return UserDto::create($item); } }
DTO class:
use Dldash\DataTransferObject\Models\DataTransferObject; class OrderDto extends DataTransferObject { public function __construct( public int $orderId, public UserDtoCollection $users ) {} }
Usage:
$request = [ 'orderId' => 100, 'users' => [ [ 'userId' => 100, 'username' => 'admin' ], [ 'userId' => 200, 'username' => null ] ] ]; $dto = OrderDto::create($request);
Partial update
Let's imagine that we need to update some model, but we want to do a partial update.
In this case, not all the required fields can be passed to the DTO class.
You can add the Undefined
type to the desired field.
NOTE: If you pass a null
value, it will also be null
.
DTO class:
use Dldash\DataTransferObject\Objects\Undefined; use Dldash\DataTransferObject\Models\DataTransferObject; class OrderDto extends DataTransferObject { public function __construct( public int $orderId, public string|null|Undefined $name ) {} }
Usage:
use Dldash\DataTransferObject\Objects\Undefined; $request = [ 'orderId' => 100 ]; $dto = OrderDto::create($request); if (Undefined::isPresent($dto->name)) { // Update this field }
Serialized name
DTO class:
use Dldash\DataTransferObject\Attributes\SerializedName; use Dldash\DataTransferObject\Models\DataTransferObject; class OrderDto extends DataTransferObject { public function __construct( #[SerializedName('order_id')] public int $id, #[SerializedName('order_name')] public string $name ) {} }
Usage:
$request = [ 'order_id' => 100, 'order_name' => 'Order' ]; $dto = OrderDto::create($request); echo $dto->id; // 100 echo $dto->name; // Order echo json_encode($dto); // {"order_id": 100, "order_name": "Order"}
💫 Testing
composer test