Tutorial

Laravel Form Validation

Draft updated on Invalid Date
author

Chris on Code

Laravel Form Validation

This tutorial is out of date and no longer maintained.

Introduction

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.

What We’ll Be Building

Our application will do many things. These include:

  • Validate required, unique in the database, and matching form fields
  • Use Laravel to show errors
  • Use Laravel to show old inputs so a user doesn’t have to retype inputs
  • Create custom error messages

That’s a lot to do so let’s get started. We’ll start by setting up our database.

Database and Models

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?

Migration

Go into the command line and type

  1. 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:

  1. php artisan migrate

Model

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

Setting Up Our Routes

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

Creating Our View

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.

Validating Our 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.

Basic Form Validation

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.

Creating Rules

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:

  • A required name
  • A required email that has to be in email form
    • An email that has to be unique in the database
  • A required password
  • A password_confirm field that needs to match password

So 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.

Showing Errors In the View

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.

Dumping Out All Error Messages

<!-- 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.

Hand-Picking Error Messages

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.

Showing Old Inputs In the View

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 –>

Custom Error Messages

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.

Model Level Rules

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.

Conclusion

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.

Learn more about our products

About the authors
Default avatar
Chris on Code

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


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!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.