Skip to content

Complete Examples

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

πŸ“– Complete Examples

This page contains all the practical examples you need to master Laravel Arc, from simple DTOs to complex nested structures and API integrations.

Table of Contents


Basic Examples

Simple User DTO

# Basic user DTO with validation and transformers
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

Product DTO

# E-commerce product DTO
header:
  dto: ProductDTO
  namespace: App\DTO\Catalog
  traits: [HasTimestamps, HasUuid, HasSlug]

fields:
  name:
    type: string
    required: true
    max_length: 255
    transformers: [trim, title_case]
    
  slug:
    type: string
    unique: true
    transformers: [slugify]
    
  description:
    type: text
    max_length: 2000
    transformers: [trim, strip_tags]
    
  price:
    type: decimal
    precision: 10
    scale: 2
    min: 0
    
  sku:
    type: string
    required: true
    unique: true
    transformers: [trim, uppercase]
    
  category_id:
    type: integer
    required: true
    
  is_active:
    type: boolean
    default: true
    
  stock_quantity:
    type: integer
    min: 0
    default: 0

Behavioral Traits Examples

Comprehensive Traits Example

# Example showing all behavioral traits working together
header:
  dto: AdvancedUserDTO
  model: App\Models\User
  namespace: App\DTO
  traits:
    - HasTimestamps    # Adds created_at, updated_at
    - HasUuid         # Adds UUID field
    - HasSoftDeletes  # Adds deleted_at, restore methods
    - HasTagging      # Adds tags field and tag methods
    - HasAuditing     # Adds creator_id, updater_id tracking
    - HasCaching      # Adds cache methods
    - HasSlug         # Adds slug field from name
    - HasStatus       # Adds status field with state management
    - ValidatesData   # Adds validation methods
    - ConvertsData    # Adds export methods

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]
  
  bio:
    type: text
    required: false
    validation: [nullable, string, max:1000]
    transformers: [trim]

# Traits configuration
trait_options:
  HasSlug:
    source_field: name
    unique: true
  HasStatus:
    default: "active"
    allowed: [active, inactive, pending, banned]
  HasCaching:
    ttl: 3600

Individual Trait Examples

# HasTimestamps only
---
header:
  dto: UserWithTimestampsDTO
  namespace: App\DTO
  traits: [HasTimestamps]

fields:
  name: { type: string, required: true }
  email: { type: string, required: true }

# HasTimestamps adds:
# - created_at: datetime field
# - updated_at: datetime field
# - touch() method
# - wasRecentlyCreated() method

---
# HasStatus with custom states
header:
  dto: OrderStatusDTO
  namespace: App\DTO
  traits: [HasStatus]

trait_config:
  HasStatus:
    default: "pending"
    states: [pending, processing, shipped, delivered, cancelled]
    transitions:
      pending: [processing, cancelled]
      processing: [shipped, cancelled]
      shipped: [delivered]

fields:
  order_number: { type: string, required: true }

Nested DTO Examples

Complete E-commerce Order

# Complex nested DTO for e-commerce orders
header:
  dto: OrderDTO
  table: orders
  model: App\Models\Order
  namespace: App\DTO\Ecommerce
  traits:
    - HasTimestamps
    - HasUuid
    - HasSoftDeletes
    - HasVersioning
    - HasAuditing

fields:
  order_number:
    type: string
    required: true
    validation: [required, string, unique:orders, size:12]
  
  status:
    type: enum
    values: [pending, processing, shipped, delivered, cancelled, refunded]
    default: pending
    
  # Customer as nested DTO
  customer:
    type: dto
    dto: CustomerDTO
    required: true
    
  # Collection of order items
  items:
    type: array
    items:
      type: dto
      dto: OrderItemDTO
    min_items: 1
    
  # Billing address
  billing_address:
    type: dto
    dto: AddressDTO
    required: true
    
  # Optional shipping address
  shipping_address:
    type: dto
    dto: AddressDTO
    required: false
    
  # Payment information
  payment:
    type: dto
    dto: PaymentDTO
    required: true

  # Totals
  subtotal:
    type: decimal
    precision: 10
    scale: 2
    
  tax_amount:
    type: decimal
    precision: 10
    scale: 2
    
  total_amount:
    type: decimal
    precision: 10
    scale: 2

