Create an Artisan Command to View Twilio Calls

August 23, 2022
Written by
Reviewed by

Create an Artisan Command to View Twilio Calls

Laravel's Artisan Console provides a wealth of helpful commands to assist with all manner of tasks when building and managing Laravel applications. It can clear the application and configuration cache, create all manner of classes, generate the application's key, manage database migrations, and so much more.

In this tutorial, you're going to learn how to create a custom Artisan command to list the voice calls you've made on your Twilio account and print the call information in tabular form.

Prerequisites

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

Create a new Laravel project

The first thing to do, if you don't already have an existing Laravel application, is to generate a new one using Composer. To do so, run the following commands to create one and change into the new project's directory.

composer create-project laravel/laravel twilio-artisan-command
cd twilio-artisan-command

Add the required dependencies

While Laravel comes with a wealth of dependencies, you will need to add two more. These are:

Run the following command in the current directory to install them.

composer require \
    twilio/sdk \
    moneyphp/money

Retrieve your Twilio credentials

The next thing to do is to make your Twilio credentials (your Twilio Account SID and Auth Token) available to the application. You're going to make use of Laravel's existing environment variable functionality to make life easier.

Start off by pasting the code below at the bottom of the .env file, in the project's top-level directory.

TWILIO_ACCOUNT_SID=<TWILIO_ACCOUNT_SID>
TWILIO_AUTH_TOKEN=<TWILIO_AUTH_TOKEN>

These add an environment variable for each of the required values.

Next, from the Twilio Console's Dashboard, copy your Account SID and Auth Token and paste them in place of the respective placeholder values (<TWILIO_ACCOUNT_SID> and <TWILIO_AUTH_TOKEN>) in the .env file.

Retrieve your Twilio auth token and account SID

Generate the new Artisan command

The next thing to do is to generate the stub of the Artisan command, using Artisan, by running the command below.

php artisan make:command TwilioListCalls

Then, in the new Command class (app/Console/Commands/TwilioListCalls.php) replace the code with the following.

<?php

declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Money\Currencies\ISOCurrencies;
use Money\Currency;
use Money\Formatter\IntlMoneyFormatter;
use Money\Money;
use NumberFormatter;
use Twilio\Exceptions\EnvironmentException;
use Twilio\Rest\Api\V2010\Account\CallInstance;
use Twilio\Rest\Client;

use function abs;
use function count;
use function env;
use function floatval;
use function sprintf;
use function ucfirst;

class TwilioListCalls extends Command
{
    public const SHORT_DATE_FORMAT = 'd/m/Y H:i';
    public const LONG_DATE_FORMAT = 'r';

    protected $signature = 'twilio:list-calls {--short-date : Display all dates in the short form}';

    protected $description = 'List calls on your Twilio account';

    public function handle()
    {
        $client = new Client(
            env('TWILIO_ACCOUNT_SID'),
            env('TWILIO_AUTH_TOKEN')
        );

        try {
            $calls = $client->calls->read();
        } catch (EnvironmentException $e) {
            $this->error("Unable to retrieve calls from your account");
            return -1;
        }

        if (empty($calls)) {
            $this->info("No calls are available on your account");
        }

        $dateFormat = $this->option('short-date')
            ? self::SHORT_DATE_FORMAT
            : self::LONG_DATE_FORMAT;

        $callDetails = [];
        foreach ($calls as $call) {
            $callDetails[] = [
                $call->sid,
                $call->to,
                ucfirst($call->status),
                $call->startTime->format($dateFormat),
                $call->endTime->format($dateFormat),
                $this->formatCallPrice($call),
                $call->priceUnit,
            ];
        }

        $this->info("The current list of calls available on your account:");

        $this->table(
            [
                'Call ID',
                'Recipient',
                'Status',
                'Started At',
                'Ended At',
                'Price',
                'Price Unit',
            ],
            $callDetails,
        );

        $this->info(sprintf("Total calls: %d", count($calls)));

        return 0;
    }

    private function formatCallPrice(CallInstance $call, string $locale = 'en_US'): string
    {
        $money           = new Money(
            abs((int)round($call->price * 100)),
            new Currency($call->priceUnit)
        );
        $currencies      = new ISOCurrencies();
        $numberFormatter = new NumberFormatter(
            $locale, 
            NumberFormatter::CURRENCY
        );
        $moneyFormatter  = new IntlMoneyFormatter($numberFormatter, $currencies);

        return $moneyFormatter->format($money);
    }
}

The class starts by defining two date constants. These are used depending on whether the user chooses to view the call information in short date format or not, using an option in the command signature.

