Introduction to SimpleDTO
SimpleDTO is a powerful, framework-agnostic Data Transfer Object (DTO) library for PHP 8.2+ that makes working with structured data simple, type-safe, and performant.
What is a DTO?
Section titled “What is a DTO?”A Data Transfer Object (DTO) is a design pattern used to transfer data between different parts of an application. DTOs are simple objects that:
- Contain only data (no business logic)
- Are immutable (readonly properties)
- Are type-safe (PHP 8.2+ types)
- Can be easily serialized/deserialized
Example: Without DTO
Section titled “Example: Without DTO”// Controller - messy array handlingpublic function store(Request $request){ $data = $request->all();
// Manual validation if (empty($data['name']) || !is_string($data['name'])) { throw new ValidationException('Invalid name'); }
// Manual type casting $age = isset($data['age']) ? (int) $data['age'] : null;
// Manual mapping $user = new User(); $user->name = $data['name']; $user->age = $age; $user->email = $data['email'] ?? null;
return response()->json([ 'name' => $user->name, 'age' => $user->age, // Forgot to include email! ]);}Example: With SimpleDTO
Section titled “Example: With SimpleDTO”// DTO - clean and type-safeclass UserDTO extends SimpleDTO{ public function __construct( #[Required, StringType, Min(3)] public readonly string $name,
#[Required, IntegerType, Between(18, 120)] public readonly int $age,
#[Required, Email] public readonly string $email, ) {}}
// Controller - simple and cleanpublic function store(UserDTO $dto){ $user = User::create($dto->toArray()); return response()->json($dto);}Why SimpleDTO?
Section titled “Why SimpleDTO?”Framework Agnostic
Section titled “Framework Agnostic”Works with Laravel, Symfony, and plain PHP. No framework lock-in.
// Laravel$dto = UserDTO::fromRequest($request);
// Symfony$dto = UserDTO::fromArray($request->request->all());
// Plain PHP$dto = UserDTO::fromArray($_POST);Type Safety
Section titled “Type Safety”Full PHP 8.2+ type support with automatic casting.
class ProductDTO extends SimpleDTO{ public function __construct( public readonly string $name, public readonly float $price, public readonly Carbon $createdAt, public readonly Status $status, // Enum ) {}}Validation
Section titled “Validation”30+ built-in validation attributes.
class UserDTO extends SimpleDTO{ public function __construct( #[Required, StringType, Min(3), Max(50)] public readonly string $name,
#[Required, Email] public readonly string $email,
#[Required, IntegerType, Between(18, 120)] public readonly int $age,
#[Url] public readonly ?string $website = null, ) {}}
// Automatic validation$dto = UserDTO::validateAndCreate($data);Conditional Properties
Section titled “Conditional Properties”18 conditional attributes for dynamic visibility.
class UserDTO extends SimpleDTO{ public function __construct( public readonly string $name,
#[WhenAuth] // Only when authenticated public readonly ?string $email = null,
#[WhenCan('view-admin')] // Only with permission public readonly ?array $adminData = null,
#[WhenNotNull] // Only when not null public readonly ?string $phone = null, ) {}}Property Mapping
Section titled “Property Mapping”Map source keys to different property names.
class UserDTO extends SimpleDTO{ public function __construct( #[MapFrom('full_name')] public readonly string $name,
#[MapFrom('email_address')] public readonly string $email, ) {}}
$dto = UserDTO::fromArray([ 'full_name' => 'John Doe', 'email_address' => 'john@example.com',]);Type Casting
Section titled “Type Casting”20+ built-in casts for automatic type conversion.
class OrderDTO extends SimpleDTO{ public function __construct( #[Cast(DateTimeCast::class, format: 'Y-m-d')] public readonly Carbon $orderDate,
#[Cast(EnumCast::class, enum: Status::class)] public readonly Status $status,
#[Cast(CollectionCast::class, of: OrderItemDTO::class)] public readonly DataCollection $items, ) {}}Lazy Properties
Section titled “Lazy Properties”Defer expensive operations until needed.
class UserDTO extends SimpleDTO{ public function __construct( public readonly string $name,
#[Lazy] public readonly ?array $posts = null, // Only loaded when accessed ) {}}
$dto = UserDTO::fromModel($user);// Posts are NOT loaded yet
$posts = $dto->posts;// Posts are loaded NOWComputed Properties
Section titled “Computed Properties”Calculate values on-the-fly.
class ProductDTO extends SimpleDTO{ public function __construct( public readonly float $price, public readonly float $taxRate, ) {}
#[Computed] public function priceWithTax(): float { return $this->price * (1 + $this->taxRate); }}
$dto = new ProductDTO(price: 100, taxRate: 0.19);echo $dto->priceWithTax(); // 119.0
$array = $dto->toArray();// ['price' => 100, 'taxRate' => 0.19, 'priceWithTax' => 119.0]Collections
Section titled “Collections”Built-in collection support with pagination.
$users = UserDTO::collection($userArray);// DataCollection of UserDTO instances
$paginated = UserDTO::paginatedCollection($users, page: 1, perPage: 10);// [// 'data' => [...],// 'meta' => ['current_page' => 1, 'per_page' => 10, ...],// ]Key Features
Section titled “Key Features”Core Features
Section titled “Core Features”- Immutable by design - Use readonly properties
- Type-safe - Full PHP type hinting support
- JSON serializable - Implements
JsonSerializable - Array conversion -
toArray()andfromArray() - Nested DTOs - Support for complex structures
- Collections - Built-in collection support
Validation
Section titled “Validation”- 30+ validation attributes - Required, Email, Min, Max, Between, etc.
- Custom validation - Create your own validators
- Automatic validation -
validateAndCreate()method - Validation caching - 198x faster with caching
Advanced Features
Section titled “Advanced Features”- 18 Conditional Attributes - WhenAuth, WhenCan, WhenValue, etc.
- with() Method - Dynamic property addition
- Context-Based Conditions - Context-aware properties
- Lazy properties - Lazy loading and evaluation
- Custom casts - Create your own type casts
- TypeScript generation - Generate TypeScript interfaces
- IDE support - PHPStorm, VS Code
Framework Integration
Section titled “Framework Integration”- Laravel: Eloquent, validation, Artisan commands
- Symfony: Doctrine, security, console commands
- Plain PHP: Works without any framework
Performance
Section titled “Performance”- Validation caching - 198x faster
- Cast instance caching - Reuse cast instances
- Optimized reflection - Minimal overhead
- Lazy evaluation - Only compute when needed
Quick Start
Section titled “Quick Start”Installation
Section titled “Installation”composer require event4u/data-helpersCreate Your First DTO
Section titled “Create Your First DTO”use Event4u\DataHelpers\SimpleDTO;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,
public readonly ?int $age = null, ) {}}
// Create from array$dto = UserDTO::fromArray([ 'name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30,]);
// Access propertiesecho $dto->name; // 'John Doe'
// Convert to array$array = $dto->toArray();
// Convert to JSON$json = json_encode($dto);Next Steps
Section titled “Next Steps”For Beginners
Section titled “For Beginners”- Creating DTOs - Learn how to create DTOs
- Type Casting - Automatic type conversion
- Validation - Validate your data
For Experienced Developers
Section titled “For Experienced Developers”- Conditional Properties - Advanced visibility control
- Lazy Properties - Defer expensive operations
- Computed Properties - Calculate values on-the-fly
Advanced Topics
Section titled “Advanced Topics”- Collections - Work with collections of DTOs
- Nested DTOs - Complex nested structures
- Security & Visibility - Control data exposure
See Also
Section titled “See Also”- DataMapper - Transform data with Fluent API
- DataAccessor - Read nested data
- DataFilter - Query and filter data