Skip to content

Creating Dtos

Learn all the different ways to create Dto instances in SimpleDto.

SimpleDto provides multiple ways to create instances:

MethodUse CaseExample
fromArray()From associative arrayUserDto::fromArray($data)
fromJson()From JSON stringUserDto::fromJson($json)
fromRequest()From HTTP request (Laravel)UserDto::fromRequest($request)
fromModel()From Eloquent model (Laravel)UserDto::fromModel($user)
fromEntity()From Doctrine entity (Symfony)UserDto::fromEntity($user)
fromXml()From XML stringUserDto::fromXml($xml)
fromYaml()From YAML stringUserDto::fromYaml($yaml)
fromCsv()From CSV stringUserDto::fromCsv($csv)
validateAndCreate()With validationUserDto::validateAndCreate($data)
newDirect instantiationnew UserDto(...)
use Tests\Utils\Docu\Dtos\UserDto;
$dto = UserDto::fromArray([
'name' => 'John Doe',
'email' => 'john@example.com',
'age' => 30,
]);
// Result: UserDto instance
use Tests\Utils\Docu\Dtos\UserDto;
$dto = UserDto::fromArray([
'name' => 'John Doe',
'email' => 'john@example.com',
'address' => [
'street' => '123 Main St',
'city' => 'New York',
'country' => 'USA',
],
]);
// Result: UserDto instance with nested address array
use Tests\Utils\Docu\Dtos\UserDto;
// Extra keys are automatically ignored
$dto = UserDto::fromArray([
'name' => 'John Doe',
'email' => 'john@example.com',
'age' => 30,
'extra_field' => 'ignored', // Ignored
'another_field' => 'ignored', // Ignored
]);
// Result: UserDto instance (extra fields ignored)
use Tests\Utils\Docu\Dtos\UserDto;
$json = '{"name":"John Doe","email":"john@example.com","age":30}';
$dto = UserDto::fromJson($json);
// Result: UserDto instance
$json = file_get_contents('user.json');
$dto = UserDto::fromJson($json);
use Tests\Utils\Docu\Dtos\UserDto;
$json = '{
"name": "John Doe",
"email": "john@example.com",
"address": {
"street": "123 Main St",
"city": "New York"
}
}';
$dto = UserDto::fromJson($json);
// Result: UserDto instance with nested address
use Illuminate\Http\Request;
class UserController extends Controller
{
public function store(Request $request)
{
$dto = UserDto::fromRequest($request);
// Or with validation
$dto = UserDto::validateAndCreate($request->all());
}
}
use Symfony\Component\HttpFoundation\Request;
class UserController
{
public function store(Request $request)
{
$dto = UserDto::fromArray($request->request->all());
}
}
// From $_POST
$dto = UserDto::fromArray($_POST);
// From $_GET
$dto = UserDto::fromArray($_GET);
// From php://input
$json = file_get_contents('php://input');
$dto = UserDto::fromJson($json);
use App\Models\User;
// From single model
$user = User::find(1);
$dto = UserDto::fromModel($user);
// From collection
$users = User::all();
$dtos = $users->map(fn($user) => UserDto::fromModel($user));
// Or use DataCollection
$dtos = DataCollection::make($users, UserDto::class);
use App\Entity\User;
// From single entity
$user = $entityManager->find(User::class, 1);
$dto = UserDto::fromEntity($user);
// From multiple entities
$users = $repository->findAll();
$dtos = array_map(
fn($user) => UserDto::fromEntity($user),
$users
);
// Or use DataCollection
$dtos = DataCollection::make($users, UserDto::class);
use Tests\Utils\Docu\Dtos\UserDto;
$xml = '<?xml version="1.0"?>
<user>
<name>John Doe</name>
<email>john@example.com</email>
<age>30</age>
</user>';
$dto = UserDto::fromXml($xml);
$xml = file_get_contents('user.xml');
$dto = UserDto::fromXml($xml);
$yaml = '
name: John Doe
email: john@example.com
age: 30
';
$dto = UserDto::fromYaml($yaml);
$yaml = file_get_contents('user.yaml');
$dto = UserDto::fromYaml($yaml);
use Tests\Utils\Docu\Dtos\UserDto;
$csv = '"name","email","age"
"John Doe","john@example.com",30';
$dto = UserDto::fromCsv($csv);
// Result: UserDto instance with auto-casted types
$csv = file_get_contents('user.csv');
$dto = UserDto::fromCsv($csv);
use event4u\DataHelpers\SimpleDto\Attributes\Required;
use event4u\DataHelpers\SimpleDto\Attributes\Email;
class UserDto extends SimpleDto
{
public function __construct(
#[Required]
public readonly string $name,
#[Required, Email]
public readonly string $email,
) {}
}
// Validates automatically
$dto = UserDto::validateAndCreate([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
// Throws ValidationException if invalid
try {
$dto = UserDto::validateAndCreate([
'name' => '', // ❌ Required
'email' => 'invalid', // ❌ Invalid email
]);
} catch (ValidationException $e) {
echo $e->getMessage();
}
use Tests\Utils\Docu\Dtos\UserDto;
$dto = new UserDto(
name: 'John Doe',
email: 'john@example.com',
age: 30
);
use Tests\Utils\Docu\Dtos\UserDto;
// ✅ Good - clear and explicit
$dto = new UserDto(
name: 'John Doe',
email: 'john@example.com',
age: 30
);
// ❌ Bad - unclear order
$dto = new UserDto('John Doe', 'john@example.com', 30);
use Tests\Utils\Docu\Dtos\UserDto;
$dto1 = UserDto::fromArray([
'name' => 'John Doe',
'email' => 'john@example.com',
'age' => 30,
]);
// Create new Dto with modified values
$dto2 = new UserDto(
name: 'Jane Doe', // Changed
email: $dto1->email,
age: $dto1->age
);
class UserDto extends SimpleDto
{
public function __construct(
public readonly string $name,
public readonly string $email,
) {}
}
class UserResourceDto extends SimpleDto
{
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly string $createdAt,
) {}
public static function fromUserDto(UserDto $user): self
{
return new self(
name: $user->name,
email: $user->email,
createdAt: now()->toIso8601String()
);
}
}
$userDto = UserDto::fromArray(['name' => 'John', 'email' => 'john@example.com']);
$resourceDto = UserResourceDto::fromUserDto($userDto);
class UserDto extends SimpleDto
{
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly string $role,
) {}
public static function admin(string $name, string $email): self
{
return new self(
name: $name,
email: $email,
role: 'admin'
);
}
public static function guest(string $name, string $email): self
{
return new self(
name: $name,
email: $email,
role: 'guest'
);
}
}
// Use factory methods
$admin = UserDto::admin('John Doe', 'john@example.com');
$guest = UserDto::guest('Jane Doe', 'jane@example.com');
$data = [
['name' => 'John', 'email' => 'john@example.com'],
['name' => 'Jane', 'email' => 'jane@example.com'],
['name' => 'Bob', 'email' => 'bob@example.com'],
];
$dtos = array_map(
fn($item) => UserDto::fromArray($item),
$data
);
use event4u\DataHelpers\SimpleDto\DtoCollection;
use Tests\Utils\Docu\Dtos\UserDto;
$data = [
['name' => 'John', 'email' => 'john@example.com', 'age' => 25],
['name' => 'Jane', 'email' => 'jane@example.com', 'age' => 17],
['name' => 'Bob', 'email' => 'bob@example.com', 'age' => 30],
];
$collection = DtoCollection::make($data, UserDto::class);
// Filter returns a DtoCollection with filtered DTOs
$filtered = $collection->filter(fn($dto) => str_contains($dto->email, 'john'));
// Map transforms each DTO and returns a new DtoCollection
$adults = $collection->filter(fn($dto) => $dto->age > 18);
$mapped = $adults->map(fn($dto) => UserDto::fromArray([
'name' => strtoupper($dto->name),
'email' => $dto->email,
'age' => $dto->age,
]));
// Result: DtoCollection with uppercase names for adult users (JOHN and BOB)
// ✅ Good - clear intent
$dto = UserDto::fromArray($data);
// ❌ Bad - unclear
$dto = new UserDto(...$data);
// ✅ Good - validate at creation
$dto = UserDto::validateAndCreate($request->all());
// ❌ Bad - validate later
$dto = UserDto::fromArray($request->all());
$dto->validate();
// ✅ Good - use specific method
$dto = UserDto::fromJson($json);
// ❌ Bad - manual parsing
$data = json_decode($json, true);
$dto = UserDto::fromArray($data);
try {
$dto = UserDto::validateAndCreate($data);
} catch (ValidationException $e) {
// Handle validation errors
return response()->json([
'errors' => $e->errors()
], 422);
}

