Creating Dtos
Learn all the different ways to create Dto instances in SimpleDto.
Creation Methods Overview
Section titled “Creation Methods Overview”SimpleDto provides multiple ways to create instances:
| Method | Use Case | Example |
|---|---|---|
fromArray() | From associative array | UserDto::fromArray($data) |
fromJson() | From JSON string | UserDto::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 string | UserDto::fromXml($xml) |
fromYaml() | From YAML string | UserDto::fromYaml($yaml) |
fromCsv() | From CSV string | UserDto::fromCsv($csv) |
validateAndCreate() | With validation | UserDto::validateAndCreate($data) |
new | Direct instantiation | new UserDto(...) |
From Array
Section titled “From Array”Basic Usage
Section titled “Basic Usage”use Tests\Utils\Docu\Dtos\UserDto;
$dto = UserDto::fromArray([ 'name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30,]);// Result: UserDto instanceWith Nested Arrays
Section titled “With Nested Arrays”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 arrayWith Extra Keys (Ignored)
Section titled “With Extra Keys (Ignored)”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)From JSON
Section titled “From JSON”Basic Usage
Section titled “Basic Usage”use Tests\Utils\Docu\Dtos\UserDto;
$json = '{"name":"John Doe","email":"john@example.com","age":30}';$dto = UserDto::fromJson($json);// Result: UserDto instanceFrom JSON File
Section titled “From JSON File”$json = file_get_contents('user.json');$dto = UserDto::fromJson($json);With Nested JSON
Section titled “With Nested 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 addressFrom HTTP Request
Section titled “From HTTP Request”Laravel Request
Section titled “Laravel Request”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()); }}Symfony Request
Section titled “Symfony Request”use Symfony\Component\HttpFoundation\Request;
class UserController{ public function store(Request $request) { $dto = UserDto::fromArray($request->request->all()); }}Plain PHP
Section titled “Plain PHP”// 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);From Database Models
Section titled “From Database Models”Laravel Eloquent
Section titled “Laravel Eloquent”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);Symfony Doctrine
Section titled “Symfony Doctrine”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);From XML
Section titled “From XML”Basic Usage
Section titled “Basic Usage”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);From XML File
Section titled “From XML File”$xml = file_get_contents('user.xml');$dto = UserDto::fromXml($xml);From YAML
Section titled “From YAML”Basic Usage
Section titled “Basic Usage”$yaml = 'name: John Doeemail: john@example.comage: 30';
$dto = UserDto::fromYaml($yaml);From YAML File
Section titled “From YAML File”$yaml = file_get_contents('user.yaml');$dto = UserDto::fromYaml($yaml);From CSV
Section titled “From CSV”Basic Usage
Section titled “Basic Usage”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 typesFrom CSV File
Section titled “From CSV File”$csv = file_get_contents('user.csv');$dto = UserDto::fromCsv($csv);With Validation
Section titled “With Validation”Validate and Create
Section titled “Validate and Create”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 invalidtry { $dto = UserDto::validateAndCreate([ 'name' => '', // ❌ Required 'email' => 'invalid', // ❌ Invalid email ]);} catch (ValidationException $e) { echo $e->getMessage();}Direct Instantiation
Section titled “Direct Instantiation”Using Constructor
Section titled “Using Constructor”use Tests\Utils\Docu\Dtos\UserDto;
$dto = new UserDto( name: 'John Doe', email: 'john@example.com', age: 30);With Named Arguments
Section titled “With Named Arguments”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);From Other Dtos
Section titled “From Other Dtos”Clone and Modify
Section titled “Clone and Modify”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);Convert Between Dtos
Section titled “Convert Between Dtos”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);Factory Methods
Section titled “Factory Methods”Custom Factory Methods
Section titled “Custom Factory Methods”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');Bulk Creation
Section titled “Bulk Creation”From Array of Arrays
Section titled “From Array of Arrays”$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);Using DtoCollection
Section titled “Using DtoCollection”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)Best Practices
Section titled “Best Practices”Use Static Factory Methods
Section titled “Use Static Factory Methods”// ✅ Good - clear intent$dto = UserDto::fromArray($data);
// ❌ Bad - unclear$dto = new UserDto(...$data);Validate Early
Section titled “Validate Early”// ✅ Good - validate at creation$dto = UserDto::validateAndCreate($request->all());
// ❌ Bad - validate later$dto = UserDto::fromArray($request->all());$dto->validate();Use Type-Specific Methods
Section titled “Use Type-Specific Methods”// ✅ Good - use specific method$dto = UserDto::fromJson($json);
// ❌ Bad - manual parsing$data = json_decode($json, true);$dto = UserDto::fromArray($data);Handle Errors Gracefully
Section titled “Handle Errors Gracefully”try { $dto = UserDto::validateAndCreate($data);} catch (ValidationException $e) { // Handle validation errors return response()->json([ 'errors' => $e->errors() ], 422);}Code Examples
Section titled “Code Examples”The following working examples demonstrate Dto creation:
- Basic Dto - Simple Dto with required properties
- Dto Factory - Factory pattern for Dtos
- Wrapping - Wrapping existing data
- Optional Properties - Handling optional properties
All examples are fully tested and can be run directly:
php examples/simple-dto/creating-dtos/basic-dto.phpphp examples/simple-dto/creating-dtos/dto-factory.phpRelated Tests
Section titled “Related Tests”The functionality is thoroughly tested. Key test files:
- SimpleDtoTest.php - Core Dto functionality
- DtoFactoryTest.php - Factory pattern tests
- OptionalPropertiesTest.php - Optional properties tests
Run the tests:
# Run all SimpleDto teststask test:unit -- --filter=SimpleDto
# Run specific test filevendor/bin/pest tests/Unit/SimpleDto/SimpleDtoTest.phpIntrospection
Section titled “Introspection”Getting Property Keys
Section titled “Getting Property Keys”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]attributeincludeHiddenFromJson(default:true) - Include properties with#[HiddenFromJson]attribute
Use Cases:
// Dynamic property iterationforeach ($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), ];}See Also
Section titled “See Also”- Type Casting - Automatic type conversion
- Validation - Validate your data
- Property Mapping - Map property names
- Collections - Working with collections