Supporting Nested DTOs

# Customer DTO
---
header:
  dto: CustomerDTO
  namespace: App\DTO\Ecommerce
  traits: [HasTimestamps]

fields:
  customer_id:
    type: integer
    required: true
  name:
    type: string
    required: true
    validation: [required, string, max:255]
  email:
    type: email
    required: true
  phone:
    type: string
    nullable: true
    validation: [nullable, string, max:20]

---
# Address DTO
header:
  dto: AddressDTO
  namespace: App\DTO\Ecommerce

fields:
  street:
    type: string
    required: true
    max_length: 255
  city:
    type: string
    required: true
    max_length: 100
  state:
    type: string
    required: true
    max_length: 100
  postal_code:
    type: string
    required: true
    pattern: "^[0-9]{5}(-[0-9]{4})?$"
  country:
    type: dto
    dto: CountryDTO
    required: true

---
# Country DTO
header:
  dto: CountryDTO
  namespace: App\DTO\Ecommerce

fields:
  code:
    type: string
    required: true
    validation: [required, string, size:2]
  name:
    type: string
    required: true
    max_length: 100

API Controller Examples

Complete REST API Controller

<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\DTO\UserDTO;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

final class UserController extends Controller
{
    /**
     * Display a listing of users with DTO transformation
     */
    public function index(Request $request): JsonResponse
    {
        $users = User::query()
            ->when($request->search, function ($query, $search) {
                $query->where('name', 'like', "%{$search}%")
                    ->orWhere('email', 'like', "%{$search}%");
            })
            ->when($request->status, function ($query, $status) {
                $query->where('status', $status);
            })
            ->paginate($request->per_page ?? 15);

        // Transform to DTOs with behavioral traits
        $userDtos = $users->getCollection()->map(function ($user) {
            return UserDTO::fromModel($user);
        });

        return response()->json([
            'data' => $userDtos,
            'pagination' => [
                'current_page' => $users->currentPage(),
                'last_page' => $users->lastPage(),
                'per_page' => $users->perPage(),
                'total' => $users->total(),
            ],
        ]);
    }

    /**
     * Store a newly created user with comprehensive validation
     */
    public function store(Request $request): JsonResponse
    {
        // Use ValidatesData trait for validation
        if (UserDTO::fails($request->all())) {
            return response()->json([
                'message' => 'Validation failed',
                'errors' => UserDTO::validator($request->all())->errors(),
            ], 422);
        }

        // Create user with validated data
        $validated = UserDTO::validate($request->all());
        $user = User::create($validated);

        // Convert to DTO and demonstrate behavioral traits
        $userDto = UserDTO::fromModel($user);

        // Use HasTagging trait if available
        if (method_exists($userDto, 'addTag')) {
            $userDto = $userDto->addTag('new_user');
        }

        return response()->json([
            'message' => 'User created successfully',
            'user' => $userDto->toArray(),
        ], 201);
    }

    /**
     * Display the specified user
     */
    public function show(User $user): JsonResponse
    {
        $userDto = UserDTO::fromModel($user);

        return response()->json([
            'user' => $userDto->toArray(),
        ]);
    }

    /**
     * Update the specified user
     */
    public function update(Request $request, User $user): JsonResponse
    {
        // Validate with DTO
        $validated = UserDTO::validate($request->all());
        
        // Update model
        $user->update($validated);
        
        // Convert to DTO
        $userDto = UserDTO::fromModel($user->fresh());
        
        // Use HasTimestamps trait
        if (method_exists($userDto, 'touch')) {
            $userDto->touch(); // Updates updated_at
        }

        return response()->json([
            'message' => 'User updated successfully',
            'user' => $userDto->toArray(),
        ]);
    }

    /**
     * Bulk operations example
     */
    public function bulkStore(Request $request): JsonResponse
    {
        $users = collect($request->users)->map(function ($userData) {
            // Validate each user
            $validated = UserDTO::validate($userData);
            $user = User::create($validated);
            return UserDTO::fromModel($user);
        });

        return response()->json([
            'message' => 'Users created successfully',
            'users' => $users->toArray(),
            'count' => $users->count(),
        ], 201);
    }

