Call Tracking with PHP and Laravel

Download the Code

This Laravel web application shows how you can use Twilio to track the effectiveness of different marketing channels.

Call tracking home page

This application has three main features:

  • It purchases phone numbers from Twilio to use in different marketing campaigns (like a billboard or a bus advertisement)
  • It forwards incoming calls for those phone numbers to a salesperson
  • It displays charts showing data about the phone numbers and the calls they receive

In this tutorial, we'll point out the key bits of code that make this application work. Check out the project README on GitHub to see how to run the code yourself.

Check out how Whatclinic.com used Twilio to build a call tracking platform for healthcare providers.

Search for available phone numbers

Call tracking requires us to search for and buy phone numbers on demand, associating a specific phone number with a lead source. We make a server-side request (possibly with a filter area code) asking Twilio for available phone numbers using the Twilio PHP helper library.

Loading Code Samples...
Language
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use Illuminate\Http\Request;
use Twilio\Rest\Client;

class AvailableNumberController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Display numbers available for purchase. Fetched from the API
     *
     * @param  Request $request
     * @return Response
     */
    public function index(Request $request)
    {
        $areaCode = $request->input('areaCode');

        $numbers = $this->_twilioClient->availablePhoneNumbers("US")
            ->local->stream(
                [
                    'areaCode' => $areaCode
                ]
            );

        return response()->view(
            'available_numbers.index',
            [
                'numbers' => $numbers,
                'areaCode' => $areaCode
            ]
        );
    }
}
app/Http/Controllers/AvailableNumberController.php
Search Phone Numbers

app/Http/Controllers/AvailableNumberController.php

Now let's see how we will display these numbers for the user to purchase them and enable their campaigns.

Display available phone numbers

When the user searches for a phone number to use for call tracking, we display a list of phone numbers that are available for purchase through the Twilio API. For each number, we create a form that, when submitted, will purchase that number through the Twilio API.

Loading Code Samples...
Language
SDK Version:
  • blade
@extends('layouts.master')

