Cómo crear un canal de notificación en Laravel para WhatsApp con Twilio

November 22, 2019
Redactado por
Chimezie Enyinnaya
Colaborador
Las opiniones expresadas por los colaboradores de Twilio son propias.

Cómo crear un canal de notificación en Laravel para WhatsApp con Twilio

Laravel facilita el envío de notificaciones en su aplicación PHP. De manera predeterminada, es compatible con varios canales, como correos, SMS, Slack y bases de datos. ¿Qué pasa si queremos enviar notificaciones a un canal diferente aparte de estos, por ejemplo, WhatsApp? En este tutorial le mostraremos cómo implementar las notificaciones de WhatsApp en la aplicación Laravel con la API de Twilio para WhatsApp.

Herramientas necesarias para completar este tutorial

Para realizar este tutorial, necesitará lo siguiente:

Qué estaremos creando

A efectos de este tutorial, utilizaremos el concepto de un sistema de pedidos. Para ser breve, no crearemos un sistema de pedidos con todas las funciones, sino solo la parte del sistema que envía notificaciones.

Creación de una nueva aplicación Laravel

Empecemos por crear una nueva aplicación Laravel. Utilizaremos el instalador de Laravel mencionado previamente. Ejecute el siguiente comando en su consola:

$ laravel new laravel-whatsapp-notification
$ cd laravel-whatsapp-notification

Cuando la aplicación esté creada, debemos instalar las dependencias de NPM (porque Bootstrap viene precomprimido como una dependencia NPM):

$ npm install

Una vez que se instalen las dependencias, ejecute lo siguiente:

$ npm run dev

Cómo agregar autenticación

A continuación, agregamos la autenticación. Desde Laravel 6, el andamiaje de autenticación se ha extraído en un paquete separado, por lo que necesitamos instalarlo con Composer:

$ composer require laravel/ui --dev

Luego, podemos ejecutar para obtener el andamiaje de autenticación:

$ php artisan ui vue --auth

Ya que en WhatsApp se utilizan números de teléfono, necesitamos una manera de recopilar los números de teléfono de los usuarios en nuestra aplicación. Una forma de lograrlo es recopilar los números de teléfono de los usuarios en el momento del registro. Actualicemos el formulario de registro para incluir el campo de número de teléfono. Agregue el siguiente código register.blade.php inmediatamente después del campo de dirección de correo electrónico:

// resources/views/auth/register.blade.php

<div class="form-group row">
  <label for="phone_number" class="col-md-4 col-form-label text-md-right">{{ __('Phone Number') }}</label>
  <div class="col-md-6">
    <input id="phone_number" type="text" class="form-control @error('phone_number') is-invalid @enderror" name="phone_number" value="{{ old('phone_number') }}" required autocomplete="phone_number">
    @error('phone_number')
      <span class="invalid-feedback" role="alert">
        <strong>{{ $message }}</strong>
      </span>
    @enderror
  </div>
</div>

Nota: Los números de teléfono del usuario deben estar en formato E.164.

Formulario de registro de Laravel

A continuación, actualicemos los métodos validator() y create() de RegisterController, como se muestra a continuación:

// app/Http/Controllers/Auth/RegisterController.php

protected function validator(array $data)
{
  return Validator::make($data, [
    'name' => ['required', 'string', 'max:255'],
    'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
    'phone_number' => ['required', 'string', 'unique:users'],
    'password' => ['required', 'string', 'min:8', 'confirmed'],
  ]);
}


protected function create(array $data)
{
  return User::create([
    'name' => $data['name'],
    'email' => $data['email'],
    'phone_number' => $data['phone_number'],
    'password' => Hash::make($data['password']),
  ]);
}

Hemos agregado algunas reglas de validación para el campo de número de teléfono y guardamos dicho número en la base de datos junto con los otros datos que se están recopilando.

Por último, necesitamos agregar el campo de número de teléfono a la lista de campos que se pueden asignar masivamente dentro del modelo de usuario:

// app/User.php

protected $fillable = [
  'name', 'email', 'password', 'phone_number'
];

Creación de modelos y migraciones

También debemos actualizar el archivo de migración de tablas de los usuarios, que viene con la aplicación predeterminada Laravel. Para ello, agregamos un nuevo campo para el número de teléfono:

// database/migrations/2014_10_12_000000_create_users_table.php

$table->string('phone_number')->unique();

A continuación, vamos a crear un modelo de pedido y su correspondiente archivo de migración:

$ php artisan make:model Order -m

Luego, actualizamos el archivo de migración como se indica a continuación:

// database/migrations/2019_11_14_123551_create_orders_table.php

Schema::create('orders', function (Blueprint $table) {
  $table->bigIncrements('id');
  $table->string('name');
  $table->integer('amount');
  $table->timestamps();
});

Para simplificar las cosas, la tabla de pedidos solo contiene los campos de ID, nombre, cantidad y marcas de fecha.

Antes de ejecutar la migración, asegurémonos de tener nuestra base de datos configurada. Para que las cosas sean simples y rápidas, usaremos SQLite para nuestra base de datos. Actualice el archivo .env como se indica a continuación:

// .env

DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

De manera predeterminada, Laravel buscará un archivo database.sqlite dentro del directorio de la base de datos. Para crearlo:

$ touch database/database.sqlite

Ahora, podemos ejecutar la migración:

$ php artisan migrate

Implementación de la realización de pedidos

Como dije antes, no vamos a crear un sistema de pedidos con todas las funciones. Solo implementaremos un pedido de muestra. Para ello, necesitamos crear una clase de fábrica para generar datos falsos al azar. Ejecute el siguiente comando:

$ php artisan make:factory OrderFactory

Esto creará un nuevo archivo OrderFactory.php dentro del directorio database/factories. Reemplace el contenido del archivo por el siguiente código:

// database/factories/OrderFactory.php

<?php

use App\Order;
use Faker\Generator as Faker;

$factory->define(Order::class, function (Faker $faker) {
    return [
        'name' => $faker->sentence,
        'amount' => $faker->numberBetween($min = 1000, $max = 9000),
    ];
});

A continuación, vamos a crear la UI para la realización del pedido. Lo agregaremos en home.blade.php inmediatamente debajo del texto “Inició sesión”:

// resources/views/home.blade.php

<form action="{{ route('order') }}" method="post">
    @csrf
    <button type="submit" class="btn btn-primary">Place Order</button>
</form>

Nada sofisticado. Solo un simple formulario con un botón que enviará a una ruta nombrada designada como pedido.

Botón para realizar pedidos en Laravel

A continuación, debemos crear la ruta:

// routes/web.php

Route::post('/order', 'OrderController@store')->name('order')->middleware('auth');

Por último, creamos los puntos de ruta Controlador del pedido para:

$ php artisan make:controller OrderController

Luego, agregamos el siguiente código:

// app/Http/Controllers/OrderController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class OrderController extends Controller
{
  public function store(Request $request)
  {
    $order = factory(\App\Order::class)->create();


    return redirect()->route('home')->with('status', 'Order Placed!');
  }
}

Aquí estamos utilizando la fábrica que creamos antes para generar un nuevo pedido después del envío. Luego, volvemos a la página con un mensaje de estado exitoso.

Configuración del sandbox de Twilio para WhatsApp

Para enviar mensajes con WhatsApp durante la producción, tenemos que esperar a que nuestra cuenta se apruebe formalmente mediante WhatsApp. Pero eso no significa que debemos esperar para empezar a crear. Con sandbox de Twilio para WhatsApp podemos probar nuestra app en un entorno de desarrollador. Para usar el sandbox, primero debemos establecer una conexión mediante el envío de un mensaje de WhatsApp desde nuestro dispositivo a un número que nos otorgarán. Para comenzar, siga las instrucciones en la pestaña Learn (Aprender). Una vez que su cuenta esté conectada, podrá enviar cualquier mensaje.

Consola de Twilio en WhatsApp

Una vez que se configura el sandbox, recopile sus credenciales de Twilio. Las utilizaremos para configurar el acceso a SDK de PHP de Twilio. Vaya a su panel de control de Twilio y copie el SID DE SU CUENTA y el TOKEN DE AUTENTICACIÓN. Anote el número de teléfono que está asignado a su sandbox, ya que es el número desde el que enviará las notificaciones.

A continuación, vamos a crear variables de entorno para guardar estos detalles en .env:

// .env

