https://a.storyblok.com/f/270183/1368x665/130eed24e1/25oct_dev_blog_laravel-liveware-reverb-echo.jpg

RCS-Nachrichtenübermittlung mit Laravel, Livewire, Reverb und Echo

Zuletzt aktualisiert am October 21, 2025

Lesedauer: 13 Minuten

Abstract graphic depecting messaging on a phoneTime to get our hands dirty with RCS and Laravel!TLDR; Sie finden den den Demo-Code hier.

Laravel Livewire ist eine leistungsstarke Möglichkeit, die Komplexität des Frontends zu reduzieren. In diesem Tutorial werden wir es verwenden, um einen RCS (Rich Communication Services) Messenger mit Vonage Messages APIIch kann nicht glauben, dass es so lange gedauert hat, bis ich meine Hände an Laravel Livewirein die Hände zu bekommen, wenn man bedenkt, dass die Version 1.0.0 bereits im Jahr 2020 veröffentlicht wurde. Livewire ist inspiriert von der Ruby on Rails Bibliothek Hotwire und tut etwas, das mir wirklich am Herzen liegt: Es nimmt komplexen Frontend-Code heraus. Als Teil dessen, was unter dem Namen TALL Stacks bekannt geworden ist, wird sie sicherlich sehr häufig eingesetzt.

RCS steht für Reichhaltige Kommunikationsdiensteund ist ein modernes und fortschrittlicheres Nachrichtenprotokoll als der De-facto-Standard SMS. SMS wurde mit dem Aufkommen von MMS (Multimedia Messaging) verbessert, war aber auch deutlich langsamer, da letzteres immer noch auf das GSMA-Netz angewiesen war. RCS verwendet ausschließlich Daten, so dass es keine Rolle spielt, ob Sie Wi-Fi oder 4/5G verwenden: In unserer hypervernetzten Welt der Dateninfrastruktur bedeutet dies, dass Ihre Nachrichten jetzt deutlich schneller sind. Außerdem ist RCS in denselben Messaging-Applikationen auf Mobilfunkgeräten implementiert wie die native SMS, so dass RCS auf den meisten Geräten, die in den letzten 5 Jahren hergestellt wurden, einsatzbereit ist.

Gibt es einen besseren Anwendungsfall, um mit Livewire etwas in Echtzeit zu tun, als RCS in eine Messaging-Webanwendung zu implementieren? Genau das werden wir in diesem Tutorial tun.

Voraussetzungen

  • PHP 8.4+

  • Laravel-Installateur

  • Knoten 22+

  • Npm 6+

  • Ein Vonage Account

  • ngrok

Vonage API-Konto

Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.

Laravel installieren

Das Laravel-Installationsprogramm ist ein ordentlicher Wrapper um Composer den Sie global installieren können, um neue Laravel-Applikationen bequem zu starten. Wählen Sie bei der Installation das Livewire-Starterkit, die integrierte Authentifizierung von Laravel, Volt kann übersprungen werden, und die Wahl des Test-Frameworks spielt keine Rolle. Sie haben nun eine vollständige Laravel-Anwendung installiert. Stellen Sie sicher, dass Sie die integrierten Migrationen ausführen, um die Users-Tabelle für die Authentifizierung einzurüsten.

Livewire installieren

Caleb Porzio brachte Livewire im Jahr 2020 auf den Markt und erregte damals großes Aufsehen. Ich habe bereits gesagt, dass es die Komplexität des Frontends beseitigt, aber was genau ist es? Vielleicht geht es Ihnen, lieber Leser, wie mir. Ich bin ein Backend-Entwickler, der sich bei den einfachsten Frontend-Aufgaben ständig am Kopf kratzt. Livewire liefert PHP-Frontend-Komponenten so aus, als wären sie JavaScript-Komponenten. Daher erfolgt die Handhabung von Status und Verhalten innerhalb des PHP-Codes, den Sie kennen und lieben, mit einer gut dokumentierten API zum Erforschen. Um Livewire zu installieren, verwenden Sie Composer:

composer install livewire/livewire

Migrationen und Modelle erstellen

Es gibt zwei Entitäten für die Nachrichtenübermittlung, die wir benötigen: a Message und a Conversation. Die Beziehung hier ist, dass Messages gehören zu einer Konversation und eine Konversation gehört zu einem Benutzer. Dies ist eine wichtige Beziehung, die es zu beachten und zu etablieren gilt, da das Frontend bei der Übertragung von Ereignissen (z. B. eingehende Nachrichten) in der Lage sein muss, diese mit einem Benutzer zu verknüpfen.

Erstellen Sie Ihre Migrationen in der Befehlszeile:

php artisan make:model Conversation --migration
php artisan make:model Message --migration

Beachten Sie, dass wir, da wir das Modell und nicht die Migration erstellen, die Einzahl und nicht die Mehrzahl verwenden. Die Migration wurde erzeugt durch Hinzufügen von --Migration an den Befehl angehängt, so dass wir nun festlegen können, wie diese Entitäten in der Datenbank aussehen.

create_conversations_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
   /**
    * Run the migrations.
    */

   public function up(): void
   {
       Schema::create('conversations', function (Blueprint $table) {
           $table->id();
           $table->string('uuid');
           $table->foreignId('user_id')->constrained('users');
       });
   }

   /**
    * Reverse the migrations.
    */

   public function down(): void
   {
       Schema::dropIfExists('conversations');
   }
};

create_messages_migration.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
   /**
    * Run the migrations.
    */

   public function up(): void
   {
       Schema::create('messages', function (Blueprint $table) {
           $table->id();
           $table->string('message');
           $table->timestamps();
           $table->foreignId('conversation_id')->constrained();
           $table->string('source');
       });
   }

   /**
    * Reverse the migrations.
    */
   public function down(): void
   {
       Schema::dropIfExists('messages');
   }
};

Wichtig ist, dass Sie sehen können, dass es ein source Feld gibt, das nur zwei Werte haben wird:

  • internal

  • external

Dies ist wichtig, damit das Frontend eine konversationsähnliche Ansicht korrekt darstellen kann.

Wir haben auch die notwendigen Beziehungen hinzugefügt, so dass wir jetzt die Beziehungen in den Modellen definieren:

Models\Conversation.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Conversation extends Model
{
   public $timestamps = false;

   public function messages(): HasMany
   {
       return $this->hasMany(Message::class);

   }

   public function user() 
  {
       return $this->belongsTo(User::class);
   }
}

Models\Messages.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;

class Message extends Model

{
   use BroadcastsEvents;

   public $timestamps = true;
   public $table = 'messages';
   public $fillable = ['message', 'conversation_id', 'created_at', 'updated_at'];

   public function conversation()
   {
       return $this->belongsTo(Conversation::class);
   }

Seeding Ihrer Datenbank

Es gibt zwei Dinge, die wir säen müssen:

  • Ein Testbenutzer (anstatt sich über die Benutzeroberfläche zu registrieren)

