Adding a Click-to-Call Button to your Laravel Application

March 19, 2020
Written by
Brian Iyoha
Contributor
Opinions expressed by Twilio contributors are their own

Adding a Click to Call Button to your Laravel Application

In this tutorial, we will be building a simple Laravel application that allows users to place automated calls at the click of a button using Twilio Programmable Voice.

Prerequisites

To follow through with this tutorial, you will need the following:

Project Setup

Get started by first creating a new Laravel project using the Laravel installer. Open up a terminal and run the following:

$ laravel new twilio-call-button

NOTE: You need to have the Laravel installer already installed on your local machine. If you don't, then head over to the official documentation to see how to get it installed.

The Twilio PHP SDK is required to make API requests to the Twilio servers. Open up a terminal in your project directory (twilio-call-button) and run the following command to get it installed via Composer:

$ composer require twilio/sdk

To authenticate and identify requests made from your application using the Twilio SDK, your Account SID and Auth Token are needed to initialize the Twilio SDK. Head to your Twilio console to copy both credentials:

Twilio Dashboard

Next, you will also need to copy your active Twilio phone number (in E.164 format) which will be used for placing outgoing calls:

Twilio Phone Number Dashboard

Now, safely store your credentials in your environment variable. Open up the .env file and add the following variables:

TWILIO_SID="YOUR ACCOUNT SID"
TWILIO_AUTH_TOKEN="YOUR ACCOUNT AUTH TOKEN"
TWILIO_NUMBER="YOUR TWILIO NUMBER"

Getting User's Phone Number

To place an outbound call using the Twilio Voice API you must provide a valid E.164 phone number to the Twilio SDK. One way to do this is by collecting phone numbers from your frontend using a form. Open up resources/views/welcome.blade.php and replace its content with the following to add a form for collecting a user phone number:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel</title>

    <!-- Fonts -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
    <!-- Styles -->
    <style>
        html,
        body {
            background-color: #fff;
            color: #636b6f;
            font-family: 'Nunito', sans-serif;
            font-weight: 200;
            height: 100vh;
            margin: 0;
        }

        .full-height {
            height: 100vh;
        }

        .flex-center {
            align-items: center;
            display: flex;
            justify-content: center;
        }

        .position-ref {
            position: relative;
        }

        .top-right {
            position: absolute;
            right: 10px;
            top: 18px;
        }

        .content {
            text-align: center;
        }

        .title {
            font-size: 84px;
        }

        .links {
            margin-top: 60px
        }

        .links>a {
            color: #636b6f;
            padding: 0 25px;
            font-size: 13px;
            font-weight: 600;
            letter-spacing: .1rem;
            text-decoration: none;
            text-transform: uppercase;
        }

        .m-b-md {
            margin-bottom: 30px;
        }

        label {
            font-weight: 600;
            font-size: 13px;
        }

        .btn-primary {
            color: #fff;
            background-color: #636a6e;
            border-color: #545b62;
            font-weight: 600;
        }

        .btn-primary:hover {
            color: #545b62;
            background-color: #fff;
            border-color: #545b62;
            font-weight: 600;
        }
    </style>
</head>

<body>
    <div class="flex-center position-ref full-height">
        @if (Route::has('login'))
        <div class="top-right links">
            @auth
            <a href="{{ url('/home') }}">Home</a>
            @else
            <a href="{{ route('login') }}">Login</a>

            @if (Route::has('register'))
            <a href="{{ route('register') }}">Register</a>
            @endif
            @endauth
        </div>
        @endif

        <div class="content">
            <div class="title m-b-md">
                Laravel

            </div>
            @if ($errors->any())
            <div class="alert alert-danger">
                <ul>
                    @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                    @endforeach
                </ul>
            </div>
            @endif
            @if (isset($message))
            <div class="alert alert-success">
                <ul>
                    <li>{{ $message }}</li>
                </ul>
            </div>
            @endif
            <form action="{{route('placeCall')}}" method="POST">
                @csrf
                <div class="form-group row">
                    <label for="phoneNumber" class="col-sm-2 col-form-label">Phone Number</label>
                    <div class="col-sm-10">
                        <input type="tel" name="phoneNumber" class="form-control" id="phoneNumber"
                            placeholder="Phone number">
                    </div>
                </div>
                <button type="submit" class="btn btn-primary">Call Me</button>
            </form>
            <div class="links">
                <a href="https://twilio.com/blog">Twilio Blog</a>
                <a href="https://github.com/thecodearcher/laravel-click-to-call">GitHub</a>
            </div>
        </div>
    </div>
</body>

</html>

NOTE: Bootstrap is used to help expedite the styling of the form.

The code above adds a form with an input field for collecting a user's phone number. After submission, the phone number collected will be submitted to a named route placeCall (which will be created in the later section of this tutorial) which will place a call to the number entered with a message containing a pseudo confirmation pin.

Making Outbound Calls

First, generate a Controller class where the application logic for making a call will be included. Open up a terminal in the project directory and run the following command:

$ php artisan make:controller HomeController

Next, open the newly create file app/Http/Controllers/HomeController.php, and make the following changes:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Twilio\Rest\Client;
use Twilio\TwiML\VoiceResponse;

class HomeController extends Controller
{
    public function index()
    {
        return view('welcome');
    }

    public function placeCall(Request $request)
    {
        $request->validate([
            'phoneNumber' => 'required|numeric',
        ]);

        $to_number = $request->input('phoneNumber');

        $account_sid = getenv("TWILIO_SID");
        $auth_token = getenv("TWILIO_AUTH_TOKEN");
        $twilio_number = getenv("TWILIO_NUMBER");

        $client = new Client($account_sid, $auth_token);

        $pin = implode('. ', str_split(rand(10000, 99999)));

        $client->account->calls->create(
            $to_number,
            $twilio_number,
            [
                "twiml" => $this->callMessage($pin),
            ]
        );
        return view('welcome', ['message' => 'You will receive a call shortly!']);
    }

    public function callMessage($pin)
    {
        $response = new VoiceResponse();
        $response->say("Your Laravel test pin is: $pin.");
        $response->say("GoodBye!");
        $response->hangup();
        return $response;
    }
}

Three new methods - index(), placeCall(), and callMessage() has been added to the controller class. The index() method simply returns the resources/views/welcome.blade.php view. The placeCall() method as the name indicates, handles placing a call to a phone number with is gotten from the phoneNumber property on the request body. It makes use of the Twilio SDK to place a call by first initializing a new instance of the Twilio Client using the credentials stored as environment variables in the earlier section of this tutorial:

$account_sid = getenv("TWILIO_SID");
$auth_token = getenv("TWILIO_AUTH_TOKEN");
$twilio_number = getenv("TWILIO_NUMBER");

$client = new Client($account_sid, $auth_token);

Next, a five (5) digit pseudo pin is generated using the built-in rand() function in PHP:

$pin = implode('. ', str_split(rand(10000, 99999)));

NOTE: The generated pseudo pin is converted to an array using str_split() and later turned back into a string using the implode() function which joins each element together by adding a period (.) and white space between each digit (element). This is to ensure the TwiML reads each digit as an individual character.

Next, using the chained account->calls->create() method of the Twilio Client instance, an outbound call is made to the phone number sent in from the form:

 $client->account->calls->create(
            $to_number,
            $twilio_number,
            [
                "twiml" => $this->callMessage($pin),
            ]
        );

The account->calls->create() method takes on three arguments; to, from, and an array of properties to pass to the Twilio Voice API. As the names indicate; to and from are both the phone number you want to call and your Twilio phone number respectively. Twilio allows passing different properties to configure how your call will behave and in this tutorial, the twiml property is used. The twiml property allows passing in direct TwiML instructions which will be executed when the call is answered. To make things neater, the construction of the TwiML instructions are done in a separate function callMessage() which is passed as the value for twiml. The callMessage() method makes use of the VoiceResponse() class which is a helper class from the Twilio SDK to construct the needed XML markup which will be played to the user when the call is answered:

public function callMessage($pin)
    {
        $response = new VoiceResponse();
        $response->say("Your Laravel test pin is: $pin.");
        $response->say("GoodBye!");
        $response->hangup();
        return $response;
    } 

Looking at the snippet above, a new VoiceResponse() instance is instantiated and further used to construct the Say verb using the fluent say() method. The say() method takes in a string that will be read to the user when the call is answered. Next, the Hangup verb is added which will end the call immediately after the message has been read to the user.

Next, the user will be returned to the welcome view with a message to inform them that their call request was successful:

return view('welcome', ['message' => 'You will receive a call shortly!']);

Registering Routes

Next, you have to create routes that will be used to access your application and capture the data submitted from the form we created earlier. Open up routes/web.php and make the following changes:

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/','HomeController@index')->name('home');
Route::post('/','HomeController@placeCall')->name('placeCall'); 

Testing

Awesome! Now that you have finished building your application, you can now proceed to test your implementation. To get started, you need to first start up your Laravel application. To do this open up a terminal in your working directory and run the following command:

$ php artisan serve

You should see a message like "Laravel development server started: http://127.0.0.1:8000" printed out on the terminal. Now open up your browser and navigate to the URL printed out, usually http://127.0.0.1:8000 and you should be greeted with a page similar to this:

Laravel Click-to-call Application

Next, enter a valid phone number into the form field provided and click on the Call Me button and you should get a call shortly after reading out a pseudo pin to you.

Conclusion

Now that you have finished this tutorial, you have learned how to implement a click-to-call button in a Laravel application using the Twilio Programmable Voice API. And with it, you have also learned how to construct TwiML instructions using the helper methods provided by the Twilio SDK. If you would like to take a look at the complete source code for this tutorial, you can find it on Github.

I’d love to answer any question(s) you might have concerning this tutorial. You can reach me via