TWILIO_AUTH_SID=YOUR_TWILIO_AUTH_SID
TWILIO_AUTH_TOKEN=YOUR_TWILIO_AUTH_TOKEN
TWILIO_WHATSAPP_FROM=YOUR_TWILIO_WHATSAPP_FROM

Cree una configuración de servicio dedicada para Twilio. Agregue el siguiente código en config/services.php:

// config/services.php

'twilio' => [
  'sid' => env('TWILIO_AUTH_SID'),
  'token' => env('TWILIO_AUTH_TOKEN'),
  'whatsapp_from' => env('TWILIO_WHATSAPP_FROM')
],

Descripción general del envío de notificaciones con la API de Twilio para WhatsApp

Antes de profundizar en el envío de notificaciones con la API de Twilio para WhatsApp, tomémonos un momento para entender cómo funciona. Existen dos tipos de mensajes que se pueden enviar mediante la API de Twilio para WhatsApp: mensajería unidireccional y bidireccional. El envío de notificaciones se clasifica como mensaje unidireccional y el envío de mensajes conversacionales como mensaje bidireccional. Para poder enviar mensajes de notificación, debemos utilizar las plantillas de mensaje de WhatsApp.

Una plantilla de mensaje de WhatsApp es un formato de mensaje que se puede volver a utilizar para enviar mensajes a los usuarios una vez que hayan aceptado y otorgado permiso a la aplicación para enviarles mensajes. Los mensajes de plantilla se utilizan para ayudar a mantener contenido de alta calidad y evitar el spam en el ecosistema.

Los mensajes de plantilla utilizan valores de marcadores de posición que se pueden reemplazar por contenido dinámico cuando se envía el mensaje. De forma predeterminada, el sandbox de Twilio para WhatsApp incluye tres plantillas preconfiguradas:

  • Su código {{1}} es {{2}}
  • Su cita {{1}} es el {{2}}
  • Su pedido {{1}} de {{2}} se envió y debería ser entregado el {{3}}. Detalles: {{4}}

A efectos de este tutorial, utilizaremos la tercera plantilla. Para obtener más información sobre plantillas y cómo crear la suya, consulte estos documentos.

Creación de un canal de notificación personalizado

Tal como está, nuestros usuarios pueden realizar un pedido. Ahora, tenemos que enviarles una notificación para hacerles saber que su pedido se ha procesado. Como queremos enviar esta notificación a través de WhatsApp, tenemos que crear un canal de notificación personalizado en Laravel. Para ello, necesitaremos dos archivos: WhatsAppChannel.php y WhatsAppMessage.php. El primero contendrá la implementación para enviar un mensaje (notificación), mientras que el segundo contendrá la API para redactar un mensaje.

Comencemos por crear un nuevo directorio llamado Channels en nuestra carpeta app. Dentro de ella, crearemos otro directorio llamado Messages. Dentro de él, crearemos WhatsAppMessage.php y pegaremos el siguiente código:

// app/Channels/Messages/WhatsAppMessage.php

<?php


namespace App\Channels\Messages;

class WhatsAppMessage
{
  public $content;
  
  public function content($content)
  {
    $this->content = $content;

    return $this;
  }
}

Esta es una clase simple que contiene propiedad del $content y un fijador (método de contenido) para establecer el valor de la propiedad del contenido. Todos los datos que se pasen por el método serán parte del contenido de la notificación que enviaremos.

A continuación, creamos el archivo WhatsAppChannel.php directamente dentro del directorio Channels y pegamos el siguiente código:

// app/Channels/WhatsAppChannel.php

<?php
namespace App\Channels;

use Illuminate\Notifications\Notification;
use Twilio\Rest\Client;

class WhatsAppChannel
{
    public function send($notifiable, Notification $notification)
    {
        $message = $notification->toWhatsApp($notifiable);


        $to = $notifiable->routeNotificationFor('WhatsApp');
        $from = config('services.twilio.whatsapp_from');


        $twilio = new Client(config('services.twilio.sid'), config('services.twilio.token'));


        return $twilio->messages->create('whatsapp:' . $to, [
            "from" => 'whatsapp:' . $from,
            "body" => $message->content
        ]);
    }
}

Cada clase de canal de notificación debe tener un método send() que contendrá la implementación real para enviar la notificación. Debe aceptar dos argumentos: un $notifiable y un $notification. El primero es una característica que cualquier modelo que envía notificaciones debe tener, mientras que el segundo es una instancia de la notificación real (que crearemos en breve).

