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(...)
$dto = UserDTO::fromArray([
'name' => 'John Doe',
'email' => 'john@example.com',
'age' => 30,
]);
$dto = UserDTO::fromArray([
'name' => 'John Doe',
'email' => 'john@example.com',
'address' => [
'street' => '123 Main St',
'city' => 'New York',
'country' => 'USA',
],
]);
// 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
]);
$json = '{"name":"John Doe","email":"john@example.com","age":30}';
$dto = UserDTO::fromJson($json);
$json = file_get_contents('user.json');
$dto = UserDTO::fromJson($json);
$json = '{
"name": "John Doe",
"email": "john@example.com",
"address": {
"street": "123 Main St",
"city": "New York"
}
}';
$dto = UserDTO::fromJson($json);
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);
$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);
$csv = '"name","email","age"
"John Doe","john@example.com",30';
$dto = UserDTO::fromCsv($csv);
$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();
}
$dto = new UserDTO(
name: 'John Doe',
email: 'john@example.com',
age: 30
);
// ✅ 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);
$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\DataCollection;
$data = [
['name' => 'John', 'email' => 'john@example.com'],
['name' => 'Jane', 'email' => 'jane@example.com'],
['name' => 'Bob', 'email' => 'bob@example.com'],
];
$collection = DataCollection::make($data, UserDTO::class);
// Now you can use collection methods
$filtered = $collection->filter(fn($dto) => str_contains($dto->email, 'john'));
$mapped = $collection->map(fn($dto) => $dto->name);
// ✅ 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