The following working examples demonstrate Dto creation:

All examples are fully tested and can be run directly:

Terminal window
php examples/simple-dto/creating-dtos/basic-dto.php
php examples/simple-dto/creating-dtos/dto-factory.php

The functionality is thoroughly tested. Key test files:

Run the tests:

Terminal window
# Run all SimpleDto tests
task test:unit -- --filter=SimpleDto
# Run specific test file
vendor/bin/pest tests/Unit/SimpleDto/SimpleDtoTest.php

Use getKeys() to get all property names of the DTO:

use event4u\DataHelpers\SimpleDto;
use event4u\DataHelpers\SimpleDto\Attributes\Hidden;
use event4u\DataHelpers\SimpleDto\Attributes\HiddenFromArray;
use event4u\DataHelpers\SimpleDto\Attributes\HiddenFromJson;
class UserDto extends SimpleDto
{
public function __construct(
public readonly string $name,
public readonly string $email,
#[Hidden]
public readonly string $password,
#[HiddenFromArray]
public readonly string $internalId,
#[HiddenFromJson]
public readonly string $debugInfo,
public readonly int $age,
) {}
}
$user = UserDto::fromArray([
'name' => 'John',
'email' => 'john@example.com',
'password' => 'secret',
'internalId' => '123',
'debugInfo' => 'debug',
'age' => 30,
]);
// Get all property keys (including hidden)
$keys = $user->getKeys();
// ['name', 'email', 'password', 'internalId', 'debugInfo', 'age']
// Exclude properties hidden from array
$keys = $user->getKeys(includeHiddenFromArray: false);
// ['name', 'email', 'debugInfo', 'age']
// Exclude properties hidden from JSON
$keys = $user->getKeys(includeHiddenFromJson: false);
// ['name', 'email', 'internalId', 'age']
// Exclude all hidden properties
$keys = $user->getKeys(includeHiddenFromArray: false, includeHiddenFromJson: false);
// ['name', 'email', 'age']

Parameters:

  • includeHiddenFromArray (default: true) - Include properties with #[HiddenFromArray] attribute
  • includeHiddenFromJson (default: true) - Include properties with #[HiddenFromJson] attribute

Use Cases:

// Dynamic property iteration
foreach ($user->getKeys() as $key) {
$value = $user->get($key);
echo "$key: $value\n";
}
// Get only visible properties for API response
$visibleKeys = $user->getKeys(includeHiddenFromArray: false, includeHiddenFromJson: false);
// Property validation
$requiredKeys = ['name', 'email'];
$actualKeys = $user->getKeys();
$missingKeys = array_diff($requiredKeys, $actualKeys);
// Generate documentation
$properties = [];
foreach ($user->getKeys() as $key) {
$properties[$key] = [
'type' => gettype($user->get($key)),
'value' => $user->get($key),
];
}