@section('content')
<div class="col-lg-6">
<h2>Purchase phone numbers</h2>
    <h3>Available numbers</h3>
    <p>For area code: {{ $areaCode or &#x27;any&#x27; }}</p>
    <p>The number you choose will be used to create a Lead Source. On the next page, you will set a name and forwarding number for this lead source.</p>
    <table class="table">
        <thead>
            <th>Phone number</th>
            <th>State</th>
            <th></th>
        </thead>
        <tbody>
            @foreach ($numbers as $number)
                <tr>
                    <td> {{ $number-&gt;friendlyName }} </td>
                    <td> {{ $number-&gt;region }} </td>
                    <td>
                        {!! Form::open(['url' => route('lead_source.store')]) !!}
                        {!! Form::hidden('phoneNumber', $number->phoneNumber) !!}
                        {!! Form::submit('Purchase', ['class' => 'btn btn-primary btn-xs']) !!}
                        {!! Form::close() !!}
                    </td>
                </tr>
            @endforeach
        </tbody>
    </table>
</div>
@stop
resources/views/available_numbers/index.blade.php
Available Phone Numbers List Template

resources/views/available_numbers/index.blade.php

We've seen how we can display available phone numbers for purchase with the help of the Twilio PHP helper library. Now let's look at how we can buy an available phone number.

Buy a phone number

Once the user has selected a phone number to purchase, we complete the transaction using the Twilio API. When we buy the number, we specify that it should look up caller ID info on every call, and that it should use a TwiML Application we created to handle incoming calls.

When a phone number is purchased, we associate it with a LeadSource model, which the user can edit after a redirect.

Loading Code Samples...
Language
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use App\LeadSource;
use Illuminate\Http\Request;
use Twilio\Rest\Client;

class LeadSourceController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Store a new lead source (i.e phone number) and redirect to edit
     * page
     *
     * @param  Request $request
     * @return Response
     */
    public function store(Request $request)
    {
        $appSid = $this->_appSid();

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

        $this->_twilioClient->incomingPhoneNumbers
            ->create(
                [
                    "phoneNumber" => $phoneNumber,
                    "voiceApplicationSid" => $appSid,
                    "voiceCallerIdLookup" => true
                ]
            );

        $leadSource = new LeadSource(
            [
                'number' => $phoneNumber
            ]
        );
        $leadSource->save();

        return redirect()->route('lead_source.edit', [$leadSource]);
    }

    /**
     * Show the form for editing a lead source
     *
     * @param  int $id
     * @return Response
     */
    public function edit($id)
    {
        $leadSourceToEdit = LeadSource::find($id);

        return response()->view(
            'lead_sources.edit',
            ['leadSource' => $leadSourceToEdit]
        );
    }

    /**
     * Update the lead source in storage.
     *
     * @param  Request $request
     * @param  int $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        $this->validate(
            $request,
            [
                'forwarding_number' => 'required',
                'description' => 'required'
            ]
        );

        $leadSourceToUpdate = LeadSource::find($id);
        $leadSourceToUpdate->fill($request->all());
        $leadSourceToUpdate->save();

        return redirect()->route('dashboard');
    }

    /**
     * Remove the lead source from storage and release the number
     *
     * @param  int $id
     * @return Response
     */
    public function destroy($id)
    {
        $leadSourceToDelete = LeadSource::find($id);
        $phoneToDelete = $this->_twilioClient->incomingPhoneNumbers
            ->read(
                [
                    "phoneNumber" => $leadSourceToDelete->number
                ]
            );

        if ($phoneToDelete) {
            $phoneToDelete[0]->delete();
        }
        $leadSourceToDelete->delete();

        return redirect()->route('dashboard');
    }

    /**
     * The Twilio TwiML App SID to use
     * @return string
     */
    private function _appSid()
    {
        $appSid = config('app.twilio')['TWILIO_APP_SID'];
        if (isset($appSid)) {
            return $appSid;
        }

        return $this->_findOrCreateCallTrackingApp();
    }

    private function _findOrCreateCallTrackingApp()
    {
        $existingApp = $this->_twilioClient->applications->read(
            array(
                "friendlyName" => 'Call tracking app'
            )
        );
        if ($existingApp) {
            return $existingApp[0]->sid;
        }

        $newApp = $this->_twilioClient->applications
            ->create('Call tracking app');

        return $newApp->sid;
    }
}
app/Http/Controllers/LeadSourceController.php
Purchase Phone Number

app/Http/Controllers/LeadSourceController.php

If you don't know where you can get this application SID, don't panic, the next step will show you how.

Set webhook URLs in a TwiML Application

When we purchase a phone number, we specify a voice application SID. This is an identifier for a TwiML application, which you can create through the REST API or your Twilio Console.

Create TwiML App

Associate a phone number with a lead source

Once we have bought a number, we display a form so the user can add a forwarding number and a description for this number. From now on, any call to this number will be attributed to this source. All phone numbers should be in E.164 format.

Loading Code Samples...
Language
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use App\LeadSource;
use Illuminate\Http\Request;
use Twilio\Rest\Client;

class LeadSourceController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Store a new lead source (i.e phone number) and redirect to edit
     * page
     *
     * @param  Request $request
     * @return Response
     */
    public function store(Request $request)
    {
        $appSid = $this->_appSid();

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

        $this->_twilioClient->incomingPhoneNumbers
            ->create(
                [
                    "phoneNumber" => $phoneNumber,
                    "voiceApplicationSid" => $appSid,
                    "voiceCallerIdLookup" => true
                ]
            );

        $leadSource = new LeadSource(
            [
                'number' => $phoneNumber
            ]
        );
        $leadSource->save();

        return redirect()->route('lead_source.edit', [$leadSource]);
    }

    /**
     * Show the form for editing a lead source
     *
     * @param  int $id
     * @return Response
     */
    public function edit($id)
    {
        $leadSourceToEdit = LeadSource::find($id);

        return response()->view(
            'lead_sources.edit',
            ['leadSource' => $leadSourceToEdit]
        );
    }

    /**
     * Update the lead source in storage.
     *
     * @param  Request $request
     * @param  int $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        $this->validate(
            $request,
            [
                'forwarding_number' => 'required',
                'description' => 'required'
            ]
        );

        $leadSourceToUpdate = LeadSource::find($id);
        $leadSourceToUpdate->fill($request->all());
        $leadSourceToUpdate->save();

        return redirect()->route('dashboard');
    }

    /**
     * Remove the lead source from storage and release the number
     *
     * @param  int $id
     * @return Response
     */
    public function destroy($id)
    {
        $leadSourceToDelete = LeadSource::find($id);
        $phoneToDelete = $this->_twilioClient->incomingPhoneNumbers
            ->read(
                [
                    "phoneNumber" => $leadSourceToDelete->number
                ]
            );

        if ($phoneToDelete) {
            $phoneToDelete[0]->delete();
        }
        $leadSourceToDelete->delete();

        return redirect()->route('dashboard');
    }

    /**
     * The Twilio TwiML App SID to use
     * @return string
     */
    private function _appSid()
    {
        $appSid = config('app.twilio')['TWILIO_APP_SID'];
        if (isset($appSid)) {
            return $appSid;
        }

        return $this->_findOrCreateCallTrackingApp();
    }

    private function _findOrCreateCallTrackingApp()
    {
        $existingApp = $this->_twilioClient->applications->read(
            array(
                "friendlyName" => 'Call tracking app'
            )
        );
        if ($existingApp) {
            return $existingApp[0]->sid;
        }

        $newApp = $this->_twilioClient->applications
            ->create('Call tracking app');

        return $newApp->sid;
    }
}
app/Http/Controllers/LeadSourceController.php
Create Lead Source

