At some point in your application workflow, you may need to pass important information to your users. Thanks to the advancement in web technologies, this can easily be done with push notifications. However, most of these services require your users to have an internet connection and unfortunately, this isn’t always the case. Luckily, we can overcome this by using a notification system that does not rely on the internet.
In this tutorial, we will teach you how to use Twilio’s Programmable SMS to create an SMS notification portal using Laravel. After we’re finished, you would have developed a custom SMS notification portal that allows you to notify your users via a dashboard with SMS.
Prerequisites
In order to follow this tutorial, you will need:
- Basic knowledge of Laravel
- Laravel Installed on your local machine
- Composer globally installed
- MySQL setup on your local machine
- Twilio Account
Setup Project
Firstly, we need to create a new Laravel project, either using the Laravel installer or Composer. We will be making use of the Laravel installer in this tutorial. If you don’t have it installed, you can check out how to do so from the Laravel documentation. To generate a fresh Laravel project, run this command in your terminal:
$ laravel new sms-portal
Now change your working directory to sms-portal
and install the Twilio SDK via Composer:
$ cd sms-portal
$ composer require twilio/sdk
If you don’t have composer installed on your PC you can do so by following the instructions here.
After installing the Twilio PHP SDK, we need to get our Twilio credentials from the Twilio dashboard. Head over to your dashboard and grab your account_sid
and auth_token
.
Now navigate to the Phone Number section to get your SMS enabled phone number.
The next step is to update the .env
file with our Twilio credentials. So open up .env
located at the root of the project directory and add these values:
TWILIO_SID="INSERT YOUR TWILIO SID HERE"
TWILIO_AUTH_TOKEN="INSERT YOUR TWILIO TOKEN HERE"
TWILIO_NUMBER="INSERT YOUR TWILIO NUMBER IN [E.164] FORMAT"
Setup Database
Now that we have a basic Laravel project with the Twilio SDK installed, let’s create our database. If you use a GUI application like phpMyAdmin to manage your database then go ahead and create a database named sms_portal
and skip this section. If you don’t have that, an equivalent tool and don’t have MySQL installed, then install MySQL from the official site for your platform.
Fire up the terminal and run this command to log in to MySQL:
$ mysql -u {your_user_name}
NOTE: Add the -p
flag if you have a password for your MySQL instance.
Once you are logged in, run the following command to create a new database:
mysql> create database sms_portal;
mysql> exit;
Let’s proceed to change our database configuration accordingly in the .env
file at the root of our project folder.
DB_DATABASE=sms_portal
DB_USERNAME=root
DB_PASSWORD=
Create Migration
Since we have our database created, let’s create our database migration. We can simply do this by running this command in our terminal:
$ php artisan make:migration create_users_phone_number_table
This will generate a migration file {current_time_stamp}_create_users_phone_number_table
in the /database/migrations
directory.
Now, open up the project folder in your favorite IDE/text editor so we can begin making changes as needed. Open the migration file we just created. We should have the same content as this:
We need to add the phone_number
column to our table. We can do that by editing the up()
method as follows:
public function up() {
Schema::create('users_phone_number', function (Blueprint $table) {
$table->increments('id');
$table->string('phone_number');
$table->timestamps();
});
}
We now have our migration file ready to be migrated. We can simply do that by running the following in our terminal:
$ php artisan migrate
We should have an output similar to this:
Creating the User Interface
At this point, we have our project setup. It’s time to build a simple user interface for adding data to our database and also for sending out SMS notifications.
Open up /resources/views/welcome.blade.php
and make the following changes to the <head>
block.
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SMS Portal With Twilio</title>
<!-- Bootstrap styles CDN -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
</head>
We simply removed the initial styling in the page and added Bootstrap using BootstrapCDN to ease styling. Next, we are going to create two forms on the page. One for registering users phone number, and another to send out custom notification messages to selected users. Make the following changes to the body
block.
<body>
<div class="container">
<div class="jumbotron">
<div class="row">
<div class="col">
<div class="card">
<div class="card-header">
Add Phone Number
</div>
<div class="card-body">
<form>
<div class="form-group">
<label>Enter Phone Number</label>
<input type="tel" class="form-control" placeholder="Enter Phone Number">
</div>
<button type="submit" class="btn btn-primary">Register User</button>
</form>
</div>
</div>
</div>
<div class="col">
<div class="card">
<div class="card-header">
Send SMS message
</div>
<div class="card-body">
<form>
<div class="form-group">
<label>Select users to notify</label>
<select multiple class="form-control">
@foreach ($users as $user)
<option>{{$user->phone_number}}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label>Notification Message</label>
<textarea class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Send Notification</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
If you take a closer look at the code above you will notice we have:
<select multiple class="form-control">
@foreach ($users as $user)
<option>{{$user->phone_number}}</option>
@endforeach
</select>
This snippet helps generate an option field for each available user phone number returned with this view. We will be implementing this feature shortly.
Storing Users Phone Number
Firstly, let’s create a model which we will use to query and also insert records to the database. Fire up your terminal on the project directory and run:
$ php artisan make:model UsersPhoneNumber
Open up the created file at app/UsersPhoneNumber.php
and add the following code:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class UsersPhoneNumber extends Model
{
protected $table= "users_phone_number";
protected $fillable = [
'phone_number'
];
}
NOTE: Here are a couple of things to consider
- Adding
protected $table= "users_phone_number";
tells Eloquent the table name to make use of. If this is not provided, the plural name of the class will be used as the table name. - Adding
protected $fillable
tells Eloquent to make the field mass assignable (Read more from the link above).
The next thing to do is create the controller where we will be implementing the logic needed for each request route. Once more, let’s fire up the terminal and run:
$ php artisan make:controller HomeController
This will generate a controller file at app/Http/Controllers/HomeController.php
with the following content:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
//
}
Creating the Save Phone Number Method
Let’s create a function that instantiates a new UsersPhoneNumber
model with the data passed from the request body:
<?php
/**
* Store a new user phone number.
*
* @param Request $request
* @return Response
*/
public function storePhoneNumber(Request $request)
{
//run validation on data sent in
$validatedData = $request->validate([
'phone_number' => 'required|unique:users_phone_number|numeric'
]);
$user_phone_number_model = new UsersPhoneNumber($request->all());
$user_phone_number_model->save();
return back()->with(['success'=>"{$request->phone_number} registered"]);
}
From the above code, we are running validation on the data passed in from the $request
body before proceeding to create a new instance of UsersPhoneNumber
. After storing the user's phone number, we are taken back to the welcome page with a success message flashed to the session.
Returning View with Users Phone Numbers
Now we need to return the view with data of registered phone numbers. Let’s write a simple function in the HomeController that queries the users_phone_number
table and returns the results from the query to the view:
<?php
/**
* Show the forms with users phone number details.
*
* @return Response
*/
public function show()
{
$users = UsersPhoneNumber::all(); //query db with model
return view('welcome', compact("users")); //return view with data
}
NOTE: compact() is a PHP function that allows you to create an array with variable names and their values.
Sending Messages with Twilio Programmable SMS
Next step, we implement the sending of SMS using Twilio’s Programmable SMS library. Create a private function in the HomeController to serve as a helper function for sending messages:
<?php
/**
* Sends sms to user using Twilio's programmable sms client
* @param String $message Body of sms
* @param Number $recipients string or array of phone number of recepient
*/
private function sendMessage($message, $recipients)
{
$account_sid = getenv("TWILIO_SID");
$auth_token = getenv("TWILIO_AUTH_TOKEN");
$twilio_number = getenv("TWILIO_NUMBER");
$client = new Client($account_sid, $auth_token);
$client->messages->create($recipients,
['from' => $twilio_number, 'body' => $message] );
}
The function receives two parameters of $message
and $recipients
. We then get our stored Twilio credentials from the environment variables using the built-in PHP getenv()
function, after which we instantiate a new Twilio client with the credentials. We can now proceed to send the SMS by calling:
$client->messages->create($recipients, [
'from' => $twilio_number,
'body' => $message
]);
The Twilio messages->create()
function takes in two parameters of a receiver of the message and an array with the properties of from
and body
where from
is your active Twilio phone number.
Send User Notification When Registered
So far, we have completed our sendMessage()
function which we will use to send messages to users. Now let’s update our storePhoneNumber()
function to notify users when they get successfully registered. To do this, make the following changes to the storePhoneNumber()
function:
<?php
/**
* Store a new user phone number.
*
* @param Request $request
* @return Response
*/
public function storePhoneNumber(Request $request)
{
//run validation on data sent in
$validatedData = $request->validate([
'phone_number' => 'required|unique:users_phone_number|numeric',
]);
$user_phone_number_model = new UsersPhoneNumber($request->all());
$user_phone_number_model->save();
$this->sendMessage('User registration successful!!', $request->phone_number);
return back()->with(['success' => "{$request->phone_number} registered"]);
}
Great! Now whenever a user’s phone number is added to our database, we can send the user a notification message alerting them about the action which was carried out.
Sending Custom Notifications
Next, let’s write a function to send out custom messages to selected users. Add the following code to the HomeController
:
<?php
/**
* Send message to a selected users
*/
public function sendCustomMessage(Request $request)
{
$validatedData = $request->validate([
'users' => 'required|array',
'body' => 'required',
]);
$recipients = $validatedData["users"];
// iterate over the array of recipients and send a twilio request for each
foreach ($recipients as $recipient) {
$this->sendMessage($validatedData["body"], $recipient);
}
return back()->with(['success' => "Messages on their way!"]);
}
This function passes the validated data from the $request
body into the $validatedData
variable, allowing us to iterate over the array of $validatedData[users]
and send each user the message received from $validatedData["body"]
. After which, we redirect back to the welcome page with a message flashed to the session.
Creating Routes
We have successfully created our controller functions. Now let’s add our routes to the application. Open routes/web.php
and make the following changes:
<?php
Route::get('/', 'HomeController@show');
Route::post('/', 'HomeController@storePhoneNumber');
Route::post('/custom', 'HomeController@sendCustomMessage');
Updating Form Field With Routes
Now head over to resources/views/welcome.blade.php
and make the following changes to the forms field:
//add the method attribute to the Register User form
// also add the name attributes to the input field
<form method="POST">
@csrf
<div class="form-group">
<label>Enter Phone Number</label>
<input type="tel" class="form-control" name="phone_number" placeholder="Enter Phone Number">
</div>
<button type="submit" class="btn btn-primary">Register User</button>
</form>
and
//add the method and action attributes to the Send custom message form
// also add the name attributes to the input fields
<form method="POST" action="/custom">
@csrf
<div class="form-group">
<label>Select users to notify</label>
<select name="users[]" multiple class="form-control">
@foreach ($users as $user)
<option>{{$user->phone_number}}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label>Notification Message</label>
<textarea name="body" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Send Notification</button>
</form>
Testing Our Code
Let’s bring all the code we have done so far together. At this point, your HomeController.php
should look like this:
<?php
namespace App\Http\Controllers;
use App\UsersPhoneNumber;
use Illuminate\Http\Request;
use Twilio\Rest\Client;
class HomeController extends Controller
{
/**
* Show the forms with users phone number details.
*
* @return Response
*/
public function show()
{
$users = UsersPhoneNumber::all();
return view('welcome', compact("users"));
}
/**
* Store a new user phone number.
*
* @param Request $request
* @return Response
*/
public function storePhoneNumber(Request $request)
{
//run validation on data sent in
$validatedData = $request->validate([
'phone_number' => 'required|unique:users_phone_number|numeric',
]);
$user_phone_number_model = new UsersPhoneNumber($request->all());
$user_phone_number_model->save();
$this->sendMessage('User registration successful!!', $request->phone_number);
return back()->with(['success' => "{$request->phone_number} registered"]);
}
/**
* Send message to a selected users
*/
public function sendCustomMessage(Request $request)
{
$validatedData = $request->validate([
'users' => 'required|array',
'body' => 'required',
]);
$recipients = $validatedData["users"];
// iterate over the array of recipients and send a twilio request for each
foreach ($recipients as $recipient) {
$this->sendMessage($validatedData["body"], $recipient);
}
return back()->with(['success' => "Messages on their way!"]);
}
/**
* Sends sms to user using Twilio's programmable sms client
* @param String $message Body of sms
* @param Number $recipients Number of recipient
*/
private function sendMessage($message, $recipients)
{
$account_sid = getenv("TWILIO_SID");
$auth_token = getenv("TWILIO_AUTH_TOKEN");
$twilio_number = getenv("TWILIO_NUMBER");
$client = new Client($account_sid, $auth_token);
$client->messages->create($recipients, ['from' => $twilio_number, 'body' => $message]);
}
}
and for our view, your welcome.blade.php
should look like this:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SMS Portal With Twilio</title>
<!-- Styles -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS"
crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="jumbotron">
@if (session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="row">
<div class="col">
<div class="card">
<div class="card-header">
Add Phone Number
</div>
<div class="card-body">
<form method="POST">
@csrf
<div class="form-group">
<label>Enter Phone Number</label>
<input type="tel" class="form-control" name="phone_number" placeholder="Enter Phone Number">
</div>
<button type="submit" class="btn btn-primary">Register User</button>
</form>
</div>
</div>
</div>
<div class="col">
<div class="card">
<div class="card-header">
Send SMS message
</div>
<div class="card-body">
<form method="POST" action="/custom">
@csrf
<div class="form-group">
<label>Select users to notify</label>
<select name="users[]" multiple class="form-control">
@foreach ($users as $user)
<option>{{$user->phone_number}}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label>Notification Message</label>
<textarea name="body" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Send Notification</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
If your code is the same you are ready to proceed. If not, double check your code to find out what’s missing.
Running Our Application
Open up your terminal and navigate to the project directory and run the following command:
$ php artisan serve
This will serve your Laravel application on a localhost port, normally 8000
. Open up the localhost link printed out after running the command in your browser and you should be greeted with a page like this:
Go ahead and register a new phone number. If everything goes well, you should receive an SMS shortly notifying you about your registration.
You can also test out sending custom notifications by selecting a user from the select field and enter the text to be sent to the selected user(s) in the textarea. When done, click on the send notification button and you should receive an SMS with the custom notification message.
Conclusion
Now that you have completed this tutorial, you should be able to integrate the Twilio programmable SMS into your Laravel application and send notification messages via SMS. If you will like to take a look at the complete source code for this tutorial, you can find it on Github.
You can take this further by allowing your users to take actions from SMS notifications sent to them.
I’d love to answer any question(s) you might have concerning this tutorial. You can reach me via:
- Email: brian.iyoha@gmail.com
- Twitter: thecodearcher
- GitHub: thecodearcher