Paulund
2017-12-05 #laravel

Creating A Laravel Contact Form Package

In this tutorial we're going to create our own Laravel package that will give you all the functionality you need to add a contact form to your website. If you want to learn more about building your own Laravel packages you can view a previous tutorial here.

A contact form is something you'll have on most of the project you build it allows your visitors a quick way of contacting you with any feedback or problems. The problem is if this contact form is open to the internet then you have to be careful about spam. Therefore in this package we're going to create the contact form using VueJS with a API to send the email.

Composer JSON

The first thing you need to do when creating a package is to add your composer.json file for the package. This needs to go at the root level of your package and will create the namespace for the package.

{
  "name": "paulund/contact-form",
  "description": "Paulund laravel contact form",
  "type": "project",
  "autoload": {
    "psr-4": {
      "Paulund\\ContactForm\\": "src/"
    }
  }
}

Contact Form Service Provider

The main PHP file in your package is the service provider /ContactFormServiceProvider.php it tells Laravel what your files are and how to use your package. In this file we need a boot method which will create the API route and a location to publish the VueJS component.

<?php

namespace Paulund\ContactForm;

use Illuminate\Support\ServiceProvider;

class ContactFormServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // Load routes
        $this->loadRoutesFrom(__DIR__ . '/Routes/api.php');

        // Assets
        $this->publishes([
            __DIR__.'/Resources/assets' => resource_path('paulund/assets/contactform')
        ], 'paulund');
    }
}

Contact Form VueJS Component

The VueJS component will be located in /Resources/assets/js folder. The below code will create the contact form in VueJS and send the formData to the API route of the contact form using the axios library.

<template>
    <form v-on:submit.prevent="submitForm">

        <div class="control">
            <label>Name</label>
            <input type="type" v-model="name" required="true">
        </div>

        <div class="control">
            <label>Email</label>
            <input type="email" v-model="email" required="true">
        </div>

        <div class="control">
            <label>Message</label>
            <textarea v-model="message" required="true"></textarea>
        </div>

        
        <div class="control">
            <input type="submit" class="button" value="Send">
        </div>
    </form>
</template>

<script>
  import axios from 'axios';
    export default {
      data: function(){
        return {
          name: '',
          email: '',
          message: ''
        }
      },
      methods: {
        submitForm(){
          let formData = {
            name:this.name,
            email:this.email,
            message:this.message,
          };
          axios.post('/api/contact', formData).then(data => {
            console.log('Message sent');
          });
        }
      }
    }
</script>

API Routes

As we have an API route we need to create a route file at /Routes/api.php. We only need one API route that will be a POST to /api/contact and will send the request to the ContactController.

<?php
/**
 * Contact form API
 */
Route::namespace('Paulund\ContactForm\Http\Controllers')->prefix('api')->group(function ($api) {
    $api->post('contact', 'ContactController@store');
});

Contact Controller

We'll need to create a controller folder located in Http/Controllers inside this folder we can then create a ContactController.php. This file will need a store method which will validate the request and send the email and return with a JSON of success.

<?php

namespace Paulund\ContactForm\Http\Controllers;

use Illuminate\Http\Response;
use Illuminate\Support\Facades\Mail;
use Paulund\ContactForm\Http\Requests\ContactFormRequest;
use Paulund\ContactForm\Mail\ContactEmail;
use Paulund\LaravelCommon\Http\Controllers\Controller;

class ContactController extends Controller
{
    public function store( ContactFormRequest $request )
    {
        Mail::to( config('mail.from.address') )->send( new ContactEmail($request->only([
            'name', 'email', 'message'
        ])) );

        return response()->json( ['sent' => true], Response::HTTP_OK);
    }
}

You'll notice there's a \Paulund\ContactForm\Mail\ContactEmail object which is used to send the email and we pass in 'name', 'email', 'message' from the request so we can send them to the admin email address.

Contact Form Request

You'll notice in the ContractController::store method we're passing in a ContactFormRequest object. This will inherit the FormRequest class which is used to validate the request but adding a rules method.

<?php

namespace Paulund\ContactForm\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ContactFormRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required',
            'email' => 'required|email',
            'message' => 'required',
        ];
    }
}

This will make sure that the request object inside the controller is validated correctly.

Mail

In the ContactController we call the ContactEmail object so we need to create that email object, passing in the array of the contact form information.

<?php

namespace Paulund\ContactForm\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 $contact;

    /**
     * Create a new message instance.
     *
     */
    public function __construct(array $contact)
    {
        $this->contact = $contact;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->markdown('mail.contact');
    }
}

Mail Resources

We'll need to create a view file for the email resource located at /Resources/assets/views. In the ContactEmail class we use the markdown method to call a view resource of mail.contact this will need to show the name, email and the message.

@component('mail::message')
# Contact Form

<p>From: {{ $contact['name'] }}</p>

<p>Email: {{ $contact['email'] }}</p>

{{ $contact['message'] }}

Thanks,<br>
{{ config('app.name') }}
@endcomponent

This is everything you need to create a Contact Form Laravel package. If you put these into your own package you can have a quick contact form in your project.