app/Http/Controllers/LeadSourceController.php

So far our method for creating a Lead Source and associating a Twilio phone number with it is pretty straightforward. Now let's have a closer look at our Lead Source model which will store this information.

The LeadSource model

This is the model that contains the information provided in the form from the previous step. The LeadSource model associates a Twilio number to a named lead source (like "Wall Street Journal Ad" or "Dancing guy with sign"). It also tracks a phone number to which we'd like all the calls redirected, like your sales or support help line. It also provides a convenience method to find leads associated with this lead source.

Loading Code Samples...
Language
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Lead;

class LeadSource extends Model
{
    protected $fillable = ['number', 'forwarding_number', 'description'];

    public function leads()
    {
        return $this->hasMany('App\Lead');
    }
}
app/LeadSource.php
Lead Source Model

app/LeadSource.php

As the application will be collecting leads and associating them to each LeadSource or campaign, it is necessary to have a Lead model as well to keep track of each Lead as it comes in and associate it to the LeadSource.

The Lead model

A Lead represents a phone call generated by a LeadSource. Each time somebody calls a phone number associated with a LeadSource, we'll use the Lead model to record some of the data Twilio gives us about their call.

Loading Code Samples...
Language
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\LeadSource;
use DB;

class Lead extends Model
{
    protected $fillable = ['caller_number', 'city', 'state', 'caller_name', 'call_sid'];

    public function leadSource()
    {
        return $this->belongsTo('App\LeadSource');
    }

    public static function byLeadSource()
    {
        $leadsBySource
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(
                DB::raw('count(1) as lead_count'),
                'lead_sources.description',
                'lead_sources.number'
            )
            ->groupBy(
                'lead_source_id',
                'lead_sources.description',
                'lead_sources.number'
            )
            ->orderBy('lead_count', 'DESC')
            ->orderBy('lead_sources.description', 'DESC')
            ->get();

        return $leadsBySource;
    }

    public static function byCity()
    {
        $leadsByCity
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(DB::raw('count(1) as lead_count'), 'leads.city')
            ->groupBy('leads.city')
            ->get();

        return $leadsByCity;
    }
}
app/Lead.php
Lead Model

app/Lead.php

