Laravel Form Validation in Practice
A repeatable pattern for safely handling user input: Laravel validation rules and error messages.
Every web application requires you to validate user input. I used to do this separately for every form: combinations of empty(), strlen(), filter_var(), hand-written error messages, and repetitive chains of if statements. It worked, but maintenance became painful and I kept rewriting the same patterns for every new form.
Laravel’s validation component turned that process into a standard, repeatable pattern. I’ve been using it on a live project for a few weeks now and wanted to share how practical it is.
Basic Usage
In your controller, you use the Validator class:
<?php
class KayitController extends BaseController
{
public function store()
{
$kurallar = [
'ad' => 'required|min:2|max:50',
'email' => 'required|email|unique:kullanicilar',
'sifre' => 'required|min:6|confirmed',
];
$dogrulayici = Validator::make(Input::all(), $kurallar);
if ($dogrulayici->fails()) {
return Redirect::back()
->withErrors($dogrulayici)
->withInput();
}
// Validation passed — create the record
Kullanici::create(Input::only('ad', 'email', 'sifre'));
return Redirect::to('/giris')->with('mesaj', 'Kayıt başarılı.');
}
}
Validator::make() takes two parameters: the data to validate and an array of rules. If fails() returns false, you continue processing.
Validation Rules
Rules are chained together with |. Here are the ones I use most often:
| Rule | Meaning |
|---|---|
required | Cannot be empty |
email | Must be a valid email format |
min:6 | At least 6 characters |
max:100 | At most 100 characters |
unique:tablo | Must be unique in the table |
confirmed | Must match the field_confirmation field |
numeric | Must be a number |
in:a,b,c | Must be one of the specified values |
date | Must be a valid date format |
The confirmed rule is especially useful for password confirmation. If you apply it to the sifre field, the form must also include a field named sifre_confirmation; if the two don’t match, validation fails.
Displaying Error Messages in the View
With withErrors($dogrulayici), the errors are written to the session and automatically become available in the view as the $errors variable:
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $hata)
<li>{{ $hata }}</li>
@endforeach
</ul>
</div>
@endif
<form method="POST" action="/kayit">
<div class="form-group {{ $errors->has('email') ? 'has-error' : '' }}">
<label>E-posta</label>
<input type="email" name="email" value="{{ Input::old('email') }}">
@if ($errors->has('email'))
<span class="help-block">{{ $errors->first('email') }}</span>
@endif
</div>
...
</form>
$errors->has('email') checks whether there is an error for a specific field. $errors->first('email') returns the first error message for that field. Input::old('email') repopulates the form with the value the user typed when validation fails — saving the user from having to retype everything.
Custom Error Messages
To define custom messages instead of the default English ones, you pass a third parameter to Validator::make():
$mesajlar = [
'ad.required' => 'Ad alanı zorunludur.',
'email.required' => 'E-posta alanı zorunludur.',
'email.email' => 'Geçerli bir e-posta adresi giriniz.',
'email.unique' => 'Bu e-posta adresi zaten kayıtlı.',
'sifre.min' => 'Şifre en az 6 karakter olmalıdır.',
];
$dogrulayici = Validator::make(Input::all(), $kurallar, $mesajlar);
You write them in field.rule format. You can define a separate message for every field–rule combination.
A Global Solution via Language Files
Rather than rewriting all those messages in every controller, you can create an app/lang/tr/validation.php file. Laravel loads it automatically:
<?php
return [
'required' => ':attribute alanı zorunludur.',
'email' => ':attribute geçerli bir e-posta adresi olmalıdır.',
'min' => [
'string' => ':attribute en az :min karakter olmalıdır.',
],
// ...
];
The field name is substituted in place of :attribute automatically. Set this up once and every validation message across the entire project uses your custom language — no need to repeat it in every controller.
A Gotcha with the unique Rule
On edit forms, the unique rule can behave unexpectedly. On a registration form, unique:kullanicilar works perfectly — it rejects an email address that already exists. But on an edit form, when a user saves their profile without changing their email, the rule sees that the email is already in the table and throws an error.
To work around this, you include the current record’s ID in the rule definition:
$kurallar = [
'email' => 'required|email|unique:kullanicilar,email,' . $kullanici->id,
];
The unique:table,column,excluded_id format excludes the row belonging to that ID from the uniqueness check. I discovered this on an edit form — a rule that worked fine on registration was blocking users from saving their profile without making any changes.
Why Does This Matter?
If you don’t validate user input, two problems arise: the application runs with inconsistent data, and security vulnerabilities open up. Laravel’s validation layer provides a standard, repeatable solution for both. I no longer write if chains from scratch for every form; I write a list of rules and the framework handles the rest.
It might seem like a small thing, but in a large project with dozens of forms the value of that standardization compounds quickly. Especially when you join a project mid-stream — having rules defined in a central, consistent place makes it straightforward to understand how each form behaves, without having to hunt through controllers for scattered if blocks.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.