This tutorial is out of date and no longer maintained.
Today we’ll be handling form validation in Laravel. There are many things that need to happen to make sure that everything works the way a user would expect it to so let’s get started.
Our application will do many things. These include:
That’s a lot to do so let’s get started. We’ll start by setting up our database.
Once we’ve got Laravel all set up, let’s go to our command line and create our migration so that our database table will be created. We will need this so we can do validation to make sure that emails entered are unique in the database. We wouldn’t want multiple users with the same email right?
Go into the command line and type
- php artisan migrate:make create_ducks_table --create=ducks
Now let’s edit that newly generated migration file.
<?php
// app/database/migrations/####_##_##_######_create_ducks_table.php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateDucksTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('ducks', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->string('email');
$table->string('password');
$table->timestamps();
});
}
}
Now make sure your database settings are good in app/config/local/database.php
or app/config/database.php
and then let’s run our migration:
- php artisan migrate
We are going to create our Eloquent model so that we can save our ducks to the database. This is also how we will be able to test to make sure that our new duck/user has a unique email in the database. Create the model at app/models/Duck.php
.
<?php
// app/models/Duck.php
class Duck extends Eloquent {
protected $fillable = array('name', 'email', 'password');
}
With our database and model ready to go, now we can get to our actual validation.
Further Reading: A Guide to Using Eloquent ORM in Laravel
We will be handling the routing for our application in the app/routes.php
file that Laravel provides. We’ll be handling the GET
for showing the form and the POST
for processing the form here.
<?php
// app/routes.php
// route to show the duck form
Route::get('ducks', function()
{
return View::make('duck-form');
});
// route to process the ducks form
Route::post('ducks', function()
{
// process the form here
});
This will be accessible at http://example.com/ducks
and then we’ll also be POSTing to the same URL. With our routes ready, let’s create the duck-form that we are displaying to our user.
Further Reading: Simple and Easy Laravel Routing
The view file will be at app/views/duck-form.blade.php
and we’ll use Laravel’s Blade to handle our views.
Further Reading: Simple Laravel Layouts Using Blade
Here’s that view file. We’ll use Bootstrap to make our views look good and then we’ll start our validation.
<!-- app/views/duck-form.blade.php -->
<!doctype html>
<html>
<head>
<title>Laravel Form Validation!</title>
<!-- load bootstrap -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<style>
body { padding-bottom:40px; padding-top:40px; }
</style>
</head>
<body class="container">
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div class="page-header">
<h1><span class="glyphicon glyphicon-flash"></span> Ducks Fly!</h1>
</div>
<!-- FORM STARTS HERE -->
<form method="POST" action="/ducks" novalidate>
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" name="name" placeholder="Somebody Important">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" class="form-control" name="email" placeholder="email@example.com">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" class="form-control" name="password">
</div>
<div class="form-group">
<label for="password_confirm">Confirm Password</label>
<input type="password" id="password_confirm" class="form-control" name="password_confirm">
</div>
<button type="submit" class="btn btn-success">Go Ducks Go!</button>
</form>
</div>
</div>
</body>
</html>
Now our beautiful form has taken… well… form.
Now that we have our view, we’ll be going through all the validations needed. Since we already have our form’s action="/ducks"
ready to go, our form will send a POST
request to http://example.com/ducks
and then we handle that in the route we made earlier in app/routes.php
.
Let’s start off our validation now in that routes.php
file. We’re going to create our rules, run the validation on the form inputs, and handle the error messages from there.
Let’s create those rules:
<?php
// app/routes.php
...
// route to process the ducks form
Route::post('ducks', function()
{
// process the form here
// create the validation rules ------------------------
$rules = array(
'name' => 'required', // just a normal required validation
'email' => 'required|email|unique:ducks', // required and must be unique in the ducks table
'password' => 'required',
'password_confirm' => 'required|same:password' // required and has to match the password field
);
// do the validation ----------------------------------
// validate against the inputs from our form
$validator = Validator::make(Input::all(), $rules);
// check if the validator failed -----------------------
if ($validator->fails()) {
// get the error messages from the validator
$messages = $validator->messages();
// redirect our user back to the form with the errors from the validator
return Redirect::to('ducks')
->withErrors($validator);
} else {
// validation successful ---------------------------
// our duck has passed all tests!
// let him enter the database
// create the data for our duck
$duck = new Duck;
$duck->name = Input::get('name');
$duck->email = Input::get('email');
$duck->password = Hash::make(Input::get('password'));
// save our duck
$duck->save();
// redirect ----------------------------------------
// redirect our user back to the form so they can do it all over again
return Redirect::to('ducks');
}
});
...
With this setup, we have:
name
email
that has to be in email form
password
password_confirm
field that needs to match passwordSo we have set the rules for our inputs. We have run the validation and checked if that worked. If it didn’t work, we are sending our user back to our form with the errors. If the validation succeeded, we are going to create the duck in our database and redirect the user back to the form. For a full list of the validation rules available to you, go look at the available validation rules.
Let’s say that our user did not pass the validation. We want to show off all the messages in our view. All we have to do is go into our view and add that in.
<!-- app/views/duck-form.blade.php -->
...
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div class="page-header">
<h1><span class="glyphicon glyphicon-flash"></span> Ducks Fly!</h1>
</div>
@if ($errors->has())
<div class="alert alert-danger">
@foreach ($errors->all() as $error)
{{ $error }}<br>
@endforeach
</div>
@endif
<!-- FORM STARTS HERE -->
<form method="POST" action="/ducks" novalidate>
...
Just like that, we know can show off our errors. This may not always be ideal though. Sometimes our user will expect the error to be placed next to the input it corresponds to.
We have the ability to do this in Laravel and we can pick out single errors using:
// select the first error that corresponds to the name field
{{ $errors->first('name') }}
We can add this to each of our inputs and also we will use an if statement to add a Bootstrap error class (has-error
) so that Bootstrap will turn our inputs red.
<!-- app/views/duck-form.blade.php -->
...
<!-- FORM STARTS HERE -->
<form method="POST" action="/ducks" novalidate>
<div class="form-group @if ($errors->has('name')) has-error @endif">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" name="name" placeholder="Somebody Awesome">
@if ($errors->has('name')) <p class="help-block">{{ $errors->first('name') }}</p> @endif
</div>
<div class="form-group @if ($errors->has('email')) has-error @endif">
<label for="email">Email</label>
<input type="text" id="email" class="form-control" name="email" placeholder="email@example.com">
@if ($errors->has('email')) <p class="help-block">{{ $errors->first('email') }}</p> @endif
</div>
<div class="form-group @if ($errors->has('password')) has-error @endif">
<label for="password">Password</label>
<input type="password" id="password" class="form-control" name="password">
@if ($errors->has('password')) <p class="help-block">{{ $errors->first('password') }}</p> @endif
</div>
<div class="form-group @if ($errors->has('password_confirm')) has-error @endif">
<label for="password_confirm">Confirm Password</label>
<input type="password" id="password_confirm" class="form-control" name="password_confirm">
@if ($errors->has('password_confirm')) <p class="help-block">{{ $errors->first('password_confirm') }}</p> @endif
</div>
<button type="submit" class="btn btn-success">Go Ducks Go!</button>
</form>
...
Now we are using if statements that will show errors if Laravel has shown there is an error for that field. Each input will have the correct errors next to it now.
Now that our errors are good to go, our users will find those messages helpful. One other thing that they would appreciate also is that they would probably want to have the inputs they provided to still populate the form. We wouldn’t want our users to enter their name and email all over again just because their two password fields didn’t match up. We have to add something to our form validation on the backend side of things and then we’ll add the information to our view file.
// app/routes.php
...
// check if the validator failed -----------------------
if ($validator->fails()) {
// redirect our user back with error messages
$messages = $validator->messages();
// also redirect them back with old inputs so they dont have to fill out the form again
// but we wont redirect them with the password they entered
return Redirect::to('ducks')
->withErrors($validator)
->withInput(Input::except('password', 'password_confirm'));
} else {
...
We are redirecting users back to the form with all inputs except the password
and password_confirm
fields. This way they won’t have to enter their name and email again. Now, we have to populate our form with the data that comes back. We’ll use our input
field’s value
attribute and the way we get old input data from Laravel is to use:
{{ Input::old('name') }}
We’ll add that to our form now.
<!-- app/views/duck-form.blade.php -->
...
<!-- FORM STARTS HERE -->
<form method="POST" action="/ducks" novalidate>
<div class="form-group @if ($errors->has('name')) has-error @endif">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" name="name" placeholder="Somebody Awesome" value="{{ Input::old('name') }}">
@if ($errors->has('name')) <p class="help-block">{{ $errors->first('name') }}</p> @endif
</div>
<div class="form-group @if ($errors->has('email')) has-error @endif">
<label for="email">Email</label>
<input type="text" id="email" class="form-control" name="email" placeholder="email@example.com" value="{{ Input::old('email') }}">
@if ($errors->has('email')) <p class="help-block">{{ $errors->first('email') }}</p> @endif
</div>
...
Just like that, we are now populating our form with data that the user submitted. Our users will thank us for not having to enter information again, especially on larger forms!
<– https://cask.scotch.io/2014/07/laravel-form-validation-old-input.png –>
The last thing we’ll handle in form validation for Laravel today is to create custom error messages. Sometimes the default ones just aren’t fun enough for our flare and pizazz. All we have to do for this is to create our custom messages and pass them into the $validator
in our routes.php
file. Let’s change the messages for our required
and same
fields.
// app/routes.php
// route to process the ducks form
Route::post('ducks', function()
{
// create the validation rules ------------------------
$rules = array(
'name' => 'required', // just a normal required validation
'email' => 'required|email|unique:ducks', // required and must be unique in the ducks table
'password' => 'required',
'password_confirm' => 'required|same:password' // required and has to match the password field
);
// create custom validation messages ------------------
$messages = array(
'required' => 'The :attribute is really really really important.',
'same' => 'The :others must match.'
);
// do the validation ----------------------------------
// validate against the inputs from our form
$validator = Validator::make(Input::all(), $rules, $messages);
// check if the validator failed -----------------------
if ($validator->fails()) {
By just adding that Laravel will automatically send back those error messages to the view. We don’t have to change anything on the view side of our code.
You can create your own messages by using the :attribute
and :other
fillers to fill that space with the field name.
Another way to set rules for attributes is to do it in your models. This is a great way to do this since all the rules are attached to the model. This way, no matter where you have to validate, you can always reference back to the model. Let’s look at how we can do this. In your model, let’s create the same rules we created earlier:
<?php
// app/models/Duck.php
class Duck extends Eloquent {
protected $fillable = array('name', 'email', 'password');
public static $rules = array(
'name' => 'required', // just a normal required validation
'email' => 'required|email|unique:ducks', // required and must be unique in the ducks table
'password' => 'required',
'password_confirm' => 'required|same:password' // required and has to match the password field
);
}
That’s all we have to do in the model. Now to access those rules when we validate, we just pass in those rules using ModelName::$rules
.
$validator = Validator::make(Input::all(), ModelName::$rules);
You can also use this method to set rules based on user levels, like for an admin vs a normal user with differently named rule sets. So you would be able to create $adminRules
and $userRules
and access them directly. Thanks to longshot for pointing out this great Jeffrey Way tip.
Hopefully, this was a good example of the flexibility and features that Laravel provides when validating forms. There is still much more to dive into like creating custom validation rules and conditionally adding rules. I would definitely suggest checking out the official docs for more information about the great things you can do.
Let us know if you have any questions or comments on any validation tactics and thanks for reading.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!