How to build a Laravel Twilio Package for SMS

February 21, 2020
Written by
Dotun Jolaoso
Contributor
Opinions expressed by Twilio contributors are their own

How to Build a Laravel Twilio Package

I recently realized that every time I had to do an integration with Twilio for sending SMS in a Laravel project, I used a custom wrapper around the Twilio PHP library to help me simplify the process. However, this became a bit monotonous for me as I always had to copy and paste this wrapper every time I was starting a new Laravel project. In this tutorial, you’ll join me in learning how to build a Laravel Twilio Package to eliminate copying and pasting and benefit from package management. This will also allow other developers such as yourself to make use of this package.

Technical Requirements

To complete this tutorial, you will need the following:

Setting up a New Package

We’ll be using Composer to set up the package. From the terminal, cd into your project’s directory and run the following command:

$ composer init

This will prompt you to pick a name for the package you’re creating. It is important to note that Composer has a recommended way for naming packages.

vendor/package-name

I’ve decided to name this package LaraTwilio, so for me the package name  will be dotunj/laratwilio. Once you’ve picked a name for your package, Composer will ask you further questions of which the default options will suffice. Once you’re done, a composer.json file will be generated for you in the root of your project’s directory.

Tip: You can read more about naming packages here.

Autoloading

When it comes to autoloading in Laravel packages, psr-4 is the recommended standard. With psr-4 we simply map a namespace to a file path relative to our package root. Add the following code to the composer.json file:

 "autoload": {
        "psr-4": {
            "Dotunj\\LaraTwilio\\":"src/"
        }
    }

Here, we’ve defined a namespace similar to that of the package’s name and mapped it to a src directory which we’ll be creating shortly.

NOTE: You will need to replace the package name “Dotun\\LaraTwilio” with your own.

Config File

We need a way to ensure users of our package provide us with their Twilio credentials as this is needed to process API requests. In the root of your project’s directory, run the following command:

$ mkdir config && touch config/laratwilio.php

This will create a config directory with a laratwilio.php file in it. Add the following code to the file we just created:

<?php

return [
    'account_sid' => env('TWILIO_ACCOUNT_SID'),
    'auth_token' => env('TWILIO_AUTH_TOKEN'),
    'sms_from' => env('TWILIO_SMS_FROM'),
];

Here we’ve simply defined an array with the necessary keys mapped to their respective Twilio credentials. These values will usually be read from the application’s .env file where our package has been installed.

Installing Twilio PHP

Since our package is simply a wrapper around the Twilio PHP SDK Library, we’ll need to add it as a dependency to our package. Run the following command to install the library:

$ composer require twilio/sdk

Creating the LaraTwilio Class

In the root of your project directory, create a src directory and within the directory, create a LaraTwilio.php file. This class will serve as the public API for our package. Add the following code to the file:

<?php

namespace Dotunj\LaraTwilio;

use Twilio\Rest\Client;

class LaraTwilio
{
    /** @var Twilio\Rest\Client */
    protected $client;

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

    public function notify(string $number, string $message)
    {
        return $this->client->messages->create($number, [
            'from' => config('laratwilio.sms_from'),
            'body' => $message
        ]);
    }
}

Using dependency injection via the constructor, we assign the Twilio Rest Client to the client property of the class. For this example, the notify() method will handle sending outbound SMS notifications using the Twilio API. It accepts two arguments, the phone number that should receive the SMS and the message itself.

LaraTwilio Service Provider

Service Providers serve as the connection point between your package and Laravel. They are responsible for binding things into Laravel’s service container and informing Laravel how to load package resources, such as config files.

In the src directory, create a LaraTwilioServiceProvider.php file and add the following code to the file:

<?php

namespace Dotunj\LaraTwilio;

use Exception;
use Twilio\Rest\Client;
use Dotunj\LaraTwilio\LaraTwilio;
use Illuminate\Support\ServiceProvider;

class LaraTwilioServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->mergeConfigFrom(__DIR__ . '/../config/laratwilio.php', 'laratwilio');

        $this->app->bind('laratwilio', function () {
            $this->ensureConfigValuesAreSet();
            $client = new Client(config('laratwilio.account_sid'), config('laratwilio.auth_token'));
            return new LaraTwilio($client);
        });
    }

    public function boot()
    {
        if ($this->app->runningInConsole()) {
            $this->publishConfig();
        }
    }

    protected function ensureConfigValuesAreSet()
    {
        $mandatoryAttributes = config('laratwilio');

        foreach ($mandatoryAttributes as $key => $value) {
            if (empty($value)) {
                throw new Exception("Please provide a value for ${key}");
            }
        }
    }

    protected function publishConfig()
    {
        $this->publishes([
            __DIR__ . '/../config/laratwilio.php' => config_path('laratwilio.php'),
        ], 'laratwilio-config');
    }
}

Service providers always extend the base  Illuminate\Support\ServiceProvider class and usually implement two methods register() and boot().

  • In the register() method, we call the mergeConfigFrom() method Laravel provides which allows us to merge our config file with the application’s config file. Next, we register a binding into the service container such that the LaraTwilio class we created earlier gets a configured Twilio Rest Client injected via its constructor.
  • The boot() method is used to publish the package’s config file.
  • The ensureConfigValuesAreSet() method is used to ensure that all the keys we defined in the config file have an associated value.

LaraTwilio Facade

In Laravel, Facades typically provide access to a class available in the service container. They usually extend the base Facade class and always return a service container binding. In the src directory, run the following command:

$ mkdir Facades && touch Facades/LaraTwilio.php

This will create a LaraTwilio.php file in the Facades folder. Edit the file with the following code:

<?php

namespace Dotunj\LaraTwilio\Facades;

use Illuminate\Support\Facades\Facade;

class LaraTwilio extends Facade
{
    public static function getFacadeAccessor()
    {
        return 'laratwilio';
    }
}

Here, the getFacadeAccessor() method returns the string laratwilio which is the name of the service container binding we created in the service provider file.

Package Discovery

To ensure that Laravel will automatically register our facades and service provider whenever the package is installed, we need to configure our package for discovery. To do that, we need to define the provider and facade in the extra section of our composer.json file. Head over to the composer.json file and add the extra section as follows:

  "extra": {
        "laravel": {
            "providers": [
                "Dotunj\\LaraTwilio\\LaraTwilioServiceProvider"
            ],
            "aliases": {
                "LaraTwilio": "Dotunj\\LaraTwilio\\Facades\\LaraTwilio"
            }
        }
    }

Conclusion

Packages can serve as a great way of providing code reusability and help us to follow the Don’t Repeat Yourself (DRY) principle which is the issue I had in my case. In this tutorial, we’ve seen how we can build a Twilio package intended specifically for use with Laravel. The code, as well as installation instructions, can be found on Github.  

Dotun Jolaoso

Website: https://dotunj.dev/
Github: https://github.com/Dotunj
Twitter: https://twitter.com/Dotunj_