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
,SMALLINT
→int
VARCHAR
,TEXT
,CHAR
→string
DECIMAL
,FLOAT
,DOUBLE
→float
BOOLEAN
,TINYINT(1)
→bool
JSON
→array
TIMESTAMP
,DATETIME
,DATE
→Carbon
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
- Method Analysis: Scans all public methods in the model
- Return Type Check: Analyzes method return types via reflection
- Eloquent Detection: Identifies Laravel relationship classes
- Safe Invocation: Attempts method execution when database available
- 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
-
Use Model Casts (Highest Priority)
// In your model protected $casts = [ 'age' => 'integer', 'is_active' => 'boolean', 'metadata' => 'array', 'price' => 'decimal:2', ];
-
Ensure Database Access (Development)
- Configure database connection
- Run in environment with database access
- Ensure table exists before DTO generation
-
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
-
Document Relationships (Auto-Discovery)
// Add return type hints for better detection public function posts(): HasMany { return $this->hasMany(Post::class); }
For CI/CD Compatibility
- Use Test Models for testing DTO generation
- Provide fallback configuration when database unavailable
- Leverage pattern recognition for consistent results
- 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
- Auto-Discovery Relations - Detailed relationship mapping
- Smart Validation Rules - Pattern recognition and validation
- Type Safety - Understanding type detection
- Best Practices - Optimization recommendations
- FAQ - Common questions and solutions
🏆 Advanced Usage
For advanced scenarios and custom configurations, see:
- API Reference - Programmatic usage
- Examples Gallery - Real-world examples
- Debug & Analysis Tools - DTO analysis and debugging