  • Eine Platzhalter-Konversation, an die die Nachrichten angehängt werden. In der Realität würden Sie diese Konversationen dynamisch erstellen wollen, aber für die Zwecke dieses Tutorials wird jede Nachricht an einen Platzhalter gebunden sein.

Erzeugen Sie die MessagesSeeder in der Befehlszeile:

php artisan make:seeder MessagesSeeder

Jetzt wird der Seeder beide Platzhalter, die wir benötigen, verarbeiten:

MessagesSeeder.php

<?php

namespace Database\Seeders;

use App\Models\Conversation;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class MessagesSeeder extends Seeder
{
   /**
    * Run the database seeds.
    */
   public function run(): void
   {
       $user = User::create([
           'name' => 'Admin',
           'email' => 'admin@admin.com',
           'password' => Hash::make('password'),
       ]);

       $conversation = Conversation::create([
           'uuid' => 'e2efbc00-b65e-4e47-8996-1de0043ed667',
           'user_id' => $user->id
       ]);
   }
}

Durch die Ausführung der Migrationen und Seeder wird nun alles in der Datenbank eingerichtet, bevor wir mit ihnen interagieren:

php artisan migrate
php artisan db:seed

Schreiben Sie den Controller

Nachdem wir unsere Daten eingerichtet haben, ist es nun an der Zeit, eine Route und einen Controller zu erstellen.

php artisan make:controller MessagesController

Im Moment wird der Controller nur eine Sache tun, nämlich eine Ansicht rendern.

<?php

namespace App\Http\Controllers;

use App\Models\Message;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class MessagesController extends Controller
{
   public function index()
   {
       return view('messages');
   }
}

Diese Ansicht, messages, gibt es noch nicht, also erstellen wir sie:

php artisan make:view messages

Und verschlüsseln Sie es:

<!DOCTYPE html>
<html lang="en">

<head>
   <title>Livewire Messenger</title>
   <link rel="preconnect" href="https://fonts.bunny.net">
   <link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
   @vite(['resources/css/app.css', 'resources/js/app.js'])
   @fluxAppearance
</head>

<body class="bg-gray-100 min-h-screen flex flex-col" style="background-image: url('{{ asset('vonage background.png') }}'); background-size: cover; background-position: center;">
   <div class="flex items-center space-x-3 p-4 bg-black">
       <img src="{{ asset('vonage-logo.png') }}" alt="Vonage Logo" class="h-16 px-4 w-auto">
       <h2 class="text-xl font-bold text-white drop-shadow">Laravel Livewire x Reverb x Echo Messenger</h2>
   </div>
</body>
</html>

Verbinden Sie schließlich alle diese Elemente in einer Route:

routes/web.php

Route::get('/messages', [MessagesController::class, 'index']);

Eine Livewire-Komponente schreiben

Es ist an der Zeit, einige Funktionen einzuführen. Anstelle des traditionellen Ansatzes eines Model-View-Controllers wird sich diese Anwendung auf die Funktionalität einer Livewire-Komponente stützen. Für PHP-Entwickler, Livewire-Komponenten wie ein normaler Controller mit einem eigenen gepaarten View-Template aussehen, aber die Zustandsänderungen werden an das Frontend weitergegeben. Erstellen Sie einen Livewire-Controller in der Kommandozeile:

php artisan livewire:make RcsComponent

Diese Livewire-Komponente wird in die message Ansicht. Diese Komponente lädt alle Nachrichten für die gesetzte Konversation und führt dann zwei Dinge aus:

  • Die Option zum Senden einer Nachricht, die mit Hilfe des PHP-SDK. Durch das Senden dieser Nachricht wird die Komponente neu geladen, indem die Nachrichten mithilfe der ORMLivewire überträgt den aktualisierten Zustand

  • Hört auf Änderungen in der Seeded Conversation und lädt sie, wenn ein Controller einen Webhook von Vonage erhält

Schreiben Sie die Komponentenvorlage

Livewire-Vorlagen befinden sich in einem anderen Verzeichnis als normale Blade Vorlagen. Navigieren Sie zur Vorlage der neuen Komponente und fügen Sie einige Stilelemente ein:

livewire/rcs-component.blade.php

<div class="flex-1 flex flex-col justify-between px-4">
   <div class="overflow-y-auto space-y-2 mb-4 px-2" style="max-height: calc(100vh - 200px);">
       @forelse ($messages as $message)
           <div class="flex {{ $message->source === 'internal' ? 'justify-end' : 'justify-start' }}">
               <div class="max-w-xs md:max-w-md px-4 py-2 rounded-lg
                   {{ $message->source === 'internal' ? 'bg-green-500 text-white rounded-br-none' : 'bg-white text-gray-800 rounded-bl-none shadow' }}">

                   <p>{{ $message->message }}</p>

                   <p class="text-xs text-gray-300 mt-1 text-right">
                       {{ $message->created_at->diffForHumans() }}
                   </p>
               </div>
           </div>
       @empty
           <p class="text-gray-100 text-center mt-4">No messages found.</p>
       @endforelse
   </div>

   <form wire:submit.prevent="sendMessage" class="flex items-center space-x-2 border-t pt-2 bg-white p-2 rounded shadow">
       <input
           type="text"
           wire:model.defer="postMessage"
           placeholder="Type a message"
           class="flex-1 border text-black rounded-full px-4 py-2 focus:outline-none focus:ring-2 focus:ring-offset-purple-500"
       >

       <button type="submit" class="bg-purple-500 text-white px-4 py-2 rounded-full hover:bg-purple-400">
           Send
       </button>
   </form>
</div>

Damit wird ein Nachrichten-Panel im Stil von "WhatsApp" erstellt. Die Komponente nimmt eine beliebige Sammlung, die als $messagesenthaltene Sammlung, gibt sie aus und enthält die Syntax für den Rückruf des PHP-Codes in der Livewire-Komponente, um eine Nachricht zu senden, indem sie die Methode sendMessage(). Wir haben das noch nicht kodiert, also gehen Sie zur Logik der Livewire-Komponente und kodieren Sie das Folgende:

Livewire\RcsComponent

<?php

namespace App\Livewire;

use App\Models\Conversation;
use App\Models\Message;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
use Vonage\Client;
use Vonage\Messages\Channel\RCS\RcsText;

class Rcs extends Component
{
   public $messages;
   public string $postMessage = '';

   public function mount()
   {
       $this->loadMessages();
   }

   public function loadMessages(): void
   {
       $conversation = Conversation::where('uuid', env('CONVERSATION_ID'))->first();

       $this->messages = Message::where('conversation_id', $conversation->id)->orderBy('timestamp', 'desc')->get();
   }

   public function sendMessage(): void
   {
       Http::withHeaders(['Accept' => 'application/json'])
           ->post(route('messages.store'), [
           'message' => $this->postMessage,
           'source' => 'internal'
       ]);

       $this->postMessage = '';
       $this->loadMessages();
   }

   public function render()
   {
       return view('livewire.rcs-component', $this->messages);
   }

   public function refresh()

   {
       $this->loadMessages();
   }
}

Hier gibt es eine ganze Menge zu entpacken, also gehen wir die Logik durch:

  • Die Eigenschaft class $postMessage fungiert als Zustand für die Komponente. Dieser Zustand ist die aktuelle Nachricht, die bearbeitet wird, und wenn Sie sich die Vorlage für die Komponente ansehen, können Sie sehen, dass es eine Syntax gibt, die das Frontend und das Backend verbindet: wire:model.defer="postMessage"

  • Die Klasseneigenschaft $messages fungiert ebenfalls als Status für die Komponente und ist die vollständige Sammlung von Nachrichten, die an die Konversation angehängt sind. Diese Eigenschaft wird dann in der Vorlage, die wir zuvor erstellt haben, wiedergegeben for $messages as $message)

  • Hier gibt es drei Livewire-spezifische magische Methoden: mount() wird ausgeführt, wenn die Komponente zum ersten Mal gerendert wird, refresh() wird ausgeführt, wenn sich der Zustand ändert, und render() wird am Ende des Lebenszyklus der Komponente ausgeführt, daher der Code zum Einziehen der Vorlage.

  • mount() ruft eine Methode auf, die wiederverwendet wird in render() mit dem Namen loadMessages()

  • loadMessages() verwendet den Eloquent ORM, um zwei Dinge zu tun. Erstens haben wir ein wenig mit dem Abrufen einer Conversationein wenig geschummelt, da es eine Umgebungsvariable verwendet, CONVERSATION_IDverwendet, die unsere gesetzte Conversation. Alle Nachrichten, die mit dieser ID verbunden sind, werden dann abgerufen und in die $messages Eigenschaft geschrieben.

Wir haben die Umgebungsvariable nicht hinzugefügt, also gehen Sie zu Ihrem .env und fügen Sie CONVERSATION_ID=e2efbc00-b65e-4e47-8996-1de0043ed667 hinzu. Diese ID ist die gleiche UUID, die in die Dummy-Konversation geschrieben wurde.

Da wir eine Mock-API schreiben, die im Wesentlichen zeigt, wie diese Entitäten funktionieren, ist es eine gute Praxis, Ihre Entitäten über REST zu veröffentlichen. Sie werden feststellen, dass die sendMessage Methode nicht den Eloquent ORM verwendet, um eine neue Nachricht zu erstellen und sie in der Datenbank zu halten; stattdessen nimmt sie den Inhalt von $postMessage und POSTet ihn an den exponierten internen API-Endpunkt. Dies erfordert einen Endpunkt, der noch nicht kodiert wurde, also gehen Sie zu Ihrer Routendatei und fügen Sie ihn hinzu:

routes\web.php

Route::post('/create-message', [MessagesController::class, 'store'])->name(messages.store');

Fügen Sie nun die store() Methode zu der MessagesController:

MessagesController.php

public function store(Request $request): JsonResponse
{
   $validated = $request->validate([
       'message' => 'required|string',
   ]);

   $conversation = Conversation::where('uuid', env('CONVERSATION_ID'))->first();

   $message = new Message();
   $message->message = $validated['message'];
   $message->created_at = now();
   $message->updated_at = now();
   $message->conversation_id = $conversation->id;
   $message->save();

   return response()->json([
       'status' => 'success',
       'data' => $message
   ], 201);
}

Die Eingabe wird validiert, dann wird in dieser Logik die Message Entität von der Datenbank persistiert und mit der Dummy-Entität Conversation Entität angehängt.

Livewire-Integration

Livewire benötigt einige Stile und JavaScript, die zu Ihren Anwendungsvorlagen hinzugefügt werden müssen, um zu funktionieren. Es gibt einige praktische Hilfsmethoden, die in Blade verwendet werden können. Wechseln Sie zur übergeordneten Vorlagenseite der Komponente, und ändern Sie den Code wie folgt:

<!DOCTYPE html>
<html lang="en">

<head>
   <title>Livewire Messenger</title>
   @livewireStyles
   <link rel="preconnect" href="https://fonts.bunny.net">
   <link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
   @vite(['resources/css/app.css', 'resources/js/app.js'])
   @fluxAppearance
</head>

<body class="bg-gray-100 min-h-screen flex flex-col" style="background-image: url('{{ asset('vonage background.png') }}'); background-size: cover; background-position: center;">
   <div class="flex items-center space-x-3 p-4 bg-black">
       <img src="{{ asset('vonage-logo.png') }}" alt="Vonage Logo" class="h-16 px-4 w-auto">
       <h2 class="text-xl font-bold text-white drop-shadow">Laravel Livewire x Reverb x Echo Messenger</h2>
   </div>
   <livewire:rcs />
   @livewireScripts
</body>
</html>

Die drei Ergänzungen hier sind:

  • @livewireStyles um wichtige CSS-Klassen einzubringen

  • @livewireScripts um wichtige JavaScript-Funktionen einzubringen

  • <livewire:rcs /> fügt unsere Livewire-Komponente in die Seite ein.

Schreiben Sie den Webhook-Controller

Als nächstes muss die App in der Lage sein, eingehende Daten von Vonage in Form eines Webhooks zu verarbeiten. Dieser Webhook wird im Vonage-Dashboard so konfiguriert, dass er an eine vom Benutzer definierte URL als JSON-Payload abgefeuert wird, wenn ein Benutzer auf die konfigurierte Nummer in der Konversation auf dem Endbenutzergerät antwortet. HTTP POST. Fügen Sie zunächst die Route hinzu:

routes\web.php

Route::post('/messages/webhook', [MessagesController::class, 'webhook'])->name(messages.webhook');

Jetzt fügen wir die webhook() Methode zu der MessagesController.

MessagesContoller.php

public function webhook(Request $request)
{
   $payload = $request->all();
 
   $newMessage = Message::create([
       'message' => $payload['text'],
       'source' => 'external',
       'conversation_id' => 1
   ]);

   return response()->json([
       'status' => 200
   ]);
}

Ursprünglich habe ich diese Logik geschrieben, um die REST-API wiederzuverwenden, aber es gab Sicherheitsimplikationen bei der Verwendung von zwei verschiedenen Domänen zur Laufzeit, also habe ich in diesem Beispiel geschummelt und Eloquent verwendet, um die Webhook-Nachricht in die Datenbank zu schreiben und eine 200 an Vonage zurückzugeben.

Wir haben jetzt alle internen Teile miteinander verdrahtet, aber es ist Ihnen wahrscheinlich nicht entgangen, dass wir noch keine tatsächlich noch nichts an Vonage senden. Dies muss in Ihrer sendMessage Methode in der Livewire-Komponente geschehen. Das Vonage PHP SDK benötigt eine Application ID und eine private.key, die im Vonage Dashboard erstellt wird, und eine Nummer, die der Anwendung zugewiesen werden muss.

  • Um eine Anwendung zu erstellen, gehen Sie auf die Seite Erstellen einer Anwendung auf dem Vonage Dashboard und legen Sie einen Namen für Ihre Anwendung fest.

  • Wenn Sie eine API verwenden möchten, die Webhooks nutzt, benötigen Sie einen privaten Schlüssel. Klicken Sie auf "Generate public and private key", der Download sollte automatisch starten. Bewahren Sie ihn sicher auf; dieser Schlüssel kann bei Verlust nicht erneut heruntergeladen werden. Er folgt der Namenskonvention privat_<Ihre App-ID>.key. Dieser Schlüssel kann nun zur Authentifizierung von API-Aufrufen verwendet werden. Hinweis: Ihr Schlüssel funktioniert erst, wenn Ihre Anwendung gespeichert ist.

  • Wählen Sie die benötigten Funktionen (z. B. Voice, Nachrichten, RTC usw.) und stellen Sie die erforderlichen Webhooks bereit (z. B. Ereignis-URLs, Antwort-URLs oder URLs für eingehende Nachrichten). Diese werden im Lernprogramm beschrieben.

  • Zum Speichern und Bereitstellen klicken Sie auf "Neue Anwendung generieren", um die Einrichtung abzuschließen. Ihre Anwendung ist nun bereit für die Verwendung mit Vonage-APIs.

RCS erfordert eine Registrierung als Agent, bevor Sie es nutzen können. Informationen dazu finden Sie in diesem Artikel, finden Sie in diesem Artikel.

Ihre Anwendung muss dem Internet zugänglich gemacht werden, damit Vonage Webhooks an sie senden kann. Wir tun dies mit ngrok. Wenn Sie ngrok installiert haben, starten Sie es in der Kommandozeile:

ngrok http 8080

Sie erhalten eine öffentlich zugängliche URL, die auf Ihren Port 8080 verweist. Diese URL muss in das Vonage Dashboard für Ihre RCS-Anwendung eingegeben werden, etwa so:

Screenshot showing the Vonage Application dashboard where webhook fields are configuredConfiguring our webhooks

Konfigurieren Sie Vonage in PHP

Die sendMessage() sendet derzeit noch keine Nachricht, also ist es an der Zeit, dies zu konfigurieren. Installieren Sie das Vonage PHP SDK mit Composer auf der Kommandozeile:

composer require vonage/client

Mit den Anmeldedaten für unseren Vonage Account und dem private.key die wir aus dem Dashboard heruntergeladen haben, richten wir unser Client-Objekt ein und verwenden es zum Senden der RCS-Nachricht. Ihre sendMessage() sollte wie folgt aussehen:

public function sendMessage(): void
{
   $applicationId = 'your-application-id';

   $privateKey = file_get_contents(base_path(config('path-to-your-private-key')));

   $credentials = new Client\Credentials\Keypair($privateKey, $applicationId);

   $client = new Client($credentials);

   $rcsMessage = new RcsText('your-vonage-number, 'your-configured-from-id, $this->postMessage);

   $client->messages()->send($rcsMessage);

   Http::withHeaders(['Accept' => 'application/json'])
       ->post(route('messages.store'), [
       'message' => $this->postMessage,
       'source' => 'internal'
   ]);

   $this->postMessage = '';
   $this->loadMessages();
}

Die Client wird mit einer Keypairerstellt, die ihn so konfiguriert, dass er automatisch die JWT-Authentifizierung für alle Vonage-Anrufe durchführt. Sie ruft dann die Messages API mit der verketteten messages() Methode auf und verwendet send(). Diese Methode, als Teil der Messages API-Integration, nimmt jedes gültige Objekt, das intern mit den Message Interfaces konform ist. Das Objekt zum Senden einer RCS-Nachricht ist RcsText.

Es gibt einige Umgebungsvariablen, die Sie hier eingeben müssen - wir haben uns bereits Ihre Anmeldedaten angesehen, aber RCS benötigt auch die "to"- und "from"-Nummern. Die "to"-Nummer ist Ihr Zielgerät und die "from"-Nummer ist der Schlüssel, der mit Ihrem RCS-Agenten konfiguriert ist.

Jetzt ist es Zeit für die Magie. Die Einschränkung hier ist, dass mit Livewire die Komponente aktualisiert wird, wenn Sie eine Nachricht senden (da sie die Livewire-Funktion refresh(), die dann den Befehl loadMessages() ABER, woher weiß die Livewire-Komponente von einem eingehenden Webhook, der dann den Status aktualisieren sollte?

Die Antwort kommt in Form des super-glänzenden Modell-Übertragung Funktionalität. Übersetzt ins Englische gibt Ihnen Laravel die Möglichkeit, das bestehende Event-System anzuzapfen, wenn ein Modell geändert wird. Das bedeutet, dass jedes Mal, wenn ein Message erstellt wird (d.h. wenn ein Webhook eingeht und in die Datenbank geschrieben wird), können wir einen WebSocket-Server verwenden, um zuzuhören und Livewire zu sagen refresh().

Hierfür müssen wir zwei Bibliotheken installieren: Laravel Reverb (der Broadcasting-Websocket-Server) und Laravel Echo (clientseitige Bibliothek zum Abhören von Ereignissen). Reverb wird über die Laravel-Konsole installiert:

php artisan install:broadcasting

Echo wird mit npm installiert:

npm install --save-dev laravel-echo pusher-js

pusher-js ist das Protokoll, das Echo unter der Haube verwendet, weshalb es in dem Befehl enthalten ist.

Echo einbinden

Die Wurzel des JavaScript Ihrer Anwendung muss über eine konfigurierte Echo Klasse bereithalten, um zu hören, was Reverb sendet. Gehen Sie zu resources\js und erstellen Sie eine neue Datei namens echo.js. Füllen Sie sie wie folgt aus:

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

let echo = new Echo({
   broadcaster: 'reverb',
   key: import.meta.env.VITE_REVERB_APP_KEY,
   wsHost: import.meta.env.VITE_REVERB_HOST,
   wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
   wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
   forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
   enabledTransports: ['ws', 'wss'],
});

echo.privateApp.Models.Conversation.1)
   .listen('.MessageCreated', (e) => {
       console.log(e);
   });

window.Echo = echo;

Hier wird ein zu hörender Kanal angegeben: App.Models.Conversation.1 ist fest einkodiert. Da wir nur ein gesetztes Objekt haben Conversation Objekt haben, wird es in diesem Fall immer dieses sein. Die Namenskonvention für den Kanal stammt aus unserer kanal.php die noch nicht geschrieben wurde, was in Kürze geschehen wird, aber es ist interessant zu sehen, dass .MessageCreated eine Namenskonvention von Laravel's eingebautem Model Broadcasting ist.

echo.private wird verwendet, weil Model Broadcasting-Ereignisse nur von privaten Kanälen ausgesendet werden können. Eine Sache, auf die man wirklich achten sollte (und die ich ursprünglich nicht beachtet habe, was 2 Stunden Debugging bedeutete) ist, dass es sich nur um private Kanäle handeln kann, weil Model Broadcasting ist an den Auth-Mechanismus von Laravel gebunden. Also, für diese zu arbeiten, müssen Sie als der Seeded-Benutzer eingeloggt werden wir erstellt.

Die echo.js muss an der Stelle des Bootstraps der App eingebunden werden, also fügen Sie sie in die resources\js\app.js Datei ein:

/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allow your team to quickly build robust real-time web applications.
*/

import './echo';

Integration von Reverb

Wir haben etwas, das auf die Ereignisse hört, aber wir haben die Übertragung noch nicht kodiert. Dazu gibt es drei Teile:

  • Einrichten der Sendekanalroute

  • Hinzufügen der Sendung zum Modell

  • Livewire so konfigurieren, dass es auf aufgetauchte Ereignisse reagiert

Einrichten des Übertragungskanals

Bei der Installation von Reverb wird die neue Routendatei für Kanäle wie folgt erstellt routes\channels.php. Hier teilen wir Reverb mit, dass es senden soll.

channels.php

Broadcast::channel('App.Models.Conversation.{id}', function ($user, $id) {
   return $user->conversations->firstOrFail('id', $id)->exists;
});

Die Methode channel Methode erwartet einen Booleschen Wert, der angibt, ob die Konversations-ID für den Benutzer als Authentifizierungsgatter verfügbar ist.

Hinzufügen von Broadcasting zum Modell

Es gibt zwei Dinge, die Sie dem Modell hinzufügen müssen - das Modell ist in diesem Fall die Message Entität. Reverb hat einen Trait namens BroadcastEvents die die Schnittstelle für die Verwendung von WebSocket öffnet. Sie müssen dies in den Code einfügen, wodurch die broadcastOn Methode zum Überladen öffnet.

Der Code des Endmodells sieht wie folgt aus:

<?php

namespace App\Models;
use Illuminate\Database\Eloquent\BroadcastsEvents;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;

class Message extends Model
{
   use BroadcastsEvents;

   public $timestamps = true;
   public $table = 'messages';
   public $fillable = ['message', 'conversation_id', 'created_at', 'updated_at'];

   public function conversation()
   {
       return $this->belongsTo(Conversation::class);
   }

   public function broadcastOn(string $event)
   {
       return [$this->conversation];
   }
}

Bevor wir uns mit der Logik hinter broadcastOn()kommen, werden Sie feststellen, dass mehrere Felder in $fillable. Diese Eigenschaft gibt an, welche Felder des Modells mit der Hydrierung automatisch befüllt werden können, sodass diese Felder aufgrund der Webhook-Hydrierung in das Array aufgenommen wurden.

Aufgrund von Model Broadcasting wäre die eingebaute Kanaladresse dieses Modells App.Model.Conversationsein, so dass die Rückgabe eines Wertes von $this->conversation zurückgegeben wird, ergibt sich der erforderliche Broadcast String Identifier von App.Model.Conversation.{id}. BroadcastEvents sendet die CRUD-Aktionen auf diesem Modell, aber wir haben es angewiesen, auf der Conversation ID für das Abhören zu senden.

Alles zusammenbinden

OK, ich gebe es zu: Wir haben einen außerordentlichen Aufwand an Logik betrieben, um einfach nicht JavaScript zu machen. Aber ich habe kein Problem damit, denn ich bin der beste Entwickler der Welt. Außerdem liebe ich die Innovationen, die Frameworks wie Laravel vorantreiben.

Es gibt jetzt zwei Server, die Sie betreiben müssen: Vite muss laufen, um Frontend-Assets zu kompilieren, und Reverb muss laufen, um die Ereignisse zu senden, auf die Echo hört. Starten Sie diese in Ihrem Terminal:

php artisan reverb:start
npm run dev

Puh! Das ist eine Menge an Verkabelung. Aber das ist es wert, oder? Wenn alles hochgefahren ist, loggen Sie sich ein und beginnen Sie mit dem Versenden von Nachrichten!

Screenshot showing our complete messenger with some example messagesI absolutely did not use ChatGPT to sort out my styling

Haben Sie eine Frage oder möchten Sie uns mitteilen, was Sie gerade bauen?

Bleiben Sie auf dem Laufenden und halten Sie sich über die neuesten Nachrichten, Tipps und Veranstaltungen für Entwickler auf dem Laufenden.

Teilen Sie:

https://a.storyblok.com/f/270183/400x385/12b3020c69/james-seconde.png
James SecondeSenior PHP Entwickler Advocate

Als ausgebildeter Schauspieler mit einer Dissertation in Standup-Comedy bin ich über die Meetup-Szene zur PHP-Entwicklung gekommen. Man findet mich, wenn ich über Technik spreche oder schreibe, oder wenn ich seltsame Platten aus meiner Vinylsammlung spiele oder kaufe.