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