شرح Laravel Notifications: إرسال الإشعارات عبر Mail وDatabase وSMS وBroadcast وQueues

تعتبر Notifications من أهم الأدوات التي توفرها Laravel لإبلاغ المستخدمين بالأحداث التي تحدث داخل التطبيق.

فمثلاً قد نحتاج إلى إرسال إشعار عندما:

  • يتم إنشاء حساب جديد.
  • يتغير وضع طلب شراء.
  • يتم دفع فاتورة.
  • يتم الرد على تعليق أو سؤال.
  • يتم تسجيل دخول جديد إلى الحساب.
  • تتم إضافة رسالة أو إشعار إداري.

بدلاً من كتابة منطق منفصل لكل طريقة إرسال، توفر Laravel نظام Notifications موحداً يسمح بإرسال نفس الإشعار عبر قناة واحدة أو عدة قنوات مثل:

Mail
Database
Broadcast
SMS
Slack

وفي هذا المقال سنتعرف بالتفصيل على إنشاء Notifications وإرسالها وتخزينها في قاعدة البيانات ووضعها في Queue والتعامل مع الإشعارات المقروءة وغير المقروءة.

ما هي Laravel Notifications؟

Notification عبارة عن Class يمثل إشعاراً معيناً في التطبيق.

مثلاً:

NewUserNotification
OrderShipped
InvoicePaid
NewMessage
PasswordChanged

ثم تحدد داخل هذا Class القنوات التي تريد إرسال الإشعار من خلالها.

على سبيل المثال:

User Registered
      │
      ▼
Notification
      │
      ├── Mail
      │
      ├── Database
      │
      └── Broadcast

وبهذا لا نحتاج إلى إنشاء منطق مختلف لكل قناة.

ما الفرق بين Mailable وNotification؟

قد يتساءل البعض عن الفرق بين Laravel Mailables وNotifications.

MailableNotification
مخصصة بشكل أساسي للبريد الإلكترونييمكن إرسالها عبر عدة Channels
مناسبة للرسائل البريدية الكاملةمناسبة للإشعارات القصيرة المرتبطة بحدث
Email-centricMulti-channel
يمكن أن تحتوي على Templates معقدةتركز على إشعار المستخدم بحدث

إذا كنت ترسل فاتورة Email كاملة، يمكن أن تكون Mailable مناسبة.

أما إذا كنت تريد إعلام المستخدم بأن فاتورته تم دفعها عن طريق Email وDatabase وSMS في الوقت نفسه، فإن Notification غالباً أنسب.

قنوات Notifications في Laravel

Laravel توفر مجموعة من Channels الرسمية.

Mail

إرسال الإشعار عن طريق البريد الإلكتروني.

Database

تخزين الإشعار داخل قاعدة البيانات ليظهر لاحقاً داخل الموقع أو لوحة التحكم.

Broadcast

إرسال الإشعار في الوقت الحقيقي إلى الواجهة باستخدام نظام Broadcasting.

Vonage

تستخدم لإرسال SMS من خلال Vonage.

Slack

إرسال الإشعارات إلى Slack.

كما يمكن إنشاء Custom Notification Channels أو استخدام Community Channels لخدمات أخرى مثل Telegram وغيرها.

إنشاء Notification

يمكن إنشاء Notification باستخدام Artisan:

php artisan make:notification NewUserNotification

سيتم إنشاء:

app/Notifications/NewUserNotification.php

الشكل الأساسي للـ Notification

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class NewUserNotification extends Notification
{
    use Queueable;


    public function __construct()
    {
    }


    public function via(object $notifiable): array
    {
        return [
            'mail',
        ];
    }


    public function toMail(
        object $notifiable
    ): MailMessage {

        return (new MailMessage)
            ->line(
                'Welcome to our application.'
            )
            ->action(
                'Visit Your Account',
                url('/')
            )
            ->line(
                'Thank you for using our application.'
            );
    }


    public function toArray(
        object $notifiable
    ): array {

        return [];
    }
}

