- π PHP >= 8.0
composer require dldash/data-transfer-object
- π Simple DTO
- π Value Objects
- π Nested DTO classes
- π Typed DTO arrays and collections
- π Partial update
- π Serialized name
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);
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);
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);
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);
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
}
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"}
composer test