الفرق بين المراجعتين لصفحة: «Laravel/broadcasting»
لا ملخص تعديل |
رؤيا-بنعطية (نقاش | مساهمات) لا ملخص تعديل |
||
(22 مراجعة متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:}}</noinclude> | <noinclude>{{DISPLAYTITLE:البث (Broadcasting) في Laravel}}</noinclude> | ||
== مقدمة == | |||
في العديد من التطبيقات الحديثة، تُستعمل Websockets لتنفيذ واجهات استخدام فورية ذات تحيين مباشر. عند رفع بعض البيانات للخادم، تُرسَل في العادة رسالة على اتصال websocket لتُعالَج من قبل العميل. يوفّر هذا بديلًا فعالًا للسحب المتواصل للتطبيق من أجل التغييرات. | في العديد من التطبيقات الحديثة، تُستعمل Websockets لتنفيذ واجهات استخدام فورية ذات تحيين مباشر. عند رفع بعض البيانات للخادم، تُرسَل في العادة رسالة على اتصال websocket لتُعالَج من قبل العميل. يوفّر هذا بديلًا فعالًا للسحب المتواصل للتطبيق من أجل التغييرات. | ||
لمساعدتك في بناء هذا النوع من التطبيقات، يجعل Laravel من السهل "بث" أحداث عبر صلة websocket. يسمح بث الأحداث بمشاركة نفس الأحداث بين شيفرة من جهة الخادم وشيفرة من جهة العميل. | لمساعدتك في بناء هذا النوع من التطبيقات، يجعل [[Laravel]] من السهل "بث" أحداث عبر صلة websocket. يسمح بث الأحداث بمشاركة نفس الأحداث بين شيفرة من جهة الخادم وشيفرة من جهة العميل. | ||
ملاحظة: قبل التعمق في بث الأحداث، تأكد من قراءة توثيق Laravel الخاص بالأحداث والمستمعات. | |||
الضبط | <u>ملاحظة</u>: قبل التعمق في بث الأحداث، تأكد من قراءة [[Laravel/events|توثيق Laravel الخاص بالأحداث والمستمعات]]. | ||
تُخزّن كل خيارات ضبط البث في الملف config/broadcast.php. يدعم Laravel | |||
مزودو خدمات البث | === الضبط === | ||
قبل بث أي حدث، يجب عليك أولا تسجيله في الملف App\Providers\BroadcastServiceProvider. في التطبيقات الجديدة، ستحتاج إلى إلغاء التعليق في مصفوفة providers من الملف config/app.php. سيسمح هذا المزود بتسجيل مسارات الترخيص والنداءات. | تُخزّن كل خيارات ضبط البث في الملف <code>config/broadcast.php</code>. يدعم [[Laravel]] برامج تشغيل بث عديدة من البداية مثل Pusher و Redis والمشغل المحلي log للبرمجة والإصلاح. وتتوافر أيضًا القيمة <code>null</code> مما يسمح بالتعطيل الكامل لعملية البث. يوجد مثال ضبط لكل هذه المشغلات في الملف <code>config/broadcast.php</code>. | ||
الرمز المميز CSRF | |||
يحتاج Laravel Echo الولوج لرموز CSRF للدورة الحالية. يجب أن تتأكد من أنّ العنصر <head> في HTML يعرف العنصر <meta> الذي يحتوي على الرمز CSRF: | ==== مزودو خدمات البث ==== | ||
قبل بث أي حدث، يجب عليك أولا تسجيله في الملف <code>App\Providers\BroadcastServiceProvider</code>. في التطبيقات الجديدة، ستحتاج إلى إلغاء التعليق في مصفوفة <code>providers</code> من الملف <code>config/app.php</code>. سيسمح هذا المزود بتسجيل مسارات الترخيص والنداءات. | |||
==== الرمز المميز CSRF ==== | |||
يحتاج Laravel Echo الولوج لرموز CSRF للدورة الحالية. يجب أن تتأكد من أنّ العنصر <code><head></code> في [[HTML]] يعرف العنصر <code><meta></code> الذي يحتوي على الرمز CSRF:<syntaxhighlight lang="php"> | |||
<meta name="csrf-token" content="{{ csrf_token() }}"> | <meta name="csrf-token" content="{{ csrf_token() }}"> | ||
متطلبات المشغّل | </syntaxhighlight> | ||
Pusher | |||
=== متطلبات المشغّل === | |||
==== Pusher ==== | |||
إذا كنت تبث الأحداث باستخدام Pusher، فيجب عليك تثبيت Pusher PHP SDK باستعمال منظم الحزم Composer: | إذا كنت تبث الأحداث باستخدام Pusher، فيجب عليك تثبيت Pusher PHP SDK باستعمال منظم الحزم Composer: | ||
<syntaxhighlight lang="php"> | |||
composer require pusher/pusher-php-server "~3.0" | composer require pusher/pusher-php-server "~3.0" | ||
ثم يتوجب عليك دفع اعتمادات Pusher للملف config/broadcast.php. يتضمن الملف مثال ضبط Pusher مما يسمح لك بتخصيص مفتاح، وسر، ومعرف Pusher بسرعة. يسمح مثال الضبط بتخصيص خيارات options أخرى يدعمها Pusher مثل cluster. | </syntaxhighlight> | ||
ثم يتوجب عليك دفع اعتمادات Pusher للملف <code>config/broadcast.php</code>. يتضمن الملف مثال ضبط <code>Pusher</code> مما يسمح لك بتخصيص مفتاح، وسر، ومعرف <code>Pusher</code> بسرعة. يسمح مثال الضبط بتخصيص خيارات <code>options</code> أخرى يدعمها Pusher مثل <code>cluster</code>. | |||
<syntaxhighlight lang="php"> | |||
'options' => [ | 'options' => [ | ||
'cluster' => 'eu', | |||
'encrypted' => true | |||
] | ] | ||
عند استعمال Pusher و Laravel ECHO، يجب تحديد pusher كخيار البث عند بدء | |||
</syntaxhighlight> | |||
عند استعمال Pusher و Laravel ECHO، يجب تحديد pusher كخيار البث عند بدء نسخة Echo في الملف <code>resources/assets/js/bootstrap.js</code>: | |||
<syntaxhighlight lang="php"> | |||
import Echo from "laravel-echo" | import Echo from "laravel-echo" | ||
سطر 26: | سطر 43: | ||
window.Echo = new Echo({ | window.Echo = new Echo({ | ||
broadcaster: 'pusher', | |||
key: 'your-pusher-key' | |||
}); | }); | ||
Redis | |||
إذا كنت تستعمل الباث Redis، يجب عليك تثبيت المكتبة Predis: | |||
</syntaxhighlight> | |||
==== Redis ==== | |||
إذا كنت تستعمل الباث Redis، يجب عليك تثبيت المكتبة Predis:<syntaxhighlight lang="php"> | |||
composer require predis/predis | composer require predis/predis | ||
</syntaxhighlight> | |||
يبث Redis الأحداث باستخدام الخاصية pub/sub لكن عليك إضافة خادم Websocket ليتلقى رسائل Redis و يبثها لقنوات Websocket. | يبث Redis الأحداث باستخدام الخاصية pub/sub لكن عليك إضافة خادم Websocket ليتلقى رسائل Redis و يبثها لقنوات Websocket. | ||
عندما يبث Redis حدثًا، فسيُنشر على القناة المخصصة للحدث وسيحمل سلسلة محارف مشفرة بطريقة JSON تتضمن اسم الحدث ومعلومات data ومعرف المستخدم الذي صنع التوصيل socket (إن أمكن). | |||
Socket.io | عندما يبث Redis حدثًا، فسيُنشر على القناة المخصصة للحدث وسيحمل سلسلة محارف مشفرة بطريقة [[JSON]] تتضمن اسم الحدث ومعلومات <code>data</code> ومعرف المستخدم الذي صنع التوصيل socket (إن أمكن). | ||
إذا كنت ستضيف Socket.io للباث Redis، ستحتاج لإضافة مكتبة عميل JavaScript للتطبيق. يمكنك تثبيته عبر منظم الخدمات NPM: | |||
==== Socket.io ==== | |||
إذا كنت ستضيف Socket.io للباث Redis، ستحتاج لإضافة مكتبة عميل [[JavaScript]] للتطبيق. يمكنك تثبيته عبر منظم الخدمات NPM:<syntaxhighlight lang="php"> | |||
npm install --save socket.io-client | npm install --save socket.io-client | ||
ثم عليك بدء Echo بموصل socket.io و host: | ثم عليك بدء Echo بموصل socket.io و host: | ||
import Echo from "laravel-echo" | import Echo from "laravel-echo" | ||
سطر 43: | سطر 71: | ||
window.Echo = new Echo({ | window.Echo = new Echo({ | ||
broadcaster: 'socket.io', | |||
host: window.location.hostname + ':6001' | |||
}); | }); | ||
أخيرا، عليك تشغيل خادم Socket.io متوافق. لا يتضمن Laravel خادم socket.io لكن هنالك خادمٌ يتكفل به المجتمع موجودٌ في github في المستودع tlaverdure/laravel-echo-server. | |||
متطلبات | |||
قبل بث الأحداث, ستحتاج لضبط و تشغيل مستمعي | </syntaxhighlight> | ||
نظرة عامة على | |||
يسمح بث الأحداث في Laravel ببث أحداث من جهة الخادم إلى سكربات JavaScript التابعة لتطبيقك من جهة العميل باستخدام مقاربة مبنية على المشغلات في Websockets. | أخيرا، عليك تشغيل خادم Socket.io متوافق. لا يتضمن [[Laravel]] خادم socket.io لكن هنالك خادمٌ يتكفل به المجتمع موجودٌ في github في المستودع [https://github.com/tlaverdure/laravel-echo-server tlaverdure/laravel-echo-server]. | ||
==== متطلبات طوابير الانتظار ==== | |||
قبل بث الأحداث, ستحتاج لضبط و تشغيل مستمعي طوابير الانتظار. يتم البث عن طريق مهمات موجودة في قائمات انتظار حتى لا يتأثر وقت اجابة التطبيق. | |||
== نظرة عامة على مفهوم البث == | |||
يسمح بث الأحداث في [[Laravel]] ببث أحداث من جهة الخادم إلى سكربات [[JavaScript]] التابعة لتطبيقك من جهة العميل باستخدام مقاربة مبنية على المشغلات في Websockets. | |||
تبث الأحداث في قنوات "channels" قد تكون عامة أو خاصة. يمكن لأي مستخدم للتطبيق أن ينخرط في قناة عامة دون الحاجة لترخيص أو استيثاق. لكن للاستماع على قناة خاصة لا بد من الاستيثاق والترخيص. | تبث الأحداث في قنوات "channels" قد تكون عامة أو خاصة. يمكن لأي مستخدم للتطبيق أن ينخرط في قناة عامة دون الحاجة لترخيص أو استيثاق. لكن للاستماع على قناة خاصة لا بد من الاستيثاق والترخيص. | ||
استخدام تطبيق مثال | |||
=== استخدام تطبيق مثال === | |||
قبل التعمق في كل مكون من بث الأحداث، لنأخذ نظرة عامة على تطبيق تسوق إلكتروني على سبيل المثال. لن ندقق في ضبط Pusher أو Laravel Echo لأن ذلك مذكور في أقسام أخرى من التوثيق. | قبل التعمق في كل مكون من بث الأحداث، لنأخذ نظرة عامة على تطبيق تسوق إلكتروني على سبيل المثال. لن ندقق في ضبط Pusher أو Laravel Echo لأن ذلك مذكور في أقسام أخرى من التوثيق. | ||
لنفترض أنّ لدينا في هذا التطبيق صفحة تسمح للمستخدم بالإطلاع على حالة شحن طلب معين. لنفترض أيضًا أن الحدث ShippingStatusUpdated يُطلق كلما تم تحديث حالة طلب شحن يعالجه التطبيق: | |||
لنفترض أنّ لدينا في هذا التطبيق صفحة تسمح للمستخدم بالإطلاع على حالة شحن طلب معين. لنفترض أيضًا أن الحدث <code>ShippingStatusUpdated</code> يُطلق كلما تم تحديث حالة طلب شحن يعالجه التطبيق:<syntaxhighlight lang="php"> | |||
event(new ShippingStatusUpdated($update)); | event(new ShippingStatusUpdated($update)); | ||
الواجهة ShouldBroadcast | |||
عندما يطّلع المستخدم على أحد طلباته، لا نريده أن يُحدّث الصفحة ليرى تحيين الحالة. بل نريد بث تحديثات التطبيق عند إنشائها. لذا يجب إضافة الواجهة ShouldBroadcast للحدث ShippingStatusUpdated. مما سيخبر Laravel أن يبث الحدث عند إطلاقه: | |||
</syntaxhighlight> | |||
==== الواجهة ShouldBroadcast ==== | |||
عندما يطّلع المستخدم على أحد طلباته، لا نريده أن يُحدّث الصفحة ليرى تحيين الحالة. بل نريد بث تحديثات التطبيق عند إنشائها. لذا يجب إضافة الواجهة <code>ShouldBroadcast</code> للحدث <code>ShippingStatusUpdated</code>. مما سيخبر Laravel أن يبث الحدث عند إطلاقه:<syntaxhighlight lang="php"> | |||
<?php | <?php | ||
سطر 70: | سطر 112: | ||
class ShippingStatusUpdated implements ShouldBroadcast | class ShippingStatusUpdated implements ShouldBroadcast | ||
{ | { | ||
/** | |||
* معلومات عن حالة الشحن. | |||
* | |||
* @var string | |||
*/ | |||
public $update; | |||
} | } | ||
تتطلب الواجهة من صنف الحدث تعريف التابع broadcastOn. هذا التابع مسؤول عن إعادة القنوات التي على الحدث البث عليها. يكون التابع فارغًا في كل أصناف الأحداث المُنتجَة ونحتاج فقط لملء التفاصيل. نريد لصاحب الطلب فقط أن يرى حالة الشحن لذا سنبث الحدث على قناة خاصة مرتبطة بالطلب. | |||
</syntaxhighlight> | |||
تتطلب الواجهة من صنف الحدث تعريف التابع <code>broadcastOn</code>. هذا التابع مسؤول عن إعادة القنوات التي على الحدث البث عليها. يكون التابع فارغًا في كل أصناف الأحداث المُنتجَة ونحتاج فقط لملء التفاصيل. نريد لصاحب الطلب فقط أن يرى حالة الشحن لذا سنبث الحدث على قناة خاصة مرتبطة بالطلب. | |||
<syntaxhighlight lang="php"> | |||
/** | /** | ||
* الحصول على معلومات على قناة البث. | |||
* | |||
* @return \Illuminate\Broadcasting\Channel|array | |||
*/ | |||
public function broadcastOn() | public function broadcastOn() | ||
{ | { | ||
return new PrivateChannel('order.'.$this->update->order_id); | |||
} | } | ||
ترخيص القنوات | |||
تذكر انّ المستخدم يجب أن يسجل الدخول ليستمع للقنوات الخاصة. يمكن تعريف قواعد تراخيص القناة في routes/channels.php. في هذا المثال، يجب التأكد من أن المستخدم الذي يريد الاستماع على القناة الخاصة order.1 هو صاحب الطلب: | |||
</syntaxhighlight> | |||
==== ترخيص القنوات ==== | |||
تذكر انّ المستخدم يجب أن يسجل الدخول ليستمع للقنوات الخاصة. يمكن تعريف قواعد تراخيص القناة في <code>routes/channels.php</code>. في هذا المثال، يجب التأكد من أن المستخدم الذي يريد الاستماع على القناة الخاصة <code>order.1</code> هو صاحب الطلب:<syntaxhighlight lang="php"> | |||
Broadcast::channel('order.{orderId}', function ($user, $orderId) { | Broadcast::channel('order.{orderId}', function ($user, $orderId) { | ||
return $user->id === Order::findOrNew($orderId)->user_id; | |||
}); | }); | ||
يقبل التابع channel معاملين: اسم القناة ونداء يُرجع القيمة true أو false للدلالة على إذا كان المستخدم يملك ترخيصًا للاستماع على القناة أم لا. | |||
كل نداءات التراخيص تتلقى المستخدم المسجل حاليا كمعامل أول و معامل بديل عن أي معامل إضافي. في هذا المثال، نستخدم البديل {orderId} للإعلام أنّ القسم "ID" من اسم القناة متغير. | |||
</syntaxhighlight> | |||
بعد ذلك، كل ما تبقى هو الإستماع للحدث في شيفرة JavaScript للتطبيق. يمكن القيام بهذا باستعمال Laravel Echo. أولًا، نستعمل التابع private للدخول إلى القناة الخاصة. ثم، يمكننا استعمال التابع listen للاستماع للحدث ShippingStatusUpdated. في العادة، كل الخاصيات العامة للحدث تُضمَّن في حدث البث: | |||
يقبل التابع <code>channel</code> معاملين: اسم القناة ونداء يُرجع القيمة <code>true</code> أو <code>false</code> للدلالة على إذا كان المستخدم يملك ترخيصًا للاستماع على القناة أم لا. | |||
كل نداءات التراخيص تتلقى المستخدم المسجل حاليا كمعامل أول و معامل بديل عن أي معامل إضافي. في هذا المثال، نستخدم البديل <code>{orderId}</code> للإعلام أنّ القسم "ID" من اسم القناة متغير. | |||
==== الاستماع لبث الحدث ==== | |||
بعد ذلك، كل ما تبقى هو الإستماع للحدث في شيفرة <code>JavaScript</code> للتطبيق. يمكن القيام بهذا باستعمال Laravel Echo. أولًا، نستعمل التابع <code>private</code> للدخول إلى القناة الخاصة. ثم، يمكننا استعمال التابع <code>listen</code> للاستماع للحدث <code>ShippingStatusUpdated</code>. في العادة، كل الخاصيات العامة للحدث تُضمَّن في حدث البث:<syntaxhighlight lang="php"> | |||
Echo.private(`order.${orderId}`) | Echo.private(`order.${orderId}`) | ||
تعريف أحداث البث | .listen('ShippingStatusUpdated', (e) => { | ||
لإعلام Laravel أن حدثا ما يجب بثّه، نفذ | console.log(e.update); | ||
تتطلب الواجهة ShouldBroadcast كتابة تابع وحيد هو broadcastOn. يعيد هذا التابع قناة أو مصفوفة قنوات يبث عليها الحدث. يجب أن تكون القناة | }); | ||
</syntaxhighlight> | |||
== تعريف أحداث البث == | |||
لإعلام [[Laravel]] أن حدثا ما يجب بثّه، نفذ الواجهة<code>Illuminate\Contracts\Broadcasting\ShouldBroadcast</code> في صنف الحدث. تُحمَّل هذه الواجهة في كل أصناف الأحداث لذا يمكنك إضافتها بسهولة لأي حدث. | |||
تتطلب الواجهة <code>ShouldBroadcast</code> كتابة تابع وحيد هو <code>broadcastOn</code>. يعيد هذا التابع قناة أو مصفوفة قنوات يبث عليها الحدث. يجب أن تكون القناة نسخة <code>Channel</code> أو <code>PrivateChannel</code> أو <code>PresenceChannel</code>. تمثل نسخة <code>Channel</code> القنوات العامة التي يمكن لأي مستخدم الدخول فيها في حين <code>PrivateChannel</code> و <code>PresenceChannel</code> تمثل قنوات تتطلب ترخيصًا:<syntaxhighlight lang="php"> | |||
<?php | <?php | ||
namespace App\Events; | namespace App\Events; | ||
use Illuminate\Broadcasting\Channel; | use Illuminate\Broadcasting\Channel; use Illuminate\Queue\SerializesModels; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | ||
use Illuminate\Queue\SerializesModels; | |||
use Illuminate\Broadcasting\PrivateChannel; | class ServerCreated implements ShouldBroadcast { | ||
use Illuminate\Broadcasting\PresenceChannel; | |||
use Illuminate\Broadcasting\InteractsWithSockets; | |||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | |||
use SerializesModels; | |||
{ | public $user; | ||
/** | |||
* إنشاء نسخة حدث جديد | |||
* | |||
* @return void | |||
*/ | |||
public function __construct(User $user) | |||
{ | |||
$this->user = $user; | |||
} | |||
/** | |||
* جلب القنوات التي يجب من الحدث البث فيها | |||
* | |||
* @return Channel|array | |||
*/ | |||
public function broadcastOn() | |||
{ | |||
return new PrivateChannel('user.'.$this->user->id); | |||
} | |||
} | |||
</syntaxhighlight> | |||
ثم عليك إطلاق حدث كما تفعل عادة. عند إطلاق الحدث، تبث مهمة في قائمة الإنتظار آليًا الحدث على المشغل الذي اخترته. | ثم عليك إطلاق حدث كما تفعل عادة. عند إطلاق الحدث، تبث مهمة في قائمة الإنتظار آليًا الحدث على المشغل الذي اخترته. | ||
اسم البث | |||
في العادة، يبث Laravel الأحداث باستخدام أسماء أصناف الأحداث. لكن بإمكانك تخصيص اسم البث عبر تعريف التابع broadcastAs في الحدث: | === اسم البث === | ||
في العادة، يبث [[Laravel]] الأحداث باستخدام أسماء أصناف الأحداث. لكن بإمكانك تخصيص اسم البث عبر تعريف التابع <code>broadcastAs</code> في الحدث:<syntaxhighlight lang="php"> | |||
/** | /** | ||
* اسم الحدث. | |||
* | |||
* @return string | |||
public function broadcastAs() | */ | ||
public function broadcastAs() { | |||
return 'server.created'; | |||
} | } | ||
إذا غيّرت اسم البث باستخدام | |||
</syntaxhighlight> | |||
إذا غيّرت اسم البث باستخدام <code>broadcastAs</code>، يجب عليك التأكد من تسجيل المستمع مسبوقًا بالرمز ".". سيُخبر هذا Echo بإضافة مجال أسماء للحدث:<syntaxhighlight lang="php"> | |||
.listen('.server.created', function (e) { | .listen('.server.created', function (e) { | ||
.... | |||
}); | }); | ||
بيانات البث | |||
عند بث حدث، تتم سلسلة كل خاصياته العامة آليًا كتحميل للحدث، مما يسمح لك بالولوج لكل بياناته العامة من تطبيق JavaScript. لذا لو كان للحدث خاصية واحدة user$ مثلًا تحتوي على نموذج | |||
</syntaxhighlight> | |||
=== بيانات البث === | |||
عند بث حدث، تتم سلسلة كل خاصياته العامة آليًا كتحميل للحدث، مما يسمح لك بالولوج لكل بياناته العامة من تطبيق [[JavaScript]]. لذا لو كان للحدث خاصية واحدة <code>user$</code> مثلًا تحتوي على نموذج [[Laravel/eloquent|Eloquent]]، يكون نحميل البث كما يلي: | |||
<syntaxhighlight lang="php"> | |||
{ | { | ||
"user": { | |||
"id": 1, | |||
"name": "Patrick Stewart" | |||
... | |||
} | |||
} | } | ||
لكن إذا أردت تحكما أفضل في تحميل البث، يمكنك إضافة التابع broadcastWith. يعيد هذا التابع مصفوفة البيانات التي تريد إرسالها كتحميل للبث: | |||
</syntaxhighlight> | |||
لكن إذا أردت تحكما أفضل في تحميل البث، يمكنك إضافة التابع <code>broadcastWith</code>. يعيد هذا التابع مصفوفة البيانات التي تريد إرسالها كتحميل للبث:<syntaxhighlight lang="php"> | |||
/** | /** | ||
* بيانات البث | |||
* | |||
* @return array | |||
public function broadcastWith() | */ | ||
public function broadcastWith() { | |||
return ['id' => $this->user->id]; | |||
} | } | ||
في العادة، يوضع كل أحداث البث في | |||
</syntaxhighlight> | |||
=== طابور انتظار البث === | |||
في العادة، يوضع كل أحداث البث في طابور الانتظار الأولية للصلة الأولية المعرّفة في ملف الضبط <code>queue.php</code>. يمكنك تخصيص طابور انتظار البث عبر تعريف الخاصية <code>broadcastQueue</code> في صنف الحدث. يجب أن تحدد هذه الخاصية اسم طابور الانتظار الذي تود استعماله عند البث:<syntaxhighlight lang="php"> | |||
/** | /** | ||
* اسم قائمة الإنتظار. | |||
* | |||
* @var string | |||
*/ | |||
public $broadcastQueue = 'your-queue-name'; | public $broadcastQueue = 'your-queue-name'; | ||
إذا أردت بث الأحداث باستعمال | |||
</syntaxhighlight> | |||
إذا أردت بث الأحداث باستعمال طابور الانتظار <code>sync</code> بدل المشغل العادي، يمكنك تنفيذ <code>shouldBroadcastNow</code> بدل <code>ShouldBoradcast</code>: | |||
<syntaxhighlight lang="php"> | |||
<?php | <?php | ||
سطر 191: | سطر 280: | ||
class ShippingStatusUpdated implements ShouldBroadcastNow | class ShippingStatusUpdated implements ShouldBroadcastNow | ||
{ | { | ||
// | |||
} | } | ||
شروط البث | |||
في بعض الأحيان، قد تريد بث الأحداث فقط إن تحقق شرط معين. يمكنك تحديد هذه الشروط عبر إضافة التابع broadcastWhen لصنف الحدث: | |||
</syntaxhighlight> | |||
=== شروط البث === | |||
في بعض الأحيان، قد تريد بث الأحداث فقط إن تحقق شرط معين. يمكنك تحديد هذه الشروط عبر إضافة التابع <code>broadcastWhen</code> لصنف الحدث:<syntaxhighlight lang="php"> | |||
/** | /** | ||
* تحديد إذا كان يجب بث الحدث | |||
* | |||
* @return bool | |||
public function broadcastWhen() | */ | ||
public function broadcastWhen() { | |||
return $this->value > 100; | |||
} | } | ||
الترخيص للقنوات | |||
</syntaxhighlight> | |||
== الترخيص للقنوات == | |||
تتطلب القنوات الخاصة ترخيصًا ليتمكن المستخدم المسجل حاليًا من الإستماع إليها. يتم هذا عبر إطلاق طلب HTTP للتطبيق باسم القناة وجعل التطبيق يقرر هل يسمح للمستخدم بالإستماع أم لا. عند استخدام Laravel Echo، يُصنع طلب HTTP للترخيص بالإنخراط في القنوات الخاصة تلقائيًا. لكن عليك تعريف المسار للإجابة على الطلب. | تتطلب القنوات الخاصة ترخيصًا ليتمكن المستخدم المسجل حاليًا من الإستماع إليها. يتم هذا عبر إطلاق طلب HTTP للتطبيق باسم القناة وجعل التطبيق يقرر هل يسمح للمستخدم بالإستماع أم لا. عند استخدام Laravel Echo، يُصنع طلب HTTP للترخيص بالإنخراط في القنوات الخاصة تلقائيًا. لكن عليك تعريف المسار للإجابة على الطلب. | ||
تعريف مسارات الترخيص | |||
من حسن الحظ، يجعل Laravel تعريف المسارات لإجابة طلبات الترخيص أمرًا سهلًا. في مزود الخدمات BroadcastServiceProvider المضمن في تطبيق | === تعريف مسارات الترخيص === | ||
من حسن الحظ، يجعل Laravel تعريف المسارات لإجابة طلبات الترخيص أمرًا سهلًا. في مزود الخدمات <code>BroadcastServiceProvider</code> المضمن في تطبيق [[Laravel]]، سترى نداء للتابع <code>Broadcast::routes</code>. سيسجل هذا التابع المسار <code>broadcasting/auth</code> لمعالجة طلبات الترخيص.<syntaxhighlight lang="php"> | |||
Broadcast::routes(); | Broadcast::routes(); | ||
يضع التابع Broadcast::routes آليًا مساراته في في مجموعة الوسيط web لكن بإمكانك تمرير أي صفوفة من خصائص المسارات للتابع إذا أردت تخصيص الخاصيات. | </syntaxhighlight> | ||
يضع التابع <code>Broadcast::routes</code> آليًا مساراته في في مجموعة الوسيط <code>web</code> لكن بإمكانك تمرير أي صفوفة من خصائص المسارات للتابع إذا أردت تخصيص الخاصيات.<syntaxhighlight lang="php"> | |||
Broadcast::routes($attributes); | Broadcast::routes($attributes); | ||
تعريف نداءات الترخيص | </syntaxhighlight> | ||
بعد ذلك، نحتاج لتعريف التحكم المنطقي الذي سيقوم بالترخيص. يتم هذا في الملف routes/channels.php في التطبيق. في هذا الملف، يمكنك استخدام التابع Broadcast::channel لتسجيل نداءات ترخيص القنوات: | |||
=== تعريف نداءات الترخيص === | |||
بعد ذلك، نحتاج لتعريف التحكم المنطقي الذي سيقوم بالترخيص. يتم هذا في الملف <code>routes/channels.php</code> في التطبيق. في هذا الملف، يمكنك استخدام التابع <code>Broadcast::channel</code> لتسجيل نداءات ترخيص القنوات:<syntaxhighlight lang="php"> | |||
Broadcast::channel('order.{orderId}', function ($user, $orderId) { | Broadcast::channel('order.{orderId}', function ($user, $orderId) { | ||
return $user->id === Order::findOrNew($orderId)->user_id; | |||
}); | }); | ||
يقبل التابع channel معاملين وهما اسم القناة ودالة رد نداء تعيد القيمة true أو false للدلالة على إذا كان المستخدم يملك ترخيصًا للاستماع أم لا. | |||
كل نداءات التراخيص تتلقى المستخدم المسجل حاليًا كمعامل أول و معامل بديل عن أي معامل إضافي. في المثال السابق، نستخدم البديل {orderId} للإعلام أنّ القسم "ID" من اسم القناة متغير. | |||
ترخيص نداءات ربط النماذج | </syntaxhighlight> | ||
مثل مسارات HTTP، تستفيد مسارات القنوات من ربط النماذج المباشر و غير المباشر. مثلًا، بدل تلقي سلسلة محارف أو معرّف رقمي، يمكن أن تطلب نسخة من Order: | |||
يقبل التابع <code>channel</code> معاملين وهما اسم القناة ودالة رد نداء تعيد القيمة <code>true</code> أو <code>false</code> للدلالة على إذا كان المستخدم يملك ترخيصًا للاستماع أم لا. | |||
كل نداءات التراخيص تتلقى المستخدم المسجل حاليًا كمعامل أول و معامل بديل عن أي معامل إضافي. في المثال السابق، نستخدم البديل <code>{orderId}</code> للإعلام أنّ القسم "<code>ID</code>" من اسم القناة متغير. | |||
==== ترخيص نداءات ربط النماذج ==== | |||
مثل مسارات HTTP، تستفيد مسارات القنوات من ربط النماذج المباشر و غير المباشر. مثلًا، بدل تلقي سلسلة محارف أو معرّف رقمي، يمكن أن تطلب نسخة من <code>Order</code>: | |||
<syntaxhighlight lang="php"> | |||
use App\Order; | use App\Order; | ||
Broadcast::channel('order.{order}', function ($user, Order $order) { | Broadcast::channel('order.{order}', function ($user, Order $order) { | ||
return $user->id === $order->user_id; | |||
}); | }); | ||
تعريف أصناف القنوات | |||
إذا كان التطبيق يستعمل العديد من القنوات، سيصبح الملف routes/channels.php ضخمًا. لذا، بدل استعمال Closure لترخيص القنوات، يمكن استعمال أصناف للقنوات. لإنشاء أصناف القنوات، استعمل الأمر make:channel. سيضع الأمر الأصناف المصنوعة في المجلد App/Broadcasting | |||
</syntaxhighlight> | |||
=== تعريف أصناف القنوات === | |||
إذا كان التطبيق يستعمل العديد من القنوات، سيصبح الملف <code>routes/channels.php</code> ضخمًا. لذا، بدل استعمال <code>Closure</code> لترخيص القنوات، يمكن استعمال أصناف للقنوات. لإنشاء أصناف القنوات، استعمل الأمر <code>make:channel</code>. سيضع الأمر الأصناف المصنوعة في المجلد <code>App/Broadcasting</code><syntaxhighlight lang="php"> | |||
php artisan make:channel OrderChannel | php artisan make:channel OrderChannel | ||
ثم سجل الصنف في الملف routes/channels.php | </syntaxhighlight> | ||
ثم سجل الصنف في الملف <code>routes/channels.php</code><syntaxhighlight lang="php"> | |||
use App\Broadcasting\OrderChannel; | use App\Broadcasting\OrderChannel; | ||
Broadcast::channel('order.{order}', OrderChannel::class); | Broadcast::channel('order.{order}', OrderChannel::class); | ||
أخيرًا، يمكنك وضع التحكم المنطقي في الترخيص في الصنف في التابع join. سيحتوي هذا التابع نفس الشيفرة التي كنت ستضعها في عادة في القسم Closure. يمكن طبعًا الاستفادة من ربط النماذج هنا أيضًا. | |||
</syntaxhighlight> | |||
أخيرًا، يمكنك وضع التحكم المنطقي في الترخيص في الصنف في التابع <code>join</code>. سيحتوي هذا التابع نفس الشيفرة التي كنت ستضعها في عادة في القسم <code>Closure</code>. يمكن طبعًا الاستفادة من ربط النماذج هنا أيضًا.<syntaxhighlight lang="php"> | |||
<?php | <?php | ||
namespace App\Broadcasting; | namespace App\Broadcasting; | ||
use App\User; | use App\User; use App\Order; | ||
use App\Order; | |||
class OrderChannel | class OrderChannel { | ||
{ | |||
/** | /** | ||
* إنشاء نسخة قناة جديدة | |||
* | |||
* @return void | |||
*/ | |||
public function __construct() | |||
{ | |||
// | |||
} | |||
/** | |||
* استيثاق مستخدم القناة | |||
* | |||
* @param \App\User $user | |||
* @param \App\Order $order | |||
* @return array|bool | |||
*/ | |||
public function join(User $user, Order $order) | |||
{ | |||
return $user->id === $order->user_id; | |||
} | |||
} | } | ||
ملاحظة: كالعديد من الأصناف في | |||
بث الأحداث | |||
بعد تعريف الحدث وإضافة الواجهة | </syntaxhighlight> | ||
<u>ملاحظة</u>: كالعديد من الأصناف في [[Laravel]]، تُعالج أصناف القنوات في حاوي الخدمات. لذا يمكنك التلميح إلى نوع الإعتماديات التي تحتاج لها القناة في باني الصنف التي يحتاجها باني الصنف. | |||
== بث الأحداث == | |||
بعد تعريف الحدث وإضافة الواجهة <code>ShouldBroadcast</code>، تحتاج فقط لإطلاق الحدث باستعمال الدالة <code>event</code>. سيُلاحظ مُطلِق الأحداث أن الحدث تم ترميزه بالواجهة <code>ShouldBroadcast</code> ويضيفه لقائمة انتظار البث:<syntaxhighlight lang="php"> | |||
event(new ShippingStatusUpdated($update)); | event(new ShippingStatusUpdated($update)); | ||
فقط للآخرين | </syntaxhighlight> | ||
عند بناء تطبيق يستعمل تقنية البث، يمكنك تعويض الدالة event بالدالة broadcast. مثل | |||
=== فقط للآخرين === | |||
عند بناء تطبيق يستعمل تقنية البث، يمكنك تعويض الدالة <code>event</code> بالدالة <code>broadcast</code>. مثل <code>event</code>، يُطلق <code>broadcast</code> الحدث من جهة الخادم للمستمع في جهة العميل<syntaxhighlight lang="php"> | |||
broadcast(new ShippingStatusUpdated($update)); | broadcast(new ShippingStatusUpdated($update)); | ||
لكن الدالة broadcast توفر أيضًا التابع toOthers الذي يسمح باستثناء المستخدم الحالي من لائحة المستقبلين: | </syntaxhighlight> | ||
لكن الدالة <code>broadcast</code> توفر أيضًا التابع <code>toOthers</code> الذي يسمح باستثناء المستخدم الحالي من لائحة المستقبلين:<syntaxhighlight lang="php"> | |||
broadcast(new ShippingStatusUpdated($update))->toOthers(); | broadcast(new ShippingStatusUpdated($update))->toOthers(); | ||
لفهم أفضل متى قد تريد استعمال التابع | </syntaxhighlight> | ||
لفهم أفضل متى قد تريد استعمال التابع <code>toOthers</code>، لنتخيل تطبيقا للائحة مهام حيث يمكن للمستخدم صناعة مهمة جديدة بتمرير اسم المهمة. لإنشاء مهمة، يبعث التطبيق طلبًا لنقطة النهاية task/ التي تبث صناعة المهمة وتعيد تمثيل <code>JSON</code> للمهمة الجديدة. يتلقى تطبيق <code>javascript</code> الجواب من نقطة النهاية، يمكنه إضافة المهمة الجديدة للائحته كالآتي<syntaxhighlight lang="php"> | |||
axios.post('/task', task) | axios.post('/task', task) | ||
.then((response) => { | |||
this.tasks.push(response.data); | |||
لكن تذكر أننا نبث أيضًا صناعة المهمة، إذا كان تطبيق JavaScript يستمع للحدث ليضيف المهام الجديدة للائحة المهام، سيكون لديك نفس المهمة مرتين: واحد من نقطة النهاية وواحد من البث. يمكن حل هذا المشكل باستخدام التابع toOthers لإعلام الباث بعدم بث الحدث للمستخدم الحالي. | }); | ||
تنبيه: يجب على الحدث استخدام الخاصية Illuminate\Broadcasting\InteractsWithSockets للاستعمال التابع toOthers. | |||
الضبط | </syntaxhighlight> | ||
عند بدء مثيل Laravel Echo، يُعطى معرّف توصيل (Socket id) للصلة. إذا كنت تستخدم Vue و Axios، يُرفق المعرّف تلقائيًا بكل طلب خارج كعنوان x-socket-ID. ثم عندما تنادي التابع | |||
إذا كنت لا تستخدم Vue و | لكن تذكر أننا نبث أيضًا صناعة المهمة، إذا كان تطبيق [[JavaScript]] يستمع للحدث ليضيف المهام الجديدة للائحة المهام، سيكون لديك نفس المهمة مرتين: واحد من نقطة النهاية وواحد من البث. يمكن حل هذا المشكل باستخدام التابع <code>toOthers</code> لإعلام الباث بعدم بث الحدث للمستخدم الحالي. | ||
<u>تنبيه</u>: يجب على الحدث استخدام الخاصية <code>Illuminate\Broadcasting\InteractsWithSockets</code> للاستعمال التابع <code>toOthers</code>. | |||
==== الضبط ==== | |||
عند بدء مثيل Laravel Echo، يُعطى معرّف توصيل (Socket id) للصلة. إذا كنت تستخدم Vue و Axios، يُرفق المعرّف تلقائيًا بكل طلب خارج كعنوان <code>x-socket-ID</code>. ثم عندما تنادي التابع <code>toOthers</code>، يأخذ Laravel المعرّف من العنوان ويأمر الباث بعدن البث لأي صلة تحمل ذلك المعرّف. | |||
إذا كنت لا تستخدم <code>Vue</code> و <code>Axios</code>، ستحتاج لضبط تطبيق [[JavaScript]] يدويًا ليُرسل العنوان <code>x-socket-ID</code>. يمكنك استرجاع معرّف التوصيل بالتابع <code>Echo.socketID</code>: | |||
<syntaxhighlight lang="php"> | |||
var socketId = Echo.socketId(); | var socketId = Echo.socketId(); | ||
تلقي البث | </syntaxhighlight> | ||
تثبيت Laravel echo | |||
Laravel Echo هي مكتبة Javascript تجعل الانخراط في قناة و والإستماع للأحداث أمرًا سهلًا. يمكنك تثبيت Echo عبر منظم الحزم NPM. في هذا المثال، سنثبت أيضًا pusher-js حيث سنستخدم المشغل pusher للبث: | == تلقي البث == | ||
=== تثبيت Laravel echo === | |||
Laravel Echo هي مكتبة [[JavaScript|Javascript]] تجعل الانخراط في قناة و والإستماع للأحداث أمرًا سهلًا. يمكنك تثبيت Echo عبر منظم الحزم NPM. في هذا المثال، سنثبت أيضًا <code>pusher-js</code> حيث سنستخدم المشغل pusher للبث:<syntaxhighlight lang="php"> | |||
npm install --save laravel-echo pusher-js | npm install --save laravel-echo pusher-js | ||
بعد تثبيت Echo، أنت الآن جاهزٌ لإنشاء نسخة Echo في تطبيق JavaScript. نهاية الملف resources/assets/js/bootstrap.js هي مكان جيد للقيام بهذا: | </syntaxhighlight> | ||
بعد تثبيت Echo، أنت الآن جاهزٌ لإنشاء نسخة Echo في تطبيق JavaScript. نهاية الملف <code>resources/assets/js/bootstrap.js</code> هي مكان جيد للقيام بهذا:<syntaxhighlight lang="php"> | |||
import Echo from "laravel-echo" | import Echo from "laravel-echo" | ||
window.Echo = new Echo({ | window.Echo = new Echo({ | ||
broadcaster: 'pusher', | |||
key: 'your-pusher-key' | |||
}); | }); | ||
عند إنشاء نسخة Echo يستخدم الباث pusher، يمكنك أيضًا تخصيص cluster بالإضافة إلى تحديد إذا ما كانت الصلة تستوجب تشفيرًا: | |||
</syntaxhighlight> | |||
عند إنشاء نسخة Echo يستخدم الباث pusher، يمكنك أيضًا تخصيص cluster بالإضافة إلى تحديد إذا ما كانت الصلة تستوجب تشفيرًا:<syntaxhighlight lang="php"> | |||
window.Echo = new Echo({ | window.Echo = new Echo({ | ||
broadcaster: 'pusher', | |||
key: 'your-pusher-key', | |||
cluster: 'eu', | |||
encrypted: true | |||
}); | }); | ||
بعد تثبيت Echo و تشغيله، أنت الآن جاهز للاستماع للأحداث. أولًا، استخدم التابع channel لإعادة نسخة من القناة، ثم استدع التابع listen لحدث معين: | |||
</syntaxhighlight> | |||
=== الاستماع للأحداث === | |||
بعد تثبيت Echo و تشغيله، أنت الآن جاهز للاستماع للأحداث. أولًا، استخدم التابع <code>channel</code> لإعادة نسخة من القناة، ثم استدع التابع <code>listen</code> لحدث معين:<syntaxhighlight lang="php"> | |||
Echo.channel('orders') | Echo.channel('orders') | ||
.listen('OrderShipped', (e) => { | |||
console.log(e.order.name); | |||
إذا أردت الاستماع لأحداث في قناة خاصة، استعمل التابع private بدل channel. يمكنك المواصلة في إضافة نداءات listen للاستماع لعدة أحداث في قناة واحدة | }); | ||
</syntaxhighlight> | |||
إذا أردت الاستماع لأحداث في قناة خاصة، استعمل التابع <code>private</code> بدل <code>channel</code>. يمكنك المواصلة في إضافة نداءات <code>listen</code> للاستماع لعدة أحداث في قناة واحدة<syntaxhighlight lang="php"> | |||
Echo.private('orders') | Echo.private('orders') | ||
.listen(...) | |||
.listen(...) | |||
مغادرة قناة | .listen(...); | ||
لمغادرة قناة، ينكنك نداء التابع leave في نسخة Echo: | |||
</syntaxhighlight> | |||
=== مغادرة قناة === | |||
لمغادرة قناة، ينكنك نداء التابع <code>leave</code> في نسخة Echo:<syntaxhighlight lang="php"> | |||
Echo.leave('orders'); | Echo.leave('orders'); | ||
</syntaxhighlight> | |||
قد تكون لاحظت في الأمثلة السابقة أننا لم نحدد | |||
=== مجالات الأسماء === | |||
قد تكون لاحظت في الأمثلة السابقة أننا لم نحدد مجال اسم (namespace) كامل لأصناف الأحداث. هذا لأن Echo يتوقع تلقائيا أن الأحداث موجودة في مجال الأسماء <code>App\Events</code>. لكن يمكنك ضبط جذر مجال الأسماء عند تشغيل Echo بتمرير خيار الضبط <code>namespace</code><syntaxhighlight lang="php"> | |||
window.Echo = new Echo({ | window.Echo = new Echo({ | ||
broadcaster: 'pusher', | |||
key: 'your-pusher-key', | |||
namespace: 'App.Other.Namespace' | |||
}); | }); | ||
طريقة أخرى هي سبق أصناف الأحداث بنقطة "." عند الانخراط فيها باستعمال Echo. سيسمح لك هذا بذكر اسم كامل للصنف | |||
</syntaxhighlight> | |||
طريقة أخرى هي سبق أصناف الأحداث بنقطة "." عند الانخراط فيها باستعمال Echo. سيسمح لك هذا بذكر اسم كامل للصنف<syntaxhighlight lang="php"> | |||
Echo.channel('orders') | Echo.channel('orders') | ||
.listen('.Namespace.Event.Class', (e) => { | |||
// | |||
}); | |||
</syntaxhighlight> | |||
== قنوات الحضور == | |||
تبني قنوات الحضور (presence) على أمان القنوات الخاصة في حين تستغل الخاصية الإضافية بالعلم بمن ينخرط في القناة. مما يسهل من بناء خاصيات قوية وتشاركية مثل تنبيه المستخدم حين يرى مستخدم آخر نفس الصفحة. | تبني قنوات الحضور (presence) على أمان القنوات الخاصة في حين تستغل الخاصية الإضافية بالعلم بمن ينخرط في القناة. مما يسهل من بناء خاصيات قوية وتشاركية مثل تنبيه المستخدم حين يرى مستخدم آخر نفس الصفحة. | ||
ترخيص قنوات الحضور | |||
كل قنوات الحضور قنواتٌ خاصةٌ، لذا، يجب الترخيص للمستخدمين لاستعمالها. لكن عند تعريف نداء ترخيص لقناة حضور، لن تعيد true إذا كان المستخدم مرخصًا له بل يجب أن تعيد مصفوفة ببيانات المستخدم. | === ترخيص قنوات الحضور === | ||
تكون البيانات الموفّرة من قبل نداء الترخيص متوفِّرة لمستمعي قنوات الحضور في تطبيق JavaScript. إذا لم يكن المستخدم مرخصًا له لدخول القناة، فيجب أن تعيد false أو null: | كل قنوات الحضور قنواتٌ خاصةٌ، لذا، يجب الترخيص للمستخدمين لاستعمالها. لكن عند تعريف نداء ترخيص لقناة حضور، لن تعيد <code>true</code> إذا كان المستخدم مرخصًا له بل يجب أن تعيد مصفوفة ببيانات المستخدم. | ||
تكون البيانات الموفّرة من قبل نداء الترخيص متوفِّرة لمستمعي قنوات الحضور في تطبيق JavaScript. إذا لم يكن المستخدم مرخصًا له لدخول القناة، فيجب أن تعيد <code>false</code> أو <code>null</code>: | |||
<syntaxhighlight lang="php"> | |||
Broadcast::channel('chat.{roomId}', function ($user, $roomId) { | Broadcast::channel('chat.{roomId}', function ($user, $roomId) { | ||
if ($user->canJoinRoom($roomId)) { | |||
return ['id' => $user->id, 'name' => $user->name]; | |||
} | |||
}); | }); | ||
الانضمام لقنوات الحضور | |||
للانضمام لقنوات الحضور، يمكنك استعمال التابع join. سيعيد هذا التابع تنفيذًا للتابع PresenceChannel الذي، بالإضافة لتوفير التابع | |||
</syntaxhighlight> | |||
=== الانضمام لقنوات الحضور === | |||
للانضمام لقنوات الحضور، يمكنك استعمال التابع <code>join</code>. سيعيد هذا التابع تنفيذًا للتابع <code>PresenceChannel</code> الذي، بالإضافة لتوفير التابع <code>listen</code>، يسمح أيضا بالانخراط في الأحداث <code>here</code> و <code>joining</code> و <code>leaving</code>. | |||
<syntaxhighlight lang="php"> | |||
Echo.join(`chat.${roomId}`) | Echo.join(`chat.${roomId}`) | ||
.here((users) => { | |||
// | |||
}) | |||
.joining((user) => { | |||
console.log(user.name); | |||
}) | |||
.leaving((user) => { | |||
console.log(user.name); | |||
يُنفَّذ النداء here مباشرة عند الانضمام الناجح للقناة، ويتلقى مصفوفة من بيانات المستخدم لبقية المستخدمين المنخرطين في القناة. يُنفَّذ التابع joining عندما انضم مستخدم جديد في حين ينفَّذ التابع leaving عندما يغادر مستخدم القناة. | }); | ||
البث لقنوات الحضور | |||
تتلقى قنوات الحضور أحداثًا مثل القنوات العامة أو الخاصة. باستخدام مثال غرف الرسائل، قد نريد بث الحدث NewMessage لقناة حضور الغرفة. للقيم بذلك، سنعيد نسخة PresenceChannel من التابع broadcastOn في الحدث: | </syntaxhighlight> | ||
يُنفَّذ النداء <code>here</code> مباشرة عند الانضمام الناجح للقناة، ويتلقى مصفوفة من بيانات المستخدم لبقية المستخدمين المنخرطين في القناة. يُنفَّذ التابع <code>joining</code> عندما انضم مستخدم جديد في حين ينفَّذ التابع <code>leaving</code> عندما يغادر مستخدم القناة. | |||
=== البث لقنوات الحضور === | |||
تتلقى قنوات الحضور أحداثًا مثل القنوات العامة أو الخاصة. باستخدام مثال غرف الرسائل، قد نريد بث الحدث <code>NewMessage</code> لقناة حضور الغرفة. للقيم بذلك، سنعيد نسخة <code>PresenceChannel</code> من التابع <code>broadcastOn</code> في الحدث:<syntaxhighlight lang="php"> | |||
/** | /** | ||
*الحصول على قناة البث. | |||
* | |||
* @return Channel|array | |||
public function broadcastOn() | */ | ||
public function broadcastOn() { | |||
return new PresenceChannel('room.'.$this->message->room_id); | |||
} | } | ||
مثل القنوات العامة والخاصة، يمكن بث أحداث في قنوات الحضور باستخدام الدالة broadcast. كما في بقية الأحداث، يإمكانك استخدام التابع toOthers لاستثناء المستخدم الحالي من تلقي البث: | |||
</syntaxhighlight> | |||
مثل القنوات العامة والخاصة، يمكن بث أحداث في قنوات الحضور باستخدام الدالة <code>broadcast</code>. كما في بقية الأحداث، يإمكانك استخدام التابع <code>toOthers</code> لاستثناء المستخدم الحالي من تلقي البث:<syntaxhighlight lang="php"> | |||
broadcast(new NewMessage($message)); | broadcast(new NewMessage($message)); | ||
broadcast(new NewMessage($message))->toOthers(); | broadcast(new NewMessage($message))->toOthers(); | ||
يمكنك الإستماع لأحداث الإنضمام عبر التابع listen: | |||
</syntaxhighlight> | |||
يمكنك الإستماع لأحداث الإنضمام عبر التابع <code>listen</code>: | |||
<syntaxhighlight lang="php"> | |||
Echo.join(`chat.${roomId}`) | Echo.join(`chat.${roomId}`) | ||
.here(...) | |||
.joining(...) | |||
.leaving(...) | |||
.listen('NewMessage', (e) => { | |||
// | |||
أحداث العملاء | }); | ||
ملاحظة: عند استعمال Pusher، عليك تفعيل الخيار "Client Events" في القسم "App Settings" من لوحة التحكم لقبول الأحداث من جهة العملاء. | |||
</syntaxhighlight> | |||
== أحداث العملاء == | |||
'''ملاحظة''': عند استعمال Pusher، عليك تفعيل الخيار "<code>Client Events</code>" في القسم "<code>App Settings</code>" من لوحة التحكم لقبول الأحداث من جهة العملاء. | |||
قد تريد في بعض الأحيان بث حدث لبقية المستخدمين دون المرور بتطبيق Laravel. يكون هذا مفيدًا في حالات مثل تنبيهات الكتابة، أين يمكنك أن تُعلم المستخدم أنّ مستخدمًا آخر بصدد الكتابة في شاشة معينة. | قد تريد في بعض الأحيان بث حدث لبقية المستخدمين دون المرور بتطبيق Laravel. يكون هذا مفيدًا في حالات مثل تنبيهات الكتابة، أين يمكنك أن تُعلم المستخدم أنّ مستخدمًا آخر بصدد الكتابة في شاشة معينة. | ||
لبث أحداث العملاء، يمكن استخدام التابع whisper: | |||
لبث أحداث العملاء، يمكن استخدام التابع <code>whisper</code>: | |||
<syntaxhighlight lang="php"> | |||
Echo.private('chat') | Echo.private('chat') | ||
.whisper('typing', { | |||
name: this.user.name | |||
للاستماع لأحداث العملاء، استخدم التابع listenForWhisper: | }); | ||
</syntaxhighlight> | |||
للاستماع لأحداث العملاء، استخدم التابع <code>listenForWhisper</code>:<syntaxhighlight lang="php"> | |||
Echo.private('chat') | Echo.private('chat') | ||
.listenForWhisper('typing', (e) => { | .listenForWhisper('typing', (e) => { | ||
console.log(e.name); | console.log(e.name); | ||
}); | }); | ||
</syntaxhighlight> | |||
عبر إرفاق بث الأحداث | |||
بعد ضبط التنبيهات لاستخدام قنوات البث، يمكنك الإستماع للأحداث باستعمال التابع notification. تذكر أن اسم القناة يجب أن يوافق اسم صنف الكائن المتلقي | == الإشعارات == | ||
عبر إرفاق بث الأحداث بالإشعارات، يتلقى تطبيق [[JavaScript]] الإشعارات حين تصل دون الحاجة لتحديث الصفحة. أولا، تأكد من الاطلاع على [[Laravel/notifications|توثيق الإشعارات]]. | |||
بعد ضبط التنبيهات لاستخدام قنوات البث، يمكنك الإستماع للأحداث باستعمال التابع <code>notification</code>. تذكر أن اسم القناة يجب أن يوافق اسم صنف الكائن المتلقي لللإشعار:<syntaxhighlight lang="php"> | |||
Echo.private(`App.User.${userId}`) | Echo.private(`App.User.${userId}`) | ||
.notification((notification) => { | |||
console.log(notification.type); | |||
في هذا المثال، يتلقى النداء كل التنبيهات المبعوثة إلى App\User عبر القناة broadcast. نداء ترخيص للقناة App.User.{id} يكون مضمنًا في مزود الخدمات BroadcastServiceProvider الذي يأتي مع الإطار Laravel. | }); | ||
مصادر | |||
صفحة Broadcasting في توثيق Laravel الرسمي. | </syntaxhighlight> | ||
في هذا المثال، يتلقى النداء كل التنبيهات المبعوثة إلى <code>App\User</code> عبر القناة <code>broadcast</code>. نداء ترخيص للقناة <code>App.User.{id}</code> يكون مضمنًا في مزود الخدمات <code>BroadcastServiceProvider</code> الذي يأتي مع الإطار [[Laravel]]. | |||
== مصادر == | |||
* [https://laravel.com/docs/5.6/broadcasting صفحة Broadcasting في توثيق Laravel الرسمي.] | |||
[[تصنيف:Laravel|{{SUBPAGENAME}}]] | |||
[[تصنيف:Laravel Digging deeper|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 14:03، 24 أكتوبر 2018
مقدمة
في العديد من التطبيقات الحديثة، تُستعمل Websockets لتنفيذ واجهات استخدام فورية ذات تحيين مباشر. عند رفع بعض البيانات للخادم، تُرسَل في العادة رسالة على اتصال websocket لتُعالَج من قبل العميل. يوفّر هذا بديلًا فعالًا للسحب المتواصل للتطبيق من أجل التغييرات. لمساعدتك في بناء هذا النوع من التطبيقات، يجعل Laravel من السهل "بث" أحداث عبر صلة websocket. يسمح بث الأحداث بمشاركة نفس الأحداث بين شيفرة من جهة الخادم وشيفرة من جهة العميل.
ملاحظة: قبل التعمق في بث الأحداث، تأكد من قراءة توثيق Laravel الخاص بالأحداث والمستمعات.
الضبط
تُخزّن كل خيارات ضبط البث في الملف config/broadcast.php
. يدعم Laravel برامج تشغيل بث عديدة من البداية مثل Pusher و Redis والمشغل المحلي log للبرمجة والإصلاح. وتتوافر أيضًا القيمة null
مما يسمح بالتعطيل الكامل لعملية البث. يوجد مثال ضبط لكل هذه المشغلات في الملف config/broadcast.php
.
مزودو خدمات البث
قبل بث أي حدث، يجب عليك أولا تسجيله في الملف App\Providers\BroadcastServiceProvider
. في التطبيقات الجديدة، ستحتاج إلى إلغاء التعليق في مصفوفة providers
من الملف config/app.php
. سيسمح هذا المزود بتسجيل مسارات الترخيص والنداءات.
الرمز المميز CSRF
يحتاج Laravel Echo الولوج لرموز CSRF للدورة الحالية. يجب أن تتأكد من أنّ العنصر <head>
في HTML يعرف العنصر <meta>
الذي يحتوي على الرمز CSRF:
<meta name="csrf-token" content="{{ csrf_token() }}">
متطلبات المشغّل
Pusher
إذا كنت تبث الأحداث باستخدام Pusher، فيجب عليك تثبيت Pusher PHP SDK باستعمال منظم الحزم Composer:
composer require pusher/pusher-php-server "~3.0"
ثم يتوجب عليك دفع اعتمادات Pusher للملف config/broadcast.php
. يتضمن الملف مثال ضبط Pusher
مما يسمح لك بتخصيص مفتاح، وسر، ومعرف Pusher
بسرعة. يسمح مثال الضبط بتخصيص خيارات options
أخرى يدعمها Pusher مثل cluster
.
'options' => [
'cluster' => 'eu',
'encrypted' => true
]
عند استعمال Pusher و Laravel ECHO، يجب تحديد pusher كخيار البث عند بدء نسخة Echo في الملف resources/assets/js/bootstrap.js
:
import Echo from "laravel-echo"
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-key'
});
Redis
إذا كنت تستعمل الباث Redis، يجب عليك تثبيت المكتبة Predis:
composer require predis/predis
يبث Redis الأحداث باستخدام الخاصية pub/sub لكن عليك إضافة خادم Websocket ليتلقى رسائل Redis و يبثها لقنوات Websocket.
عندما يبث Redis حدثًا، فسيُنشر على القناة المخصصة للحدث وسيحمل سلسلة محارف مشفرة بطريقة JSON تتضمن اسم الحدث ومعلومات data
ومعرف المستخدم الذي صنع التوصيل socket (إن أمكن).
Socket.io
إذا كنت ستضيف Socket.io للباث Redis، ستحتاج لإضافة مكتبة عميل JavaScript للتطبيق. يمكنك تثبيته عبر منظم الخدمات NPM:
npm install --save socket.io-client
ثم عليك بدء Echo بموصل socket.io و host:
import Echo from "laravel-echo"
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
أخيرا، عليك تشغيل خادم Socket.io متوافق. لا يتضمن Laravel خادم socket.io لكن هنالك خادمٌ يتكفل به المجتمع موجودٌ في github في المستودع tlaverdure/laravel-echo-server.
متطلبات طوابير الانتظار
قبل بث الأحداث, ستحتاج لضبط و تشغيل مستمعي طوابير الانتظار. يتم البث عن طريق مهمات موجودة في قائمات انتظار حتى لا يتأثر وقت اجابة التطبيق.
نظرة عامة على مفهوم البث
يسمح بث الأحداث في Laravel ببث أحداث من جهة الخادم إلى سكربات JavaScript التابعة لتطبيقك من جهة العميل باستخدام مقاربة مبنية على المشغلات في Websockets.
تبث الأحداث في قنوات "channels" قد تكون عامة أو خاصة. يمكن لأي مستخدم للتطبيق أن ينخرط في قناة عامة دون الحاجة لترخيص أو استيثاق. لكن للاستماع على قناة خاصة لا بد من الاستيثاق والترخيص.
استخدام تطبيق مثال
قبل التعمق في كل مكون من بث الأحداث، لنأخذ نظرة عامة على تطبيق تسوق إلكتروني على سبيل المثال. لن ندقق في ضبط Pusher أو Laravel Echo لأن ذلك مذكور في أقسام أخرى من التوثيق.
لنفترض أنّ لدينا في هذا التطبيق صفحة تسمح للمستخدم بالإطلاع على حالة شحن طلب معين. لنفترض أيضًا أن الحدث ShippingStatusUpdated
يُطلق كلما تم تحديث حالة طلب شحن يعالجه التطبيق:
event(new ShippingStatusUpdated($update));
الواجهة ShouldBroadcast
عندما يطّلع المستخدم على أحد طلباته، لا نريده أن يُحدّث الصفحة ليرى تحيين الحالة. بل نريد بث تحديثات التطبيق عند إنشائها. لذا يجب إضافة الواجهة ShouldBroadcast
للحدث ShippingStatusUpdated
. مما سيخبر Laravel أن يبث الحدث عند إطلاقه:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ShippingStatusUpdated implements ShouldBroadcast
{
/**
* معلومات عن حالة الشحن.
*
* @var string
*/
public $update;
}
تتطلب الواجهة من صنف الحدث تعريف التابع broadcastOn
. هذا التابع مسؤول عن إعادة القنوات التي على الحدث البث عليها. يكون التابع فارغًا في كل أصناف الأحداث المُنتجَة ونحتاج فقط لملء التفاصيل. نريد لصاحب الطلب فقط أن يرى حالة الشحن لذا سنبث الحدث على قناة خاصة مرتبطة بالطلب.
/**
* الحصول على معلومات على قناة البث.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('order.'.$this->update->order_id);
}
ترخيص القنوات
تذكر انّ المستخدم يجب أن يسجل الدخول ليستمع للقنوات الخاصة. يمكن تعريف قواعد تراخيص القناة في routes/channels.php
. في هذا المثال، يجب التأكد من أن المستخدم الذي يريد الاستماع على القناة الخاصة order.1
هو صاحب الطلب:
Broadcast::channel('order.{orderId}', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});
يقبل التابع channel
معاملين: اسم القناة ونداء يُرجع القيمة true
أو false
للدلالة على إذا كان المستخدم يملك ترخيصًا للاستماع على القناة أم لا.
كل نداءات التراخيص تتلقى المستخدم المسجل حاليا كمعامل أول و معامل بديل عن أي معامل إضافي. في هذا المثال، نستخدم البديل {orderId}
للإعلام أنّ القسم "ID" من اسم القناة متغير.
الاستماع لبث الحدث
بعد ذلك، كل ما تبقى هو الإستماع للحدث في شيفرة JavaScript
للتطبيق. يمكن القيام بهذا باستعمال Laravel Echo. أولًا، نستعمل التابع private
للدخول إلى القناة الخاصة. ثم، يمكننا استعمال التابع listen
للاستماع للحدث ShippingStatusUpdated
. في العادة، كل الخاصيات العامة للحدث تُضمَّن في حدث البث:
Echo.private(`order.${orderId}`)
.listen('ShippingStatusUpdated', (e) => {
console.log(e.update);
});
تعريف أحداث البث
لإعلام Laravel أن حدثا ما يجب بثّه، نفذ الواجهةIlluminate\Contracts\Broadcasting\ShouldBroadcast
في صنف الحدث. تُحمَّل هذه الواجهة في كل أصناف الأحداث لذا يمكنك إضافتها بسهولة لأي حدث.
تتطلب الواجهة ShouldBroadcast
كتابة تابع وحيد هو broadcastOn
. يعيد هذا التابع قناة أو مصفوفة قنوات يبث عليها الحدث. يجب أن تكون القناة نسخة Channel
أو PrivateChannel
أو PresenceChannel
. تمثل نسخة Channel
القنوات العامة التي يمكن لأي مستخدم الدخول فيها في حين PrivateChannel
و PresenceChannel
تمثل قنوات تتطلب ترخيصًا:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel; use Illuminate\Queue\SerializesModels; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ServerCreated implements ShouldBroadcast {
use SerializesModels;
public $user;
/**
* إنشاء نسخة حدث جديد
*
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* جلب القنوات التي يجب من الحدث البث فيها
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'.$this->user->id);
}
}
ثم عليك إطلاق حدث كما تفعل عادة. عند إطلاق الحدث، تبث مهمة في قائمة الإنتظار آليًا الحدث على المشغل الذي اخترته.
اسم البث
في العادة، يبث Laravel الأحداث باستخدام أسماء أصناف الأحداث. لكن بإمكانك تخصيص اسم البث عبر تعريف التابع broadcastAs
في الحدث:
/**
* اسم الحدث.
*
* @return string
*/
public function broadcastAs() {
return 'server.created';
}
إذا غيّرت اسم البث باستخدام broadcastAs
، يجب عليك التأكد من تسجيل المستمع مسبوقًا بالرمز ".". سيُخبر هذا Echo بإضافة مجال أسماء للحدث:
.listen('.server.created', function (e) {
....
});
بيانات البث
عند بث حدث، تتم سلسلة كل خاصياته العامة آليًا كتحميل للحدث، مما يسمح لك بالولوج لكل بياناته العامة من تطبيق JavaScript. لذا لو كان للحدث خاصية واحدة user$
مثلًا تحتوي على نموذج Eloquent، يكون نحميل البث كما يلي:
{
"user": {
"id": 1,
"name": "Patrick Stewart"
...
}
}
لكن إذا أردت تحكما أفضل في تحميل البث، يمكنك إضافة التابع broadcastWith
. يعيد هذا التابع مصفوفة البيانات التي تريد إرسالها كتحميل للبث:
/**
* بيانات البث
*
* @return array
*/
public function broadcastWith() {
return ['id' => $this->user->id];
}
طابور انتظار البث
في العادة، يوضع كل أحداث البث في طابور الانتظار الأولية للصلة الأولية المعرّفة في ملف الضبط queue.php
. يمكنك تخصيص طابور انتظار البث عبر تعريف الخاصية broadcastQueue
في صنف الحدث. يجب أن تحدد هذه الخاصية اسم طابور الانتظار الذي تود استعماله عند البث:
/**
* اسم قائمة الإنتظار.
*
* @var string
*/
public $broadcastQueue = 'your-queue-name';
إذا أردت بث الأحداث باستعمال طابور الانتظار sync
بدل المشغل العادي، يمكنك تنفيذ shouldBroadcastNow
بدل ShouldBoradcast
:
<?php
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class ShippingStatusUpdated implements ShouldBroadcastNow
{
//
}
شروط البث
في بعض الأحيان، قد تريد بث الأحداث فقط إن تحقق شرط معين. يمكنك تحديد هذه الشروط عبر إضافة التابع broadcastWhen
لصنف الحدث:
/**
* تحديد إذا كان يجب بث الحدث
*
* @return bool
*/
public function broadcastWhen() {
return $this->value > 100;
}
الترخيص للقنوات
تتطلب القنوات الخاصة ترخيصًا ليتمكن المستخدم المسجل حاليًا من الإستماع إليها. يتم هذا عبر إطلاق طلب HTTP للتطبيق باسم القناة وجعل التطبيق يقرر هل يسمح للمستخدم بالإستماع أم لا. عند استخدام Laravel Echo، يُصنع طلب HTTP للترخيص بالإنخراط في القنوات الخاصة تلقائيًا. لكن عليك تعريف المسار للإجابة على الطلب.
تعريف مسارات الترخيص
من حسن الحظ، يجعل Laravel تعريف المسارات لإجابة طلبات الترخيص أمرًا سهلًا. في مزود الخدمات BroadcastServiceProvider
المضمن في تطبيق Laravel، سترى نداء للتابع Broadcast::routes
. سيسجل هذا التابع المسار broadcasting/auth
لمعالجة طلبات الترخيص.
Broadcast::routes();
يضع التابع Broadcast::routes
آليًا مساراته في في مجموعة الوسيط web
لكن بإمكانك تمرير أي صفوفة من خصائص المسارات للتابع إذا أردت تخصيص الخاصيات.
Broadcast::routes($attributes);
تعريف نداءات الترخيص
بعد ذلك، نحتاج لتعريف التحكم المنطقي الذي سيقوم بالترخيص. يتم هذا في الملف routes/channels.php
في التطبيق. في هذا الملف، يمكنك استخدام التابع Broadcast::channel
لتسجيل نداءات ترخيص القنوات:
Broadcast::channel('order.{orderId}', function ($user, $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});
يقبل التابع channel
معاملين وهما اسم القناة ودالة رد نداء تعيد القيمة true
أو false
للدلالة على إذا كان المستخدم يملك ترخيصًا للاستماع أم لا.
كل نداءات التراخيص تتلقى المستخدم المسجل حاليًا كمعامل أول و معامل بديل عن أي معامل إضافي. في المثال السابق، نستخدم البديل {orderId}
للإعلام أنّ القسم "ID
" من اسم القناة متغير.
ترخيص نداءات ربط النماذج
مثل مسارات HTTP، تستفيد مسارات القنوات من ربط النماذج المباشر و غير المباشر. مثلًا، بدل تلقي سلسلة محارف أو معرّف رقمي، يمكن أن تطلب نسخة من Order
:
use App\Order;
Broadcast::channel('order.{order}', function ($user, Order $order) {
return $user->id === $order->user_id;
});
تعريف أصناف القنوات
إذا كان التطبيق يستعمل العديد من القنوات، سيصبح الملف routes/channels.php
ضخمًا. لذا، بدل استعمال Closure
لترخيص القنوات، يمكن استعمال أصناف للقنوات. لإنشاء أصناف القنوات، استعمل الأمر make:channel
. سيضع الأمر الأصناف المصنوعة في المجلد App/Broadcasting
php artisan make:channel OrderChannel
ثم سجل الصنف في الملف routes/channels.php
use App\Broadcasting\OrderChannel;
Broadcast::channel('order.{order}', OrderChannel::class);
أخيرًا، يمكنك وضع التحكم المنطقي في الترخيص في الصنف في التابع join
. سيحتوي هذا التابع نفس الشيفرة التي كنت ستضعها في عادة في القسم Closure
. يمكن طبعًا الاستفادة من ربط النماذج هنا أيضًا.
<?php
namespace App\Broadcasting;
use App\User; use App\Order;
class OrderChannel {
/**
* إنشاء نسخة قناة جديدة
*
* @return void
*/
public function __construct()
{
//
}
/**
* استيثاق مستخدم القناة
*
* @param \App\User $user
* @param \App\Order $order
* @return array|bool
*/
public function join(User $user, Order $order)
{
return $user->id === $order->user_id;
}
}
ملاحظة: كالعديد من الأصناف في Laravel، تُعالج أصناف القنوات في حاوي الخدمات. لذا يمكنك التلميح إلى نوع الإعتماديات التي تحتاج لها القناة في باني الصنف التي يحتاجها باني الصنف.
بث الأحداث
بعد تعريف الحدث وإضافة الواجهة ShouldBroadcast
، تحتاج فقط لإطلاق الحدث باستعمال الدالة event
. سيُلاحظ مُطلِق الأحداث أن الحدث تم ترميزه بالواجهة ShouldBroadcast
ويضيفه لقائمة انتظار البث:
event(new ShippingStatusUpdated($update));
فقط للآخرين
عند بناء تطبيق يستعمل تقنية البث، يمكنك تعويض الدالة event
بالدالة broadcast
. مثل event
، يُطلق broadcast
الحدث من جهة الخادم للمستمع في جهة العميل
broadcast(new ShippingStatusUpdated($update));
لكن الدالة broadcast
توفر أيضًا التابع toOthers
الذي يسمح باستثناء المستخدم الحالي من لائحة المستقبلين:
broadcast(new ShippingStatusUpdated($update))->toOthers();
لفهم أفضل متى قد تريد استعمال التابع toOthers
، لنتخيل تطبيقا للائحة مهام حيث يمكن للمستخدم صناعة مهمة جديدة بتمرير اسم المهمة. لإنشاء مهمة، يبعث التطبيق طلبًا لنقطة النهاية task/ التي تبث صناعة المهمة وتعيد تمثيل JSON
للمهمة الجديدة. يتلقى تطبيق javascript
الجواب من نقطة النهاية، يمكنه إضافة المهمة الجديدة للائحته كالآتي
axios.post('/task', task)
.then((response) => {
this.tasks.push(response.data);
});
لكن تذكر أننا نبث أيضًا صناعة المهمة، إذا كان تطبيق JavaScript يستمع للحدث ليضيف المهام الجديدة للائحة المهام، سيكون لديك نفس المهمة مرتين: واحد من نقطة النهاية وواحد من البث. يمكن حل هذا المشكل باستخدام التابع toOthers
لإعلام الباث بعدم بث الحدث للمستخدم الحالي.
تنبيه: يجب على الحدث استخدام الخاصية Illuminate\Broadcasting\InteractsWithSockets
للاستعمال التابع toOthers
.
الضبط
عند بدء مثيل Laravel Echo، يُعطى معرّف توصيل (Socket id) للصلة. إذا كنت تستخدم Vue و Axios، يُرفق المعرّف تلقائيًا بكل طلب خارج كعنوان x-socket-ID
. ثم عندما تنادي التابع toOthers
، يأخذ Laravel المعرّف من العنوان ويأمر الباث بعدن البث لأي صلة تحمل ذلك المعرّف.
إذا كنت لا تستخدم Vue
و Axios
، ستحتاج لضبط تطبيق JavaScript يدويًا ليُرسل العنوان x-socket-ID
. يمكنك استرجاع معرّف التوصيل بالتابع Echo.socketID
:
var socketId = Echo.socketId();
تلقي البث
تثبيت Laravel echo
Laravel Echo هي مكتبة Javascript تجعل الانخراط في قناة و والإستماع للأحداث أمرًا سهلًا. يمكنك تثبيت Echo عبر منظم الحزم NPM. في هذا المثال، سنثبت أيضًا pusher-js
حيث سنستخدم المشغل pusher للبث:
npm install --save laravel-echo pusher-js
بعد تثبيت Echo، أنت الآن جاهزٌ لإنشاء نسخة Echo في تطبيق JavaScript. نهاية الملف resources/assets/js/bootstrap.js
هي مكان جيد للقيام بهذا:
import Echo from "laravel-echo"
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-key'
});
عند إنشاء نسخة Echo يستخدم الباث pusher، يمكنك أيضًا تخصيص cluster بالإضافة إلى تحديد إذا ما كانت الصلة تستوجب تشفيرًا:
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-key',
cluster: 'eu',
encrypted: true
});
الاستماع للأحداث
بعد تثبيت Echo و تشغيله، أنت الآن جاهز للاستماع للأحداث. أولًا، استخدم التابع channel
لإعادة نسخة من القناة، ثم استدع التابع listen
لحدث معين:
Echo.channel('orders')
.listen('OrderShipped', (e) => {
console.log(e.order.name);
});
إذا أردت الاستماع لأحداث في قناة خاصة، استعمل التابع private
بدل channel
. يمكنك المواصلة في إضافة نداءات listen
للاستماع لعدة أحداث في قناة واحدة
Echo.private('orders')
.listen(...)
.listen(...)
.listen(...);
مغادرة قناة
لمغادرة قناة، ينكنك نداء التابع leave
في نسخة Echo:
Echo.leave('orders');
مجالات الأسماء
قد تكون لاحظت في الأمثلة السابقة أننا لم نحدد مجال اسم (namespace) كامل لأصناف الأحداث. هذا لأن Echo يتوقع تلقائيا أن الأحداث موجودة في مجال الأسماء App\Events
. لكن يمكنك ضبط جذر مجال الأسماء عند تشغيل Echo بتمرير خيار الضبط namespace
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-pusher-key',
namespace: 'App.Other.Namespace'
});
طريقة أخرى هي سبق أصناف الأحداث بنقطة "." عند الانخراط فيها باستعمال Echo. سيسمح لك هذا بذكر اسم كامل للصنف
Echo.channel('orders')
.listen('.Namespace.Event.Class', (e) => {
//
});
قنوات الحضور
تبني قنوات الحضور (presence) على أمان القنوات الخاصة في حين تستغل الخاصية الإضافية بالعلم بمن ينخرط في القناة. مما يسهل من بناء خاصيات قوية وتشاركية مثل تنبيه المستخدم حين يرى مستخدم آخر نفس الصفحة.
ترخيص قنوات الحضور
كل قنوات الحضور قنواتٌ خاصةٌ، لذا، يجب الترخيص للمستخدمين لاستعمالها. لكن عند تعريف نداء ترخيص لقناة حضور، لن تعيد true
إذا كان المستخدم مرخصًا له بل يجب أن تعيد مصفوفة ببيانات المستخدم.
تكون البيانات الموفّرة من قبل نداء الترخيص متوفِّرة لمستمعي قنوات الحضور في تطبيق JavaScript. إذا لم يكن المستخدم مرخصًا له لدخول القناة، فيجب أن تعيد false
أو null
:
Broadcast::channel('chat.{roomId}', function ($user, $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
});
الانضمام لقنوات الحضور
للانضمام لقنوات الحضور، يمكنك استعمال التابع join
. سيعيد هذا التابع تنفيذًا للتابع PresenceChannel
الذي، بالإضافة لتوفير التابع listen
، يسمح أيضا بالانخراط في الأحداث here
و joining
و leaving
.
Echo.join(`chat.${roomId}`)
.here((users) => {
//
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
});
يُنفَّذ النداء here
مباشرة عند الانضمام الناجح للقناة، ويتلقى مصفوفة من بيانات المستخدم لبقية المستخدمين المنخرطين في القناة. يُنفَّذ التابع joining
عندما انضم مستخدم جديد في حين ينفَّذ التابع leaving
عندما يغادر مستخدم القناة.
البث لقنوات الحضور
تتلقى قنوات الحضور أحداثًا مثل القنوات العامة أو الخاصة. باستخدام مثال غرف الرسائل، قد نريد بث الحدث NewMessage
لقناة حضور الغرفة. للقيم بذلك، سنعيد نسخة PresenceChannel
من التابع broadcastOn
في الحدث:
/**
*الحصول على قناة البث.
*
* @return Channel|array
*/
public function broadcastOn() {
return new PresenceChannel('room.'.$this->message->room_id);
}
مثل القنوات العامة والخاصة، يمكن بث أحداث في قنوات الحضور باستخدام الدالة broadcast
. كما في بقية الأحداث، يإمكانك استخدام التابع toOthers
لاستثناء المستخدم الحالي من تلقي البث:
broadcast(new NewMessage($message));
broadcast(new NewMessage($message))->toOthers();
يمكنك الإستماع لأحداث الإنضمام عبر التابع listen
:
Echo.join(`chat.${roomId}`)
.here(...)
.joining(...)
.leaving(...)
.listen('NewMessage', (e) => {
//
});
أحداث العملاء
ملاحظة: عند استعمال Pusher، عليك تفعيل الخيار "Client Events
" في القسم "App Settings
" من لوحة التحكم لقبول الأحداث من جهة العملاء.
قد تريد في بعض الأحيان بث حدث لبقية المستخدمين دون المرور بتطبيق Laravel. يكون هذا مفيدًا في حالات مثل تنبيهات الكتابة، أين يمكنك أن تُعلم المستخدم أنّ مستخدمًا آخر بصدد الكتابة في شاشة معينة.
لبث أحداث العملاء، يمكن استخدام التابع whisper
:
Echo.private('chat')
.whisper('typing', {
name: this.user.name
});
للاستماع لأحداث العملاء، استخدم التابع listenForWhisper
:
Echo.private('chat')
.listenForWhisper('typing', (e) => {
console.log(e.name);
});
الإشعارات
عبر إرفاق بث الأحداث بالإشعارات، يتلقى تطبيق JavaScript الإشعارات حين تصل دون الحاجة لتحديث الصفحة. أولا، تأكد من الاطلاع على توثيق الإشعارات.
بعد ضبط التنبيهات لاستخدام قنوات البث، يمكنك الإستماع للأحداث باستعمال التابع notification
. تذكر أن اسم القناة يجب أن يوافق اسم صنف الكائن المتلقي لللإشعار:
Echo.private(`App.User.${userId}`)
.notification((notification) => {
console.log(notification.type);
});
في هذا المثال، يتلقى النداء كل التنبيهات المبعوثة إلى App\User
عبر القناة broadcast
. نداء ترخيص للقناة App.User.{id}
يكون مضمنًا في مزود الخدمات BroadcastServiceProvider
الذي يأتي مع الإطار Laravel.