ما هي via()؟

الدالة:

via()

تحدد Channels التي سيتم إرسال Notification من خلالها.

مثلاً:

public function via(
    object $notifiable
): array {

    return [
        'mail',
        'database',
    ];
}

يعني أن Laravel سترسل الإشعار عبر:

Email
+
Database

اختيار Channel بناءً على المستخدم

لا يشترط أن ترسل جميع المستخدمين عبر القنوات نفسها.

يمكن مثلاً كتابة:

public function via(
    object $notifiable
): array {

    if ($notifiable->prefers_sms) {

        return [
            'vonage',
        ];

    }

    return [
        'mail',
        'database',
    ];
}

وبالتالي يمكن جعل Channels ديناميكية حسب إعدادات المستخدم.

Notifiable Trait

حتى يستطيع Model استقبال Notifications يجب أن يستخدم:

Illuminate\Notifications\Notifiable

مثلاً:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;
}

Laravel تضيف هذا Trait إلى User Model بشكل افتراضي في المشاريع المعتادة.

لكن يمكنك استخدامه مع Models أخرى أيضاً.

مثلاً:

Admin
Customer
Vendor
Employee

إرسال Notification إلى مستخدم

بعد إضافة Notifiable يمكن استخدام:

use App\Notifications\NewUserNotification;

$user->notify(
    new NewUserNotification()
);

Laravel ستقرأ:

via()

ثم ترسل Notification إلى القنوات المحددة.

تمرير بيانات إلى Notification

في أغلب الحالات نحتاج إلى تمرير Model أو بيانات.

مثلاً:

php artisan make:notification OrderShipped

ثم:

public function __construct(
    public Order $order
) {
}

وعند الإرسال:

$user->notify(
    new OrderShipped($order)
);

إنشاء Mail Notification

إذا كان:

via()

يحتوي على:

'mail'

فإن Laravel تستخدم:

toMail()

مثال Mail Notification

public function toMail(
    object $notifiable
): MailMessage {

    return (new MailMessage)

        ->subject(
            'تم شحن طلبك'
        )

        ->greeting(
            'مرحباً ' . $notifiable->name
        )

        ->line(
            'تم شحن طلبك بنجاح.'
        )

        ->action(
            'عرض الطلب',
            url(
                '/orders/' . $this->order->id
            )
        )

        ->line(
            'شكراً لاستخدام خدماتنا.'
        );
}

أهم دوال MailMessage

يمكن استخدام:

->subject()
->greeting()
->line()
->action()
->salutation()

مثلاً:

return (new MailMessage)

    ->subject(
        'Account Created'
    )

    ->greeting(
        'Hello!'
    )

    ->line(
        'Your account has been created.'
    )

    ->action(
        'Open Account',
        url('/dashboard')
    )

    ->salutation(
        'Thanks, My Company'
    );

Database Notifications

من أكثر أنواع Notifications استخداماً تخزين الإشعارات داخل قاعدة البيانات.

مثلاً عندما تدخل إلى تطبيق وترى:

Notifications (5)

فغالباً يتم تخزين هذه الإشعارات في Database مع حالة:

read
unread

إنشاء جدول Notifications

لتخزين الإشعارات نحتاج إلى جدول:

notifications

يمكن إنشاء Migration باستخدام:

php artisan make:notifications-table

ثم:

php artisan migrate

شكل جدول Notifications

يحتوي عادة على حقول مثل:

id
type
notifiable_type
notifiable_id
data
read_at
created_at
updated_at

حقل:

data

يحتوي بيانات Notification.

أما:

read_at

فيحدد هل تم قراءة Notification أم لا.

تفعيل Database Channel

داخل:

via()

أضف:

public function via(
    object $notifiable
): array {

    return [
        'mail',
        'database',
    ];
}

استخدام toDatabase()

يمكن تحديد البيانات التي سيتم تخزينها باستخدام:

toDatabase()

مثلاً:

public function toDatabase(
    object $notifiable
): array {

    return [

        'title' => 'تم شحن الطلب',

        'message' =>
            'تم شحن طلبك بنجاح.',

        'order_id' =>
            $this->order->id,

        'url' =>
            url(
                '/orders/' .
                $this->order->id
            ),

    ];
}

استخدام toArray()

يمكن أيضاً استخدام:

toArray()

لتوفير البيانات المستخدمة بواسطة Database أو بعض القنوات الأخرى عندما لا يوجد Formatter مخصص لها.

مثلاً:

public function toArray(
    object $notifiable
): array {

    return [

        'message' =>
            'تم إنشاء الحساب بنجاح.',

    ];
}

ما الفرق بين toDatabase() وtoArray()؟

إذا عرفت:

toDatabase()

فستستخدم Laravel هذه الدالة لتنسيق البيانات المخصصة لـ Database Channel.

أما:

toArray()

فهي Representation عامة يمكن استخدامها عندما لا توجد طريقة مخصصة للقناة.

في التطبيقات الكبيرة يفضل غالباً استخدام:

toDatabase()

إذا كنت تريد أن يكون شكل Database Notification مختلفاً عن القنوات الأخرى.

مثال Notification عبر Mail وDatabase

<?php

namespace App\Notifications;

use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class OrderShipped extends Notification
{
    use Queueable;


    public function __construct(
        public Order $order
    ) {
    }


    public function via(
        object $notifiable
    ): array {

        return [
            'mail',
            'database',
        ];
    }


    public function toMail(
        object $notifiable
    ): MailMessage {

        return (new MailMessage)

            ->subject(
                'تم شحن طلبك'
            )

            ->line(
                'تم شحن الطلب #' .
                $this->order->id
            )

            ->action(
                'عرض الطلب',
                url(
                    '/orders/' .
                    $this->order->id
                )
            );
    }


    public function toDatabase(
        object $notifiable
    ): array {

        return [

            'title' =>
                'تم شحن الطلب',

            'message' =>
                'تم شحن الطلب #' .
                $this->order->id,

            'order_id' =>
                $this->order->id,

        ];
    }
}

قراءة جميع Notifications للمستخدم

Notifiable Trait توفر Relationship جاهزة:

$user->notifications

مثلاً:

$notifications =
    auth()->user()
        ->notifications;

قراءة Notifications غير المقروءة

$notifications =
    auth()->user()
        ->unreadNotifications;

مثلاً:

@foreach(
    auth()->user()->unreadNotifications
    as $notification
)

    {{ $notification->data['message'] }}

@endforeach

قراءة Notifications المقروءة

$notifications =
    auth()->user()
        ->readNotifications;

عرض عدد الإشعارات غير المقروءة

{{ auth()
    ->user()
    ->unreadNotifications
    ->count()
}}

مثلاً:

Notifications (7)

Mark Notification As Read

يمكن تحديد إشعار واحد كمقروء:

$notification
    ->markAsRead();

تحديد جميع الإشعارات كمقروءة

auth()
    ->user()
    ->unreadNotifications
    ->markAsRead();

التحديد كمقروء باستخدام Query

إذا كان عدد Notifications كبيراً، فمن الأفضل في كثير من الحالات تحديثها من قاعدة البيانات مباشرة.

auth()
    ->user()
    ->unreadNotifications()
    ->update([
        'read_at' => now(),
    ]);

وهذا يتجنب تحميل جميع Notifications إلى الذاكرة أولاً.

حذف Notification واحدة

$notification->delete();

حذف جميع Notifications للمستخدم

auth()
    ->user()
    ->notifications()
    ->delete();

عدم تحميل آلاف Notifications دفعة واحدة

في التطبيقات الحقيقية قد يمتلك المستخدم آلاف الإشعارات.

لذلك لا يفضل دائماً:

$user->notifications

لعرض جميع السجلات.

الأفضل استخدام Pagination:

$notifications =
    auth()
        ->user()
        ->notifications()
        ->latest()
        ->paginate(20);

إرسال Notification لعدة مستخدمين

