Smart Validation Rules - Grazulex/laravel-arc GitHub Wiki
🛡️ Smart Validation Rules
Smart Validation Rules automatically generate Laravel validation rules based on field names, types, and common patterns. This feature saves time and ensures consistent validation across your application.
🎯 Overview
The smart validation system analyzes property names and types to intelligently suggest appropriate validation rules, reducing manual configuration while maintaining security and data integrity.
Key Benefits
- Intelligent Detection: Recognizes common field patterns automatically
- Security-First: Generates secure validation rules by default
- Pattern Recognition: 20+ built-in patterns for common fields
- Customizable: Add your own patterns and rules
- Strict Mode: Enhanced security for sensitive applications
🛠️ How It Works
Pattern Matching Process
- Field Analysis: Examines property names and types
- Pattern Recognition: Matches against built-in patterns
- Rule Generation: Creates appropriate Laravel validation rules
- Security Enhancement: Applies strict mode rules if enabled
Recognition Levels
Level | Description | Examples |
---|---|---|
Exact Match | Field name exactly matches pattern | email , password , phone |
Suffix Match | Field ends with pattern | *_email , *_phone , *_url |
Prefix Match | Field starts with pattern | is_* , has_* , can_* |
Contains Match | Field contains pattern | *password* , *secret* |
Type-Based | Based on PHP type hints | int , float , bool , string |
🚀 Usage
Basic Smart Validation
# Generate DTO with smart validation
php artisan make:dto User --model=User --with-validation
Strict Mode (Enhanced Security)
# Generate with strict security rules
php artisan make:dto User --model=User --with-validation --validation-strict
Custom Patterns
# Generate with custom validation patterns
php artisan make:dto User --model=User --with-validation --validation-patterns=custom
📋 Built-in Patterns
Email Fields
// Detected patterns: email, *_email, *email*
class UserDTO extends LaravelArcDTO
{
#[Property(type: 'string', required: true, validation: 'required|string|email|max:254')]
public string $email;
#[Property(type: 'string', required: false, validation: 'nullable|string|email|max:254')]
public ?string $backup_email;
}
Password Fields
// Detected patterns: password, *_password, *password*
class UserDTO extends LaravelArcDTO
{
// Standard mode
#[Property(type: 'string', required: true, validation: 'required|string|min:8')]
public string $password;
// Strict mode
#[Property(type: 'string', required: true, validation: 'required|string|min:12|regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/')]
public string $password_strict;
}
Phone Fields
// Detected patterns: phone, mobile, telephone, *_phone
class ContactDTO extends LaravelArcDTO
{
#[Property(type: 'string', required: false, validation: 'nullable|string|regex:/^[+]?[0-9\s\-\(\)]+$/|max:20')]
public ?string $phone;
#[Property(type: 'string', required: false, validation: 'nullable|string|regex:/^[+]?[0-9\s\-\(\)]+$/|max:20')]
public ?string $mobile_phone;
}
Age and Numeric Fields
// Detected patterns: age, year, count, quantity, amount
class PersonDTO extends LaravelArcDTO
{
#[Property(type: 'int', required: true, validation: 'required|integer|min:0|max:150')]
public int $age;
#[Property(type: 'int', required: true, validation: 'required|integer|min:1900|max:2100')]
public int $birth_year;
#[Property(type: 'int', required: true, validation: 'required|integer|min:1')]
public int $quantity;
}
URL Fields
// Detected patterns: url, website, link, *_url
class ProfileDTO extends LaravelArcDTO
{
#[Property(type: 'string', required: false, validation: 'nullable|string|url|max:2048')]
public ?string $website;
#[Property(type: 'string', required: false, validation: 'nullable|string|url|max:2048')]
public ?string $portfolio_url;
}
Boolean Fields
// Detected patterns: is_*, has_*, can_*, *_active, *_enabled
class UserDTO extends LaravelArcDTO
{
#[Property(type: 'bool', required: false, default: true, validation: 'boolean')]
public bool $is_active;
#[Property(type: 'bool', required: false, default: false, validation: 'boolean')]
public bool $has_verified_email;
#[Property(type: 'bool', required: false, default: false, validation: 'boolean')]
public bool $can_login;
}
Country and Language Codes
// Detected patterns: country_code, language_code, locale, *_code
class AddressDTO extends LaravelArcDTO
{
#[Property(type: 'string', required: true, validation: 'required|string|size:2|alpha')]
public string $country_code;
#[Property(type: 'string', required: false, validation: 'nullable|string|size:2|alpha')]
public ?string $language_code;
}
Date and Time Fields
// Detected patterns: *_at, *_date, *_time, birth_date, created_at
class EventDTO extends LaravelArcDTO
{
#[Property(type: 'date', required: false, validation: 'nullable|date')]
public ?Carbon $created_at;
#[Property(type: 'date', required: false, validation: 'nullable|date|before:today')]
public ?Carbon $birth_date;
#[Property(type: 'date', required: true, validation: 'required|date|after:now')]
public Carbon $event_date;
}
🕰️ Complete Pattern Library
All Built-in Patterns
Pattern | Field Examples | Validation Rules |
---|---|---|
email , user_email |
||
Password | password , new_password |
min:8 (standard), `min:12 |
Phone | phone , mobile , telephone |
`regex:/^[+]?[0-9\s-()]+$/ |
URL | url , website , portfolio_url |
`url |
Age | age |
`integer |
Year | year , birth_year |
`integer |
Count | count , quantity , amount |
`integer |
Price | price , cost , amount |
`numeric |
Boolean | is_* , has_* , can_* |
boolean |
Country Code | country_code , cc |
`size:2 |
Language | language_code , locale |
`size:2 |
Postal Code | postal_code , zip_code |
`max:20 |
Name | name , first_name , last_name |
`max:255 |
Username | username , login |
`min:3 |
Slug | slug , permalink |
`max:255 |
IP Address | ip , ip_address |
ip |
UUID | uuid , *_uuid |
uuid |
JSON | json , *_json , metadata |
json |
Date | *_at , *_date |
date |
Color | color , *_color |
regex:/^#[a-fA-F0-9]{6}$/ |
Rating | rating , score |
`integer |
🔧 Custom Patterns
Adding Custom Patterns
// In a service provider
public function boot()
{
ValidationRuleGenerator::addPattern('api_key', [
'validation' => 'required|string|size:32|alpha_num',
'security_level' => 'high'
]);
ValidationRuleGenerator::addPattern('*_token', [
'validation' => 'required|string|min:40|max:255',
'strict_validation' => 'required|string|size:60|regex:/^[a-zA-Z0-9]+$/'
]);
}
Pattern Configuration
class CustomValidationPatterns
{
public static function getPatterns(): array
{
return [
// Exact matches
'iban' => [
'validation' => 'required|string|iban',
'description' => 'International Bank Account Number'
],
// Regex patterns
'/.*_reference$/' => [
'validation' => 'required|string|max:50|alpha_num',
'description' => 'Reference numbers'
],
// Type-based patterns
'float:price' => [
'validation' => 'required|numeric|min:0|max:999999.99',
'description' => 'Price fields'
]
];
}
}
🛡️ Strict Mode Features
Enhanced Security Rules
// Standard vs Strict mode comparison
class SecurityDTO extends LaravelArcDTO
{
// Standard mode
#[Property(type: 'string', validation: 'required|string|min:8')]
public string $password;
// Strict mode - Enhanced security
#[Property(type: 'string', validation: 'required|string|min:12|regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/')]
public string $password_strict;
// Standard email
#[Property(type: 'string', validation: 'required|email|max:254')]
public string $email;
// Strict email - Additional checks
#[Property(type: 'string', validation: 'required|email:rfc,dns|max:254|not_regex:/\+.*@/')]
public string $email_strict;
}
Strict Mode Patterns
Field Type | Standard | Strict Mode Enhancement |
---|---|---|
Password | min:8 |
min:12 + complexity regex |
email |
email:rfc,dns + disposable email blocking |
|
Phone | Basic regex | International format validation |
URL | url |
url + domain whitelist |
Name | max:255 |
+ XSS prevention regex |
Username | alpha_num_dash |
+ reserved word blocking |
🎨 Advanced Examples
Complete User Registration DTO
class UserRegistrationDTO extends LaravelArcDTO
{
#[Property(
type: 'string',
required: true,
validation: 'required|string|max:255|regex:/^[\pL\s\-]+$/u',
transform: [TrimTransformer::class]
)]
public string $first_name;
#[Property(
type: 'string',
required: true,
validation: 'required|string|max:255|regex:/^[\pL\s\-]+$/u',
transform: [TrimTransformer::class]
)]
public string $last_name;
#[Property(
type: 'string',
required: true,
validation: 'required|string|email:rfc,dns|max:254|unique:users,email',
transform: [TrimTransformer::class, LowercaseTransformer::class]
)]
public string $email;
#[Property(
type: 'string',
required: true,
validation: 'required|string|min:12|regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/',
transform: [HashTransformer::class]
)]
public string $password;
#[Property(
type: 'string',
required: false,
validation: 'nullable|string|regex:/^[+]?[1-9]\d{1,14}$/',
transform: [TrimTransformer::class]
)]
public ?string $phone;
#[Property(
type: 'date',
required: false,
validation: 'nullable|date|before:today|after:1900-01-01'
)]
public ?Carbon $birth_date;
#[Property(
type: 'string',
required: true,
validation: 'required|string|size:2|alpha|in:US,CA,GB,DE,FR,ES,IT',
transform: [UppercaseTransformer::class]
)]
public string $country_code;
}
E-commerce Product DTO
class ProductDTO extends LaravelArcDTO
{
#[Property(
type: 'string',
required: true,
validation: 'required|string|max:255|min:3',
transform: [TrimTransformer::class]
)]
public string $name;
#[Property(
type: 'string',
required: true,
validation: 'required|string|max:255|regex:/^[a-z0-9]+(?:-[a-z0-9]+)*$/|unique:products,slug',
transform: [TrimTransformer::class, LowercaseTransformer::class, SlugTransformer::class]
)]
public string $slug;
#[Property(
type: 'float',
required: true,
validation: 'required|numeric|min:0.01|max:999999.99'
)]
public float $price;
#[Property(
type: 'string',
required: true,
validation: 'required|string|max:20|alpha_num|unique:products,sku',
transform: [TrimTransformer::class, UppercaseTransformer::class]
)]
public string $sku;
#[Property(
type: 'int',
required: true,
validation: 'required|integer|min:0|max:99999'
)]
public int $stock_quantity;
#[Property(
type: 'float',
required: false,
validation: 'nullable|numeric|min:0|max:100'
)]
public ?float $discount_percentage;
}
🛠️ Testing Validation Rules
Unit Testing
class ValidationRulesTest extends TestCase
{
public function test_email_validation_rules(): void
{
$rules = UserDTO::rules();
$this->assertStringContainsString('email', $rules['email']);
$this->assertStringContainsString('max:254', $rules['email']);
}
public function test_password_strict_validation(): void
{
$this->expectException(ValidationException::class);
new UserDTO([
'email' => '[email protected]',
'password' => 'weak' // Should fail strict validation
]);
}
public function test_phone_format_validation(): void
{
$user = new UserDTO([
'email' => '[email protected]',
'password' => 'StrongPass123!',
'phone' => '+1-555-123-4567'
]);
$this->assertEquals('+1-555-123-4567', $user->phone);
}
}
Integration Testing
class SmartValidationIntegrationTest extends TestCase
{
public function test_generates_appropriate_rules_for_common_fields(): void
{
$generator = new ValidationRuleGenerator();
$rules = $generator->generateRules([
'email' => 'string',
'password' => 'string',
'age' => 'int',
'is_active' => 'bool'
]);
$this->assertStringContainsString('email', $rules['email']);
$this->assertStringContainsString('min:', $rules['password']);
$this->assertStringContainsString('integer', $rules['age']);
$this->assertStringContainsString('boolean', $rules['is_active']);
}
}
📚 Best Practices
1. Use Appropriate Security Levels
// ✅ Good - Use strict mode for sensitive data
class AdminUserDTO extends LaravelArcDTO
{
#[Property(type: 'string', validation: 'required|string|min:12|regex:/complex_pattern/')]
public string $admin_password;
}
// ✅ Good - Standard mode for regular fields
class ProfileDTO extends LaravelArcDTO
{
#[Property(type: 'string', validation: 'required|string|max:255')]
public string $display_name;
}
2. Combine with Transformations
class UserDTO extends LaravelArcDTO
{
#[Property(
type: 'string',
validation: 'required|email|max:254',
transform: [TrimTransformer::class, LowercaseTransformer::class]
)]
public string $email;
}
3. Document Custom Rules
class ApiKeyDTO extends LaravelArcDTO
{
/**
* API key must be exactly 32 characters, alphanumeric only
* Pattern: Custom API key validation for security
*/
#[Property(
type: 'string',
required: true,
validation: 'required|string|size:32|alpha_num'
)]
public string $api_key;
}
🔗 Related Pages
- Property Attributes - Learn about Property configurations
- Transformation Pipeline - Data transformations
- Advanced Features - Overview of all advanced features
- Debug & Analysis Tools - Test your validation rules
- Examples Gallery - Real-world usage examples
⬅️ Back to: Auto-Discovery Relations | ➡️ Next: Debug & Analysis Tools