Mediante el ejemplo de notificación, usamos el método ToWhatsApp() (que crearemos más tarde) y lo pasamos a $notifiable. Aquí, el $message será una instancia del mensaje de WhatsApp y contendrá la notificación que queremos enviar.

Para obtener el número de teléfono del usuario al que queremos enviar la notificación, usamos el método routeNotificationFor() en la característica $notification. Exhaustivamente, Laravel buscará el método routeNotificationForWhatsApp() en el modelo utilizando la característica.

Por último, creamos una nueva instancia de SDK de PHP de Twilio que utilizaremos para enviar la notificación. Tenga en cuenta que debemos prefijar los números de teléfono (hacia y desde) en WhatsApp.

Como estamos usando el SDK de PHP de Twilio, debemos asegurarnos de que esté instalado:

$ composer require twilio/sdk

¿Recuerda que dije que tenemos que tener el método routeNotificationForWhatsApp() en el modelo utilizando las características notificables? En nuestro caso, ese es el modelo de usuario:

// app/User.php

public function routeNotificationForWhatsApp()
{
  return $this->phone_number;
}

Solo devolvimos el campo de número de teléfono, ya que es el campo que contiene los números de teléfono de nuestros usuarios.

Ahora podemos crear una notificación que utilizará nuestro canal de notificación personalizado:

$ php artisan make:notification OrderProcessed

Esto creará un nuevo archivo OrderProcessed.php dentro de app/Notifications. Ábralo y reemplace el contenido con lo siguiente:

// app/Notifications/OrderProcessed.php

<?php

namespace App\Notifications;

use App\Channels\Messages\WhatsAppMessage;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use App\Channels\WhatsAppChannel;
use App\Order;


class OrderProcessed extends Notification
{
  use Queueable;


  public $order;
  
  public function __construct(Order $order)
  {
    $this->order = $order;
  }
  
  public function via($notifiable)
  {
    return [WhatsAppChannel::class];
  }
  
  public function toWhatsApp($notifiable)
  {
    $orderUrl = url("/orders/{$this->order->id}");
    $company = 'Acme';
    $deliveryDate = $this->order->created_at->addDays(4)->toFormattedDateString();


    return (new WhatsAppMessage)
        ->content("Your {$company} order of {$this->order->name} has shipped and should be delivered on {$deliveryDate}. Details: {$orderUrl}");
  }
}

Dentro del método via(), le estamos comunicando a Laravel que queremos usar nuestro canal personalizado. En el método toWhatsApp() redactaremos el mensaje para enviarlo. Creamos y devolvemos una nueva instancia del mensaje de WhatsApp mientras establecemos el contenido de la notificación usando el método content(). Tenga en cuenta que utilizamos la plantilla de mensaje de WhatsApp que mencionamos anteriormente.

Por último, actualicemos el método de OrderController.php para incluir el código que envía la notificación:

// app/Http/Controllers/OrderController.php

// add this at the top of the class
use App\Notifications\OrderProcessed;


public function store(Request $request)
{
  $order = factory(\App\Order::class)->create();


  $request->user()->notify(new OrderProcessed($order));


  return redirect()->route('home')->with('status', 'Order Placed!');
}

Probar nuestra aplicación

Probemos lo que hemos estado construyendo hasta ahora. En primer lugar, asegurémonos de que nuestra aplicación se esté ejecutando:

$ php artisan serve

Cree una cuenta con el mismo número de teléfono que agregó al sandbox. Cuando haga clic en el botón “Place Order” (Realizar pedido), aparecerá un mensaje similar al que se muestra.

Notificación de pedido de WhatsApp

Conclusión

En este tutorial aprendió cómo enviar notificaciones en la aplicación Laravel a través de WhatsApp. No se limita a enviar solo notificaciones, ya que puede enviar mensajes conversacionales con la API de Twilio para WhatsApp.

Puede encontrar la fuente completa de este tutorial en GitHub.

Este artículo fue traducido del original "How to Create a Laravel Notification Channel for WhatsApp with Twilio". Mientras estamos en nuestros procesos de traducción, nos encantaría recibir sus comentarios en help@twilio.com - las contribuciones valiosas pueden generar regalos de Twilio.