بدلاً من تنفيذ:

foreach ($users as $user) {

    $user->notify(
        new NewUserNotification()
    );

}

يمكن استخدام Notification Facade:

use Illuminate\Support\Facades\Notification;

Notification::send(
    $users,
    new NewUserNotification()
);

On-Demand Notifications

ليس من الضروري أن يكون المستلم User محفوظاً في قاعدة البيانات.

يمكن إرسال Notification مباشرة إلى Email:

use Illuminate\Support\Facades\Notification;

Notification::route(
    'mail',
    'customer@example.com'
)->notify(
    new InvoicePaid($invoice)
);

وهذا مفيد مثلاً عندما نريد إرسال Notification لشخص لا يمتلك Account داخل التطبيق.

إرسال On-Demand لعدة Channels

Notification::routes([

    'mail' =>
        'customer@example.com',

    'vonage' =>
        '970599000000',

])->notify(
    new InvoicePaid($invoice)
);

Routing Notifications

بشكل افتراضي ستستخدم Mail Notification عادة حقل:

email

في Model.

لكن يمكن تخصيص ذلك باستخدام:

routeNotificationForMail()

مثلاً:

public function routeNotificationForMail(
    Notification $notification
): array|string {

    return $this->work_email;

}

Queueing Notifications

بعض Channels تتطلب الاتصال بخدمات خارجية.

مثلاً:

Email Provider
SMS API
Slack API

إذا تم إرسالها داخل HTTP Request مباشرة، فقد تزيد مدة استجابة المستخدم.

لذلك توفر Laravel إمكانية Queueing Notifications.

تحويل Notification إلى Queue

نضيف:

ShouldQueue

إلى Class.

use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped
    extends Notification
    implements ShouldQueue
{
    use Queueable;
}

بعدها عندما نكتب:

$user->notify(
    new OrderShipped($order)
);

سيتم وضع عملية إرسال Notification في Queue.

لماذا Queue مهمة؟

بدون Queue:

User Request
     │
     ▼
Send Mail
     │
     ▼
Call SMS API
     │
     ▼
Wait
     │
     ▼
Response

مع Queue:

User Request
     │
     ▼
Queue Notification
     │
     ▼
Response


Queue Worker
     │
     ├── Mail
     ├── SMS
     └── Slack

وهذا يجعل التطبيق أسرع بالنسبة للمستخدم.

تشغيل Queue Worker

بعد إعداد Queue:

php artisan queue:work

وفي Production يجب تشغيل Queue Worker من خلال Process Manager مناسب حتى يبقى عاملاً باستمرار.

تأخير Notification

يمكن تأخير الإرسال:

$user->notify(

    (new OrderShipped($order))
        ->delay(
            now()->addMinutes(10)
        )

);

تأخير مختلف لكل Channel

يمكن تحديد Delay مختلف للقنوات.

public function withDelay(
    object $notifiable
): array {

    return [

        'mail' =>
            now()->addMinutes(5),

        'vonage' =>
            now()->addMinutes(10),

    ];
}

وهذه طريقة منظمة عندما يكون لكل Channel وقت إرسال مختلف.

Queue مختلفة لكل Channel

Laravel تسمح بتخصيص Queue لكل Channel باستخدام:

viaQueues()

مثلاً:

public function viaQueues(): array
{
    return [

        'mail' =>
            'mail-queue',

        'slack' =>
            'slack-queue',

    ];
}

وبهذا تستطيع فصل Email Jobs عن بقية Notifications.

Connection مختلفة لكل Channel

يمكن أيضاً تخصيص Queue Connection من خلال:

viaConnections()

مثلاً:

public function viaConnections(): array
{
    return [

        'mail' => 'redis',

        'database' => 'sync',

    ];
}

Notifications وDatabase Transactions

هناك نقطة مهمة جداً عند استخدام Queued Notifications.

إذا قمت بإنشاء Model داخل Database Transaction وأرسلت Notification قبل انتهاء Transaction، فقد يبدأ Queue Worker في معالجة Notification قبل تنفيذ Commit.