The backend part of the code which creates a LeadSource as well as a Twilio Number is complete. The next part of the application will be the webhooks that will handle incoming calls and forward them to the appropriate sales team member. Let's us see the way these webhooks are built.

Forward calls and create leads

Whenever a customer calls one of our Twilio numbers, Twilio will send a POST request to the URL associated with this view function (should be /lead).

We use the incoming call data to create a new Lead for a LeadSource, then return TwiML that connects our caller with the forwarding_number of our LeadSource.

Loading Code Samples...
Language
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use App\Lead;
use App\LeadSource;
use DB;
use Illuminate\Http\Request;
use Twilio\Rest\Client;
use Twilio\Twiml;

class LeadController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Display a listing of leads
     * @param Request $request
     * @return Response with all found leads
     */
    public function dashboard(Request $request)
    {
        $context = [
            'leadSources' => LeadSource::all(),
            'appSid' => $this->_appSid()
        ];

        return response()->view('leads.index', $context);
    }

    /**
     * Endpoint which store a new lead with its lead source and forward the call
     *
     * @param  Request $request Input data
     * @return Response Twiml to redirect call to the forwarding number
     */
    public function store(Request $request)
    {
        $leadSource = LeadSource::where(['number' => $request->input('To')])
            ->first();
        $lead = new Lead();
        $lead->leadSource()->associate($leadSource->id);

        $lead->city = $this->_normalizeName($request->input('FromCity'));
        $lead->state = $this->_normalizeName($request->input('FromState'));

        $lead->caller_number = $request->input('From');
        $lead->caller_name = $request->input('CallerName');
        $lead->call_sid = $request->input('CallSid');

        $lead->save();

        $forwardMessage = new Twiml();
        $forwardMessage->dial($leadSource->forwarding_number);

        return response($forwardMessage, 201)
            ->header('Content-Type', 'application/xml');
    }

    /**
     * Display all lead sources as JSON, grouped by lead source
     *
     * @param  Request $request
     * @return Response
     */
    public function summaryByLeadSource()
    {
        return response()->json(Lead::byLeadSource());
    }

    /**
     * Display all lead sources as JSON, grouped by city
     *
     * @param  Request $request
     * @return Response
     */
    public function summaryByCity()
    {
        return response()->json(Lead::byCity());
    }

    /**
     * The Twilio TwiML App SID to use
     * @return string
     */
    private function _appSid()
    {
        $appSid = config('app.twilio')['TWILIO_APP_SID'];

        if (isset($appSid)) {
            return $appSid;
        }

        return $this->_findOrCreateCallTrackingApp();
    }

    private function _findOrCreateCallTrackingApp()
    {
        $existingApp = $this->_twilioClient->applications->read(
            array(
                "friendlyName" => 'Call tracking app'
            )
        );
        if (count($existingApp)) {
            return $existingApp[0]->sid;
        }

        $newApp = $this->_twilioClient->applications
            ->create('Call tracking app');

        return $newApp->sid;
    }

    private function _normalizeName($toNormalize)
    {
        if (is_null($toNormalize)) {
            return '';
        } else {
            return $toNormalize;
        }
    }
}
app/Http/Controllers/LeadController.php
Call Forwarding

app/Http/Controllers/LeadController.php

Once we have forwarded calls and created leads, we will have a lot of incoming calls that will create leads, and that will be data for us but we need to transform that data into information in order to get benefits from it. So, let's see how we get statistics from these sources on the next step.

Get statistics about our lead sources

One useful statistic we can get from our data is how many calls each LeadSource has received. We might also want to know the cities the leads are coming from. For this we define two Eloquent queries that return these bits of data.

Loading Code Samples...
Language
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\LeadSource;
use DB;

class Lead extends Model
{
    protected $fillable = ['caller_number', 'city', 'state', 'caller_name', 'call_sid'];

    public function leadSource()
    {
        return $this->belongsTo('App\LeadSource');
    }

