Creating and Validating a Laravel 5 Form: The Definitive Guide

  • August 17, 2015

Welcome to the incredibly popular Easy Laravel 5 companion blog. To celebrate the new edition's release (updated for Laravel 5.5!) use the discount code easteregg to receive 20% off the book or book/video package! » Buy the book

In the bad old days of web development it was common practice to hand-code an HTML form, and then write some custom code to ensure the user input was valid. At some point PHP got fancy and added some standard validation and input functions however it was still up to you to define a convention for validating the input and subsequently processing the valid data, or notify the user of the invalid data and present the form anew. Laravel removes all of this hassle by providing you with both the code and convention required to implement all of these tasks.

In this tutorial I'll guide you through all of the steps necessary to create and validate a Laravel 5 form using best practices. Let's work through an example involving adding a category to the an application's categories table (which might be used to house categories subsequently associated with a blog, product catalog, or anything else requiring categorization). Begin by creating the Category model and corresponding migration.

Creating the Model and Migration

To keep things simple let's presume the categories table consists of a single field for managing the category name (in addition to the usual ID primary key and create/update timestamps). Let's generate the Category model:

$ php artisan make:model Category -m
Model created successfully.
Created Migration: 2015_08_17_152001_create_categories_table

Next, open the migration file (inside database/migrations) and update the up method to look like this:

public function up()
{
  Schema::create('categories', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->timestamps();
  });
}

Next, run the migration:

$ php artisan migrate
Migrated: 2015_08_17_152001_create_categories_table

With the model and corresponding table in place, let's next create a controller which will serve and subsequently process the form.

Creating the Resourceful Controller

Use Artisan's make:controller command to create a controller which (among other things) we'll use to present and process the form:

$ php artisan make:controller CategoriesController.php
Controller created successfully.

The make:controller command will by default create a resourceful controller containing the seven customary RESTful methods (index, show, create, store, edit, update, destroy). However, Laravel does not yet know how to respond to these methods, because their associated routes need to be defined inside app/Http/routes.php. Open this file and add the following line:

Route::resource('categories', 'CategoriesController');

Once defined, you'll be able to navigate to for instance /categories to access the Categories controller's index action, and categories/create to access the Categories controller's create action, because Laravel will map each route to an appropriate method. At this point both routes will present blank pages because we haven't yet created the views. Let's do so next.

Creating the Form View

For the purposes of this tutorial we're only interested in create and store, which is responsible for presenting the form to the user, and store, which saves the form data (presuming it passes validation; more on this in a moment). Currently these actions are empty:

...

public function create()
{
    //
}

public function store(Request $request)
{
    //
}

...

Update the create action to look like this:

public function create()
{
    return view('categories.create');
}

This tells Laravel to serve a view named create.blade.php residing in the directory resources/views/categories. Because neither the file nor the directory have been created yet, do so now, beginning with the directory:

$ cd resources/views
$ mkdir categories

Next, create a file named create.blade.php, saving it to resources/views/categories. For the moment just add the following HTML to the file:

<h1>Create a Category</h1>

Save the changes and navigate to /categories/create and you should see the above H1 header. While a nice start, we of course want the user to be presented with a form. While you could tediously create this form yourself, that's really no fun so let's instead use the fantastic laravelcollective/html package to do the hard work for us. Add the package to your project by executing the following command from inside your project root directory:

$ composer require laravelcollective/html

Next, open config/app.php and add the following line to the bottom of the providers array:

'providers' => [
  ...
  Collective\Html\HtmlServiceProvider::class,
]

Continue scrolling down and add the following line to the bottom of the aliases array:

'aliases' => [
  ...
  'Form' => Collective\Html\FormFacade::class
]

Save the changes and the package is now installed and configured! Return to create.blade.php and add the following markup:

<h1>Create a Category</h1>

{!! Form::open(
  array(
    'route' => 'categories.store', 
    'class' => 'form')
  ) !!}

@if (count($errors) > 0)
<div class="alert alert-danger">
    There were some problems adding the category.<br />
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif

<div class="form-group">
    {!! Form::label('Category') !!}
    {!! Form::text('name', null, 
      array(
        'class'=>'form-control', 
        'placeholder'=>'List Name'
      )) !!}
</div>

<div class="form-group">
    {!! Form::submit('Create Category!', 
      array('class'=>'btn btn-primary'
    )) !!}
</div>
{!! Form::close() !!}
</div>

The laravelcollective/html package's syntax is so intuitive that I'd imagine you understand everything found in this markup, however I'd like to nonetheless highlight a few key items:

  • The form route points to categories/store, because the Categories controller's store method will process the form.
  • Form::open uses the POST method by default, so there's no need to reference the method explicitly.
  • The @if...@endif block is used to present information about validation errors to the user. We'll return to this matter in a moment.
  • For demonstration purposes I'm passing along Bootstrap attributes to the form elements. Obviously the form will still work without these stylistic attributes.

With the form in place, return to categories/create and you should see the form. If you input a category and submit the form, you'll be taken categories/store however of course nothing will actually happen because we haven't written that code yet. Let's do so next.

Processing the Form

Return to CategoriesController.php and scroll down to the store method. This is where the user is taken after submitting the form. Update the store method to look like this:

use App\Category;

...

public function store(Request $request)
{

    $category = new Category;

    $category->name = $request->get('name');

    $category->save();

    return \Redirect::route('categories.show', 
        array($category->id))
        ->with('message', 'Your category has been created!');

}

It really doesn't get much simpler than this. We instantiate a new Category model object, assign the submitted category name, save the record, and then redirect the user to categories/show (which I'll leave to you as an exercise to implement). If you resubmit your form with a category name, sure enough you'll see that it has been added to the database. But wait a second, what about validation? Sure enough, you can currently submit a blank category, and an empty value will be saved to the database! This is of course not acceptable, so let's use a form request to validate the data.

Validating the Form

Laravel 5 offers a great new feature known as a form request which allows you to easily validate your form input without polluting the controller. The validation logic is managed in a separate file, and you can generate this file using Artisan's make:request feature:

$ php artisan make:request CreateCategoryFormRequest
Request created successfully.

This creates a file named CreateCategoryFormRequest.php, placing it inside app/Http/Requests. The file currently looks like this:

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class CreateCategoryFormRequest extends Request
{

    public function authorize()
    {
        return false;
    }

    public function rules()
    {
        return [
            //
        ];
    }
}

Modify the authorize method to look like this:

public function authorize()
{
    return true;
}

The authorize method can be used to ensure the user is authorized to submit this form. For instance you might only want to make the form available to logged-in users. Frankly I don't particularly understand why this is useful since one could instead use middleware to accomplish the same task, but to each his own I guess. Anyway, you'll want to set this to true because when false is returned the form will no longer be processed.

Next, modify the rules method to look like this:

public function rules()
{
    return [
      'category' => 'required'
    ];
}

This uses Laravel's validation syntax to declare the form's category field as required. Note the array key matches the name of the corresponding form field. Of course, you're free to add additional form fields and corresponding validators. You can also combine validators like so:

      'category' => 'required|alpha'

With the form request complete, you need to integrate the request into the Categories controller's store action. Add the following line to the top of CategoriesController.php:

use App\Http\Requests\CreateCategoryFormRequest;

Next, update the store action to accept a $request object of type CreateCategoryFormRequest:

public function store(CreateCategoryFormRequest $request)
{

    ...

}

With the store action updated to use the custom request, Laravel will automatically validate the submitted form data, and if invalid, will automatically return the user to the form with one or several validation-related error messages. That's right; there is nothing else you need to do to the existing store action code!

With the model, table, controller, view, and form request in place, categories can be safely added to the database!