مثلاً:

DB Transaction
     │
     ├── Create Order
     │
     ├── Queue Notification
     │
     └── Commit

إذا كان Queue سريعاً جداً فقد يبحث عن Order قبل أن يتم Commit.

لذلك يمكن استخدام:

->afterCommit()

عند الحاجة.

مثال afterCommit()

$user->notify(

    (new OrderShipped($order))
        ->afterCommit()

);

وبهذا لن يتم إرسال Queued Notification إلا بعد نجاح Database Transaction.

Broadcast Notifications

إذا كنت تريد ظهور Notification مباشرة في واجهة المستخدم دون إعادة تحميل الصفحة، يمكن استخدام:

broadcast

Channel.

مثلاً:

public function via(
    object $notifiable
): array {

    return [
        'database',
        'broadcast',
    ];
}

ثم تستخدم Laravel Broadcasting في Frontend للاستماع إلى Notification.

Database + Broadcast أفضل لعداد الإشعارات

سيناريو شائع هو:

New Notification
      │
      ├── Database
      │      │
      │      └── Permanent unread record
      │
      └── Broadcast
             │
             └── Instant frontend update

Database تحفظ Source of Truth، بينما Broadcast تجعل الواجهة تتحدث فوراً.

هذه بنية مناسبة لعداد مثل:

🔔 7

SMS Notifications

Laravel تدعم SMS من خلال Vonage.

عند استخدام Channel:

vonage

يتم تعريف:

toVonage()

داخل Notification حسب إعدادات الحزمة والخدمة.

Slack Notifications

يمكن أيضاً استخدام:

slack

لإرسال تنبيهات مثلاً إلى فريق الإدارة.

أمثلة مناسبة:

New Order
Payment Failed
Server Alert
New High-Value Customer

Custom Notification Channels

نظام Notifications ليس محدوداً بالقنوات الرسمية.

يمكن إنشاء Channel مخصص مثلاً:

WhatsApp
Telegram
Firebase FCM
Microsoft Teams
Custom SMS Provider

ليصبح:

Notification
     │
     ▼
Custom Channel
     │
     ▼
External API

Laravel Notifications وPush Notifications

من المهم التفريق بين Laravel Notification System وMobile Push Notification.

Laravel Notifications هي Architecture لتنظيم الإشعارات متعددة القنوات.

أما إرسال Push إلى Android وiOS باستخدام Firebase فهو Delivery Channel مختلف يمكن دمجه مع النظام من خلال Custom Channel أو Package مناسب.

مثلاً:

OrderShipped
     │
     ├── database
     ├── mail
     └── firebase

Localization

إذا كان التطبيق متعدد اللغات يمكن إرسال Notification باللغة المناسبة لكل مستخدم.

مثلاً يمكن استخدام:

->locale('ar')

عند الإرسال في السيناريو المناسب.

وبذلك يمكن جعل:

Arabic User
      ↓
Arabic Notification

English User
      ↓
English Notification

اختبار Notifications

في Automated Tests لا نريد عادة إرسال Email أو SMS حقيقي.

يمكن استخدام:

use Illuminate\Support\Facades\Notification;

Notification::fake();

ثم تنفيذ العملية المراد اختبارها.

بعدها:

Notification::assertSentTo(
    $user,
    OrderShipped::class
);

التحقق من عدم إرسال Notification

Notification::assertNothingSent();

أو استخدام Assertions أخرى حسب السيناريو.

أفضل تصميم لبيانات Database Notification

لا تخزن فقط:

'message' => 'New notification'

في كل الحالات.

الأفضل التفكير في البيانات التي تحتاجها الواجهة.

مثلاً:

return [

    'title' =>
        'تم شحن الطلب',

    'message' =>
        'طلبك جاهز للشحن',

    'type' =>
        'order_shipped',

    'order_id' =>
        $this->order->id,

    'url' =>
        route(
            'orders.show',
            $this->order
        ),

];

