MakeDtoCommand - Grazulex/laravel-arc GitHub Wiki

🛠️ MakeDtoCommand - Intelligent DTO Generation

The MakeDtoCommand is the core feature of Laravel Arc that intelligently generates Data Transfer Objects from your Eloquent models. It analyzes your models using multiple sophisticated techniques to create accurate, type-safe DTOs with minimal manual configuration.

🎯 Overview

The command uses a multi-layered analysis system that prioritizes different data sources to extract the most accurate type and validation information possible.

Key Features

  • 🧠 Multi-Source Analysis: Combines model casts, database schema, migration files, and pattern recognition
  • 🔍 Intelligent Type Detection: Automatically determines PHP types and nullability
  • 🛡️ Smart Validation: Generates appropriate Laravel validation rules
  • 🔗 Relation Discovery: Automatically detects and maps Eloquent relationships
  • 🌍 Environment Adaptive: Works in test, development, and production environments
  • 📊 Fallback System: Graceful degradation when sources are unavailable

🔬 Analysis Priority System

The command analyzes your models using a hierarchical priority system to ensure maximum accuracy:

1. 🥇 Model Casts (Highest Priority)

Source: $casts property in your Eloquent model
Reliability: ⭐⭐⭐⭐⭐ (Highest)
Environment: Test ✅ | Development ✅ | Production ✅

// In your User model
protected $casts = [
    'age' => 'integer',           // → public int $age (non-nullable)
    'is_active' => 'boolean',     // → public bool $is_active (non-nullable)
    'metadata' => 'array',        // → public ?array $metadata (nullable)
    'salary' => 'decimal:2',      // → public float $salary (non-nullable)
    'created_at' => 'datetime',   // → public ?Carbon $created_at (nullable)
];

// Generated DTO
class UserDTO extends LaravelArcDTO {
    #[Property(type: 'int', required: true)]
    public int $age;                    // ✅ From cast: non-nullable
    
    #[Property(type: 'bool', required: true, default: false)]
    public bool $is_active;             // ✅ From cast: non-nullable
    
    #[Property(type: 'array', required: false)]
    public ?array $metadata;            // ✅ From cast: nullable (arrays default to nullable)
    
    #[Property(type: 'float', required: true)]
    public float $salary;               // ✅ From cast: decimal → float
    
    #[Property(type: 'date', required: false)]
    public ?Carbon $created_at;         // ✅ From cast: datetime → Carbon
}

Cast Type Mapping:

  • 'integer'int (non-nullable)
  • 'boolean'bool (non-nullable)
  • 'array', 'json'array (nullable)
  • 'decimal:X'float (non-nullable)
  • 'datetime', 'date'Carbon (nullable)
  • 'string'string (nullable)

2. 🥈 Database Schema Inspection (Second Priority)

Source: Live database table structure
Reliability: ⭐⭐⭐⭐ (High)
Environment: Development ✅ | Production ✅ | Test ⚠️ (may not be available)

-- Database table structure
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,           -- → public string $name (required: true)
    email VARCHAR(255) NOT NULL UNIQUE,   -- → public string $email (required: true, validation: email)
    avatar TEXT NULL,                     -- → public ?string $avatar (required: false)
    created_at TIMESTAMP NULL,            -- → public ?Carbon $created_at (required: false)
    updated_at TIMESTAMP NULL             -- → public ?Carbon $updated_at (required: false)
);

-- Generated DTO properties
#[Property(type: 'int', required: true)]
public int $id;                    // ✅ From DB: INT NOT NULL

#[Property(type: 'string', required: true, validation: 'required|max:255')]
public string $name;               // ✅ From DB: VARCHAR(255) NOT NULL

#[Property(type: 'string', required: true, validation: 'required|email|max:255')]
public string $email;              // ✅ From DB: VARCHAR(255) NOT NULL + pattern recognition

#[Property(type: 'string', required: false, validation: 'nullable')]
public ?string $avatar;            // ✅ From DB: TEXT NULL

Database Type Mapping:

  • INT, BIGINT, SMALLINTint
  • VARCHAR, TEXT, CHARstring
  • DECIMAL, FLOAT, DOUBLEfloat
  • BOOLEAN, TINYINT(1)bool
  • JSONarray
  • TIMESTAMP, DATETIME, DATECarbon
  • NULL constraint → required: false
  • NOT NULL constraint → required: true

Multi-Database Support:

  • SQLite: PRAGMA table_info() queries
  • MySQL: SHOW COLUMNS FROM queries
  • PostgreSQL: information_schema.columns queries

3. 🥉 Migration File Analysis (Third Priority)

Source: Laravel migration files in database/migrations/
Reliability: ⭐⭐⭐ (Good)
Environment: Development ✅ | Production ✅ | Test ✅

// Migration file: 2023_01_01_000000_create_users_table.php
Schema::create('users', function (Blueprint $table) {
    $table->id();                           // → public int $id (required: true)
    $table->string('name');                 // → public string $name (required: true)
    $table->string('email')->unique();     // → public string $email (required: true, validation: email)
    $table->text('bio')->nullable();       // → public ?string $bio (required: false)
    $table->boolean('is_active')->default(true); // → public bool $is_active (required: true, default: true)
    $table->timestamps();                   // → public ?Carbon $created_at, $updated_at
});

// Generated DTO
class UserDTO extends LaravelArcDTO {
    #[Property(type: 'int', required: true)]
    public int $id;                    // ✅ From migration: id()
    
    #[Property(type: 'string', required: true, validation: 'required|max:255')]
    public string $name;               // ✅ From migration: string('name')
    
    #[Property(type: 'string', required: true, validation: 'required|email|max:255')]
    public string $email;              // ✅ From migration: string('email') + pattern
    
    #[Property(type: 'string', required: false, validation: 'nullable')]
    public ?string $bio;               // ✅ From migration: text('bio')->nullable()
    
    #[Property(type: 'bool', required: true, default: true)]
    public bool $is_active;            // ✅ From migration: boolean()->default(true)
}

Migration Method Mapping:

  • id(), bigIncrements()int (required)
  • string(), text()string
  • integer(), bigInteger()int
  • decimal(), float(), double()float
  • boolean()bool
  • json(), jsonb()array
  • timestamp(), dateTime()Carbon
  • ->nullable()required: false
  • ->default(value)default: value

4. 🏅 Pattern Recognition (Fallback)

Source: Intelligent field name pattern analysis
Reliability: ⭐⭐ (Basic)
Environment: Always available ✅

// Pattern-based detection when other sources unavailable
class UserDTO extends LaravelArcDTO {
    // Email patterns: email, *_email, *email*
    #[Property(type: 'string', required: true, validation: 'required|email')]
    public string $email;
    
    // ID patterns: id, *_id
    #[Property(type: 'int', required: true)]
    public int $user_id;
    
    // Boolean patterns: is_*, has_*, can_*
    #[Property(type: 'bool', required: false, default: false)]
    public bool $is_active;
    
    // Date patterns: *_at, *_date
    #[Property(type: 'date', required: false)]
    public ?Carbon $created_at;
    
    // Phone patterns: phone, mobile, *_phone
    #[Property(type: 'string', required: false, validation: 'nullable')]
    public ?string $phone;
    
    // Price patterns: price, amount, cost, *_price
    #[Property(type: 'float', required: false)]
    public ?float $price;
}

Built-in Patterns: See Smart Validation Rules for complete pattern library.


🔗 Relation Discovery System

The command automatically detects Eloquent relationships using reflection and maps them to appropriate DTO properties.

Relation Detection Process

  1. Method Analysis: Scans all public methods in the model
  2. Return Type Check: Analyzes method return types via reflection
  3. Eloquent Detection: Identifies Laravel relationship classes
  4. Safe Invocation: Attempts method execution when database available
  5. Type Mapping: Maps relationship types to DTO property types

Relationship Type Mapping

// User Model
class User extends Model {
    public function profile(): HasOne           // → nested DTO property
    {
        return $this->hasOne(Profile::class);
    }
    
    public function posts(): HasMany            // → collection DTO property
    {
        return $this->hasMany(Post::class);
    }
    
    public function roles(): BelongsToMany      // → collection DTO property
    {
        return $this->belongsToMany(Role::class);
    }
    
    public function company(): BelongsTo        // → nested DTO property
    {
        return $this->belongsTo(Company::class);
    }
}

// Generated DTO with relations
class UserDTO extends LaravelArcDTO {
    // Regular model properties...
    
    // Relation: HasOne → nested
    #[Property(type: 'nested', class: ProfileDTO::class, required: false)]
    public ?ProfileDTO $profile;
    