    /**
     * Export functionality
     */
    public function export(Request $request): JsonResponse
    {
        $users = User::all();
        $userDtos = $users->map(fn($user) => UserDTO::fromModel($user));

        // Use DTO export capabilities
        $format = $request->format ?? 'json';
        
        switch ($format) {
            case 'csv':
                $content = $userDtos->toCsv();
                break;
            case 'xml':
                $content = $userDtos->toXml();
                break;
            default:
                $content = $userDtos->toJson();
        }

        return response($content)
            ->header('Content-Type', "application/{$format}")
            ->header('Content-Disposition', "attachment; filename=users.{$format}");
    }
}

API Routes Configuration

// routes/api.php
Route::prefix('v1')->group(function () {
    Route::apiResource('users', UserController::class);
    Route::post('users/bulk', [UserController::class, 'bulkStore']);
    Route::get('users/export', [UserController::class, 'export']);
    
    Route::apiResource('orders', OrderController::class);
    Route::get('orders/{order}/items', [OrderController::class, 'items']);
});

Field Transformers Examples

Comprehensive Transformers

# Field transformers example showing data cleaning
header:
  dto: ContactFormDTO
  namespace: App\DTO\Contact

fields:
  # Basic string transformations
  name:
    type: string
    required: true
    transformers: [trim, title_case]
    # "  john doe  " β†’ "John Doe"
    
  email:
    type: email
    required: true
    transformers: [trim, lowercase]
    # "  [email protected]  " β†’ "[email protected]"
    
  # URL and slug transformations
  website:
    type: url
    nullable: true
    transformers: [trim, normalize_url, add_http]
    # "example.com" β†’ "http://example.com"
    
  slug:
    type: string
    transformers: [trim, lowercase, slugify]
    # "Hello World!" β†’ "hello-world"
    
  # Phone number normalization
  phone:
    type: string
    nullable: true
    transformers: [normalize_phone]
    # "(555) 123-4567" β†’ "+15551234567"
    
  # Text cleaning
  message:
    type: text
    required: true
    transformers: [trim, strip_tags, normalize_whitespace]
    # "<p>Hello\n\nworld</p>" β†’ "Hello world"
    
  # Numeric transformations
  price:
    type: decimal
    precision: 2
    transformers: [round_to_precision]
    # 19.999 β†’ 19.99
    
  # Array transformations
  tags:
    type: array
    items: { type: string }
    transformers: [trim_array, lowercase_array, unique_array]
    # ["  TAG1  ", "tag2", "TAG1"] β†’ ["tag1", "tag2"]

Chained Transformers

# Complex transformation chains
header:
  dto: ProductDataDTO
  namespace: App\DTO\Catalog

fields:
  # Product name with multiple transformations
  name:
    type: string
    required: true
    transformers: [trim, strip_tags, title_case, truncate:100]
    # "  <b>awesome product name</b>  " β†’ "Awesome Product Name"
    
  # SEO-friendly slug
  slug:
    type: string
    unique: true
    transformers: [trim, lowercase, slugify, ensure_unique]
    # "  My Awesome Product!  " β†’ "my-awesome-product" or "my-awesome-product-2"
    
  # Clean description
  description:
    type: text
    transformers: [trim, strip_tags, normalize_whitespace, smart_truncate:500]
    
  # Format SKU
  sku:
    type: string
    required: true
    transformers: [trim, uppercase, alphanumeric_dash_only]
    # "  abc-123  " β†’ "ABC-123"

Advanced Examples

Enum Field Examples

# Enum field usage examples
header:
  dto: OrderStatusDTO
  namespace: App\DTO

fields:
  # Simple enum
  status:
    type: enum
    values: [pending, confirmed, shipped, delivered, cancelled]
    default: pending
    
  # Priority enum with validation
  priority:
    type: enum
    values: [low, medium, high, urgent]
    default: medium
    validation: [required, in:low,medium,high,urgent]
    
  # Payment status with descriptions
  payment_status:
    type: enum
    values:
      pending: "Payment Pending"
      processing: "Processing Payment"
      completed: "Payment Completed"
      failed: "Payment Failed"
      refunded: "Payment Refunded"
    default: pending

Advanced Validation Examples

# Complex validation scenarios
header:
  dto: UserRegistrationDTO
  namespace: App\DTO\Auth