    public static function byLeadSource()
    {
        $leadsBySource
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(
                DB::raw('count(1) as lead_count'),
                'lead_sources.description',
                'lead_sources.number'
            )
            ->groupBy(
                'lead_source_id',
                'lead_sources.description',
                'lead_sources.number'
            )
            ->orderBy('lead_count', 'DESC')
            ->orderBy('lead_sources.description', 'DESC')
            ->get();

        return $leadsBySource;
    }

    public static function byCity()
    {
        $leadsByCity
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(DB::raw('count(1) as lead_count'), 'leads.city')
            ->groupBy('leads.city')
            ->get();

        return $leadsByCity;
    }
}
app/Lead.php
Leads By Source Stats

app/Lead.php

Up until this point, we have been focusing on the backend code to our application. Which is ready to start handling incoming calls or leads. Next, let's turn our attention to the client side. Which, in this case, is a simple Javascript application, along with Chart.js which will render these stats in an appropriate way.

Visualize our statistics with Chart.js

Back on the home page, we fetch call tracking statistics in JSON from the server using jQuery. We display the stats in colorful pie charts we create with Chart.js.

Call tracking charts

Loading Code Samples...
Language
$.getJSON('/lead/summary-by-lead-source', function(result) {
    summaryByLeadSourceData = _.map(result, function(leadSourceDataPoint) {
        return {
            value: leadSourceDataPoint.lead_count,
            color: 'hsl(' + (180 * leadSourceDataPoint.lead_count/ result.length) + ', 100%, 50%)',
            label: leadSourceDataPoint.description,
        };
    });
    var byLeadSourceContext = $("#pie-by-lead-source").get(0).getContext("2d");
    var byLeadSourceChart = new Chart(byLeadSourceContext).Pie(summaryByLeadSourceData);
});

$.getJSON('/lead/summary-by-city', function(result) {
    summaryByCityData = _.map(result, function(cityDataPoint) {
        return {
            value: cityDataPoint.lead_count,
            color: 'hsl(' + (180 * cityDataPoint.lead_count/ result.length) + ', 100%, 50%)',
            label: cityDataPoint.city
        };
    });
    var byCityContext = $("#pie-by-city").get(0).getContext("2d");
    var byCityChart = new Chart(byCityContext).Pie(summaryByCityData);
});
public/js/pieCharts.js
Pie Chart from Stats

public/js/pieCharts.js

That's it! Our Laravel application is now ready to purchase new phone numbers, forward incoming calls, and record some statistics for our business.

Where to next?

If you're a PHP developer working with Twilio, you might also enjoy these tutorials:

Click-To-Call (Laravel)

Put a button on your web page that connects visitors to live support or sales people via telephone.

Appointment Reminders (Laravel)

Send your customers automatic reminders ahead of appoiments using Twilio SMS.

Did this help?

Thanks for checking this tutorial out! If you have any feedback to share with us please contact us on Twitter, we'd love to hear it.

Mario Celi
David Prothero
Andrew Baker
Jose Oliveros
Agustin Camino

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use Illuminate\Http\Request;
use Twilio\Rest\Client;

class AvailableNumberController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Display numbers available for purchase. Fetched from the API
     *
     * @param  Request $request
     * @return Response
     */
    public function index(Request $request)
    {
        $areaCode = $request->input('areaCode');

        $numbers = $this->_twilioClient->availablePhoneNumbers("US")
            ->local->stream(
                [
                    'areaCode' => $areaCode
                ]
            );

        return response()->view(
            'available_numbers.index',
            [
                'numbers' => $numbers,
                'areaCode' => $areaCode
            ]
        );
    }
}
SDK Version:
  • blade
@extends('layouts.master')

