Are you tired of complex validation logic cluttering your Laravel controllers? Do you find yourself repeating the same validation patterns across multiple projects? Custom validation rules might be the solution you’ve been searching for!
In this comprehensive guide, we’ll walk through creating custom validation rules in Laravel that will help you write cleaner, more maintainable code while handling complex validation scenarios with ease.
Why Custom Validation Rules Matter
Laravel’s built-in validation rules are powerful, but they can’t cover every possible scenario your application might need. Custom validation rules allow you to:
- Encapsulate complex business logic
- Create reusable validation components
- Improve code readability
- Maintain consistency across your application
- Simplify testing of validation logic
Step-by-Step: Creating a Phone Number Validation Rule
Let’s create a practical custom validation rule that ensures users enter a valid phone number format.
Step 1: Generate the Validation Rule
Use Laravel’s Artisan command to create your custom rule:
php artisan make:rule PhoneNumberRule
This creates a new file at app/Rules/PhoneNumberRule.php.
Step 2: Implement the Validation Logic
Open the generated file and implement your validation logic:
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class PhoneNumberRule implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
// Basic phone number validation (adjust regex for your needs)
$pattern = '/^\+?[1-9]\d{1,14}$/';
if (!preg_match($pattern, $value)) {
$fail('The :attribute must be a valid phone number format.');
}
}
}
Step 3: Create Routes
Set up routes to handle both the form display and form submission:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
Route::prefix('users')->group(function () {
Route::get('/', [UserController::class, 'create']);
Route::post('create', [UserController::class, 'store'])->name('users.store');
});
Step 4: Build the Controller
Create a controller to handle the validation logic:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use App\Rules\PhoneNumberRule;
class UserController extends Controller
{
public function create(): View
{
return view('users.create-user');
}
public function store(Request $request): RedirectResponse
{
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|max:255|string|unique:users,email',
'phone_number' => [
'required',
new PhoneNumberRule()
]
]);
// Process valid data here (e.g., save to database)
return back()->with('success', 'User created successfully!');
}
}
Step 5: Design the Form View
Create a user-friendly form with proper error handling:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Creation</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow">
<div class="card-header bg-primary text-white">
<h2 class="h4 mb-0">User Creation Form</h2>
</div>
<div class="card-body">
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
<form method="POST" action="{{ route('users.store') }}">
@csrf
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text"
class="form-control @error('name') is-invalid @enderror"
id="name"
name="name"
value="{{ old('name') }}"
required>
@error('name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email"
class="form-control @error('email') is-invalid @enderror"
id="email"
name="email"
value="{{ old('email') }}"
required>
@error('name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="phone_number" class="form-label">Phone Number</label>
<input type="text"
class="form-control @error('phone_number') is-invalid @enderror"
id="phone_number"
name="phone_number"
value="{{ old('phone_number') }}"
placeholder="+1234567890"
required>
@error('phone_number')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
<div class="form-text">Enter your phone number in international format (e.g., +1234567890)</div>
</div>
<button type="submit" class="btn btn-primary w-100">Create</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Testing Your Custom Validation Rule
Run your Laravel development server:
php artisan serve
Visit http://localhost:8000/users in your browser to test the form. Try submitting both valid and invalid phone numbers to see the custom validation rule in action.
Expanding Your Custom Validation Toolkit
Now that you’ve mastered the basics, consider creating other useful custom validation rules:
- Email Domain Validation: Ensure emails are from specific domains
- Username Availability: Check if a username is already taken
- Password Strength: Enforce strong password requirements
- File Type Validation: Restrict uploads to specific file types
- Business Logic Rules: Validate according to your specific business requirements
Best Practices for Custom Validation Rules
- Keep Rules Focused: Each rule should handle one specific validation concern
- Provide Clear Error Messages: Help users understand what went wrong
- Test Thoroughly: Write tests for both valid and invalid inputs
- Reuse When Possible: Create rules that can be used across multiple parts of your application
- Follow Naming Conventions: Use descriptive names that indicate the rule’s purpose
Conclusion
Custom validation rules are a powerful feature in Laravel that can significantly improve your development workflow and application quality. By encapsulating validation logic in dedicated rule classes, you create more maintainable, testable, and reusable code.
The phone number validation example we’ve created demonstrates how easy it is to implement custom validation rules that handle specific business requirements. As you continue developing with Laravel, consider building a library of custom validation rules that you can reuse across projects.
Remember, the goal of validation is not just to prevent invalid data but to provide clear guidance to users and maintain data integrity throughout your application. With custom validation rules, you have the flexibility to implement exactly the validation logic your application needs.
If you found this helpful, feel free to share or drop a comment. Happy coding with Laravel! 🧱✨
Free resources for this topic
Code snippets and fixes for this topic
Get one practical tip every week
New tutorials, fixes and free cheat sheets from DEV Talk, straight to your inbox. No spam, unsubscribe in one click.
Free download: Laravel interview questions (PDF)
Have a question about this post?
Ask the community: other developers and the author can answer.
Get notified about new articles
One click, no email needed. Turn it off anytime with the bell at the top.
Get new articles on your iPhone
Add DEV Talk to your Home Screen, open it, then tap the bell.
Enjoying the content?
If this article helped you, you can support the author with a coffee. It keeps new posts coming.
Comments 0
No comments yet
Be the first to share your thoughts.