    // Relation: HasMany → collection
    #[Property(type: 'collection', class: PostDTO::class, required: false)]
    public array $posts;
    
    // Relation: BelongsToMany → collection
    #[Property(type: 'collection', class: RoleDTO::class, required: false)]
    public array $roles;
    
    // Relation: BelongsTo → nested
    #[Property(type: 'nested', class: CompanyDTO::class, required: false)]
    public ?CompanyDTO $company;
}

See: Auto-Discovery Relations for detailed relationship mapping.


🌍 Environment Adaptation

The command adapts its behavior based on the environment and available resources:

Test Environment

Model Type: Test/Mock models (contains "Test" or "Mock" in class name)
Database: Not required ❌
Cast Analysis: ✅ Enabled
Fallback: Pattern recognition

# Works without database
php artisan make:dto TestUser --model=TestUserModel
# ✅ Uses model casts + pattern recognition

Development Environment

Model Type: Real Eloquent models
Database: Required ✅
Cast Analysis: ✅ Full analysis
Fallback: Migration files → patterns

# Full analysis with database
php artisan make:dto User --model=User --with-relations
# ✅ Uses casts + database + migrations + patterns

Production Environment

Model Type: Real Eloquent models
Database: May be available ✅/❌
Cast Analysis: ✅ When DB available
Fallback: Migration files → patterns

# Graceful fallback without database
php artisan make:dto User --model=User
# ⚠️  Uses migration files + patterns (warns about limited analysis)

CI/CD Environment

Model Type: Real/Test models
Database: Usually not available ❌
Cast Analysis: ✅ For test models only
Fallback: Static analysis only

# Works reliably in CI
php artisan make:dto User --model=User
# ⚠️  "Cannot instantiate model (no database connection). Using fallback analysis."
# ✅ Generates DTO using static analysis

🚀 Command Usage Examples

Basic DTO Generation

# Simple DTO from model
php artisan make:dto User --model=User

Enhanced Type Detection

# With smart validation rules
php artisan make:dto User --model=User --with-validation

Complete Feature Set

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

Specific Relations

# Only specific relations
php artisan make:dto User --model=User --relations=profile,posts,orders

Strict Security Mode

# Enhanced security validation
php artisan make:dto User --model=User --with-validation --validation-strict

Custom Output Path

# Custom directory
php artisan make:dto User --model=User --path=app/DTOs

🎯 Optimization Tips

For Maximum Accuracy

  1. Use Model Casts (Highest Priority)

    // In your model
    protected $casts = [
        'age' => 'integer',
        'is_active' => 'boolean',
        'metadata' => 'array',
        'price' => 'decimal:2',
    ];
    
  2. Ensure Database Access (Development)

    • Configure database connection
    • Run in environment with database access
    • Ensure table exists before DTO generation
  3. Optimize Field Names (Pattern Recognition)

    // Good: Will be automatically detected
    public string $email;           // → email validation
    public bool $is_active;         // → boolean with default
    public int $user_id;            // → integer, required
    public ?Carbon $created_at;     // → date, nullable
    
  4. Document Relationships (Auto-Discovery)

    // Add return type hints for better detection
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
    

For CI/CD Compatibility

  1. Use Test Models for testing DTO generation
  2. Provide fallback configuration when database unavailable
  3. Leverage pattern recognition for consistent results
  4. Test in multiple environments to ensure reliability

🔍 Troubleshooting

Common Issues and Solutions

"Cannot instantiate model (no database connection)"

Cause: No database connection available
Solution:

  • ✅ Configure database connection
  • ✅ Use test models for testing
  • ✅ Accept fallback analysis for CI/CD

"Model not found"

Cause: Model class doesn't exist
Solution:

  • ✅ Check model class name and namespace
  • ✅ Ensure model is autoloaded
  • ✅ Use full namespace if needed

"Inaccurate type detection"

Cause: Limited information sources
Solution:

  • ✅ Add model casts for better accuracy
  • ✅ Ensure database connection for schema analysis
  • ✅ Use descriptive field names for pattern recognition

"Missing relationships"

Cause: Relationship methods not detected
Solution:

  • ✅ Add return type hints to relationship methods
  • ✅ Ensure relationships are public methods
  • ✅ Use --with-relations flag
  • ✅ Specify relations with --relations=method1,method2

📚 Related Documentation


🏆 Advanced Usage

For advanced scenarios and custom configurations, see: