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

Como criar um portal de SMS com Laravel e Twilio: demo em funcionamento

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, vamos ensinar você a usar o Programmable SMS da Twilio para criar um portal de notificações via SMS com o 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é-requisito 

Para acompanhar 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. Se ele não estiver instalado, consulte a documentação do Laravel para saber como fazer a instalação. 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 via Composer:

$ cd sms-portal
$ composer require twilio/sdk

Se o Composer não estiver instalado no PC, siga as instruções disponíveis aqui.

Depois de instalar o Twilio PHP SDK, precisamos obter as credenciais da Twilio no dashboard. Acesse o dashboard e anote o account_sid e o auth_token.

Tela do console da Twilio com as credenciais

Agora, vá para a seção Phone Number (Número de telefone) para ver seu número de telefone habilitado para SMS.

Tela do console da Twilio com a opção de compra de números

A próxima etapa é atualizar o arquivo .env com as credenciais da Twilio. Abra o arquivo .env 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. Se você usa 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. Se você não tiver esse aplicativo ou uma ferramenta equivalente e se o MySQL não estiver 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 se você tiver 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 criar 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

Ele vai 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:

Tela do Visual Studio

Precisamos adicionar a coluna phone_number à tabela. Podemos fazer isso 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:

Tela do terminal com o código executado

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

Primeiramente, vamos criar um model que usaremos 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: estes são alguns pontos a serem considerados

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

O próximo passo é criar o controller onde vamos implementar 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

Ele vai 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 instancia 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 o 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, somos levados de volta à 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 PHP com a qual é possível criar um array 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, obtemos as credenciais armazenadas da Twilio das variáveis de ambiente usando a função PHP integrada getenv() e, após ela, instanciamos 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 destinatário da mensagem e um array com as propriedades de from e body, onde from é o 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 vamos usar 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 permite iterar no array 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, vá para resources/views/welcome.blade.php e faça as seguintes alterações no campo form:

//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, seu 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, seu 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:

Tela da interface de demonstração em funcionamento

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

Tela parcial do celular com a mensagem de SMS recebida

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.

Animação com a tela da demonstração em funcionamento

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. Se você quiser dar uma olhada no 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. 

Este artigo foi traduzido do original "How to Create an SMS Portal With Laravel and Twilio". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.