Creating a Contact Form in Laravel 5 Using the Form Request Feature

  • January 02, 2017

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

Laravel 5 offers a new feature known as Form Requests which assist in the processing and validation of form data. In this post you'll learn how to create a Laravel 5 contact form using Form Requests and Laravel's e-mail transmission capabilities. Along the way I'll introduce you to various other Laravel-related development techniques and features.

The example contact form will be pretty simple but functional, consisting of three fields, including the user's name, email address, and message.

The contact form presentation and processor will require just two controller methods, meaning you could get away with managing them inside a general administrative controller. However I always prefer to follow RESTful conventions whenever possible, and so suggest instead creating a dedicated controller for this purpose. In the case of HackerPair this feature is managed by the Contact controller's create and store actions (create presents the form via the GET method and store processes it via POST). Because we're going to use only two of the seven REST methods you can eliminate the need to delete unused methods by creating a "plain" controller:

$ php artisan make:controller ContactController
Controller created successfully.

Next, to route users to the contact form using the convenient /contact shortcut you'll need to define two aliases in the routes/web.php file:

Route::get('contact', 'ContactController@create')->name('contact.create');
Route::post('contact', 'ContactController@store')->name('contact.store');

Next, you'll need to add the create and store actions to the newly created Contact controller, because we didn't specify the --resource option when generating the controller. Modify the controller to look like this:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;

class ContactController extends Controller {

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

    public function store()
    {
    }

}

The create action has been configured to serve a view named create.blade.php found in the directory resources/views/contact. However we haven't yet created this particular view so let's do so next.

Creating the Contact Form

Earlier in this chapter I showed you the rendered form HTML, introducing several key Laravel- and HTML5- related form features in the process. Note my emphasis on rendered because you won't actually hand-code the form! Instead, you'll use Laravel's fantastic form generation capabilities to manage this tedious task for you. Below I've pasted in the section of code found in HackerPair's resources/views/contact/create.blade.php view that's responsible for generating the contact form:

{!! Form::open(['route' => 'contact.store']) !!}

<div class="form-group">
    {!! Form::label('name', 'Your Name') !!}
    {!! Form::text('name', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('email', 'E-mail Address') !!}
    {!! Form::text('email', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::textarea('msg', null, ['class' => 'form-control']) !!}
</div>

{!! Form::submit('Submit', ['class' => 'btn btn-info']) !!}

{!! Form::close() !!}

View the HackerPair Contact Form View Code

You can view the HackerPair contact form view on GitHub.

This form uses the form builder made available through Laravel's HTML component. I explained how to install this component in chapter 2, but at that point we just configured the HTML Facade. To take advantage of the form-specific tags you'll need to additionally add the following alias to the config/app.php aliases array:

'Form'=> Collective\Html\FormFacade::class

If this is your first encounter with the Form::open helper then I'd imagine this example looks rather scary. However once you build a few forms in this fashion I promise you'll wonder how you ever got along without it. Let's break down the key syntax used in this example:

{!! Form::open(['route' => 'contact.store', 'class' => 'form']) !!}
...
{!! Form::close() !!}

The Form::open and Form::close() methods work together to generate the form's opening and closing tags. The Form::open method accepts an array containing various settings such as the route alias which in this case points to the About controller's store method, and a class used to stylize the form. The default method is POST however you can easily override the method to instead use GET by passing 'method' => 'get' into the array. Additionally, the Form::open method will ensure the aforementioned CSRF-prevention _token hidden field is added to the form.

Next you'll see a series of methods used to generate the various form fields. This is a relatively simplistic form therefore only a few of the available field generation methods are used, including Form::label (for creating form field labels), Form::text (for creating form text fields), Form::textarea (for creating a form text area), and Form::submit (for creating a submit button). Note how the Form::text and Form::textarea methods all accept as their first argument a model attribute name (name, email, and msg, respectively). All of the methods also accept an assortment of other options, such as class names and HTML5 form attributes.

Once you add this code to your project's resources/views/contact/create.blade.php file, navigate to /contact and you should see a form similar to that found at http://hackerpair.com/contact!

With the form created, we'll next need to create the logic used to process the form contents and send the feedback to the site administrator via e-mail.

Creating the Contact Form Request

Laravel 5 introduced a feature known as a form request. This feature is intended to remove form authorization and validation logic from your controllers, instead placing this logic in a separate class. HackerPair uses form requests in conjunction with each form used throughout the site and I'm pleased to report this feature works meets its goal quite nicely.

To create a new form request you can use Artisan's make:request feature:

$ php artisan make:request ContactFormRequest
Request created successfully.

This created a file named ContactFormRequest.php that resides in the directory app/Http/Requests/. The class skeleton looks like this (comments removed):

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ContactFormRequest extends FormRequest {

  public function authorize()
  {
    return false;
  }

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

}

View the HackerPair Contact Form Request Code

You can view the HackerPair contact form request on GitHub.

The authorize method determines whether the current user is authorized to interact with this form. I'll talk more about the purpose of this method in chapter 7. For the purposes of the contact form we want any visitor to submit a contact request and so modify the method to return true instead of false:

public function authorize()
{
  return true;
}

The rules method defines the validation rules associated with the fields found in the form. The contact form has three fields, including name, email, and msg. All three fields are required, and the email field must be a syntactically valid e-mail address, so you'll want to update the rules method to look like this:

public function rules()
{
  return [
    'name'    => 'required',
    'email'   => 'required|email',
    'msg'     => 'required'
  ];
}

The required and email validators used in this example are just a few of the many supported validation features. See chapter 6 for more information about these rules. In the examples to come I'll provide additional examples demonstrating other available validators. Additionally, note how you can use multiple validators in conjunction with a form field by concatenating the validators together using a vertical bar (|).

After saving the changes to ContactFormRequest.php open the Contact controller and modify the store method to look like this:

use App\Http\Requests\ContactFormRequest;

...

class AboutController extends Controller {

  public function store(Request $request)
  {

    $contact = [];

    $contact['name'] = $request->get('name');
    $contact['email'] = $request->get('email');
    $contact['msg'] = $request->get('msg');

    // Mail delivery logic goes here

    flash('Your message has been sent!')->success();

    return redirect()->route('contact.create');

  }

}

While we haven't yet added the e-mail delivery logic, believe it or not this action is otherwise complete. This is because the ContactForm form request will handle the validation and display of validation error messages should validation fail. For instance submitting the contact form without completing any of the fields will result in three validation error found presented in the below screenshot being displayed:

These errors won't appear out of thin air of course; they'll be displayed via the $errors array. I typically insert the following code into my project layout so the $errors variable is available whenever needed:

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

You'll also want to inform the user of a successful form submission. To do so you can use a flash message, which is populated in the store method ("Your message has been sent!"). While it's possible to do this using native Laravel code, I prefer to rely on the great laracasts/flash package for doing so. Chapter 5 shows you how to integrate this package into your application.

Only one step remains before the contact form is completely operational. We'll need to configure Laravel's mail component and integrate e-mail delivery functionality into the store method. Let's complete these steps next.

Configuring Laravel's Mail Component

Thanks to integration with the popular SwiftMailer package, it's easy to send e-mail through your Laravel application. All you'll need to do is make a few changes to the config/mail.php configuration file. In this file you'll find a number of configuration settings:

  • driver: Laravel supports several mail drivers, including SMTP, PHP's mail function, the Sendmail MTA, and the Mailgun and Mandrill e-mail delivery services. You'll set the driver setting to the desired driver, choosing from smtp, sendmail, mailgun, mandrill, ses, sparkpost, and array. You could also optionally set driver to log in order to send e-mails to your development log rather than bother with actually sending them out during the development process.
  • host: The host setting is used to set the host address of your SMTP server should you be using the smtp driver.
  • port: The port setting is used to set the port used by your SMTP server should you be using the smtp driver.
  • from: If you'd like all outbound application e-mails to use the same sender e-mail and name, you can set them using the name and address settings defined in this array.
  • encryption: The encryption setting specifies the encryption protocol used when sending e-mails.
  • username: The username setting defines the SMTP account username should you be using the smtp driver.
  • password: The password setting defines the SMTP account password should you be using the smtp driver.
  • sendmail: The sendmail setting defines the server Sendmail path should you be using the sendmail driver.
  • markdown: The markdown setting is used to configure your design templates if Markdown format is used within your e-mails.

After configuring your desired e-mail delivery solution, it's time to generate the code used to send the e-mail. We'll do that next.

Generating the Mailable

Laravel offers a great solution for managing the code responsible for generating and delivering e-mails sent from your application. It's called a Mailable, and you can generate a mailable class using Artisan:

$ php artisan make:mail ContactEmail

This will create a new skeleton class found in app/Mail/ContactEmail.php. Open this file and you'll find the following template:

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class ContactEmail extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct()
    {
        //
    }

    public function build()
    {
        return $this->view('view.name');
    }
}

View the HackerPair ContactEmail Mailable Code

You can view the HackerPair contact mailable class on GitHub.

The constructor is responsible for initializing any data passed into the Mailable class from the caller (which as you'll soon see will be the Contact controller's store method). We're going to pass in an array containing the contact form's name, e-mail address, and message values, so let's modify the constructor to assign the array to a class instance variable:

public $contact;

public function __construct($contact)
{
    $this->contact = $contact;
}

The build method is responsible for generating and delivering the e-mail, identifying the recipient address, e-mail subject, and view used for the e-mail content (among other things). The HackerPair build method looks like this:

public function build()
{
    return $this
        ->to(config('mail.from.address'))
        ->subject('HackerPair Inquiry')
        ->view('emails.contact');
}

The e-mail template is found in resources/views/emails/contact.blade.php. It is very simple, containing just a brief introductory note and the form values:

Hi,

A HackerPair user has sent you a message.

Name: {{ $contact['name'] }}

E-mail: {{ $contact['email'] }}

Message: {{ $contact['msg'] }}

With the template in place, there's just one more step. Invoke the ContactEmail class! Open the Contact controller and replace the mail-related placeholder with this:

Mail::to(config('mail.support.address'))->send(new ContactEmail($contact));

Don't forget to reference the class at the top of the file:

use App\Mail\ContactEmail;

After saving the changes, fill out and submit the form. If everything is properly in place, you should receive an e-mail at the recipient address within a few moments.

Summary

Whew, this was a pretty long post but hopefully it neatly explains how you can create a rock-solid contact form within your Laravel applications. Easy Laravel 5 goes into far more detail regarding form generation and e-mail delivery, so be sure to pick up a copy!

Easy Laravel 5 teaches you all about creating and processing forms inside your Laravel applications

Buy the book