Skip to content

Your First DTO

Jean-Marc Strauven edited this page Aug 6, 2025 · 1 revision

🎯 Your First DTO

Create your first Laravel Arc DTO in just 5 minutes. This guide walks you through the complete process from YAML definition to using your generated DTO.

The YAML β†’ DTO Journey

Laravel Arc follows a simple flow:

1. Write YAML Definition β†’ 2. Generate DTO β†’ 3. Use in Your Code

Let's build a User DTO step by step.

Step 1: Create the YAML Definition

Create resources/arc/user.yaml using a real-world example:

# Simple user DTO example with modern trait-based system
header:
  dto: UserDTO
  table: users
  model: App\Models\User
  namespace: App\DTO
  traits:
    - HasUuid
    - HasTimestamps
  use:
    - App\DTO\ProfileDTO
  extends: BaseDTO

fields:
  name:
    type: string
    required: true
    validation: [required, string, min:2, max:100]
    transformers: [trim, title_case]
  
  email:
    type: string
    required: true
    validation: [required, email, unique:users]
    transformers: [trim, lowercase]
  
  email_verified_at:
    type: datetime
    required: false
    validation: [nullable, date]
  
  # Profile as nested DTO
  profile:
    type: dto
    dto: ProfileDTO
    required: false

relations:
  posts:
    type: hasMany
    target: App\Models\Post
  
  roles:
    type: belongsToMany
    target: App\Models\Role

# The HasUuid trait automatically adds:
# - id field (UUID type)
# - UUID validation and generation methods

# The HasTimestamps trait automatically adds:
# - created_at and updated_at fields
# - touch() method for updating timestamps
# - wasRecentlyCreated() method

Understanding the Real YAML Structure

  • header: Contains metadata about the DTO including traits and inheritance
  • fields: Defines properties with validation and transformers
  • relations: Defines Eloquent relationships
  • traits: Behavioral traits that add automatic functionality
  • transformers: Automatic data cleaning (trim, title_case, lowercase)

Step 2: Generate the DTO

Run the generation command:

php artisan arc:generate resources/arc/user.yaml

You should see output like:

βœ… DTO generated successfully: App\DTOs\UserDto
πŸ“ File created: app/DTOs/UserDto.php

Step 3: Examine the Generated Code

Laravel Arc generates a modern PHP class at app/DTOs/UserDto.php:

<?php

declare(strict_types=1);

namespace App\DTOs;

use Grazulex\LaravelArc\Support\Traits\ValidatesData;
use Grazulex\LaravelArc\Support\Traits\ConvertsData;

final readonly class UserDto
{
    use ValidatesData, ConvertsData;

    public function __construct(
        public string $name,
        public string $email,
        public ?\DateTime $email_verified_at = null,
        public ?ProfileDTO $profile = null,
    ) {}

    public static function validationRules(): array
    {
        return [
            'name' => ['required', 'string', 'min:2', 'max:100'],
            'email' => ['required', 'email', 'unique:users,email'],
            'email_verified_at' => ['nullable', 'date'],
        ];
    }
}

Key Features Generated

βœ… Readonly Properties: Immutable data objects
βœ… Type Safety: Full PHP typing
βœ… Validation Rules: Automatic Laravel validation
βœ… Default Values: Built-in defaults
βœ… Helper Traits: Data conversion and validation methods

Step 4: Use Your DTO

Now you can use your DTO in various ways:

Creating DTOs

use App\DTOs\UserDto;

// From array (most common)
$user = UserDto::from([
    'name' => 'John Doe',
    'email' => '[email protected]',
    'age' => 30
]);

// With validation
$user = UserDto::fromValidated([
    'name' => 'John Doe',
    'email' => '[email protected]',
    'age' => 30
]);

// From request (in controllers)
$user = UserDto::fromRequest($request);

Accessing Data

// Direct property access
echo $user->name;      // "John Doe"
echo $user->email;     // "[email protected]"
echo $user->age;       // 30
echo $user->status;    // "active" (default value)

Converting Data

// To array
$array = $user->toArray();

// To JSON
$json = $user->toJson();

// To specific format
$xml = $user->toXml();
$csv = $user->toCsv();

Step 5: Use in a Laravel Controller

Here's a practical example in a controller:

<?php

namespace App\Http\Controllers;

use App\DTOs\UserDto;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        // Create and validate DTO from request
        $userDto = UserDto::fromValidated($request->all());
        
        // Use the DTO data
        $user = User::create([
            'name' => $userDto->name,
            'email' => $userDto->email,
            'age' => $userDto->age,
            'status' => $userDto->status,
        ]);
        
        // Return JSON response
        return response()->json([
            'user' => $userDto->toArray(),
            'created' => true
        ]);
    }
    
    public function show(User $user)
    {
        // Convert model to DTO
        $userDto = UserDto::from($user->toArray());
        
        return response()->json($userDto->toArray());
    }
}

Step 6: Add More Complexity

Let's enhance our YAML with more advanced features:

header:
  class: UserDto
  namespace: App\DTOs
  traits: ["HasTimestamps", "HasUuid"]  # Behavioral traits

fields:
  # Field with transformer
  name:
    type: string
    required: true
    max_length: 255
    transformers: ["trim", "title_case"]
    
  # Field with custom validation
  email:
    type: email
    required: true
    unique: true
    transformers: ["trim", "lowercase"]
    
  # Nested object
  address:
    type: object
    class: AddressDto
    required: false
    
  # Array of objects
  tags:
    type: array
    items:
      type: string
    transformers: ["trim", "lowercase"]

Common Patterns

1. API Request DTOs

header:
  class: CreateUserRequestDto
  namespace: App\DTOs\Requests

fields:
  name: { type: string, required: true, max_length: 255 }
  email: { type: email, required: true }
  password: { type: string, required: true, min_length: 8 }

2. API Response DTOs

header:
  class: UserResponseDto
  namespace: App\DTOs\Responses

fields:
  id: { type: integer, required: true }
  name: { type: string, required: true }
  email: { type: email, required: true }
  created_at: { type: datetime, required: true }

3. Configuration DTOs

header:
  class: AppConfigDto
  namespace: App\DTOs\Config

fields:
  app_name: { type: string, default: "My App" }
  debug: { type: boolean, default: false }
  cache_ttl: { type: integer, default: 3600 }

What You've Learned

βœ… How to write YAML definitions
βœ… How to generate DTOs with Arc
βœ… How to use generated DTOs in your code
βœ… How to integrate DTOs with Laravel features
βœ… Common DTO patterns and use cases

What's Next?

Now that you've created your first DTO, explore more advanced features:


πŸŽ‰ Congratulations! You've created your first Laravel Arc DTO. The journey from YAML to type-safe code is that simple!

πŸš€ Laravel Arc Wiki

🏠 Home

πŸš€ Getting Started

πŸ“š Core Concepts

πŸ—οΈ Advanced Features

βš™οΈ Configuration & CLI

🌐 Real-World Examples


🎯 Key Concepts

YAML β†’ DTO β†’ Type-Safe Code

Laravel Arc transforms your YAML definitions into powerful PHP DTOs with automatic validation, field transformers, and behavioral traits.

πŸ”— Quick Links

Clone this wiki locally