Laravel & Vue: Notificaciones en Tiempo Real usando Reverb, Redis y TDD - 02
José Rafael Gutierrez
hace 4 semanas
Capítulo 2: Creación de Canales de Notificaciones con Reverb en Laravel
Objetivo
Implementar canales de notificación seguros y personalizados en Laravel usando Reverb, comenzando con pruebas que fallan y siguiendo el ciclo TDD de rojo → verde → refactor. Esto incluye:
1. Crear canales para transmitir notificaciones a usuarios individuales o administradores.
2. Asegurar los canales con permisos y restricciones.
3. Validar el funcionamiento mediante pruebas guiadas por errores y soluciones.
Introducción
Este capítulo utiliza TDD para implementar canales de notificaciones personalizados en Laravel con Reverb. Primero escribiremos pruebas que fallarán para identificar lo que falta en la aplicación y, a partir de esos errores, desarrollaremos el código necesario.
Nos enfocaremos en dos tipos de canales:
- Canales privados para usuarios.
- Un canal global para administradores.
Por ahora, usaremos el modelo User
con el atributo is_admin
para simplificar la diferenciación de roles.
Ciclo TDD, para Canales de Usuarios
Escribir Pruebas para Canales Privados de Usuario
Crea un archivo de prueba:
sail artisan make:test UserNotificationChannelTest
Modifica tests/Feature/UserNotificationChannelTest.php
:
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserNotificationChannelTest extends TestCase
{
use RefreshDatabase;
public function test_user_can_access_own_notification_channel()
{
// Given
$user = User::factory()->create();
// When
$response = $this->actingAs($user)->post('/broadcasting/auth', [
'channel_name' => 'private-user-notifications.' . $user->id,
'socket_id' => '12345.67890', // valid socket_id format
], ['X-CSRF-TOKEN' => csrf_token()]);
// Then
$response->assertStatus(200);
}
public function test_user_cannot_access_other_users_notification_channel()
{
// Given
$user = User::factory()->create();
$otherUser = User::factory()->create();
// When
$response = $this->actingAs($user)->post('/broadcasting/auth', [
'channel_name' => 'private-user-notifications.' . $otherUser->id,
'socket_id' => '12345.67890', // valid socket_id format
], ['X-CSRF-TOKEN' => csrf_token()]);
// Then
$response->assertStatus(403);
}
}
Nota: El
socket_id
es un identificador único generado por el cliente (normalmente al establecer una conexión websocket) y debe seguir un formato específico esperado por Pusher. Unsocket_id
válido debe estar en el formato dedigits.dot.digits
como1234.5678
. Al usar Pusher durante los tests, es esencial proporcionar unsocket_id
válido para evitar errores y permitir la correcta autorización de los canales.
Ejecutar las Pruebas Iniciales (Rojo)
Ejecuta los tests:
sail artisan test --filter=UserNotificationChannelTest
Errores esperados:
-
Error 404: La ruta
/broadcasting/auth
no está definida.
Análisis del error: El error 404 indica que falta la ruta para la autenticación de canales. Este error nos guía a implementar la configuración básica de broadcasting.
Configurar la Autenticación de Canales
1. Crear el Proveedor de servicios Broadcast
sail artisan make:provider BroadcastServiceProvider
2. Habilitar el BroadcastServiceProvider
:
Asegúrate de que el servicio esté registrado en bootstrap/providers.php
:
<?php
return [
App\Providers\AppServiceProvider::class,
//...
App\Providers\BroadcastServiceProvider::class,
];
3. Definir la Ruta de Broadcasting:
Modifica el método boot
del BroadcastServiceProvider
:
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Foundation\Support\Providers\BroadcastServiceProvider as ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
public function boot()
{
Broadcast::routes(); // Registra la ruta '/broadcasting/auth'
require base_path('routes/channels.php'); // Define los canales
}
}
4. Limpiar la caché:
Después de modificar los archivos de configuración, es importante limpiar la caché de Laravel para aplicar los cambios:
sail artisan config:clear
5. Ejecutar el Servidor de Reverb:
Inicia el servidor:
sail artisan reverb:start --host="0.0.0.0" --port=8080 --hostname="localhost"
Ejecutar pruebas para Canales Privados de Usuario (Rojo)
Corre los tests nuevamente. Ahora fallarán con un error 403, porque los canales no están definidos aún:
sail artisan test --filter=UserNotificationChannelTest
Implementar los Canales Privados (Verde)
Define los canales en routes/channels.php
:
Broadcast::channel('user-notifications.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
Corre los tests nuevamente. Ambos deberían pasar:
sail artisan test --filter=UserNotificationChannelTest
Refactorización
Revisa la organización de las rutas y el código del canal. Si más canales se agregan en el futuro, podrías crear un archivo dedicado para ellos.
Repetir el Ciclo TDD, para Canales de Administradores
Escribir Pruebas para el Canal de Administradores
Crea un archivo de prueba:
sail artisan make:test AdminNotificationChannelTest
Modifica tests/Feature/AdminNotificationChannelTest.php
:
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AdminNotificationChannelTest extends TestCase
{
use RefreshDatabase;
public function test_admin_can_access_admin_notification_channel()
{
// Given
$admin = User::factory()->state(['is_admin' => true])->create();
// When
$response = $this->actingAs($admin)->post('/broadcasting/auth', [
'channel_name' => 'admin-notifications',
'socket_id' => '12345.67890', // valid socket_id format
], ['X-CSRF-TOKEN' => csrf_token()]);
// Then
$response->assertStatus(200);
}
public function test_regular_user_cannot_access_admin_notification_channel()
{
// Given
$user = User::factory()->state(['is_admin' => false])->create();
// When
$response = $this->actingAs($user)->post('/broadcasting/auth', [
'channel_name' => 'admin-notifications',
'socket_id' => '12345.67890', // valid socket_id format
], ['X-CSRF-TOKEN' => csrf_token()]);
// Then
$response->assertStatus(403);
}
}
Ejecutar las Pruebas para Administradores (Rojo)
Ejecuta los tests. Ambos fallarán, ya que el canal de administradores no está definido.
sail artisan test --filter=AdminNotificationChannelTest
Implementar el Canal de Administradores
Agrega el canal en routes/channels.php
:
Broadcast::channel('admin-notifications', function ($user) {
return $user->is_admin;
});
Ejecutar las Pruebas para Administradores (Rojo)
Ejecuta los tests. Ambos fallarán, ya que el atributo is_admin
no existe en el modelo User
.
sail artisan test --filter=AdminNotificationChannelTest
Añade el atributo faltante al modelo User
1. Crear la Migración
Ejecuta el siguiente comando para crear una nueva migración:
sail artisan make:migration add_is_admin_to_users_table --table=users
2. Modificar la Migración
Abre la migración creada en database/migrations/
y añade el campo is_admin
:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('is_admin')->default(false); // Añadir campo is_admin
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('is_admin'); // Eliminar campo is_admin
});
}
};
3. Actualizar el Modelo User
Ahora, actualiza el modelo User
(app/Models/User.php
) para que is_admin
sea tratado como un booleano:
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
'is_admin' => 'boolean',
];
4. Ejecutar la Migración
Ejecuta la migración para aplicar los cambios en la base de datos:
sail artisan migrate
Ejecutar las Pruebas para Administradores (Verde)
sail artisan test --filter=AdminNotificationChannelTest
Ahora corre este comando y verás como todos los tests pasan:
sail artisan test
Refactorizar (Si es Necesario)
Revisa el archivo routes/channels.php
. Si los canales crecen, considera agruparlos en un archivo dedicado para mejorar la organización.
Conclusión
En este capítulo, implementamos canales seguros para usuarios y administradores siguiendo el ciclo TDD. Los errores 404 y 403 nos guiaron a desarrollar las rutas y los permisos necesarios para cada canal.
El próximo capítulo, configuraremos Redis para almacenar y administrar notificaciones, optimizando el rendimiento y gestionando mensajes no leídos. 🚀