Validation API

Comprehensive validation system with built-in rules, custom validators, and advanced validation patterns. The validation system provides server-side and client-side validation with support for conditional rules, nested data validation, and internationalization.

Validator Class

Main validation class that provides a fluent interface for defining validation rules, running validations, and handling validation results. The Validator supports chaining, custom error messages, and multiple validation contexts.

Basic Validation

Creating Validators

Initialize and configure validation rules.

use Forge\Validation\Validator;
use Forge\Validation\Rules\RuleFactory;

// Create validator instance
$validator = new Validator();

// Basic validation
$validator->make($data, [
    'name' => 'required|string|min:3|max:255',
    'email' => 'required|email|unique:users,email',
    'age' => 'required|integer|min:18|max:120',
    'password.min' => 'Your password must be at least 8 characters long for security.',
    'password.confirmed' => 'The password confirmation does not match. Please try again.',
    'terms.accepted' => 'You must accept the terms and conditions to continue.'
];

// Using custom messages with validator
$validator = Validator::make($data, $rules, $messages);

// Dynamic error messages
$validator->setCustomMessages([
    'name.required' => 'Please tell us your name.',
    'email.unique' => 'This email is already registered. Try logging in or use a different email.'
]);

// Localization support
$messages = [
    'required' => trans('validation.required'),
    'email' => trans('validation.email'),
    'min' => trans('validation.min'),
    'custom' => [
        'attribute-name' => [
            'rule-name' => trans('validation.custom.attribute-name.rule-name')
        ]
    ]
];

// Attribute aliases (friendly names)
$attributes = [
    'email' => 'email address',
    'first_name' => 'first name',
    'last_name' => 'last name',
    'dob' => 'date of birth',
    'pwd' => 'password',
    'addr' => 'address',
    'ph' => 'phone number'
];

$validator = Validator::make($data, $rules, $messages, $attributes);

// Getting error messages
if ($validator->fails()) {
    // Get all errors
    $errors = $validator->errors();
    
    // Get errors for specific field
    $emailErrors = $validator->errors()->get('email');
    
    // Get first error for field
    $firstEmailError = $validator->errors()->first('email');
    
    // Get all errors as array
    $allErrors = $validator->errors()->all();
    
    // Get errors as JSON
    $errorsJson = $validator->errors()->toJson();
    
    // Get errors as array with field names
    $errorsArray = $validator->errors()->toArray();
    
    // Check if field has errors
    $hasEmailErrors = $validator->errors()->has('email');
    
    // Add custom error
    $validator->errors()->add('field', 'Custom error message');
    
    // Merge additional errors
    $validator->errors()->merge([
        'field1' => ['Additional error 1'],
        'field2' => ['Additional error 2']
    ]);
    
    // Set error bag name
    $validator->errors()->setBag('login');
    
    // Get specific error bag
    $loginErrors = $validator->errors()->getBag('login');
}

// Error message formatting
$messages = [
    'required' => 'The :attribute field is required.',
    'min' => [
        'numeric' => 'The :attribute must be at least :min.',
        'file' => 'The :attribute must be at least :min kilobytes.',
        'string' => 'The :attribute must be at least :min characters.',
        'array' => 'The :attribute must have at least :min items.'
    ],
    'between' => [
        'numeric' => 'The :attribute must be between :min and :max.',
        'file' => 'The :attribute must be between :min and :max kilobytes.',
        'string' => 'The :attribute must be between :min and :max characters.',
        'array' => 'The :attribute must have between :min and :max items.'
    ]
];

// Custom placeholders
$messages = [
    'password' => 'The :attribute must contain at least one :uppercase, one :lowercase, and one :number.',
    'password.uppercase' => 'uppercase letter',
    'password.lowercase' => 'lowercase letter',
    'password.number' => 'number'
];

Validation Feedback

Provide user-friendly validation feedback and suggestions.

// Get validation suggestions
$suggestions = $validator->suggestions();

// Add helpful suggestions
$validator->addSuggestion('password', 'Consider using a longer password with mixed case letters and numbers.');
$validator->addSuggestion('email', 'Use a professional email address for better credibility.');

// Validation hints
$hints = [
    'password' => 'Use at least 8 characters with mixed case and numbers.',
    'username' => 'Choose a unique username that represents you or your business.',
    'phone' => 'Include country code for international contacts (e.g., +1 for US).'
];

$validator->setHints($hints);

// Validation warnings (non-blocking)
$validator->addWarning('password', 'Your password is strong, but consider adding special characters for extra security.');
$validator->addWarning('email', 'Using a free email provider is fine, but a custom domain looks more professional.');

// Success messages
$validator->addSuccess('email', 'Email format is valid!');
$validator->addSuccess('password', 'Great! Your password meets all security requirements.');

// Validation summary
$summary = $validator->summary();

// Example: Return validation response for API
public function validateForm(Request $request)
{
    $validator = Validator::make($request->all(), [
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users',
        'password' => 'required|strong_password'
    ]);
    
    if ($validator->fails()) {
        return response()->json([
            'success' => false,
            'message' => 'Validation failed',
            'errors' => $validator->errors(),
            'suggestions' => $validator->suggestions(),
            'warnings' => $validator->warnings(),
            'hints' => $validator->hints()
        ], 422);
    }
    
    return response()->json([
        'success' => true,
        'message' => 'Validation passed',
        'data' => $validator->validated(),
        'successes' => $validator->successes()
    ]);
}

// Frontend-friendly error formatting
public function formatErrorsForFrontend($validator)
{
    $errors = [];
    
    foreach ($validator->errors()->toArray() as $field => $messages) {
        $errors[$field] = [
            'message' => $messages[0], // First error message
            'all_messages' => $messages,
            'suggestion' => $validator->suggestions()->get($field),
            'hint' => $validator->hints()->get($field)
        ];
    }
    
    return [
        'has_errors' => $validator->fails(),
        'errors' => $errors,
        'warnings' => $validator->warnings()->toArray(),
        'successes' => $validator->successes()->toArray()
    ];
}

Best Practices

Do's

  • • Use descriptive field names and aliases
  • • Validate early and validate often
  • • Use built-in rules when possible
  • • Create reusable custom rules
  • • Provide helpful error messages
  • • Use conditional validation for complex logic
  • • Validate file uploads comprehensively
  • • Test validation rules thoroughly
  • • Use validation groups for different contexts
  • • Implement proper error handling

Don'ts

  • • Don't trust client-side validation alone
  • • Don't expose sensitive information in errors
  • • Don't make validation rules too complex
  • • Don't ignore performance implications
  • • Don't hardcode error messages
  • • Don't validate the same data multiple times
  • • Don't forget about edge cases
  • • Don't ignore security validation
  • • Don't make assumptions about data format
  • • Don't skip validation for "trusted" sources

Performance Tips

  • • Use bail rule to stop validation on first failure
  • • Cache validation rules that don't change frequently
  • • Use database indexes for unique validation rules
  • • Batch database queries for existence validation
  • • Use lazy validation for large datasets
  • • Implement validation rule caching
  • • Use validation groups to avoid unnecessary checks
  • • Optimize regular expressions in custom rules
  • • Use native PHP functions when possible
  • • Profile validation performance in production