Data Transfer Objects (DTOs) are objects that are used to transfer data between systems. DTOs are typically used in applications to provide a simple, consistent format for transferring data between different parts of the application, such as between the user interface and the business logic.
composer require horizom/dto
use Horizom\DTO\DTO;
class UserDTO extends DTO
{
public string $name;
public string $email;
public string $password;
}
You can create a DTO
instance on many ways:
$dto = new UserDTO([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'password' => 's3CreT!@1a2B'
]);
You can also use the fromArray
static method:
$dto = UserDTO::fromArray([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'password' => 's3CreT!@1a2B'
]);
$dto = UserDTO::fromJson('{"name": "John Doe", "email": "john.doe@example.com", "password": "s3CreT!@1a2B"}');
After you create your DTO
instance, you can access any properties like an object
:
$dto = new UserDTO([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'password' => 's3CreT!@1a2B'
]);
$dto->name; // 'John Doe'
$dto->email; // 'john.doe@example.com'
$dto->password; // 's3CreT!@1a2B'
You can cast your DTO
properties to some types:
use App\Enums\UserRole;
use Carbon\Carbon;
use Horizom\DTO\DTO;
use DateTimeImmutable;
use Horizom\DTO\Casting\ArrayCast;
use Horizom\DTO\Casting\EnumCast;
class UserDTO extends DTO
{
public string $id;
public string $name;
public string $email;
public string $password;
public Carbon $created_at;
public DateTimeImmutable $updated_at;
public array $roles;
protected function casts()
{
return [
'id' => 'integer',
'name' => 'string',
'email' => 'string',
'password' => 'string',
'created_at' => Carbon::class,
'updated_at' => DateTimeImmutable::class,
'admin_role' => UserRole::class,
'roles' => new ArrayCast(new EnumCast(UserRole::class)),
];
}
}
Sometimes we can have properties that are optional and that can have default values. You can define the default values for your DTO
properties in the defaults
function:
use Horizom\DTO\DTO;
use Illuminate\Support\Str;
class UserDTO extends DTO
{
// ...
protected function defaults()
{
return [
'username' => Str::slug($this->name),
];
}
}
With the DTO
definition above you could run:
$dto = new UserDTO([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'password' => 's3CreT!@1a2B'
]);
$dto->username; // 'john_doe'
You can convert your DTO to some formats:
$dto = new UserDTO([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'password' => 's3CreT!@1a2B',
]);
$dto->toArray();
// [
// "name" => "John Doe",
// "email" => "john.doe@example.com",
// "password" => "s3CreT!@1a2B",
// ]
$dto = new UserDTO([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
'password' => 's3CreT!@1a2B',
]);
$dto->toJson();
// '{"name":"John Doe","email":"john.doe@example.com","password":"s3CreT!@1a2B"}'
You can easily create new Castable
types for your project by implementing the Horizom\DTO\Contracts\CastableContract
interface. This interface has a single method that must be implemented:
public function cast(string $property, mixed $value): mixed;
Let's say that you have a URLWrapper
class in your project, and you want that when passing a URL into your DTO
it will always return a URLWrapper
instance instead of a simple string:
use Horizom\DTO\Contracts\CastableContract;
class URLCast implements CastableContract
{
public function cast(string $property, mixed $value): URLWrapper
{
return new URLWrapper($value);
}
}
Then you could apply this to your DTO:
use Horizom\DTO\DTO;
class CustomDTO extends DTO
{
protected function casts()
{
return [
'url' => new URLCast(),
];
}
protected function defaults()
{
return [];
}
}
You can also create new Castable types for your project by using a callable/callback:
use Horizom\DTO\DTO;
class CustomDTO extends DTO
{
protected function casts(): array
{
return [
'url' => function (string $property, mixed $value) {
return new URLWrapper($value);
},
];
}
protected function defaults(): array
{
return [];
}
}
Or you can use a static method:
use Horizom\DTO\Casting\Cast;
use Horizom\DTO\DTO;
class CustomDTO extends DTO
{
protected function casts()
{
return [
'url' => Cast::make(
function (string $property, mixed $value) {
return new URLWrapper($value);
},
function (string $property, URLWrapper $value) {
return $value->toString();
}
)
];
}
protected function defaults()
{
return [];
}
}
You can extend the DTO
class to create your own DTO
class with some custom methods:
use App\Http\Resources\UserResource;
use Horizom\DTO\DTO;
use Illuminate\Database\Eloquent\Model;
class UserDTO extends DTO
{
public int $id;
public string $name;
public string $email;
public string $password;
public Carbon $created_at;
public CarbonImmutable $updated_at;
public DateTimeImmutable $verified_at;
public static function fromModel(Model $model) {
return new self($model->toArray());
}
public function toModel() {
return new Model($this->toArray());
}
public function toResource() {
return new UserResource($this->toArray());
}
protected function casts()
{
return [
'id' => 'integer',
'name' => 'string',
'email' => 'string',
'password' => 'string',
'created_at' => Carbon::class,
'updated_at' => CarbonImmutable::class,
'verified_at' => DateTimeImmutable::class,
];
}
}
The MIT License (MIT). Please see License File for more information.