It then defines the command signature and description. The signature is split into two parts: the command's name, twilio:list-calls, and the sole supported option --short-date.

The handle method

After that, it defines the handle() method, where the core business logic is defined. The method starts by instantiating a Twilio Client object, from which all interaction with the Twilio APIs are made, passing to its constructor the two Twilio environment variables defined earlier.

Then, it retrieves all calls on the user's account by calling the call property's read() method. If the method throws a \Twilio\Exceptions\EnvironmentException, an error message is printed to the terminal and the command returns a non-zero status code to indicate that the command completed unsuccessfully.

If successful, it does one of two things.

  • No calls were returned? It prints a message to the terminal saying that none were available.
  • Calls were returned? some of the returned call properties(shown in the table below) are then stored in an array ($callDetails).
PropertyDescription
sidThe call's unique id.
toThe phone number, SIP address, Client identifier or SIM SID that received this call
statusThe call's status. The value can be one of queued, ringing, in-progress, canceled, completed, failed, busy, or no-answer.
startTime & endTimeThe time that the call started and ended in RFC 2822 format.
price & priceUnitThe amount that the call cost the user.

Check out the available call properties in the documentation.

For easier readability, the created date, and start and end times are formatted using the applicable date format constant, and the call price information is formatted in the formatCallPrice() method, which you'll see shortly.

The collated call information is then printed in tabular format using the handy table method. The information is preceded by a header, telling the user that call information is available and a footer showing the total number of calls. Following that, 0 is returned to indicate that the command completed successfully.

The formatCallPrice() method

The class finishes off by defining the formatCallPrice() method. This method converts the call's price information (a string) into a float representation, then converts that to a value in cents.

Following that, it uses a combination of three classes, Money, NumberFormatter, and IntlMoneyFormatter to render the amount as an international currency string, e.g., $0.33, which is easier to read than the underlying value, e.g., -0.330000.

At this point, the new command is ready to use. You don't have to register it as that's automatically done for you by Laravel.

Test the new Artisan command

So, it's time to test that it works. To do that, run the following command.

php artisan twilio:list-calls

You should see output similar to the following in your terminal.

The current list of calls available on your account:
+------------------------------------+----------------+-----------+---------------------------------+---------------------------------+-------+------------+
| Call ID                            | Recipient      | Status    | Started At                      | Ended At                        | Price | Price Unit |
+------------------------------------+----------------+-----------+---------------------------------+---------------------------------+-------+------------+
| CAcbf9e754c4528dd7628e298a4cb6b2bc | +4917643971069 | Completed | Mon, 01 Aug 2022 10:14:26 +0000 | Mon, 01 Aug 2022 10:14:27 +0000 | $0.33 | USD        |
| CA4b45f06cc1463ae67c584f980099cc19 | +4917643971069 | Completed | Wed, 16 Feb 2022 08:36:52 +0000 | Wed, 16 Feb 2022 08:36:59 +0000 | $0.33 | USD        |
+------------------------------------+----------------+-----------+---------------------------------+---------------------------------+-------+------------+
Total calls: 2

Now, run the following command to view the same output, but with shorter dates.

php artisan twilio:list-calls --short-date

You should see output similar to the following in your terminal.

The current list of calls available on your account:
+------------------------------------+----------------+-----------+------------------+------------------+-------+------------+
| Call ID                            | Recipient      | Status    | Started At       | Ended At         | Price | Price Unit |
+------------------------------------+----------------+-----------+------------------+------------------+-------+------------+
| CAcbf9e754c4528dd7628e298a4cb6b2bc | +4917643971069 | Completed | 01/08/2022 10:14 | 01/08/2022 10:14 | $0.33 | USD        |
| CA4b45f06cc1463ae67c584f980099cc19 | +4917643971069 | Completed | 16/02/2022 08:36 | 16/02/2022 08:36 | $0.33 | USD        |
+------------------------------------+----------------+-----------+------------------+------------------+-------+------------+
Total calls: 2

That's how to create an Artisan command to view Twilio voice calls

You might have been expecting to write more code to create a custom Laravel command. However, with the official Twilio PHP Helper Library and Artisan itself, there was very little code required.

Over the next few weeks, I'll be showing how to create a number of helpful custom Artisan commands for interacting with your Twilio account, so stay tuned.

Till then, happy hacking! I can’t wait to see what you build with the Twilio APIs.

Matthew Setter is a PHP Editor in the Twilio Voices team and (naturally) a PHP developer. He’s also the author of Mezzio Essentials and Docker Essentials. When he’s not writing PHP code, he’s editing great PHP articles here at Twilio. You can find him at msetter@twilio.com, Twitter, and GitHub.