@section('content')
<div class="col-lg-6">
<h2>Purchase phone numbers</h2>
    <h3>Available numbers</h3>
    <p>For area code: {{ $areaCode or &#x27;any&#x27; }}</p>
    <p>The number you choose will be used to create a Lead Source. On the next page, you will set a name and forwarding number for this lead source.</p>
    <table class="table">
        <thead>
            <th>Phone number</th>
            <th>State</th>
            <th></th>
        </thead>
        <tbody>
            @foreach ($numbers as $number)
                <tr>
                    <td> {{ $number-&gt;friendlyName }} </td>
                    <td> {{ $number-&gt;region }} </td>
                    <td>
                        {!! Form::open(['url' => route('lead_source.store')]) !!}
                        {!! Form::hidden('phoneNumber', $number->phoneNumber) !!}
                        {!! Form::submit('Purchase', ['class' => 'btn btn-primary btn-xs']) !!}
                        {!! Form::close() !!}
                    </td>
                </tr>
            @endforeach
        </tbody>
    </table>
</div>
@stop
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use App\LeadSource;
use Illuminate\Http\Request;
use Twilio\Rest\Client;

class LeadSourceController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Store a new lead source (i.e phone number) and redirect to edit
     * page
     *
     * @param  Request $request
     * @return Response
     */
    public function store(Request $request)
    {
        $appSid = $this->_appSid();

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

        $this->_twilioClient->incomingPhoneNumbers
            ->create(
                [
                    "phoneNumber" => $phoneNumber,
                    "voiceApplicationSid" => $appSid,
                    "voiceCallerIdLookup" => true
                ]
            );

        $leadSource = new LeadSource(
            [
                'number' => $phoneNumber
            ]
        );
        $leadSource->save();

        return redirect()->route('lead_source.edit', [$leadSource]);
    }

    /**
     * Show the form for editing a lead source
     *
     * @param  int $id
     * @return Response
     */
    public function edit($id)
    {
        $leadSourceToEdit = LeadSource::find($id);

        return response()->view(
            'lead_sources.edit',
            ['leadSource' => $leadSourceToEdit]
        );
    }

    /**
     * Update the lead source in storage.
     *
     * @param  Request $request
     * @param  int $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        $this->validate(
            $request,
            [
                'forwarding_number' => 'required',
                'description' => 'required'
            ]
        );

        $leadSourceToUpdate = LeadSource::find($id);
        $leadSourceToUpdate->fill($request->all());
        $leadSourceToUpdate->save();

        return redirect()->route('dashboard');
    }

    /**
     * Remove the lead source from storage and release the number
     *
     * @param  int $id
     * @return Response
     */
    public function destroy($id)
    {
        $leadSourceToDelete = LeadSource::find($id);
        $phoneToDelete = $this->_twilioClient->incomingPhoneNumbers
            ->read(
                [
                    "phoneNumber" => $leadSourceToDelete->number
                ]
            );

        if ($phoneToDelete) {
            $phoneToDelete[0]->delete();
        }
        $leadSourceToDelete->delete();

        return redirect()->route('dashboard');
    }

    /**
     * The Twilio TwiML App SID to use
     * @return string
     */
    private function _appSid()
    {
        $appSid = config('app.twilio')['TWILIO_APP_SID'];
        if (isset($appSid)) {
            return $appSid;
        }

        return $this->_findOrCreateCallTrackingApp();
    }

    private function _findOrCreateCallTrackingApp()
    {
        $existingApp = $this->_twilioClient->applications->read(
            array(
                "friendlyName" => 'Call tracking app'
            )
        );
        if ($existingApp) {
            return $existingApp[0]->sid;
        }

        $newApp = $this->_twilioClient->applications
            ->create('Call tracking app');

        return $newApp->sid;
    }
}
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use App\LeadSource;
use Illuminate\Http\Request;
use Twilio\Rest\Client;

class LeadSourceController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Store a new lead source (i.e phone number) and redirect to edit
     * page
     *
     * @param  Request $request
     * @return Response
     */
    public function store(Request $request)
    {
        $appSid = $this->_appSid();

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

        $this->_twilioClient->incomingPhoneNumbers
            ->create(
                [
                    "phoneNumber" => $phoneNumber,
                    "voiceApplicationSid" => $appSid,
                    "voiceCallerIdLookup" => true
                ]
            );

        $leadSource = new LeadSource(
            [
                'number' => $phoneNumber
            ]
        );
        $leadSource->save();

        return redirect()->route('lead_source.edit', [$leadSource]);
    }

    /**
     * Show the form for editing a lead source
     *
     * @param  int $id
     * @return Response
     */
    public function edit($id)
    {
        $leadSourceToEdit = LeadSource::find($id);

        return response()->view(
            'lead_sources.edit',
            ['leadSource' => $leadSourceToEdit]
        );
    }

    /**
     * Update the lead source in storage.
     *
     * @param  Request $request
     * @param  int $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        $this->validate(
            $request,
            [
                'forwarding_number' => 'required',
                'description' => 'required'
            ]
        );

        $leadSourceToUpdate = LeadSource::find($id);
        $leadSourceToUpdate->fill($request->all());
        $leadSourceToUpdate->save();

        return redirect()->route('dashboard');
    }

    /**
     * Remove the lead source from storage and release the number
     *
     * @param  int $id
     * @return Response
     */
    public function destroy($id)
    {
        $leadSourceToDelete = LeadSource::find($id);
        $phoneToDelete = $this->_twilioClient->incomingPhoneNumbers
            ->read(
                [
                    "phoneNumber" => $leadSourceToDelete->number
                ]
            );

        if ($phoneToDelete) {
            $phoneToDelete[0]->delete();
        }
        $leadSourceToDelete->delete();

        return redirect()->route('dashboard');
    }

    /**
     * The Twilio TwiML App SID to use
     * @return string
     */
    private function _appSid()
    {
        $appSid = config('app.twilio')['TWILIO_APP_SID'];
        if (isset($appSid)) {
            return $appSid;
        }

        return $this->_findOrCreateCallTrackingApp();
    }

    private function _findOrCreateCallTrackingApp()
    {
        $existingApp = $this->_twilioClient->applications->read(
            array(
                "friendlyName" => 'Call tracking app'
            )
        );
        if ($existingApp) {
            return $existingApp[0]->sid;
        }

        $newApp = $this->_twilioClient->applications
            ->create('Call tracking app');

        return $newApp->sid;
    }
}
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Lead;

class LeadSource extends Model
{
    protected $fillable = ['number', 'forwarding_number', 'description'];

    public function leads()
    {
        return $this->hasMany('App\Lead');
    }
}
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\LeadSource;
use DB;

class Lead extends Model
{
    protected $fillable = ['caller_number', 'city', 'state', 'caller_name', 'call_sid'];

    public function leadSource()
    {
        return $this->belongsTo('App\LeadSource');
    }

    public static function byLeadSource()
    {
        $leadsBySource
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(
                DB::raw('count(1) as lead_count'),
                'lead_sources.description',
                'lead_sources.number'
            )
            ->groupBy(
                'lead_source_id',
                'lead_sources.description',
                'lead_sources.number'
            )
            ->orderBy('lead_count', 'DESC')
            ->orderBy('lead_sources.description', 'DESC')
            ->get();

        return $leadsBySource;
    }

    public static function byCity()
    {
        $leadsByCity
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(DB::raw('count(1) as lead_count'), 'leads.city')
            ->groupBy('leads.city')
            ->get();

        return $leadsByCity;
    }
}
<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use App\Lead;
use App\LeadSource;
use DB;
use Illuminate\Http\Request;
use Twilio\Rest\Client;
use Twilio\Twiml;

class LeadController extends Controller
{

    /**
     * Twilio Client
     */
    protected $_twilioClient;

    public function __construct(Client $twilioClient)
    {
        $this->_twilioClient = $twilioClient;
    }

    /**
     * Display a listing of leads
     * @param Request $request
     * @return Response with all found leads
     */
    public function dashboard(Request $request)
    {
        $context = [
            'leadSources' => LeadSource::all(),
            'appSid' => $this->_appSid()
        ];

        return response()->view('leads.index', $context);
    }

