Basic Usage - Grazulex/laravel-arc GitHub Wiki

🚀 Basic Usage

Overview

Laravel Arc is a powerful package for creating Data Transfer Objects (DTOs) in Laravel using PHP 8+ attributes. This guide covers the fundamental concepts and basic usage patterns for building type-safe, validated DTOs.

Getting Started

1. Basic DTO Setup

Create a DTO by extending LaravelArcDTO and using the Property attribute:

<?php

namespace App\DTOs;

use Grazulex\Arc\LaravelArcDTO;
use Grazulex\Arc\Attributes\Property;

class UserDTO extends LaravelArcDTO
{
    #[Property(
        type: 'string',
        required: true,
        validation: 'max:100'
    )]
    public string $name;

    #[Property(
        type: 'string',
        required: true,
        validation: 'email'
    )]
    public string $email;

    #[Property(
        type: 'int',
        required: false,
        validation: 'min:18|max:120'
    )]
    public ?int $age = null;
}

2. Creating and Using DTOs

// Create a DTO with data
$user = new UserDTO([
    'name' => 'John Doe',
    'email' => '[email protected]',
    'age' => 30
]);

// Access properties directly
echo $user->name;  // 'John Doe'
echo $user->email; // '[email protected]'
echo $user->age;   // 30

// Modify properties with automatic validation
$user->age = 31;   // Will validate that 31 is between 18-120
$user->name = 'John Smith';

// Convert to array
$array = $user->toArray();

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

3. Validation

Validation happens automatically based on your property attributes:

use Grazulex\Arc\Exceptions\InvalidDTOException;

try {
    $user = new UserDTO([
        'name' => '',  // Will fail - required field
        'email' => 'invalid-email',  // Will fail - not valid email
        'age' => 150   // Will fail - exceeds max of 120
    ]);
} catch (InvalidDTOException $e) {
    echo $e->getMessage();
}

Core Concepts

Supported Property Types

Laravel Arc supports these property types in the Property attribute:

use Carbon\Carbon;
use Grazulex\Arc\LaravelArcDTO;
use Grazulex\Arc\Attributes\Property;

class ExampleDTO extends LaravelArcDTO
{
    // String properties
    #[Property(type: 'string', required: true, validation: 'max:255')]
    public string $title;

    // Numeric properties
    #[Property(type: 'int', required: true, validation: 'min:0')]
    public int $count;

    #[Property(type: 'float', required: true, validation: 'min:0|max:100')]
    public float $percentage;

    // Boolean properties
    #[Property(type: 'bool', required: false, default: false)]
    public bool $is_active;

    // Date properties
    #[Property(type: 'date', required: false)]
    public ?Carbon $created_at = null;

    // Array properties
    #[Property(type: 'array', required: false, default: [])]
    public array $tags;

    // Enum support
    #[Property(type: 'enum', class: UserStatus::class)]
    public UserStatus $status;

    // Nested DTOs
    #[Property(type: 'nested', class: AddressDTO::class)]
    public AddressDTO $address;

    // Collections of DTOs
    #[Property(type: 'collection', class: OrderItemDTO::class)]
    public array $items;
}

Required vs Optional Properties

class UserDTO extends LaravelArcDTO
{
    // Required property (will validate as required)
    #[Property(type: 'string', required: true)]
    public string $name;

    // Optional property (nullable)
    #[Property(type: 'string', required: false)]
    public ?string $nickname = null;

    // Optional with default value
    #[Property(type: 'bool', required: false, default: true)]
    public bool $is_active = true;
}

Default Values

class SettingsDTO extends LaravelArcDTO
{
    #[Property(type: 'string', required: false, default: 'en')]
    public string $language = 'en';

    #[Property(type: 'int', required: false, default: 10)]
    public int $page_size = 10;

    #[Property(type: 'array', required: false, default: [])]
    public array $preferences = [];
}

Advanced Features

Data Transformation

Use transformers to process data before casting:

use Grazulex\Arc\Transformers\TrimTransformer;
use Grazulex\Arc\Transformers\LowercaseTransformer;

class UserDTO extends LaravelArcDTO
{
    #[Property(
        type: 'string',
        required: true,
        transform: [TrimTransformer::class, LowercaseTransformer::class]
    )]
    public string $email;  // '  [email protected]  ' becomes '[email protected]'
}

Enum Support

enum UserStatus: string
{
    case ACTIVE = 'active';
    case INACTIVE = 'inactive';
    case PENDING = 'pending';
}

