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. Works standalone in Pure PHP or with deep integration for Laravel and Symfony – without framework lock-in.
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 + Deep Integration
Section titled “🎯 Framework-Agnostic + Deep Integration”The best of both worlds: Use SimpleDto as a standalone library in pure PHP, or leverage deep framework integration for Laravel and Symfony – without framework lock-in.
Pure PHP - Zero Dependencies
Section titled “Pure PHP - Zero Dependencies”// Works everywhere - no framework needed$dto = UserDto::fromArray($_POST);$dto = UserDto::fromArray($apiResponse);$dto = UserDto::fromArray(json_decode($json, true));Optional Deep Integration
Section titled “Optional Deep Integration”// Laravel - Automatic controller injection & Eloquent integrationclass UserController extends Controller{ public function store(UserDto $dto): JsonResponse { // $dto is automatically validated and filled from request $user = User::create($dto->toArray()); return response()->json($user, 201); }}
$user = User::find(1);$dto = UserDto::fromModel($user); // From Eloquent Model (automatically available)$newUser = $dto->toModel(User::class); // To Eloquent Model// Note: Methods throw BadMethodCallException if Laravel is not installed
// Symfony - Automatic controller injection & Doctrine integrationclass UserController extends AbstractController{ #[Route('/users', methods: ['POST'])] public function create(UserDto $dto): JsonResponse { // $dto is automatically validated and filled from request $user = $dto->toEntity(User::class); $this->entityManager->persist($user); return $this->json($user, 201); }}
$user = $this->entityManager->find(User::class, 1);$dto = UserDto::fromEntity($user); // From Doctrine Entity (automatically available)$newUser = $dto->toEntity(User::class); // To Doctrine Entity// Note: Methods throw BadMethodCallException if Doctrine is not installedKey Benefits:
- ✅ No Framework Lock-In - Core code works everywhere
- ✅ Optional Integration - Add framework features when needed
- ✅ Portable - Move between frameworks without code changes
- ✅ Zero Dependencies - No required dependencies
Type Safety
Section titled “Type Safety”Full PHP 8.2+ type support with automatic type casting by default.
use event4u\DataHelpers\SimpleDto\Attributes\NoCasts;
// Default: Automatic type casting enabledclass ProductDto extends SimpleDto{ public function __construct( public readonly string $name, // Auto-cast from any type public readonly float $price, // Auto-cast from string/int public readonly Carbon $createdAt, // Auto-cast from string/timestamp public readonly Status $status, // Enum (always auto-cast) public readonly AddressDto $address, // Auto-cast nested DTO ) {}}
// Disable automatic casting for better performance#[NoCasts]class StrictProductDto extends SimpleDto{ public function __construct( public readonly string $name, // Must be string, no conversion public readonly float $price, // Must be float, no conversion public readonly AddressDto $address, // Must be AddressDto instance ) {}}Note: SimpleDto automatically casts ALL types by default (native types, nested DTOs, DataCollections, DateTime). Use #[NoCasts] to disable automatic casting for better performance.
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.
$users = UserDto::collection($userArray);// DataCollection of UserDto instances
// Access collection methods$filtered = $users->filter(fn($user) => $user->age >= 18);$mapped = $users->map(fn($user) => $user->name);$count = $users->count();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
- Multi-format serialization - JSON, XML, YAML, CSV, and custom formats
- 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”Framework-Agnostic Core + Optional Deep Integration:
Pure PHP (Zero Dependencies)
Section titled “Pure PHP (Zero Dependencies)”- ✅ Multi-format Support - JSON, XML, YAML, CSV, and custom formats
- ✅ No Framework Required - Standalone usage
- ✅ Portable - Move between frameworks
Laravel (Optional)
Section titled “Laravel (Optional)”- ✅ Controller Injection - Automatic validation & filling
- ✅ Eloquent Integration - fromModel(), toModel()
- ✅ Laravel Attributes - WhenAuth, WhenCan, WhenRole
- ✅ Artisan Commands - make:dto, dto:typescript
Symfony (Optional)
Section titled “Symfony (Optional)”- ✅ Controller Injection - Automatic validation & filling
- ✅ Doctrine Integration - fromEntity(), toEntity()
- ✅ Symfony Attributes - WhenGranted, WhenSymfonyRole
- ✅ Console Commands - make:dto, dto:typescript
The Power: Get framework-specific features when you need them, without framework dependencies in your core code.
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