fields:
  # Username with custom validation
  username:
    type: string
    required: true
    validation: 
      - required
      - string
      - min:3
      - max:20
      - unique:users
      - regex:/^[a-zA-Z0-9_]+$/
    transformers: [trim, lowercase]
    
  # Password with strength requirements
  password:
    type: string
    required: true
    validation:
      - required
      - string
      - min:8
      - confirmed
      - regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x]).*$/
      
  # Email with domain restriction
  email:
    type: email
    required: true
    validation:
      - required
      - email:rfc,dns
      - unique:users
      - ends_with:@company.com,@partner.com
    transformers: [trim, lowercase]
    
  # Age with business rules
  age:
    type: integer
    required: true
    validation:
      - required
      - integer
      - min:18
      - max:65
      
  # File upload validation
  avatar:
    type: file
    nullable: true
    validation:
      - nullable
      - image
      - max:2048
      - mimes:jpeg,png,jpg,gif
      - dimensions:min_width=100,min_height=100

Collection Processing Examples

<?php

// Collection processing with DTOs
class UserService
{
    public function processUserBatch(array $userData): array
    {
        $results = [
            'successful' => collect(),
            'failed' => collect(),
            'duplicates' => collect()
        ];
        
        collect($userData)->each(function($data) use (&$results) {
            try {
                // Check for duplicates
                if (User::where('email', $data['email'])->exists()) {
                    $results['duplicates']->push($data);
                    return;
                }
                
                // Validate and create DTO
                $userDto = UserDTO::fromValidated($data);
                
                // Create user
                $user = User::create($userDto->toArray());
                $results['successful']->push(UserDTO::fromModel($user));
                
            } catch (ValidationException $e) {
                $results['failed']->push([
                    'data' => $data,
                    'errors' => $e->errors()
                ]);
            }
        });
        
        return [
            'processed' => count($userData),
            'successful' => $results['successful']->count(),
            'failed' => $results['failed']->count(),
            'duplicates' => $results['duplicates']->count(),
            'errors' => $results['failed']->toArray()
        ];
    }
}

Usage Patterns

Form Request Integration

<?php

namespace App\Http\Requests;

use App\DTO\UserDTO;
use Illuminate\Foundation\Http\FormRequest;

class CreateUserRequest extends FormRequest
{
    public function rules(): array
    {
        return UserDTO::validationRules();
    }
    
    public function toDto(): UserDTO
    {
        return UserDTO::fromValidated($this->validated());
    }
}

// In controller
public function store(CreateUserRequest $request): JsonResponse
{
    $userDto = $request->toDto();
    $user = User::create($userDto->toArray());
    
    return response()->json([
        'user' => UserDTO::fromModel($user)->toArray()
    ], 201);
}

Service Layer Integration

<?php

namespace App\Services;

use App\DTO\OrderDTO;
use App\Models\Order;

class OrderService
{
    public function createOrder(OrderDTO $orderDto): Order
    {
        // Business logic with type-safe DTO
        $this->validateInventory($orderDto->items);
        $this->calculateTotals($orderDto);
        
        // Create order
        $order = Order::create($orderDto->toArray());
        
        // Process items
        foreach ($orderDto->items as $itemDto) {
            $order->items()->create($itemDto->toArray());
        }
        
        return $order;
    }
    
    private function validateInventory(Collection $items): void
    {
        $items->each(function($itemDto) {
            if ($itemDto->quantity > $this->getAvailableStock($itemDto->product_id)) {
                throw new InsufficientStockException($itemDto->product_id);
            }
        });
    }
}

Configuration Examples

Custom Configuration

// config/dto.php
return [
    'definitions_path' => resource_path('arc'),
    'output_path' => app_path('DTOs'),
    
    // Custom namespace mapping
    'namespace_mapping' => [
        'api' => 'App\\Http\\DTOs',
        'domain' => 'App\\Domain\\DTOs',
        'integration' => 'App\\Integration\\DTOs',
    ],
    
    // Generation options
    'generation' => [
        'strict_types' => true,
        'readonly_properties' => true,
        'final_classes' => true,
        'add_docblocks' => true,
    ],
];

This complete examples collection provides practical, copy-paste code for every Laravel Arc feature. Use these examples as starting points for your own DTOs.

πŸš€ 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