    /**
     * Endpoint which store a new lead with its lead source and forward the call
     *
     * @param  Request $request Input data
     * @return Response Twiml to redirect call to the forwarding number
     */
    public function store(Request $request)
    {
        $leadSource = LeadSource::where(['number' => $request->input('To')])
            ->first();
        $lead = new Lead();
        $lead->leadSource()->associate($leadSource->id);

        $lead->city = $this->_normalizeName($request->input('FromCity'));
        $lead->state = $this->_normalizeName($request->input('FromState'));

        $lead->caller_number = $request->input('From');
        $lead->caller_name = $request->input('CallerName');
        $lead->call_sid = $request->input('CallSid');

        $lead->save();

        $forwardMessage = new Twiml();
        $forwardMessage->dial($leadSource->forwarding_number);

        return response($forwardMessage, 201)
            ->header('Content-Type', 'application/xml');
    }

    /**
     * Display all lead sources as JSON, grouped by lead source
     *
     * @param  Request $request
     * @return Response
     */
    public function summaryByLeadSource()
    {
        return response()->json(Lead::byLeadSource());
    }

    /**
     * Display all lead sources as JSON, grouped by city
     *
     * @param  Request $request
     * @return Response
     */
    public function summaryByCity()
    {
        return response()->json(Lead::byCity());
    }

    /**
     * The Twilio TwiML App SID to use
     * @return string
     */
    private function _appSid()
    {
        $appSid = config('app.twilio')['TWILIO_APP_SID'];

        if (isset($appSid)) {
            return $appSid;
        }

        return $this->_findOrCreateCallTrackingApp();
    }

    private function _findOrCreateCallTrackingApp()
    {
        $existingApp = $this->_twilioClient->applications->read(
            array(
                "friendlyName" => 'Call tracking app'
            )
        );
        if (count($existingApp)) {
            return $existingApp[0]->sid;
        }

        $newApp = $this->_twilioClient->applications
            ->create('Call tracking app');

        return $newApp->sid;
    }

    private function _normalizeName($toNormalize)
    {
        if (is_null($toNormalize)) {
            return '';
        } else {
            return $toNormalize;
        }
    }
}
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\LeadSource;
use DB;

class Lead extends Model
{
    protected $fillable = ['caller_number', 'city', 'state', 'caller_name', 'call_sid'];

    public function leadSource()
    {
        return $this->belongsTo('App\LeadSource');
    }

    public static function byLeadSource()
    {
        $leadsBySource
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(
                DB::raw('count(1) as lead_count'),
                'lead_sources.description',
                'lead_sources.number'
            )
            ->groupBy(
                'lead_source_id',
                'lead_sources.description',
                'lead_sources.number'
            )
            ->orderBy('lead_count', 'DESC')
            ->orderBy('lead_sources.description', 'DESC')
            ->get();

        return $leadsBySource;
    }

    public static function byCity()
    {
        $leadsByCity
            = DB::table('leads')
            ->join('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
            ->select(DB::raw('count(1) as lead_count'), 'leads.city')
            ->groupBy('leads.city')
            ->get();

        return $leadsByCity;
    }
}
$.getJSON('/lead/summary-by-lead-source', function(result) {
    summaryByLeadSourceData = _.map(result, function(leadSourceDataPoint) {
        return {
            value: leadSourceDataPoint.lead_count,
            color: 'hsl(' + (180 * leadSourceDataPoint.lead_count/ result.length) + ', 100%, 50%)',
            label: leadSourceDataPoint.description,
        };
    });
    var byLeadSourceContext = $("#pie-by-lead-source").get(0).getContext("2d");
    var byLeadSourceChart = new Chart(byLeadSourceContext).Pie(summaryByLeadSourceData);
});

$.getJSON('/lead/summary-by-city', function(result) {
    summaryByCityData = _.map(result, function(cityDataPoint) {
        return {
            value: cityDataPoint.lead_count,
            color: 'hsl(' + (180 * cityDataPoint.lead_count/ result.length) + ', 100%, 50%)',
            label: cityDataPoint.city
        };
    });
    var byCityContext = $("#pie-by-city").get(0).getContext("2d");
    var byCityChart = new Chart(byCityContext).Pie(summaryByCityData);
});