Como criar um portal de SMS com Laravel e Twilio

March 22, 2019
Escrito por
Brian Iyoha
Contribuidor
As opiniões expressas pelos colaboradores da Twilio são de sua autoria

xfZiGIwY7kMFumujtS99SsDUOzzE3HEluKNzI4Td5Ba7yorAqM9583sLeRzWPPuI2iDcAOjRAj2f0OZoGkCTjizc-ZoKWtWz98AHxpunO00UwgncR4v9XNn3bgJrLKPySdF2rbC0f2CuaGby8A

Em algum momento do fluxo de trabalho do seu aplicativo, pode ser necessário passar informações importantes para os usuários. Graças ao avanço das tecnologias web, isso pode ser feito facilmente com notificações por push. No entanto, a maioria desses serviços exige que os usuários tenham uma conexão com a Internet e nem sempre essa é a realidade. Felizmente, podemos contornar isso usando um sistema de notificações que não depende da Internet.

Neste tutorial, ensinaremos você a usar o Programmable SMS da Twilio para criar um portal de notificações via SMS usando Laravel. Quando terminarmos, você terá desenvolvido um portal de notificações via SMS personalizadas para informar os usuários com SMS por meio de um dashboard.

Pré-requisitos 

Para seguir este tutorial, você precisará do seguinte:

Configuração do projeto

Em primeiro lugar, precisamos criar um projeto do Laravel usando o instalador do Laravel ou o Composer. Vamos usar o instalador do Laravel neste tutorial. Caso não o tenha instalado, consulte a documentação do Laravel para saber como instalar. Para gerar um novo projeto do Laravel, execute este comando no terminal:

$ laravel new sms-portal

Agora, mude o diretório de trabalho para sms-portal e instale o SDK da Twilio pelo Composer:

$ cd sms-portal
$ composer require twilio/sdk 

Caso não tenha o Composer instalado no PC, siga as instruções disponíveis aquipara instalar.

Após a instalação do SDK PHP da Twilio, precisaremos obter as credenciais da Twilio no dashboard. Acesse o dashboard e anote o account_sid e o auth_token.

Captura de tela de credenciais da Twilio

Agora vá para a seção Número de telefone para habilitar seu número para SMS.

Painel de número ativo na Twilio

A próxima etapa é atualizar o arquivo .env com as nossas credenciais da Twilio. Abra .env, localizado na raiz do diretório do projeto, e adicione estes valores:

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"

Configuração do banco de dados

Agora que temos um projeto básico do Laravel com o SDK da Twilio instalado, vamos criar o banco de dados. Caso use um aplicativo GUI, como o phpMyAdmin, para gerenciar seu banco de dados, crie um banco de dados chamado sms_portal e ignore esta seção. Caso não tenha esse aplicativo nem uma ferramenta equivalente e o MySQL não esteja instalado, instale o MySQL do site oficial na sua plataforma.

Inicie o terminal e execute este comando para fazer login no MySQL:

$ mysql -u {your_user_name}

OBSERVAÇÃO: adicione o sinalizador -p caso tenha uma senha para a instância do MySQL.

Depois de fazer login, execute o seguinte comando para criar um banco de dados:

mysql> create database sms_portal;
mysql> exit;

Agora faremos as devidas alterações na configuração do banco de dados no arquivo .env, localizado na raiz da pasta do projeto.

DB_DATABASE=sms_portal
DB_USERNAME=root
DB_PASSWORD=

Criação da migração

Depois de criarmos o banco de dados, vamos criar a migração do banco de dados. Para fazer isso, basta executar este comando no terminal:

$ php artisan make:migration create_users_phone_number_table

Isso gerará um arquivo de migração {current_time_stamp}_create_users_phone_number_table no diretório /database/migrations.

Agora, abra a pasta do projeto no editor de texto/IDE de sua preferência para começarmos a fazer as alterações necessárias. Abra o arquivo de migração que acabamos de criar. O conteúdo deve ser igual a este:

Como criar uma migração no IDE

É preciso adicionar a coluna phone_number à tabela. Podemos fazê-lo editando o método up() da seguinte maneira:

public function up() {
    Schema::create('users_phone_number', function (Blueprint $table) {
        $table->increments('id');
        $table->string('phone_number'); 
        $table->timestamps();
    });
}

Agora, temos nosso arquivo de migração pronto para ser migrado. Podemos fazer isso executando o seguinte no terminal:

$ php artisan migrate

A saída deve ser parecida com esta:

Saída do console do artisan migrate

Criação da interface do usuário

Agora, nosso projeto está configurado. É hora de criar uma interface de usuário simples para adicionar dados ao banco de dados e enviar notificações via SMS.

Abra o arquivo /resources/views/welcome.blade.php e faça as seguintes alterações no bloco <head>.

<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>

Nós apenas removemos o estilo inicial da página e adicionamos o Bootstrap usando o BootsrapCDN para facilitar a aplicação de estilo. Em seguida, vamos criar dois formulários na página. Um para registrar o número de telefone dos usuários e o outro para enviar mensagens de notificação personalizadas a usuários selecionados. Faça as seguintes alterações no bloco body.

<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>

Se você observar mais atentamente o código acima, perceberá que temos o seguinte:

      <select multiple class="form-control">
            @foreach ($users as $user)
              <option>{{$user->phone_number}}</option>
           @endforeach
      </select>

Esse trecho de código ajuda a gerar um campo de opção para cada número de telefone de usuário disponível retornado com essa exibição. Vamos implementar esse recurso em breve.  

Armazenamento do número de telefone dos usuários

Primeiro vamos criar um modelo para consultar e inserir registros no banco de dados. Inicie o terminal no diretório do projeto e execute o seguinte:

 $ php artisan make:model UsersPhoneNumber

Abra o arquivo criado em app/UsersPhoneNumber.php e adicione o seguinte código:

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class UsersPhoneNumber extends Model
{
   protected $table= "users_phone_number";
   protected $fillable = [
        'phone_number'
    ];
}

OBSERVAÇÃO: aqui estão alguns pontos a considerar

  • Adicionar protected $table= "users_phone_number"; informa ao Eloquent o nome da tabela a ser usada. Caso ele não seja informado, o nome no plural da classe será usado como nome da tabela. 
  • Adicionar protected $fillable informa ao Eloquent que ele deve tornar o campo atribuível em massa (saiba mais acessando o link acima).

O próximo passo é criar o controller, em que implementaremos a lógica necessária para cada rota de solicitação. Mais uma vez, vamos iniciar o terminal e executar o seguinte:

$ php artisan make:controller HomeController

Isso gerará um arquivo controller em app/Http/Controllers/HomeController.php com o seguinte conteúdo:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    //
}

Criação do método Salvar número de telefone

Vamos criar uma função que instancie um novo modelo UsersPhoneNumber com os dados enviados do corpo da solicitação:

<?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"]);
}

Com base no código acima, estamos executando a validação dos dados enviados do corpo de $request antes de criar uma nova instância de UsersPhoneNumber. Depois de armazenar o número de telefone do usuário, retornamos à página de boas-vindas com uma mensagem flash de sucesso exibida na sessão.

Exibição de retorno com número de telefone de usuários

Agora, precisamos retornar a exibição com dados de números de telefone registrados. Vamos escrever uma função simples no HomeController que consulte a tabela users_phone_number e retorne os resultados da consulta para a exibição:

<?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
}

OBSERVAÇÃO: compact() é uma função do PHP com a qual é possível criar uma matriz com nomes de variáveis e seus valores.

Envio de mensagens usando Programmable SMS da Twilio

Nesta próxima etapa, vamos implementar o envio de SMS usando a biblioteca Programmable SMS da Twilio. Crie uma função private no HomeController que servirá de função auxiliar para o envio de mensagens:

<?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] );
}

A função recebe dois parâmetros de $message e $recipients. Em seguida, obteremos as credenciais armazenadas da Twilio das variáveis de ambiente usando a função PHP integrada getenv(); depois dela, instanciaremos um novo Twilio Client com as credenciais. Agora, podemos enviar o SMS chamando o seguinte:

$client->messages->create($recipients, [
    'from' => $twilio_number, 
    'body' => $message
]);

A função messages->create() da Twilio usa dois parâmetros de um receptor da mensagem e uma matriz com as propriedades de frombody em que from é seu número de telefone Twilio ativo.

Envio de notificação para o usuário após o registro

Até agora, concluímos a função sendMessage(), que usaremos para enviar mensagens aos usuários. Agora vamos atualizar a função storePhoneNumber() para notificar os usuários quando o registro deles for bem-sucedido. Para isso, faça as seguintes alterações na função storePhoneNumber():

<?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"]);
}

Ótimo! Agora, sempre que o número de telefone de um usuário for adicionado ao banco de dados, poderemos enviar uma mensagem de notificação para informá-lo sobre a ação realizada.

Envio de notificações personalizadas

Em seguida, vamos escrever uma função para enviar mensagens personalizadas a usuários selecionados. Adicione o seguinte código ao 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!"]);
}

Essa função envia os dados validados do corpo de $request para a variável $validatedData, o que no permite iterar na matriz de $validatedData[users] e enviar a mensagem recebida de $validatedData["body"] para cada usuário. Depois disso, somos redirecionamos à página de boas-vindas com uma mensagem flash de sucesso exibida na sessão.

Criação de rotas

Criamos as funções de controlador com sucesso. Agora, vamos adicionar as rotas ao aplicativo. Abra routes/web.php e faça as seguintes alterações:

<?php
Route::get('/', 'HomeController@show');
Route::post('/', 'HomeController@storePhoneNumber');
Route::post('/custom', 'HomeController@sendCustomMessage');

Atualização do campo form com rotas

Agora acesse resources/views/welcome.blade.php e faça as seguintes alterações no campo de formulários:

//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>

e

//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>

Teste do código

Vamos reunir todo o código que criamos até agora. A esta altura, o HomeController.php deve estar parecido com isto:

<?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]);
    }
}

e, para a exibição, o welcome.blade.php deve estar parecido com isto:

<!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>

Caso o seu código esteja igual a esse, você pode prosseguir. Do contrário, faça uma nova verificação para descobrir o que está faltando.

Execução do aplicativo

Abra o terminal, navegue até o diretório do projeto e execute o seguinte comando:

$ php artisan serve

Ele mostrará o aplicativo Laravel em uma porta localhost, que normalmente é 8000. No navegador, abra o link de localhost que aparece depois da execução do comando. Você verá uma página como esta:

App Laravel em execução no localhost

Prossiga e registre um novo número de telefone. Se tudo der certo, você receberá um SMS notificando sobre o registro.

Exemplo de mensagem de texto da conta de teste da Twilio

 Você também pode testar o envio de notificações personalizadas selecionando um usuário no campo de seleção e inserindo o texto a ser enviado na área de texto. Quando terminar, clique no botão Send Notification (Enviar notificação) para receber um SMS com a mensagem de notificação personalizada.

Notificações personalizadas

Conclusão

Agora que você concluiu este tutorial, será capaz de integrar o Programmable SMS da Twilio ao seu aplicativo Laravel e enviar mensagens de notificação por SMS. Caso queira conferir o código-fonte completo deste tutorial, ele está disponível no Github

Você pode fazer ainda mais ao permitir que os usuários executem ações a partir das notificações via SMS enviadas. 

Adoraria esclarecer as suas dúvidas sobre este tutorial. Entre em contato comigo via: