تطبيقات لارافيل في الوقت الفعلي: دليل شامل لـ Laravel Echo
غالبًا ما تتطلب بناء تطبيقات ويب ديناميكية وتفاعلية قدرات في الوقت الفعلي - فكر في الدردشة المباشرة، والإشعارات الفورية، ولوحات المعلومات التي يتم تحديثها باستمرار. لارافيل، بفضل نظام البث القوي ومكتبة JavaScript للواجهة الأمامية Laravel Echo، يجعل دمج هذه الميزات في الوقت الفعلي أمرًا مباشرًا بشكل مدهش.
سيرشدك هذا الدليل الشامل خلال إعداد Laravel Echo، وبث الأحداث من الواجهة الخلفية (Backend)، والاستماع إليها في تطبيق JavaScript الخاص بالواجهة الأمامية (Frontend)، مع تغطية القنوات العامة (Public)، والخاصة (Private)، وقنوات الحضور (Presence).
ما هو Laravel Echo؟ #
Laravel Echo هي مكتبة JavaScript تبسط عملية الاشتراك في القنوات والاستماع إلى الأحداث التي يبثها تطبيق لارافيل الخاص بك. تعمل كجسر بين الواجهة الأمامية وخادم WebSocket الذي تختاره (مثل Pusher أو Ably أو Soketi)، مما يتيح لك بناء تجارب في الوقت الفعلي بأقل قدر من التعليمات البرمجية المتكررة.
المتطلبات الأساسية #
قبل البدء، تأكد من توفر ما يلي:
- تطبيق لارافيل يعمل (يوصى بالإصدار 9+).
- فهم أساسي لأحداث Laravel (Events) وقوائم الانتظار (Queues).
- Node.js و npm (أو yarn) مثبتان على جهاز التطوير الخاص بك.
- حساب لدى خدمة بث مثل Pusher (يتوفر مستوى مجاني) أو حل مستضاف ذاتيًا مثل Soketi. سنستخدم Pusher لأمثلة هذا الدليل نظرًا لسهولة إعداده.
الخطوة 1: إعداد الواجهة الخلفية (Laravel) #
أولاً، نحتاج إلى تهيئة تطبيق لارافيل الخاص بنا لبث الأحداث.
1. تثبيت برنامج تشغيل البث (Broadcasting Driver) #
نظام البث في لارافيل لا يعتمد على برنامج تشغيل معين. بالنسبة لـ Pusher، قم بتثبيت SDK الرسمي عبر Composer:
composer require pusher/pusher-php-server
2. تهيئة متغيرات البيئة #
افتح ملف .env الخاص بك وعيّن BROADCAST_DRIVER إلى pusher. ثم، أضف بيانات اعتماد تطبيق Pusher الخاص بك. يمكنك الحصول عليها من لوحة تحكم Pusher بعد إنشاء تطبيق جديد.
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=YOUR_PUSHER_APP_ID
PUSHER_APP_KEY=YOUR_PUSHER_APP_KEY
PUSHER_APP_SECRET=YOUR_PUSHER_APP_SECRET
PUSHER_APP_CLUSTER=YOUR_PUSHER_APP_CLUSTER # على سبيل المثال: mt1, eu, us2
FORCE_HTTPS=true # يوصى به للإنتاج
3. إزالة التعليق عن مزود خدمة البث (Broadcast Service Provider) #
تأكد من إزالة التعليق عن BroadcastServiceProvider في ملف config/app.php الخاص بك. يقوم هذا المزود بتسجيل مسارات وخدمات البث.
// في config/app.php
'providers' => [
// ... مزودون آخرون
App\Providers\BroadcastServiceProvider::class,
],
الخطوة 2: إعداد الواجهة الأمامية (Laravel Echo) #
الآن، لنقم بإعداد Laravel Echo في تطبيق JavaScript للواجهة الأمامية.
1. تثبيت Echo و Pusher JS #
قم بتثبيت مكتبة laravel-echo ومكتبة العميل pusher-js عبر npm (أو yarn):
npm install laravel-echo pusher-js
# إذا كنت تستخدم Vite، أضف --save-dev
npm install laravel-echo pusher-js --save-dev
2. تهيئة Echo في JavaScript #
افتح ملف JavaScript الرئيسي الخاص بك (على سبيل المثال، resources/js/app.js إذا كنت تستخدم Vite، أو resources/js/bootstrap.js إذا كنت تستخدم Laravel Mix) وقم بتهيئة Echo. تأكد من تعديل key و cluster بناءً على ملف .env الخاص بك.
لـ Vite (Laravel 9+)
import './bootstrap'; // أو أي نقطة دخول أخرى
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher; // اجعل Pusher متاحًا عالميًا
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY, // يستخدم البادئة VITE_ لـ Vite
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
forceTLS: true
});
console.log('Laravel Echo initialized:', window.Echo);
هام لـ Vite: تأكد من أن مفاتيح Pusher في ملف .env مسبوقة بـ VITE_ لتكون قابلة للوصول في المتصفح:
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
لـ Laravel Mix (الإعدادات القديمة)
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY, // يستخدم البادئة MIX_ لـ Mix
cluster: process.env.MIX_PUSHER_APP_CLUSTER ?? 'mt1',
forceTLS: true
});
3. تجميع الأصول (Assets) #
بعد التهيئة، قم بتجميع الأصول الخاصة بك:
npm run dev # للتطوير
# أو
npm run build # للإنتاج
الخطوة 3: إنشاء وبث الأحداث #
الآن، لنقم بإنشاء حدث سيتم بثه من الواجهة الخلفية لـ لارافيل.
1. إنشاء حدث #
php artisan make:event MessageSent
2. جعل الحدث قابلاً للبث (Broadcastable) #
افتح app/Events/MessageSent.php. قم بتنفيذ واجهة ShouldBroadcast وأضف دالة broadcastOn لتحديد القنوات التي يجب أن يُبث عليها الحدث.
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message; // يتم بث الخصائص العامة تلقائيًا
public $user; // يتم بث الخصائص العامة تلقائيًا
public function __construct(string $message, \App\Models\User $user)
{
$this->message = $message;
$this->user = $user;
}
/**
* الحصول على القنوات التي يجب أن يبث عليها الحدث.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
// للتبسيط، سنبدأ بقناة عامة.
// سنستكشف القنوات الخاصة وقنوات الحضور لاحقًا.
return [
new Channel('chat'),
];
}
/**
* الحصول على البيانات المراد بثها.
*
* @return array<string, mixed>
*/
public function broadcastWith(): array
{
return [
'message' => $this->message,
'user' => [
'id' => $this->user->id,
'name' => $this->user->name,
],
];
}
}
ملاحظة: أي خصائص عامة في الحدث الخاص بك سيتم تسلسلها وبثها تلقائيًا كحمولة للحدث. يمكنك تخصيص هذه الحمولة باستخدام دالة broadcastWith().
3. إرسال الحدث (Dispatch the Event) #
يمكنك إرسال هذا الحدث من أي جزء من تطبيقك - وحدة تحكم (Controller)، أو مهمة (Job)، أو حتى مراقب نموذج (Model Observer). للتوضيح، دعنا ننشئ مسارًا بسيطًا.
// routes/web.php
use App\Events\MessageSent;
use Illuminate\Support\Facades\Route;
use App\Models\User;
Route::get('/send-message', function () {
// في تطبيق حقيقي، سيكون المستخدم مصادقًا عليه (Auth::user())
$user = User::firstOrCreate(['email' => '[email protected]'], ['name' => 'Test User', 'password' => bcrypt('password')]);
event(new MessageSent('مرحبًا من لارافيل!', $user));
return 'تم إرسال الرسالة!';
});
قم بتشغيل php artisan migrate إذا لم يكن لديك جدول users، وتأكد من أن User::firstOrCreate لديه مستخدم للعمل معه.
الخطوة 4: الاستماع إلى الأحداث باستخدام Laravel Echo (الواجهة الأمامية) #
أخيرًا، دعنا نستمع لحدث MessageSent في الواجهة الأمامية لدينا.
1. القنوات العامة (Public Channels) #
القنوات العامة مفتوحة لأي شخص للاستماع إليها. لا تتطلب مصادقة.
أضف هذا إلى ملف resources/js/app.js الخاص بك (أو نص برمجي مخصص لمكونك):
// ... بعد تهيئة Echo
window.Echo.channel('chat') // الاشتراك في قناة 'chat'
.listen('MessageSent', (e) => { // الاستماع لحدث 'MessageSent'
console.log('القناة العامة - رسالة جديدة:', e);
const messagesDiv = document.getElementById('messages');
if (messagesDiv) {
messagesDiv.innerHTML += `<p><strong>${e.user.name}:</strong> ${e.message}</p>`;
}
});
console.log('جاري الاستماع إلى قناة الدردشة العامة...');
لمشاهدة هذا عمليًا، قم بتحديث ملف resources/views/welcome.blade.php (أو أي عرض) باستخدام عنصر div بسيط لعرض الرسائل:
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>دردشة Laravel Echo</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<div style="max-width: 800px; margin: 20px auto; padding: 20px; border: 1px solid #eee; border-radius: 8px; font-family: sans-serif; text-align: right;">
<h1>عرض دردشة الوقت الفعلي</h1>
<p>افتح هذه الصفحة في عدة علامات تبويب. ثم قم بزيارة `/send-message` في متصفحك لإرسال حدث.</p>
<hr>
<h2>الرسائل:</h2>
<div id="messages" style="border: 1px solid #ccc; padding: 15px; min-height: 150px; background-color: #f9f9f9; overflow-y: auto;">
<!-- ستظهر الرسائل هنا -->
</div>
</div>
</body>
</html>
الآن، قم بتشغيل npm run dev (أو npm run watch)، واخدم تطبيق لارافيل الخاص بك (php artisan serve)، افتح http://127.0.0.1:8000 في عدة علامات تبويب للمتصفح، ثم انتقل إلى http://127.0.0.1:8000/send-message. يجب أن ترى الرسالة تظهر فورًا في جميع علامات التبويب المفتوحة!
2. القنوات الخاصة (Private Channels) #
تتطلب القنوات الخاصة مصادقة للاستماع إليها. هذا يضمن أن المستخدمين المصرح لهم فقط يمكنهم تلقي معلومات حساسة.
2.1. تعريف مسار التفويض (Authorization Route)
أولاً، قم بإزالة التعليق عن Broadcast::routes(); في routes/channels.php. يقوم هذا بتسجيل مسار /broadcasting/auth الذي يستخدمه Laravel Echo لمصادقة اشتراكات القنوات الخاصة.
ثم، قم بتعريف منطق التفويض لقناتك الخاصة في routes/channels.php:
// routes/channels.php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('private.chat.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
يضمن رد الاتصال الخاص بهذه القناة أن المستخدم الذي يتطابق معرفه ($userId) مع User هو الوحيد الذي يمكنه الاشتراك في private.chat.{userId}.
2.2. البث إلى قناة خاصة
حدث دالة broadcastOn في حدث MessageSent الخاص بك لاستخدام PrivateChannel:
// app/Events/MessageSent.php
public function broadcastOn(): array
{
return [
new PrivateChannel('private.chat.' . $this->user->id),
];
}
2.3. الاستماع إلى قناة خاصة
في الواجهة الأمامية، استخدم Echo.private() للاشتراك. هذا يتطلب مستخدمًا مصادقًا عليه. ستقوم عادةً بتمرير معرف المستخدم المصادق عليه إلى JavaScript الخاص بك.
// في resources/js/app.js، بافتراض أن معرف المستخدم متاح (على سبيل المثال، من Blade)
// مثال: <script>window.App = { user: @json(Auth::user()) };</script>
if (window.App && window.App.user) {
window.Echo.private(`private.chat.${window.App.user.id}`)
.listen('MessageSent', (e) => {
console.log('القناة الخاصة - رسالة جديدة للمستخدم', window.App.user.id, ':', e);
// تحديث واجهة المستخدم لهذا المستخدم المحدد
})
.error((error) => {
console.error('خطأ في القناة الخاصة:', error);
});
console.log(`جاري الاستماع إلى قناة الدردشة الخاصة للمستخدم ${window.App.user.id}...`);
}
تذكر جعل Auth::user() متاحًا في عروض Blade الخاصة بك إذا كنت تستخدم نظام مصادقة لارافيل. على سبيل المثال، في تخطيط app.blade.php الخاص بك:
<script>
window.App = {
user: @json(Auth::user())
};
</script>
3. قنوات الحضور (Presence Channels) #
قنوات الحضور هي نوع خاص من القنوات الخاصة تتيح لك معرفة من يشترك حاليًا في القناة. هذا مثالي لميزات مثل "X مستخدمين متصلين" أو رؤية من في غرفة الدردشة.
3.1. تعريف مسار التفويض
في routes/channels.php، قم بتعريف قناة الحضور. يجب أن ترجع دالة رد الاتصال (callback) مصفوفة من البيانات حول المستخدم المصادق عليه.
// routes/channels.php
Broadcast::channel('chat.room.{roomId}', function ($user, $roomId) {
if ($user) { // تأكد من أن المستخدم مصادق عليه
return ['id' => $user->id, 'name' => $user->name];
}
});
3.2. البث إلى قناة حضور
حدث حدث MessageSent الخاص بك لاستخدام PresenceChannel. ستقوم عادةً بتضمين room_id في الحدث الخاص بك.
// app/Events/MessageSent.php
// ... (أضف $room_id إلى المُنشئ والخاصية)
public function broadcastOn(): array
{
return [
new PresenceChannel('chat.room.' . $this->room_id),
];
}
3.3. الاستماع إلى قناة حضور
في الواجهة الأمامية، استخدم Echo.join() للاشتراك. توفر هذه الدالة ردود اتصال (callbacks) عندما ينضم المستخدمون، يغادرون، أو يكونون موجودين بالفعل.
// في resources/js/app.js
window.Echo.join('chat.room.1') // بافتراض معرف غرفة محدد، على سبيل المثال، '1'
.here((users) => {
console.log('المستخدمون الحاليون في الغرفة:', users);
// تحديث واجهة المستخدم لعرض قائمة المستخدمين النشطين
})
.joining((user) => {
console.log(user.name, 'انضم إلى الغرفة.');
// إضافة المستخدم إلى قائمة المتصلين
})
.leaving((user) => {
console.log(user.name, 'غادر الغرفة.');
// إزالة المستخدم من قائمة المتصلين
})
.error((error) => {
console.error('خطأ في قناة الحضور:', error);
})
.listen('MessageSent', (e) => {
console.log('قناة الحضور - رسالة جديدة في الغرفة:', e);
// التعامل مع الرسائل داخل قناة الحضور
});
console.log('جاري الاستماع إلى قناة الحضور chat.room.1...');
لاختبار قنوات الحضور، ستحتاج إلى عدة مستخدمين مصادق عليهم يصلون إلى نفس الصفحة التي تشترك في قناة الحضور.
الخلاصة #
يمكّنك Laravel Echo، بالاقتران مع نظام البث في Laravel، من بناء ميزات قوية في الوقت الفعلي بسهولة ملحوظة. من خلال فهم كيفية إعداد الواجهة الخلفية الخاصة بك، وتهيئة Echo في الواجهة الأمامية، والاستفادة من القنوات العامة والخاصة وقنوات الحضور، فأنت مستعد جيدًا لإنشاء تجارب مستخدم ديناميكية وجذابة.
جرب أحداثًا وقنوات وتحديثات واجهة مستخدم مختلفة لفهم الإمكانات الكاملة للتواصل في الوقت الفعلي في تطبيقات Laravel الخاصة بك. ترميز سعيد!