وبهذا يستطيع Frontend معرفة:

ماذا يعرض؟
إلى أين ينتقل؟
ما نوع الإشعار؟
ما السجل المرتبط به؟

لا تخزن HTML غير موثوق داخل Notification

إذا كانت Notification تعتمد على Input من المستخدم، يجب الحذر من تخزين وعرض HTML غير موثوق.

في Blade:

{{ $notification->data['message'] }}

أفضل من:

{!! $notification->data['message'] !!}

إلا إذا كنت تعرف تماماً أن المحتوى آمن ومُعقم.

Notifications والأمان والخصوصية

عند بناء Notification System يجب التأكد من أن المستخدم لا يستطيع قراءة Notifications الخاصة بمستخدم آخر.

لا تستخدم مثلاً:

DatabaseNotification::find($id)

ثم تعرضها مباشرة للمستخدم دون التحقق من ملكيتها.

الأفضل:

$notification =
    auth()
        ->user()
        ->notifications()
        ->findOrFail($id);

بهذه الطريقة يتم البحث فقط داخل Notifications التابعة للمستخدم الحالي.

مثال Mark As Read آمن

public function read(
    string $id
) {

    $notification =
        auth()
            ->user()
            ->notifications()
            ->findOrFail($id);


    $notification
        ->markAsRead();


    return back();
}

هذه الطريقة أفضل من السماح للمستخدم بتعديل أي Notification ID موجود في قاعدة البيانات.

متى نستخدم Notification ومتى نستخدم Event؟

Event وNotification ليسا الشيء نفسه.

Event يمثل:

Something Happened

مثلاً:

OrderShipped Event

أما Notification فتمثل:

Tell Someone About It

يمكن أن تكون البنية:

Order Shipped
     │
     ▼
Event
     │
     ▼
Listener
     │
     ▼
Notification
     │
     ├── Mail
     ├── Database
     └── SMS

وهي بنية ممتازة في الأنظمة الكبيرة لأنها تفصل Business Logic عن Notification Logic.

مثال عملي كامل

لنفترض أن لدينا Order تم شحنه ونريد:

1. حفظ Notification في Database
2. إرسال Email
3. تنفيذ الإرسال عبر Queue

Notification:

<?php

namespace App\Notifications;

use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class OrderShipped
    extends Notification
    implements ShouldQueue
{
    use Queueable;


    public function __construct(
        public Order $order
    ) {
    }


    public function via(
        object $notifiable
    ): array {

        return [
            'mail',
            'database',
        ];
    }


    public function toMail(
        object $notifiable
    ): MailMessage {

        return (new MailMessage)

            ->subject(
                'تم شحن طلبك'
            )

            ->greeting(
                'مرحباً ' .
                $notifiable->name
            )

            ->line(
                'تم شحن الطلب #' .
                $this->order->id
            )

            ->action(
                'عرض الطلب',
                route(
                    'orders.show',
                    $this->order
                )
            )

            ->line(
                'شكراً لاستخدام خدماتنا.'
            );
    }


    public function toDatabase(
        object $notifiable
    ): array {

        return [

            'title' =>
                'تم شحن الطلب',

            'message' =>
                'تم شحن طلبك بنجاح.',

            'type' =>
                'order_shipped',

            'order_id' =>
                $this->order->id,

            'url' =>
                route(
                    'orders.show',
                    $this->order
                ),

        ];
    }
}

ثم عند شحن الطلب:

$order
    ->user
    ->notify(
        new OrderShipped($order)
    );

وبما أن Class تستخدم:

ShouldQueue

ستقوم Laravel بإرسال Channels من خلال Queue بدلاً من تعطيل HTTP Request.

أخطاء شائعة في Laravel Notifications

الاعتقاد أن Notifications تعني Email فقط

Notification System يدعم قنوات متعددة.

كتابة toDatase

الاسم الصحيح:

toDatabase()

نسيان Database Channel داخل via()

وجود:

toDatabase()

وحده لا يكفي.

يجب أن يحتوي:

via()

