Table of Contents
When building complex forms in Laravel, you’ll often need validation rules that depend on other input values. Laravel’s Rule::requiredIf() combined with custom closure validation gives you powerful control over conditional logic.
The Challenge
Imagine you’re building a file upload system where users can choose between uploading files or entering barcodes. The validation rules need to change based on that choice—files are required for one mode, barcodes for another. Hardcoding separate validation paths leads to duplication and brittle code.
The Solution: Conditional Rules with Closures
Laravel lets you build validation rules dynamically using Rule::requiredIf() for conditional requirements and custom closures for complex business logic:
use Illuminate\Validation\Rule;
$uploadType = $request->input("items.{$itemId}.upload_type");
$rules = [
"items.{$itemId}.upload_type" => 'required|in:file,barcode',
// Files only required when upload_type is 'file'
"items.{$itemId}.files" => [
"required_if:items.{$itemId}.upload_type,file",
'array',
function ($attribute, $value, $fail) use ($itemId, $maxAllowed) {
if (count($value) > $maxAllowed) {
$fail("Item {$itemId}: Too many files. Max allowed: {$maxAllowed}");
}
}
],
// Barcodes only required when upload_type is 'barcode'
"items.{$itemId}.barcodes" => [
"required_if:items.{$itemId}.upload_type,barcode",
'string',
function ($attribute, $value, $fail) use ($repository, $itemId) {
$codes = array_filter(preg_split('/[\s\n]+/', $value));
// Check for duplicates in database
$duplicates = $repository->findExisting($codes);
if ($duplicates->isNotEmpty()) {
$fail("Item {$itemId}: Duplicate barcodes found: " . $duplicates->implode(', '));
}
}
],
];
$validated = $request->validate($rules);
Why This Pattern Works
- Centralized validation: All rules in one place, no scattered if/else branches
- Flexible conditions:
Rule::requiredIf()handles simple dependencies - Custom business logic: Closures let you inject services and run complex checks
- Clear error messages: Customize failures per field and context
Taking It Further
You can nest conditions deeper with Rule::when() or combine multiple closure validators for different aspects (format validation, uniqueness, business rules). Laravel’s validation system is expressive enough to handle even the most complex form requirements without leaving the validation layer.
Pro tip: For very complex validation, consider extracting to a custom Form Request class. But for moderately complex interdependent fields, this inline approach keeps everything readable and maintainable.
Leave a Reply