Bu dərslikdə biz istifadəçilər arasında təhlükəsiz və canlı mesajlaşmanı idarə etmək üçün Laravel, Nuxt 3, Sanctum və Laravel Reverb istifadə edərək real vaxt rejimində söhbət proqramı quracağıq. Biz istifadəçi autentifikasiyasını quracağıq, təhlükəsiz API-yə qoşulacağıq və hamar və cavab verən təcrübə üçün söhbətin dərhal yenilənməsini təmin edəcəyik.
Biz SPA autentifikasiyasını idarə etmək üçün moduldan istifadə edəcəyik ki, bu da həm Tək Səhifəli Tətbiq (SPA), həm də API autentifikasiyasını səmərəli idarə edir. Bu moduldan istifadə haqqında ətraflı öyrənmək üçün Nuxt 3 SPA autentifikasiyası haqqında məqaləyə baxın.
Bu layihədə biz Laravel Reverb-i real vaxtda hadisə yayımı üçün konfiqurasiya edəcəyik, Sanctum ilə autentifikasiyanı həyata keçirəcəyik və söhbət mesajlarını dinamik şəkildə göstərən və idarə edən Nuxt 3 frontendini quracağıq. Gəlin başlayaq!
Birincisi, Laravel Sanctum-un quraşdırıldığından və konfiqurasiya edildiyindən əmin olun. Sanctum tək səhifəli proqramlar (SPA) üçün token əsaslı autentifikasiyaya imkan verir. Sonra real vaxt imkanları üçün Laravel Reverb-i quraşdırın və konfiqurasiya edin.
Aşağıdakı Reverb mühit dəyişənlərini .env
faylınıza əlavə edin:
REVERB_APP_ID=my-app-id REVERB_APP_KEY=my-app-key REVERB_APP_SECRET=my-app-secret REVERB_HOST="localhost" REVERB_PORT=8080 REVERB_SCHEME=http
Söhbət mesajlarını saxlamaq üçün chat_messages
cədvəli üçün köçürmə yaradın. Qaçış:
php artisan make:migration create_chat_messages_table
Miqrasiya faylını aşağıdakı kimi yeniləyin:
Schema::create('chat_messages', function (Blueprint $table) { $table->id(); $table->foreignId('receiver_id'); $table->foreignId('sender_id'); $table->text('text'); $table->timestamps(); });
Cədvəl yaratmaq üçün köçürməni həyata keçirin:
php artisan migrate
Mesajları real vaxtda yayımlamaq üçün MessageSent
hadisə sinfi yaradın:
php artisan make:event MessageSent
Tədbir sinifini yeniləyin:
<?php namespace App\Events; use App\Models\ChatMessage; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class MessageSent implements ShouldBroadcastNow { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct(public ChatMessage $message) { // } public function broadcastOn(): array { return [new PrivateChannel("chat.{$this->message->receiver_id}")]; } }
channels.php
-də yayım kanalını təyin edin:
Broadcast::channel('chat.{id}', function ($user, $id) { return (int) $user->id === (int) $id; });
Söhbət mesajlarının göndərilməsini və alınmasını idarə etmək üçün bu marşrutları əlavə edin:
Route::get('/messages/{user}', function (User $user, Request $request) { return ChatMessage::query() ->where(function ($query) use ($user, $request) { $query->where('sender_id', $request->user()->id) ->where('receiver_id', $user->id); }) ->orWhere(function ($query) use ($user, $request) { $query->where('sender_id', $user->id) ->where('receiver_id', $request->user()->id); }) ->with(['sender', 'receiver']) ->orderBy('id', 'asc') ->get(); })->middleware('auth:sanctum'); Route::post('/messages/{user}', function (User $user, Request $request) { $request->validate(['message' => 'required|string']); $message = ChatMessage::create([ 'sender_id' => $request->user()->id, 'receiver_id' => $user->id, 'text' => $request->message ]); broadcast(new MessageSent($message)); return $message; });
Nuxt 3-ə Reverb ilə əlaqə yaratmaq üçün bu dəyişənləri .env
faylınıza əlavə edin:
NUXT_PUBLIC_REVERB_APP_ID=my-app-id NUXT_PUBLIC_REVERB_APP_KEY=my-app-key NUXT_PUBLIC_REVERB_APP_SECRET=my-app-secret NUXT_PUBLIC_REVERB_HOST="localhost" NUXT_PUBLIC_REVERB_PORT=8080 NUXT_PUBLIC_REVERB_SCHEME=http
Sonra onları nuxt.config.ts
-ə yükləyin:
export default defineNuxtConfig({ runtimeConfig: { public: { REVERB_APP_ID: process.env.NUXT_PUBLIC_REVERB_APP_ID, REVERB_APP_KEY: process.env.NUXT_PUBLIC_REVERB_APP_KEY, REVERB_APP_SECRET: process.env.NUXT_PUBLIC_REVERB_APP_SECRET, REVERB_HOST: process.env.NUXT_PUBLIC_REVERB_HOST, REVERB_PORT: process.env.NUXT_PUBLIC_REVERB_PORT, REVERB_SCHEME: process.env.NUXT_PUBLIC_REVERB_SCHEME, }, }, });
Real vaxt yeniləmələrini idarə etmək üçün laravel-echo.client.ts
plaginini yaradın:
import Echo from "laravel-echo"; import Pusher, { type ChannelAuthorizationCallback } from "pusher-js"; declare global { interface Window { Echo: Echo; Pusher: typeof Pusher; } } export default defineNuxtPlugin(() => { window.Pusher = Pusher; const config = useRuntimeConfig(); const echo = new Echo({ broadcaster: "reverb", key: config.public.REVERB_APP_KEY, wsHost: config.public.REVERB_HOST, wsPort: config.public.REVERB_PORT ?? 80, wssPort: config.public.REVERB_PORT ?? 443, forceTLS: (config.public.REVERB_SCHEME ?? "https") === "https", enabledTransports: ["ws", "wss"], authorizer: (channel, options) => ({ authorize: (socketId, callback) => { useSanctumFetch("api/broadcasting/auth", { method: "post", body: { socket_id: socketId, channel_name: channel.name }, }) .then(response => callback(null, response)) .catch(error => callback(error, null)); }, }), }); return { provide: { echo } }; });
Nuxt 3 tətbiqimizdə real vaxt söhbətini aktivləşdirmək üçün istifadəçilərin digər istifadəçiləri seçib söhbət edə biləcəyi yeni səhifə yaratdım, chats > [id].vue
. Bu səhifə real vaxt yeniləmələri və indikatorların yazılması üçün Laravel Echo və WebSockets istifadə edərək söhbət mesajlarını və istifadəçi məlumatlarını idarə etmək üçün Laravel backendinə qoşulur.
Bu söhbət funksiyasını necə strukturlaşdırdığımızın icmalı:
Birincisi, useRoute
tərtib edilə bilən URL-dən userID
alırıq. Bu userID
söhbət etdiyimiz istifadəçini müəyyənləşdirir və lazımi istifadəçi və söhbət mesajlarını yükləyir.
const route = useRoute(); const userID = route.params.id; const { user: currentUser } = useSanctum<User>(); const { data: user } = await useAsyncData( `user-${userID}`, () => useSanctumFetch<User>(`/api/users/${userID}`) ); const { data: messages } = useAsyncData( `messages-${userID}`, () => useSanctumFetch<ChatMessage[]>(`/api/messages/${userID}`), { default: (): ChatMessage[] => [] } );
Bu fraqment, səhifə quraşdırıldıqda mesajları asinxron şəkildə yükləmək üçün xüsusi tərtib edilə bilən useSanctumFetch
istifadə edir.
Biz hər bir mesajı dinamik şəkildə təqdim edirik, onların cari istifadəçidən və ya söhbət iştirakçısından olması əsasında tərtib edirik.
<div ref="messagesContainer" class="p-4 overflow-y-auto max-h-fit"> <div v-for="message in messages" :key="message.id" class="flex items-center mb-2"> <div v-if="message.sender_id === currentUser.id" class="p-2 ml-auto text-white bg-blue-500 rounded-lg"> {{ message.text }} </div> <div v-else class="p-2 mr-auto bg-gray-200 rounded-lg"> {{ message.text }} </div> </div> </div>
Söhbət pəncərəsi avtomatik olaraq nextTick()
istifadə edərək ən son mesaja sürüşür.
watch( messages, () => { nextTick(() => messageContainerScrollToBottom()); }, { deep: true } ); function messageContainerScrollToBottom() { if (!messagesContainer.value) return; messagesContainer.value.scrollTo({ top: messagesContainer.value.scrollHeight, behavior: 'smooth' }); }
İstifadəçilər giriş sahəsi ilə mesaj göndərə bilərlər. Təqdim edildikdən sonra, POST sorğusu Laravel backendinə göndərilir.
const newMessage = ref(""); const sendMessage = async () => { if (!newMessage.value.trim()) return; const messageResponse = await useSanctumFetch<ChatMessage>(`/api/messages/${userID}`, { method: "post", body: { message: newMessage.value } }); messages.value.push(messageResponse); newMessage.value = ""; };
Mesajlar göndərildikdən dərhal sonra yenilənir.
Laravel Echo MessageSent
və typing
kimi əsas hadisələri dinləyir.
onMounted(() => { if (currentUser.value) { $echo.private(`chat.${currentUser.value.id}`) .listen('MessageSent', (response: { message: ChatMessage }) => { messages.value.push(response.message); }) .listenForWhisper("typing", (response: { userID: number }) => { isUserTyping.value = response.userID === user.value?.id; if (isUserTypingTimer.value) clearTimeout(isUserTypingTimer.value); isUserTypingTimer.value = setTimeout(() => { isUserTyping.value = false; }, 1000); }); } });
Bu, bir saniyə hərəkətsizlikdən sonra yox olan real vaxt mesaj yeniləmələrini və yazma göstəricilərini idarə edir.
Yazma göstəricisini göstərmək üçün biz whisper
ilə "yazma" hadisəsini işə salırıq.
const sendTypingEvent = () => { if (!user.value || !currentUser.value) return; $echo.private(`chat.${user.value.id}`).whisper("typing", { userID: currentUser.value.id }); };
Bu hadisə istifadəçi hər dəfə yazdıqda göndərilir və alıcı yazma göstəricisini görür.
Söhbət interfeysi seçilmiş istifadəçi adı və mesajlar üçün bölmələr və daxiletmə sahəsi ilə başlıqdan ibarətdir.
<template> <div> <header v-if="user" class="bg-white shadow"> <div class="px-4 py-6 mx-auto max-w-7xl sm:px-6 lg:px-8"> <h1 class="text-2xl font-bold ">{{ user.name }}</h1> </div> </header> <div class="flex flex-col items-center py-5"> <div class="container w-full h-full p-8 space-y-3 bg-white rounded-xl"> <div v-if="currentUser"> <div class="flex flex-col justify-end h-80"> <div ref="messagesContainer" class="p-4 overflow-y-auto max-h-fit"> <div v-for="message in messages" :key="message.id" class="flex items-center mb-2"> <div v-if="message.sender_id === currentUser.id" class="p-2 ml-auto text-white bg-blue-500 rounded-lg"> {{ message.text }} </div> <div v-else class="p-2 mr-auto bg-gray-200 rounded-lg"> {{ message.text }} </div> </div> </div> </div> <div class="flex-shrink-0"> <span v-if="user && isUserTyping" class="text-gray-500"> {{ user.name }} is typing... </span> <div class="flex items-center justify-between w-full p-4 border-t border-gray-200"> <input type="text" v-model="newMessage" @keydown="sendTypingEvent" @keyup.enter="sendMessage" class="w-full p-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Type a message..." /> <button @click.prevent="sendMessage" class="inline-flex items-center justify-center w-12 h-12 ml-4 text-white bg-blue-500 rounded-lg hover:bg-blue-600"> <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" /> </svg> </button> </div> </div> </div> </div> </div> </div> </template>
Bu, Nuxt 3 ilə Laravel Sanctum və Echo istifadə edərək real vaxt rejimində söhbət funksiyasının qurulmasını tamamlayır.
İndi biz Laravel, Sanctum, Reverb və Nuxt 3-dən istifadə edərək təhlükəsiz, real vaxt söhbət proqramı yaratdıq. Bu quraşdırma mesaj reaksiyaları və ya çoxsaylı söhbət otaqları kimi əlavə funksiyaları daxil etmək üçün asanlıqla miqyaslana bilər.
Tam kod üçün GitHub repozitoriyasına baş çəkin.