Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як зберігати сповіщення в базі даних і показувати користувачу непрочитані?

Канал database зберігає сповіщення в таблиці notifications - так будують «дзвіночок» з лічильником непрочитаних в інтерфейсі.

Таблиця:

php artisan make:notifications-table
php artisan migrate

Таблиця містить id (UUID), type (клас сповіщення), поліморфний notifiable, data (JSON), read_at і мітки часу.

Сповіщення:

class InvoicePaid extends Notification
{
    public function __construct(public Invoice $invoice) {}

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

    public function toArray(object $notifiable): array
    {
        return [
            'invoice_id' => $this->invoice->id,
            'amount' => $this->invoice->amount,
            'url' => route('invoices.show', $this->invoice),
        ];
    }
}

Масив з toArray (чи toDatabase) кодується в JSON і зберігається в колонці data. Зберігайте в ньому все потрібне для показу: ідентифікатори, короткий текст, посилання - а не лише ID, щоб для списку сповіщень не довелося підвантажувати десяток моделей.

Читання:

$user->notifications;          // усі, найновіші першими
$user->unreadNotifications;    // read_at = null
$user->unreadNotifications()->count();
@foreach (auth()->user()->unreadNotifications as $notification)
    <a href="{{ $notification->data['url'] }}">
        Рахунок на {{ $notification->data['amount'] }} оплачено
    </a>
@endforeach

Позначити прочитаними:

$notification->markAsRead();
$user->unreadNotifications->markAsRead();                     // колекцію
$user->unreadNotifications()->update(['read_at' => now()]);   // одним запитом

Останній варіант кращий для «позначити все»: не завантажує сповіщення в пам'ять.

Що варто врахувати:

  • зміна структури data: старі записи лишаються у старому форматі. Шаблон має переживати відсутні ключі, а метод databaseType дозволяє зберігати стабільний тип замість імені класу (зручно, якщо клас перейменують);
  • таблиця росте безкінечно - старі прочитані сповіщення варто видаляти за розкладом;
  • індекс на (notifiable_type, notifiable_id, read_at) прискорює підрахунок непрочитаних;
  • для показу в реальному часі додають канал broadcast.

Докладніше в документації: Сповіщення: сповіщення в базі даних

Схожі питання