على:

'database'

نسيان إنشاء notifications table

قبل استخدام Database Notifications يجب إنشاء Migration وتشغيلها.

إرسال API Notifications مباشرة داخل Request

استخدم Queue للـ Email وSMS وExternal APIs عندما يكون ذلك مناسباً.

تحميل جميع Notifications للمستخدم

استخدم Pagination عند وجود كمية كبيرة.

حذف كل Notifications عند فتح Notification واحدة

استخدم Notification ID وحدد السجل المطلوب فقط.

عدم التحقق من ملكية Notification

قم بالبحث عنها من خلال:

auth()
    ->user()
    ->notifications()

بدلاً من Query عام.

عدم استخدام afterCommit عند الحاجة

إذا كانت Queued Notification تعتمد على Model تم إنشاؤه داخل Transaction، يجب الانتباه إلى توقيت Queue.

أفضل الممارسات

  • استخدم Notification Class منفصلة لكل حدث واضح.
  • اجعل via() تحدد Channels حسب إعدادات المستخدم عند الحاجة.
  • استخدم Database Channel للإشعارات التي يجب أن تبقى ظاهرة داخل التطبيق.
  • استخدم Broadcast معها عندما تحتاج إلى Real-time UI.
  • استخدم Queue للقنوات التي تتصل بخدمات خارجية.
  • استخدم Pagination بدلاً من تحميل جميع Notifications.
  • ضع Type أو Identifier واضحاً داخل بيانات Database Notification.
  • لا تثق في Notification ID القادم من المستخدم دون التحقق من ملكيته.
  • لا تخزن Secrets أو بيانات حساسة غير ضرورية داخل Notification Data.
  • استخدم Automated Tests باستخدام Notification::fake().

البنية المقترحة لنظام Notifications احترافي

Application Event
       │
       ▼
Notification Class
       │
       ├─────────────┐
       │             │
       ▼             ▼
   Database        Queue
       │             │
       ▼       ┌─────┼─────┐
   Unread      │     │     │
   Counter     ▼     ▼     ▼
              Mail  SMS  Slack
       │
       ▼
   Broadcast
       │
       ▼
Real-time UI

بهذه الطريقة يمكن بناء Notification Center كامل يعمل على الموقع وتطبيق الهاتف والخدمات الخارجية من نفس Architecture.

الخلاصة

يوفر Laravel Notification System طريقة قوية وموحدة لإرسال الإشعارات للمستخدمين عبر عدة Channels.

يمكن تلخيص النظام بالشكل التالي:

Notification
     │
     ▼
via()
     │
     ├── mail
     ├── database
     ├── broadcast
     ├── vonage
     └── slack

يمكن إرسال Notification مباشرة إلى Model يستخدم:

Notifiable

من خلال:

$user->notify(
    new OrderShipped($order)
);

أو إرسالها إلى عدة مستخدمين باستخدام:

Notification::send()

كما يمكن استخدام On-Demand Notifications لإرسال الإشعار إلى عنوان Email أو رقم هاتف دون الحاجة إلى وجود User داخل قاعدة البيانات.

أما Database Notifications فتسمح ببناء Notification Center متكامل مع:

Unread Notifications
Read Notifications
Unread Counter
Mark As Read
Delete Notification

وعند الجمع بين:

Database
+
Broadcast

يمكن الحصول على إشعارات لحظية مع الاحتفاظ بسجل دائم للإشعارات داخل التطبيق.

وفي التطبيقات الحقيقية يفضل استخدام Queues للقنوات التي تعتمد على Services خارجية، مع الانتباه إلى Database Transactions واستخدام afterCommit() عندما تعتمد Notification على بيانات لم يتم تنفيذ Commit لها بعد.

بهذه الطريقة يصبح Laravel Notifications System طبقة موحدة يمكن توسيعها لاحقاً لتدعم البريد الإلكتروني، SMS، Slack، Firebase Push Notifications أو أي Custom Channel آخر دون إعادة كتابة منطق الإشعار من البداية.