إتقان Laravel Echo لتطبيقات الوقت الفعلي
Laravel Echo هي مكتبة JavaScript قوية تجعل الاشتراك في القنوات والاستماع إلى الأحداث التي يبثها تطبيق Laravel الخاص بك أمرًا سهلاً. من خلال الاستفادة من WebSockets، يتيح لك Echo بناء ميزات ديناميكية وفي الوقت الفعلي مثل الدردشة المباشرة والإشعارات ولوحات المعلومات بأقل جهد.
في هذا الدليل الشامل، ستتعلم كيفية إعداد Laravel Echo، بث الأحداث من الواجهة الخلفية لتطبيقك، والاستماع إليها في الواجهة الأمامية لإنشاء تجارب تفاعلية في الوقت الفعلي.
ما هو Laravel Echo؟ #
في جوهره، Laravel Echo هو مكتبة جانب العميل مصممة للتكامل بسلاسة مع نظام بث الأحداث في Laravel. يوفر واجهة برمجة تطبيقات نظيفة ومعبرة للاشتراك في القنوات والاستماع إلى الأحداث التي يتم بثها عبر WebSockets.
بدلاً من الاستعلام المستمر من الخادم للحصول على التحديثات، يدفع Echo البيانات من الخادم إلى عملائك بمجرد حدوث حدث، مما يؤدي إلى تجربة مستخدم أكثر استجابة وفعالية.
المتطلبات الأساسية #
قبل أن نبدأ، تأكد من توفر ما يلي:
- مشروع Laravel جديد أو موجود (الإصدار 8 أو أحدث).
- Node.js و npm (أو Yarn) مثبتان على جهاز التطوير الخاص بك.
- فهم أساسي لأحداث Laravel وجافاسكريبت الواجهة الأمامية.
- مشغل بث (مثل Pusher، Soketi، Ably). لهذا الدليل، سنستخدم بشكل أساسي Pusher لسهولة إعداده، ولكن المفاهيم تنطبق على المشغلات الأخرى.
الخطوة 1: تثبيت بث Laravel والمشغل #
تتطلب إمكانيات البث في Laravel بعض الخطوات الأولية.
أولاً، قم بتثبيت الحزمة الضرورية للبث:
composer require pusher/pusher-php-server "^7.0"
بعد ذلك، تأكد من أن BroadcastServiceProvider غير معلق في ملف config/app.php الخاص بك:
// config/app.php
'providers' => [
// ...
App\Providers\BroadcastServiceProvider::class,
],
الخطوة 2: تهيئة مشغل البث #
يدعم Laravel عدة مشغلات بث. سنقوم بتهيئة Pusher لهذا المثال.
افتح ملف .env الخاص بك وقم بتعيين مشغل البث وبيانات اعتماد 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
يمكنك الحصول على هذه البيانات عن طريق إنشاء حساب مجاني على Pusher.com.
بالإضافة إلى ذلك، راجع ملف config/broadcasting.php الخاص بك للتأكد من أن تهيئة Pusher صحيحة:
// config/broadcasting.php
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'forceTLS' => true, // موصى به للإنتاج
],
],
// ... مشغلات أخرى
],
الخطوة 3: تثبيت Laravel Echo و Pusher JS #
الآن، لنقم بتثبيت مكتبات جانب العميل.
npm install laravel-echo pusher-js --save-dev
# أو yarn add laravel-echo pusher-js
الخطوة 4: تهيئة Laravel Echo #
بعد التثبيت، تحتاج إلى تهيئة Echo في تطبيق JavaScript الخاص بك. تقوم تطبيقات Laravel عادةً بذلك في resources/js/bootstrap.js.
افتح resources/js/bootstrap.js وأضف ما يلي:
// resources/js/bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true
});
ملاحظة لمستخدمي Vite: إذا كنت تستخدم Vite، فتأكد من أن متغيرات .env الخاصة بك مسبوقة بـ VITE_ لتكون مكشوفة للواجهة الأمامية، على سبيل المثال، VITE_PUSHER_APP_KEY. وإلا، استخدم process.env.PUSHER_APP_KEY إذا كنت تستخدم Laravel Mix.
أخيرًا، قم بتجميع أصولك:
npm run dev # أو npm run watch
الخطوة 5: إنشاء حدث قابل للبث #
لبث حدث، يجب أن تقوم فئة الحدث الخاصة بك بتطبيق الواجهة Illuminate\Contracts\Broadcasting\ShouldBroadcast.
لننشئ حدثًا بسيطًا يسمى MessageSent:
php artisan make:event MessageSent
قم بتعديل حدث MessageSent لتطبيق ShouldBroadcast وتحديد طريقة broadcastOn. تحدد هذه الطريقة القناة (القنوات) التي سيتم بث الحدث عليها.
// app/Events/MessageSent.php
<?php
namespace App\Events;
use App\Models\User;
use App\Models\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $message;
/**
* إنشاء مثيل حدث جديد.
*/
public function __construct(User $user, Message $message)
{
$this->user = $user;
$this->message = $message;
}
/**
* الحصول على القنوات التي يجب أن يبث عليها الحدث.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
// مثال: قناة خاصة (خاصة بالمستخدم)
return [
new PrivateChannel('chat.'.$this->message->receiver_id),
new PrivateChannel('chat.'.$this->message->sender_id),
// أو لغرفة دردشة عامة:
// new Channel('public-chat-room.1'),
];
}
/**
* اسم بث الحدث.
*/
public function broadcastAs(): string
{
return 'message.sent';
}
/**
* الحصول على البيانات المراد بثها.
*
* @return array<string, mixed>
*/
public function broadcastWith(): array
{
return [
'user' => $this->user->name,
'message' => $this->message->content,
'timestamp' => now()->toDateTimeString(),
];
}
}
broadcastOn(): تحدد القنوات التي سيتم بث الحدث عليها.Channel: قنوات عامة، يمكن الوصول إليها من قبل أي شخص.PrivateChannel: قنوات خاصة، تتطلب المصادقة/التفويض.PresenceChannel: قنوات خاصة توفر معلومات حول من هو مشترك حاليًا.
broadcastAs(): (اختياري) تخصيص اسم الحدث. افتراضيًا، يكون اسم الفئة (على سبيل المثال،App\Events\MessageSent). هنا، نجعلهmessage.sent.broadcastWith(): (اختياري) تخصيص حمولة البيانات. افتراضيًا، يتم بث جميع الخصائص العامة في الحدث.
الخطوة 6: إطلاق الحدث #
يمكنك إطلاق هذا الحدث في أي مكان في تطبيقك، عادةً بعد إنشاء أو تحديث نموذج.
لنفترض أن لديك نموذج Message و ChatController:
// app/Http/Controllers/ChatController.php
<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Models\Message;
use App\Events\MessageSent;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ChatController extends Controller
{
public function sendMessage(Request $request)
{
$user = Auth::user();
$message = $user->messages()->create([
'content' => $request->input('message'),
'receiver_id' => $request->input('receiver_id'), // مثال لدردشة خاصة
// ... حقول الرسالة الأخرى
]);
broadcast(new MessageSent($user, $message))->toOthers();
return response()->json(['status' => 'تم إرسال الرسالة!', 'message' => $message]);
}
}
broadcast(new MessageSent(...))يرسل الحدث.->toOthers(): (اختياري) يضمن عدم بث الحدث إلى جلسة متصفح المستخدم الحالي، فقط إلى المستخدمين المتصلين الآخرين. هذا مفيد لتطبيقات الدردشة لتجنب رؤية رسالتك مرتين.
تذكر تحديد مسار لطريقة التحكم هذه:
// routes/web.php أو routes/api.php
Route::post('/chat/send', [ChatController::class, 'sendMessage'])->middleware('auth');
الخطوة 7: الاستماع إلى الأحداث باستخدام Laravel Echo #
الآن للواجهة الأمامية! سنستخدم Echo للاستماع إلى حدث MessageSent.
الاستماع إلى القنوات العامة #
إذا كنت تبث إلى قناة عامة public-chat-room.1:
// في مكون Vue/React الخاص بك، أو جافاسكريبت عادي بعد DOMContentLoaded
window.Echo.channel('public-chat-room.1')
.listen('message.sent', (e) => { // 'message.sent' هو الاسم broadcastAs()
console.log('تم استلام رسالة عامة:', e.user, e.message, e.timestamp);
// أضف الرسالة إلى واجهة المستخدم الخاصة بك
});
الاستماع إلى القنوات الخاصة #
تتطلب القنوات الخاصة المصادقة. يتعامل BroadcastServiceProvider في Laravel مع هذا عبر Broadcast::routes(). افتراضيًا، تتم المصادقة في /broadcasting/auth.
قم بتعديل routes/channels.php لتحديد منطق التفويض:
// routes/channels.php
use Illuminate\Support\Facades\Broadcast;
use App\Models\User;
Broadcast::channel('chat.{userId}', function (User $user, $userId) {
// اسمح فقط للمستخدم الذي يتطابق مع معرفه مع جزء القناة بالاشتراك
return (int) $user->id === (int) $userId;
});
بهذا، إذا تم بث حدث إلى chat.5، يمكن فقط للمستخدم المصادق عليه الذي يحمل المعرف 5 الاشتراك فيه. إذا حاول مستخدم بمعرف 10 الاشتراك في chat.5، فستفشل المصادقة.
ثم، في الواجهة الأمامية:
// الاشتراك في قناة خاصة
window.Echo.private(`chat.${userId}`) // userId للمستخدم المصادق عليه
.listen('message.sent', (e) => {
console.log('تم استلام رسالة خاصة:', e.user, e.message, e.timestamp);
// تحديث واجهة المستخدم للدردشة المحددة
})
.error((error) => {
console.error('خطأ في القناة:', error);
});
يتم استخدام window.Echo.private() للقنوات الخاصة. يجب أن يتطابق اسم القناة الذي تم تمريره مع ما هو محدد في broadcastOn() في الحدث الخاص بك.
الاستماع إلى قنوات التواجد (Presence Channels) #
قنوات التواجد هي نوع من القنوات الخاصة التي تخبرك بمن هو مشترك حاليًا في القناة. هذا رائع لمؤشرات "المستخدم يكتب" أو لإظهار المستخدمين النشطين في غرفة الدردشة.
أولاً، حدد قناة التواجد في routes/channels.php:
// routes/channels.php
Broadcast::channel('chat-room.{roomId}', function (User $user, $roomId) {
// مثال: اسمح فقط للمستخدمين المصادق عليهم بالانضمام، وأعد معلوماتهم الأساسية
return ['id' => $user->id, 'name' => $user->name];
// قد تضيف منطقًا أكثر تعقيدًا هنا، على سبيل المثال، if ($user->canJoinRoom($roomId))
});
ثم، في الواجهة الأمامية:
// الاشتراك في قناة التواجد
window.Echo.join(`chat-room.${roomId}`)
.here((users) => {
console.log('المستخدمون في الغرفة:', users); // مصفوفة من المستخدمين الموجودين حاليًا في القناة
})
.joining((user) => {
console.log(user.name + ' انضم.');
})
.leaving((user) => {
console.log(user.name + ' غادر.');
})
.listen('message.sent', (e) => {
console.log('رسالة في الغرفة من ' + e.user + ':', e.message);
})
.error((error) => {
console.error('خطأ في قناة التواجد:', error);
});
اعتبارات للإنتاج #
- الأمان: استخدم دائمًا القنوات الخاصة أو قنوات التواجد للبيانات الحساسة. نفذ منطق تفويض قويًا في
routes/channels.php. - قابلية التوسع: لتطبيقات واسعة النطاق، فكر في خوادم WebSockets مخصصة مثل Soketi أو Laravel WebSockets بدلاً من الاعتماد فقط على خدمات الجهات الخارجية مثل Pusher، خاصة للتحكم في التكلفة.
- معالجة الأخطاء: نفذ معالجة الأخطاء لمستمعي Echo لإدارة الانقطاعات أو فشل التفويض بأمان.
- إعادة الاتصال: يتعامل Echo مع عمليات إعادة الاتصال التلقائية، ولكن كن واعيًا لكيفية استجابة واجهة المستخدم الخاصة بك للانقطاعات المؤقتة.
الخلاصة #
يبسط Laravel Echo بشكل كبير عملية دمج وظائف الوقت الفعلي في تطبيقاتك. من خلال فهم مفاهيمه الأساسية – بث الأحداث، تهيئة المشغلات، والاشتراك في أنواع القنوات المختلفة – يمكنك بناء تجارب مستخدم تفاعلية وديناميكية بسهولة. ابدأ في تجربة Echo اليوم لإحياء تطبيقات Laravel الخاصة بك!