class UserDTO extends LaravelArcDTO
{
    #[Property(type: 'enum', class: UserStatus::class)]
    public UserStatus $status;  // 'active' becomes UserStatus::ACTIVE
}

Nested DTOs and Collections

class AddressDTO extends LaravelArcDTO
{
    #[Property(type: 'string', required: true)]
    public string $street;

    #[Property(type: 'string', required: true)]
    public string $city;
}

class UserDTO extends LaravelArcDTO
{
    #[Property(type: 'string', required: true)]
    public string $name;

    // Nested DTO
    #[Property(type: 'nested', class: AddressDTO::class)]
    public AddressDTO $address;

    // Collection of DTOs
    #[Property(type: 'collection', class: AddressDTO::class)]
    public array $addresses;
}

$user = new UserDTO([
    'name' => 'John',
    'address' => [
        'street' => '123 Main St',
        'city' => 'Paris'
    ],
    'addresses' => [
        ['street' => '123 Main St', 'city' => 'Paris'],
        ['street' => '456 Oak Ave', 'city' => 'Lyon']
    ]
]);

Model to DTO Conversion

Convert Eloquent models to DTOs using the DTOFromModelTrait:

use Grazulex\Arc\Traits\DTOFromModelTrait;

class UserDTO extends LaravelArcDTO
{
    use DTOFromModelTrait;

    #[Property(type: 'string', required: true)]
    public string $name;

    #[Property(type: 'string', required: true, validation: 'email')]
    public string $email;
}

// Convert single model
$user = User::find(1);
$userDTO = UserDTO::fromModel($user);

// Convert collection
$users = User::all();
$userDTOs = UserDTO::fromModels($users);

See Model to DTO Conversion for detailed documentation.

Factory Usage

Laravel Arc includes a powerful factory system:

// Generate fake data
$fakeUser = UserDTO::fake();

// Generate multiple DTOs
$users = UserDTO::fakeMany(5);

// Customize specific fields
$customUser = UserDTO::factory()
    ->with('name', 'John Doe')
    ->with('email', '[email protected]')
    ->fake()
    ->create();

Artisan Commands

Generate DTOs automatically with the make:dto command:

# Basic DTO generation
php artisan make:dto User

# Generate from existing model
php artisan make:dto User --model=User

# With relations and validation
php artisan make:dto User --model=User --with-relations --with-validation

# Analyze DTO structure
php artisan dto:analyze UserDTO

# Validate data against DTO
php artisan dto:validate UserDTO --data='{"name":"John"}'

Usage Patterns

API Endpoints

class UserController extends Controller
{
    public function store(Request $request)
    {
        // Create DTO from request data with automatic validation
        $userDTO = new UserDTO($request->all());
        
        // Use DTO data to create model
        $user = User::create($userDTO->toArray());
        
        return response()->json($user, 201);
    }
}

Service Layer

class UserService
{
    public function createUser(UserDTO $userDTO): User
    {
        // DTO is already validated at this point
        return User::create($userDTO->toArray());
    }
    
    public function updateUser(User $user, UserDTO $userDTO): User
    {
        $user->update($userDTO->toArray());
        return $user->fresh();
    }
}

Form Processing

class CreateUserRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }
    
    public function rules(): array
    {
        // Generate rules from DTO
        return UserDTO::rules();
    }
    
    public function toDTO(): UserDTO
    {
        return new UserDTO($this->validated());
    }
}

Error Handling

use Grazulex\Arc\Exceptions\InvalidDTOException;

try {
    $user = new UserDTO([
        'name' => '',  // Invalid - required
        'email' => 'not-an-email',  // Invalid format
        'age' => 150,  // Invalid - exceeds max
    ]);
} catch (InvalidDTOException $e) {
    // Handle validation errors
    $message = $e->getMessage();
    $field = $e->getField();  // Which field caused the error
    $value = $e->getValue();  // The invalid value
}

Next Steps

Now that you understand the basics of Laravel Arc DTOs:

  1. 🎯 Explore Property Attributes for advanced configuration
  2. ✨ Learn about Advanced Features like transformations and enums
  3. 🏭 Check out MakeDtoCommand for auto-generation
  4. 📚 Browse Examples for real-world usage patterns
  5. 🔄 Read the Migration Guide if upgrading from v1

🚀 Ready to build type-safe, validated DTOs? Laravel Arc makes data handling elegant and robust!