Сповіщення · Laravel
Вступ
Крім надсилання пошти, Laravel умієнадсилати сповіщення різними каналами доставки: email, SMS (через Vonage, раніше відомий як Nexmo) і Slack. Додатково спільнота створила десятки каналів сповіщень для найрізноманітніших сервісів. Сповіщення також можна зберігати в базі даних, щоб показувати їх у вебінтерфейсі.
Зазвичай сповіщення - це короткі інформаційні повідомлення про те, що сталося у вашому застосунку. Наприклад, у білінговому застосунку ви можете надсилати користувачам сповіщення «Invoice Paid» каналами email і SMS.
Генерація сповіщень
У Laravel кожне сповіщення - це окремий клас, який зазвичай лежить у теці app/Notifications. Якщо ви не бачите цієї теки у своєму застосунку, не хвилюйтеся: вона створиться, коли ви запустите Artisan-команду make:notification:
php artisan make:notification InvoicePaid
Команда покладе новий клас сповіщення в теку app/Notifications. Кожен клас сповіщення містить метод via і змінну кількість методів побудови повідомлення, як-от toMail чи toDatabase, які перетворюють сповіщення на повідомлення, придатне для конкретного каналу.
Надсилання сповіщень
Використання трейта Notifiable
Сповіщення можна надсилати двома способами: методом notify трейта Notifiable або через фасад Notification. Трейт Notifiable за замовчуванням підключений до моделі App\Models\User вашого застосунку:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
}
Метод notify, який дає цей трейт, очікує екземпляр сповіщення:
use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));
[!NOTE] Пам'ятайте, що трейт
Notifiableможна використовувати в будь-якій вашій моделі. Ви не обмежені лише моделлюUser.
Використання фасаду Notification
Як альтернатива, сповіщення можна надсилати через фасад Notification. Цей підхід зручний, коли потрібно надіслати сповіщення кільком notifiable-сутностям, наприклад колекції користувачів. Щоб надіслати сповіщення через фасад, передайте всі notifiable-сутності та екземпляр сповіщення в метод send:
use Illuminate\Support\Facades\Notification;
Notification::send($users, new InvoicePaid($invoice));
Також можна надіслати сповіщення негайно методом sendNow. Цей метод надішле сповіщення відразу, навіть якщо воно реалізує інтерфейс ShouldQueue:
Notification::sendNow($developers, new DeploymentCompleted($deployment));
Визначення каналів доставки
Кожен клас сповіщення має метод via, який визначає, якими каналами буде доставлено сповіщення. Сповіщення можна надсилати каналами mail, database, broadcast, vonage і slack.
[!NOTE] Якщо ви хочете використовувати інші канали доставки, наприклад Telegram чи Pusher, зазирніть на створений спільнотою сайт Laravel Notification Channels.
Метод via отримує екземпляр $notifiable - екземпляр класу, якому надсилається сповіщення. За допомогою $notifiable ви можете визначити, якими каналами доставляти сповіщення:
/**
* Отримати канали доставки сповіщення.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database'];
}
Сповіщення в чергах
[!WARNING] Перед тим як ставити сповіщення в черги, налаштуйте чергу і запустіть обробник.
Надсилання сповіщень може займати час, особливо якщо канал має звернутися до зовнішнього API. Щоб застосунок відповідав швидше, дозвольте ставити сповіщення в чергу: додайте до класу інтерфейс ShouldQueue і трейт Queueable. Інтерфейс і трейт уже імпортовані в усі сповіщення, згенеровані командою make:notification, тож ви можете відразу додати їх до свого класу сповіщення:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
// ...
}
Коли інтерфейс ShouldQueue додано до сповіщення, надсилайте сповіщення як завжди. Laravel побачить інтерфейс ShouldQueue на класі й автоматично поставить доставку сповіщення в чергу:
$user->notify(new InvoicePaid($invoice));
Під час постановки сповіщень у чергу для кожної комбінації отримувача й каналу створюється окреме завдання в черзі. Наприклад, якщо у сповіщення три отримувачі та два канали, у чергу буде відправлено шість завдань.
Затримка сповіщень
Якщо ви хочете відкласти доставку сповіщення, додайте до створення сповіщення виклик методу delay:
$delay = now()->plus(minutes: 10);
$user->notify((new InvoicePaid($invoice))->delay($delay));
Щоб задати величину затримки для окремих каналів, передайте в метод delay масив:
$user->notify((new InvoicePaid($invoice))->delay([
'mail' => now()->plus(minutes: 5),
'sms' => now()->plus(minutes: 10),
]));
Як альтернатива, ви можете визначити метод withDelay у самому класі сповіщення. Метод withDelay має повертати масив назв каналів і значень затримки:
/**
* Визначити затримку доставки сповіщення.
*
* @return array<string, \Illuminate\Support\Carbon>
*/
public function withDelay(object $notifiable): array
{
return [
'mail' => now()->plus(minutes: 5),
'sms' => now()->plus(minutes: 10),
];
}
Налаштування підключення черги для сповіщення
За замовчуванням сповіщення в чергах використовують стандартне підключення черги вашого застосунку. Якщо для певного сповіщення потрібне інше підключення, викличте метод onConnection у конструкторі сповіщення:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
/**
* Створити новий екземпляр сповіщення.
*/
public function __construct()
{
$this->onConnection('redis');
}
}
Або, якщо ви хочете задати окреме підключення черги для кожного каналу сповіщення, який підтримує це сповіщення, визначте в ньому метод viaConnections. Цей метод має повертати масив пар «назва каналу / назва підключення черги»:
/**
* Визначити, які підключення використовувати для кожного каналу сповіщення.
*
* @return array<string, string>
*/
public function viaConnections(): array
{
return [
'mail' => 'redis',
'database' => 'sync',
];
}
Налаштування черг для каналів сповіщення
Якщо ви хочете задати конкретну чергу для кожного каналу сповіщення, який підтримує це сповіщення, визначте в ньому метод viaQueues. Цей метод має повертати масив пар «назва каналу / назва черги»:
/**
* Визначити, які черги використовувати для кожного каналу сповіщення.
*
* @return array<string, string>
*/
public function viaQueues(): array
{
return [
'mail' => 'mail-queue',
'slack' => 'slack-queue',
];
}
Налаштування атрибутів завдання для сповіщення в черзі
Поведінку завдання в черзі, що стоїть за сповіщенням, можна налаштувати, визначивши атрибути черги на класі сповіщення. Ці атрибути успадкує завдання (job), яке надсилає сповіщення:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\Attributes\FailOnTimeout;
use Illuminate\Queue\Attributes\MaxExceptions;
use Illuminate\Queue\Attributes\Timeout;
use Illuminate\Queue\Attributes\Tries;
#[Tries(5)]
#[Timeout(120)]
#[MaxExceptions(3)]
#[FailOnTimeout]
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
// ...
}
Якщо ви хочете забезпечити приватність і цілісність даних сповіщення в черзі через шифрування, додайте до класу сповіщення інтерфейс ShouldBeEncrypted:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue, ShouldBeEncrypted
{
use Queueable;
// ...
}
Крім оголошення цих атрибутів безпосередньо на класі сповіщення, ви можете визначити методи backoff і retryUntil, щоб задати стратегію повторів і граничний час для завдання в черзі:
use DateTime;
/**
* Обчислити кількість секунд очікування перед повторною спробою сповіщення.
*/
public function backoff(): int
{
return 3;
}
/**
* Визначити час, після якого сповіщення має вважатися прострокованим.
*/
public function retryUntil(): DateTime
{
return now()->plus(minutes: 5);
}
[!NOTE] Більше про ці атрибути та методи завдань читайте в документації про завдання в чергах.
Middleware для сповіщень у чергах
Сповіщення в чергах можуть визначати middleware так само, як завдання в чергах. Для початку визначте метод middleware на класі сповіщення. Метод middleware отримує змінні $notifiable і $channel, завдяки яким ви можете підбирати middleware залежно від призначення сповіщення:
use Illuminate\Queue\Middleware\RateLimited;
/**
* Отримати middleware, через які має пройти завдання сповіщення.
*
* @return array<int, object>
*/
public function middleware(object $notifiable, string $channel)
{
return match ($channel) {
'mail' => [new RateLimited('postmark')],
'slack' => [new RateLimited('slack')],
default => [],
};
}
Сповіщення в чергах і транзакції бази даних
Коли сповіщення в черзі відправляються всередині транзакції бази даних, черга може обробити їх раніше, ніж транзакція буде зафіксована. У такому разі будь-які зміни моделей чи записів бази даних, зроблені під час транзакції, можуть ще не бути відображені в базі. Крім того, моделі чи записи, створені в транзакції, можуть не існувати в базі. Якщо ваше сповіщення залежить від них, під час обробки завдання, яке надсилає сповіщення, можуть виникнути неочікувані помилки.
Якщо опція after_commit у конфігурації підключення черги має значення false, ви все одно можете вказати, що конкретне сповіщення в черзі має бути відправлене після фіксації всіх відкритих транзакцій бази даних: викличте метод afterCommit під час надсилання сповіщення:
use App\Notifications\InvoicePaid;
$user->notify((new InvoicePaid($invoice))->afterCommit());
Як альтернатива, метод afterCommit можна викликати в конструкторі сповіщення:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
/**
* Створити новий екземпляр сповіщення.
*/
public function __construct()
{
$this->afterCommit();
}
}
[!NOTE] Щоб дізнатися більше про способи обійти ці проблеми, перегляньте документацію про завдання в чергах і транзакції бази даних.
Визначення, чи треба надсилати сповіщення з черги
Після того як сповіщення відправлено в чергу для фонової обробки, його зазвичай підхоплює обробник черги й надсилає призначеному отримувачу.
Проте, якщо ви хочете остаточно вирішувати, чи надсилати сповіщення вже під час обробки обробником черги, визначте на класі сповіщення метод shouldSend. Якщо цей метод повертає false, сповіщення не буде надіслано:
/**
* Визначити, чи треба надсилати сповіщення.
*/
public function shouldSend(object $notifiable, string $channel): bool
{
return $this->invoice->isPaid();
}
Після надсилання сповіщень
Якщо ви хочете виконати код після того, як сповіщення надіслано, визначте на класі сповіщення метод afterSending. Цей метод отримає notifiable-сутність, назву каналу і відповідь від каналу:
/**
* Обробити сповіщення після його надсилання.
*/
public function afterSending(object $notifiable, string $channel, mixed $response): void
{
// ...
}
Сповіщення на вимогу
Іноді потрібно надіслати сповіщення тому, хто не зберігається як «користувач» вашого застосунку. За допомогою методу route фасаду Notification ви можете задати ad-hoc інформацію про маршрутизацію сповіщення перед його надсиланням:
use Illuminate\Broadcasting\Channel;
use Illuminate\Support\Facades\Notification;
Notification::route('mail', '[email protected]')
->route('vonage', '5555555555')
->route('slack', '#slack-channel')
->route('broadcast', [new Channel('channel-name')])
->notify(new InvoicePaid($invoice));
Якщо для маршруту mail ви хочете вказати ім'я отримувача, передайте масив, де першим елементом буде пара «email-адреса як ключ, ім'я як значення»:
Notification::route('mail', [
'[email protected]' => 'Barrett Blair',
])->notify(new InvoicePaid($invoice));
Метод routes дозволяє задати ad-hoc маршрутизацію одразу для кількох каналів сповіщень:
Notification::routes([
'mail' => ['[email protected]' => 'Barrett Blair'],
'vonage' => '5555555555',
])->notify(new InvoicePaid($invoice));
Email-сповіщення
Форматування email-повідомлень
Якщо сповіщення можна надсилати як email, визначте на класі сповіщення метод toMail. Цей метод отримає notifiable-сутність $notifiable і має повертати екземпляр Illuminate\Notifications\Messages\MailMessage.
Клас MailMessage містить кілька простих методів, які допомагають будувати транзакційні email-повідомлення. Email-повідомлення можуть містити рядки тексту та «call to action». Погляньмо на приклад методу toMail:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->lineIf($this->amount > 0, "Amount paid: {$this->amount}")
->action('View Invoice', $url)
->line('Thank you for using our application!');
}
[!NOTE] Зверніть увагу: у методі
toMailми використовуємо$this->invoice->id. Будь-які дані, потрібні сповіщенню для формування повідомлення, можна передати в його конструктор.
У цьому прикладі ми реєструємо привітання, рядок тексту, call to action і ще один рядок тексту. Ці методи обʼєкта MailMessage роблять форматування невеликих транзакційних листів простим і швидким. Далі канал mail перетворить компоненти повідомлення на гарний адаптивний HTML-шаблон листа з текстовою версією. Ось приклад листа, згенерованого каналом mail:
[!NOTE] Надсилаючи email-сповіщення, обовʼязково задайте опцію конфігурації
nameу файліconfig/app.php. Це значення використовуватиметься у верхньому та нижньому колонтитулах ваших email-сповіщень.
Повідомлення про помилки
Частина сповіщень інформує користувачів про помилки, наприклад про невдалу оплату рахунку. Щоб позначити, що email-повідомлення стосується помилки, викличте метод error під час побудови повідомлення. З методом error кнопка call to action буде червоною замість чорної:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->error()
->subject('Invoice Payment Failed')
->line('...');
}
Інші способи форматування email-сповіщень
Замість оголошення «рядків» тексту в класі сповіщення ви можете скористатися методом view, щоб указати власний шаблон для рендерингу листа сповіщення:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->view(
'mail.invoice.paid', ['invoice' => $this->invoice]
);
}
Текстове представлення (view) для email-повідомлення можна задати, передавши назву представлення другим елементом масиву, який передається в метод view:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->view(
['mail.invoice.paid', 'mail.invoice.paid-text'],
['invoice' => $this->invoice]
);
}
Або, якщо ваше повідомлення має лише текстове представлення, скористайтеся методом text:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)->text(
'mail.invoice.paid-text', ['invoice' => $this->invoice]
);
}
Налаштування відправника
За замовчуванням відправник листа (адреса from) визначається у файлі конфігурації config/mail.php. Проте адресу from для конкретного сповіщення можна задати методом from:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->from('[email protected]', 'Barrett Blair')
->line('...');
}
Налаштування отримувача
Надсилаючи сповіщення каналом mail, система сповіщень автоматично шукає властивість email у вашій notifiable-сутності. Ви можете задати, яка email-адреса використовується для доставки сповіщення, визначивши метод routeNotificationForMail на notifiable-сутності:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class User extends Authenticatable
{
use Notifiable;
/**
* Маршрутизація сповіщень для каналу mail.
*
* @return array<string, string>|string
*/
public function routeNotificationForMail(Notification $notification): array|string
{
// Повернути лише email-адресу...
return $this->email_address;
// Повернути email-адресу та імʼя...
return [$this->email_address => $this->name];
}
}
Налаштування теми листа
За замовчуванням темою листа є назва класу сповіщення, відформатована в «Title Case». Тож якщо ваш клас сповіщення називається InvoicePaid, темою листа буде Invoice Paid. Якщо ви хочете задати іншу тему, викличте метод subject під час побудови повідомлення:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Notification Subject')
->line('...');
}
Налаштування mailer
За замовчуванням email-сповіщення надсилається через mailer, визначений у файлі конфігурації config/mail.php. Проте ви можете задати інший mailer під час виконання, викликавши метод mailer під час побудови повідомлення:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->mailer('postmark')
->line('...');
}
Налаштування шаблонів
HTML- і текстовий шаблон, які використовують email-сповіщення, можна змінити, опублікувавши ресурси пакета сповіщень. Після виконання цієї команди шаблони email-сповіщень будуть у теці resources/views/vendor/notifications:
php artisan vendor:publish --tag=laravel-notifications
Вкладення
Щоб додати вкладення до email-сповіщення, використовуйте метод attach під час побудови повідомлення. Метод attach приймає абсолютний шлях до файлу першим аргументом:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file');
}
[!NOTE] Метод
attach, який пропонують email-повідомлення сповіщень, також приймає attachable-обʼєкти. Щоб дізнатися більше, перегляньте повну документацію про attachable-обʼєкти.
Долучаючи файли до повідомлення, ви можете також задати відображуване імʼя та/або MIME-тип, передавши array другим аргументом методу attach:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attach('/path/to/file', [
'as' => 'name.pdf',
'mime' => 'application/pdf',
]);
}
Коли потрібно, до повідомлення можна долучити кілька файлів методом attachMany:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attachMany([
'/path/to/forge.svg',
'/path/to/vapor.svg' => [
'as' => 'Logo.svg',
'mime' => 'image/svg+xml',
],
]);
}
Метод attachFromStorageDisk долучає файл, що існує на конкретному диску файлової системи. Він приймає назву диска і шлях до файлу на цьому диску:
use App\Mail\InvoicePaid as InvoicePaidMailable;
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): Mailable
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email)
->attachFromStorageDisk('s3', '/path/to/file', 'invoice.pdf', [
'mime' => 'application/pdf',
]);
}
Вкладення з сирих даних
Метод attachData дозволяє долучити як вкладення сирий рядок байтів. Викликаючи attachData, укажіть імʼя файлу, яке має отримати вкладення:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Hello!')
->attachData($this->pdf, 'name.pdf', [
'mime' => 'application/pdf',
]);
}
Додавання теґів і метаданих
Деякі сторонні email-провайдери, як-от Mailgun і Postmark, підтримують «теґи» й «метадані» повідомлень, за якими можна групувати й відслідковувати надіслані вашим застосунком листи. Додати теґи й метадані до email-повідомлення можна методами tag і metadata:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->greeting('Comment Upvoted!')
->tag('upvote')
->metadata('comment_id', $this->comment->id);
}
Якщо ваш застосунок використовує драйвер Mailgun, більше про теґи і метадані читайте в документації Mailgun. Так само документація Postmark розповідає про їхню підтримку теґів і метаданих.
Якщо ваш застосунок надсилає листи через Amazon SES, використовуйте метод metadata, щоб долучити до повідомлення «теґи» SES.
Налаштування Symfony Message
Метод withSymfonyMessage класу MailMessage дозволяє зареєструвати замикання, яке буде викликано з екземпляром Symfony Message перед надсиланням повідомлення. Це дає можливість глибоко налаштувати повідомлення перед доставкою:
use Symfony\Component\Mime\Email;
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->withSymfonyMessage(function (Email $message) {
$message->getHeaders()->addTextHeader(
'Custom-Header', 'Header Value'
);
});
}
Використання mailable-класів
За потреби метод toMail вашого сповіщення може повертати повноцінний mailable-обʼєкт. Повертаючи Mailable замість MailMessage, ви маєте вказати отримувача повідомлення методом to цього mailable-обʼєкта:
use App\Mail\InvoicePaid as InvoicePaidMailable;
use Illuminate\Mail\Mailable;
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): Mailable
{
return (new InvoicePaidMailable($this->invoice))
->to($notifiable->email);
}
Mailable-класи і сповіщення на вимогу
Якщо ви надсилаєте сповіщення на вимогу, екземпляр $notifiable, переданий у метод toMail, буде екземпляром Illuminate\Notifications\AnonymousNotifiable, який має метод routeNotificationFor для отримання email-адреси, куди слід надіслати сповіщення на вимогу:
use App\Mail\InvoicePaid as InvoicePaidMailable;
use Illuminate\Notifications\AnonymousNotifiable;
use Illuminate\Mail\Mailable;
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): Mailable
{
$address = $notifiable instanceof AnonymousNotifiable
? $notifiable->routeNotificationFor('mail')
: $notifiable->email;
return (new InvoicePaidMailable($this->invoice))
->to($address);
}
Попередній перегляд email-сповіщень
Проєктуючи шаблон email-сповіщення, зручно швидко переглядати відрендерене повідомлення в браузері, як звичайний Blade-шаблон. Тому Laravel дозволяє повертати будь-яке email-повідомлення, згенероване email-сповіщенням, безпосередньо із замикання маршруту або контролера. Коли повертається MailMessage, він буде відрендерений і показаний у браузері, тож ви швидко перевірите дизайн, не надсилаючи листа на реальну адресу:
use App\Models\Invoice;
use App\Notifications\InvoicePaid;
Route::get('/notification', function () {
$invoice = Invoice::find(1);
return (new InvoicePaid($invoice))
->toMail($invoice->user);
});
Markdown-сповіщення поштою
Markdown-сповіщення поштою дають змогу скористатися готовими шаблонами email-сповіщень, залишаючи більше свободи для написання довших, індивідуальних повідомлень. Оскільки повідомлення написані в Markdown, Laravel може відрендерити гарні адаптивні HTML-шаблони, автоматично згенерувавши до них текстову версію.
Генерація повідомлення
Щоб згенерувати сповіщення разом із відповідним Markdown-шаблоном, скористайтеся опцією --markdown Artisan-команди make:notification:
php artisan make:notification InvoicePaid --markdown=mail.invoice.paid
Як і всі інші email-сповіщення, сповіщення з Markdown-шаблонами мають визначати метод toMail на своєму класі. Проте замість методів line і action для побудови сповіщення використовуйте метод markdown, щоб указати назву Markdown-шаблону. Масив даних, які ви хочете зробити доступними в шаблоні, можна передати другим аргументом методу:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->subject('Invoice Paid')
->markdown('mail.invoice.paid', ['url' => $url]);
}
Написання повідомлення
Markdown-сповіщення поштою поєднують Blade-компоненти і синтаксис Markdown, що дозволяє легко конструювати сповіщення, використовуючи готові компоненти сповіщень Laravel:
<x-mail::message>
# Invoice Paid
Your invoice has been paid!
<x-mail::button :url="$url">
View Invoice
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
[!NOTE] Не робіть надмірних відступів, коли пишете Markdown-листи. Згідно зі стандартами Markdown, парсери рендерять контент з відступами як блоки коду.
Компонент Button
Компонент button рендерить центровану кнопку-посилання. Компонент приймає два аргументи: url і необовʼязковий color. Підтримувані кольори: primary, green і red. Ви можете додавати до сповіщення скільки завгодно компонентів button:
<x-mail::button :url="$url" color="green">
View Invoice
</x-mail::button>
Компонент Panel
Компонент panel рендерить переданий блок тексту в панелі, колір тла якої трохи відрізняється від решти сповіщення. Так можна привернути увагу до певного блоку тексту:
<x-mail::panel>
This is the panel content.
</x-mail::panel>
Компонент Table
Компонент table перетворює Markdown-таблицю на HTML-таблицю. Компонент приймає Markdown-таблицю як свій вміст. Вирівнювання стовпців таблиці підтримується через стандартний синтаксис вирівнювання таблиць Markdown:
<x-mail::table>
| Laravel | Table | Example |
| ------------- | :-----------: | ------------: |
| Col 2 is | Centered | $10 |
| Col 3 is | Right-Aligned | $20 |
</x-mail::table>
Налаштування компонентів
Ви можете експортувати всі Markdown-компоненти сповіщень у власний застосунок, щоб їх налаштувати. Для експорту скористайтеся Artisan-командою vendor:publish і опублікуйте теґ ресурсів laravel-mail:
php artisan vendor:publish --tag=laravel-mail
Ця команда опублікує Markdown-компоненти пошти в теку resources/views/vendor/mail. Тека mail містить теки html і text, у кожній з яких лежать відповідні представлення кожного доступного компонента. Налаштовуйте ці компоненти як вам завгодно.
Налаштування CSS
Після експорту компонентів у теці resources/views/vendor/mail/html/themes буде файл default.css. Ви можете змінити CSS у цьому файлі, і ваші стилі автоматично будуть вбудовані (in-lined) у HTML-представлення ваших Markdown-сповіщень.
Якщо ви хочете створити цілком нову тему для Markdown-компонентів Laravel, покладіть CSS-файл у теку html/themes. Після того як ви назвете й збережете свій CSS-файл, оновіть опцію theme у файлі конфігурації mail, щоб вона відповідала назві нової теми.
Щоб задати тему для окремого сповіщення, викличте метод theme під час побудови email-повідомлення сповіщення. Метод theme приймає назву теми, яку слід використати під час надсилання сповіщення:
/**
* Отримати email-представлення сповіщення.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->theme('invoice')
->subject('Invoice Paid')
->markdown('mail.invoice.paid', ['url' => $url]);
}
Сповіщення в базі даних
Передумови
Канал сповіщень database зберігає інформацію про сповіщення в таблиці бази даних. Ця таблиця містить, зокрема, тип сповіщення та JSON-структуру даних, яка його описує.
Ви можете робити запити до таблиці, щоб показувати сповіщення в інтерфейсі користувача свого застосунку. Але перед цим потрібно створити таблицю бази даних для зберігання сповіщень. Команда make:notifications-table згенерує міграцію з відповідною схемою таблиці:
php artisan make:notifications-table
php artisan migrate
[!NOTE] Якщо ваші notifiable-моделі використовують первинні ключі UUID або ULID, у міграції таблиці сповіщень замініть метод
morphsна uuidMorphs або ulidMorphs.
Форматування сповіщень у базі даних
Якщо сповіщення можна зберігати в таблиці бази даних, визначте на класі сповіщення метод toDatabase або toArray. Цей метод отримає notifiable-сутність $notifiable і має повертати звичайний PHP-масив. Повернений масив буде закодований як JSON і збережений у стовпці data вашої таблиці notifications. Погляньмо на приклад методу toArray:
/**
* Отримати представлення сповіщення у вигляді масиву.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
];
}
Коли сповіщення зберігається в базі даних вашого застосунку, стовпець type за замовчуванням отримує назву класу сповіщення, а стовпець read_at буде null. Проте цю поведінку можна змінити, визначивши в класі сповіщення методи databaseType та initialDatabaseReadAtValue:
use Illuminate\Support\Carbon;
/**
* Отримати тип сповіщення для бази даних.
*/
public function databaseType(object $notifiable): string
{
return 'invoice-paid';
}
/**
* Отримати початкове значення для стовпця "read_at".
*/
public function initialDatabaseReadAtValue(): ?Carbon
{
return null;
}
toDatabase проти toArray
Метод toArray також використовує канал broadcast, щоб визначити, які дані транслювати у ваш фронтенд на JavaScript. Якщо ви хочете мати два різні представлення у вигляді масиву для каналів database і broadcast, визначте метод toDatabase замість toArray.
Доступ до сповіщень
Коли сповіщення збережені в базі даних, потрібен зручний спосіб отримувати їх із ваших notifiable-сутностей. Трейт Illuminate\Notifications\Notifiable, підключений до стандартної моделі Laravel App\Models\User, містить звʼязок Eloquent notifications, який повертає сповіщення для сутності. Щоб отримати сповіщення, звертайтеся до цього методу так само, як до будь-якого іншого звʼязку Eloquent. За замовчуванням сповіщення сортуються за часовою позначкою created_at, і найновіші стоять на початку колекції:
$user = App\Models\User::find(1);
foreach ($user->notifications as $notification) {
echo $notification->type;
}
Якщо ви хочете отримати лише «непрочитані» сповіщення, скористайтеся звʼязком unreadNotifications. Ці сповіщення теж будуть відсортовані за часовою позначкою created_at, з найновішими на початку колекції:
$user = App\Models\User::find(1);
foreach ($user->unreadNotifications as $notification) {
echo $notification->type;
}
Якщо ви хочете отримати лише «прочитані» сповіщення, скористайтеся звʼязком readNotifications:
$user = App\Models\User::find(1);
foreach ($user->readNotifications as $notification) {
echo $notification->type;
}
[!NOTE] Щоб звертатися до сповіщень із JavaScript-клієнта, визначте у своєму застосунку контролер сповіщень, який повертає сповіщення для notifiable-сутності, наприклад для поточного користувача. Далі робіть HTTP-запит до URL цього контролера зі свого JavaScript-клієнта.
Позначення сповіщень як прочитаних
Зазвичай сповіщення позначають як «прочитане», коли користувач його побачив. Трейт Illuminate\Notifications\Notifiable надає метод markAsRead, який оновлює стовпець read_at у записі сповіщення в базі даних:
$user = App\Models\User::find(1);
foreach ($user->unreadNotifications as $notification) {
$notification->markAsRead();
}
Проте замість перебору кожного сповіщення ви можете викликати метод markAsRead прямо на колекції сповіщень:
$user->unreadNotifications->markAsRead();
Також можна скористатися запитом масового оновлення, щоб позначити всі сповіщення прочитаними, не отримуючи їх із бази даних:
$user = App\Models\User::find(1);
$user->unreadNotifications()->update(['read_at' => now()]);
Ви можете викликати delete, щоб цілком видалити сповіщення з таблиці:
$user->notifications()->delete();
Broadcast-сповіщення
Передумови
Перед трансляцією сповіщень налаштуйте й вивчіть сервіси трансляції подій Laravel. Трансляція подій дає спосіб реагувати на серверні події Laravel з фронтенду на JavaScript.
Форматування broadcast-сповіщень
Канал broadcast транслює сповіщення за допомогою сервісів трансляції подій Laravel, що дозволяє фронтенду на JavaScript ловити сповіщення в реальному часі. Якщо сповіщення підтримує трансляцію, визначте на його класі метод toBroadcast. Цей метод отримає notifiable-сутність $notifiable і має повертати екземпляр BroadcastMessage. Якщо метод toBroadcast відсутній, для збору даних, які треба транслювати, буде використано метод toArray. Повернені дані будуть закодовані як JSON і транслюватимуться у ваш фронтенд на JavaScript. Погляньмо на приклад методу toBroadcast:
use Illuminate\Notifications\Messages\BroadcastMessage;
/**
* Отримати представлення сповіщення для трансляції.
*/
public function toBroadcast(object $notifiable): BroadcastMessage
{
return new BroadcastMessage([
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
]);
}
Налаштування черги для мовлення
Усі broadcast-сповіщення ставляться в чергу для мовлення. Якщо треба налаштувати підключення черги або назву черги, яка використовується для постановки операції мовлення, скористайтеся методами onConnection і onQueue класу BroadcastMessage:
return (new BroadcastMessage($data))
->onConnection('sqs')
->onQueue('broadcasts');
Налаштування типу сповіщення
Окрім вказаних вами даних, усі broadcast-сповіщення також мають поле type з повним імʼям класу сповіщення. Щоб змінити type сповіщення, визначте метод broadcastType у класі сповіщення:
/**
* Отримати тип сповіщення, яке транслюється.
*/
public function broadcastType(): string
{
return 'broadcast.message';
}
Прослуховування сповіщень
Сповіщення транслюються на приватний канал, назва якого формується за домовленістю {notifiable}.{id}. Тобто, якщо ви надсилаєте сповіщення екземпляру App\Models\User з ID 1, сповіщення транслюватиметься на приватний канал App.Models.User.1. Коли ви використовуєте Laravel Echo, слухати сповіщення на каналі можна методом notification:
Echo.private('App.Models.User.' + userId)
.notification((notification) => {
console.log(notification.type);
});
Використання React, Vue або Svelte
Laravel Echo містить хуки для React, Vue і Svelte, які роблять прослуховування сповіщень безболісним. Для початку викличте хук useEchoNotification, який слугує для прослуховування сповіщень. Хук useEchoNotification автоматично покине канали, коли компонент, що його використовує, буде демонтовано:
import { useEchoNotification } from "@laravel/echo-react";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
);
<script setup lang="ts">
import { useEchoNotification } from "@laravel/echo-vue";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
);
</script>
<script>
import { useEchoNotification } from "@laravel/echo-svelte";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
);
</script>
За замовчуванням хук слухає всі сповіщення. Щоб указати типи сповіщень, які ви хочете слухати, передайте в useEchoNotification рядок або масив типів:
import { useEchoNotification } from "@laravel/echo-react";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
'App.Notifications.InvoicePaid',
);
<script setup lang="ts">
import { useEchoNotification } from "@laravel/echo-vue";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
'App.Notifications.InvoicePaid',
);
</script>
<script>
import { useEchoNotification } from "@laravel/echo-svelte";
useEchoNotification(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.type);
},
'App.Notifications.InvoicePaid',
);
</script>
Ви також можете задати форму даних у payload сповіщення, отримавши кращу типобезпеку та зручність редагування:
type InvoicePaidNotification = {
invoice_id: number;
created_at: string;
};
useEchoNotification<InvoicePaidNotification>(
`App.Models.User.${userId}`,
(notification) => {
console.log(notification.invoice_id);
console.log(notification.created_at);
console.log(notification.type);
},
'App.Notifications.InvoicePaid',
);
Налаштування каналу сповіщень
Якщо ви хочете змінити канал, на який транслюються broadcast-сповіщення певної сутності, визначте метод receivesBroadcastNotificationsOn у сутності-отримувачі:
<?php
namespace App\Models;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* Канали, на яких користувач отримує трансляції сповіщень.
*/
public function receivesBroadcastNotificationsOn(): string
{
return 'users.'.$this->id;
}
}
SMS-сповіщення
Передумови
Надсилання SMS-сповіщень у Laravel працює через Vonage (раніше відомий як Nexmo). Перш ніж надсилати сповіщення через Vonage, встановіть пакети laravel/vonage-notification-channel і guzzlehttp/guzzle:
composer require laravel/vonage-notification-channel guzzlehttp/guzzle
Пакет містить файл конфігурації. Проте експортувати цей файл конфігурації у власний застосунок не обовʼязково. Ви можете просто використати змінні середовища VONAGE_KEY і VONAGE_SECRET, щоб задати публічний і секретний ключі Vonage.
Після визначення ключів встановіть змінну середовища VONAGE_SMS_FROM, яка задає номер телефону, з якого за замовчуванням надсилатимуться ваші SMS. Цей номер телефону можна згенерувати в панелі керування Vonage:
VONAGE_SMS_FROM=15556666666
Форматування SMS-сповіщень
Якщо сповіщення підтримує надсилання як SMS, визначте метод toVonage у класі сповіщення. Цей метод отримує сутність $notifiable і має повертати екземпляр Illuminate\Notifications\Messages\VonageMessage:
use Illuminate\Notifications\Messages\VonageMessage;
/**
* Отримати представлення сповіщення для Vonage / SMS.
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->content('Your SMS message content');
}
Вміст у Unicode
Якщо ваше SMS-повідомлення містить символи Unicode, під час створення екземпляра VonageMessage викличте метод unicode:
use Illuminate\Notifications\Messages\VonageMessage;
/**
* Отримати представлення сповіщення для Vonage / SMS.
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->content('Your unicode message')
->unicode();
}
Налаштування номера «From»
Якщо ви хочете надіслати частину сповіщень з номера, відмінного від зазначеного у змінній середовища VONAGE_SMS_FROM, викличте метод from на екземплярі VonageMessage:
use Illuminate\Notifications\Messages\VonageMessage;
/**
* Отримати представлення сповіщення для Vonage / SMS.
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->content('Your SMS message content')
->from('15554443333');
}
Додавання клієнтського ідентифікатора
Якщо ви хочете відстежувати витрати на кожного користувача, команду чи клієнта, додайте до сповіщення «client reference». Vonage дозволяє формувати звіти за цим ідентифікатором, щоб краще розуміти використання SMS конкретним клієнтом. Клієнтський ідентифікатор може бути будь-яким рядком до 40 символів:
use Illuminate\Notifications\Messages\VonageMessage;
/**
* Отримати представлення сповіщення для Vonage / SMS.
*/
public function toVonage(object $notifiable): VonageMessage
{
return (new VonageMessage)
->clientReference((string) $notifiable->id)
->content('Your SMS message content');
}
Маршрутизація SMS-сповіщень
Щоб спрямувати сповіщення Vonage на потрібний номер телефону, визначте метод routeNotificationForVonage у сутності-отримувачі:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class User extends Authenticatable
{
use Notifiable;
/**
* Маршрутизація сповіщень для каналу Vonage.
*/
public function routeNotificationForVonage(Notification $notification): string
{
return $this->phone_number;
}
}
Сповіщення у Slack
Передумови
Перед надсиланням сповіщень у Slack встановіть канал сповіщень Slack через Composer:
composer require laravel/slack-notification-channel
Крім того, вам потрібно створити Slack App для свого робочого простору Slack.
Якщо вам потрібно надсилати сповіщення лише до того ж робочого простору Slack, у якому створено застосунок, переконайтеся, що ваш App має scope-и chat:write, chat:write.public і chat:write.customize. Ці scope-и додаються на вкладці керування застосунком «OAuth & Permissions» у Slack.
Далі скопіюйте «Bot User OAuth Token» вашого застосунку і помістіть його в масив конфігурації slack у файлі services.php вашого застосунку. Цей токен можна знайти на вкладці «OAuth & Permissions» у Slack:
'slack' => [
'notifications' => [
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
],
],
Розповсюдження застосунку
Якщо ваш застосунок надсилатиме сповіщення до зовнішніх робочих просторів Slack, якими володіють користувачі вашого застосунку, вам потрібно «розповсюдити» (distribute) ваш App через Slack. Розповсюдження застосунку налаштовується на вкладці «Manage Distribution» вашого застосунку в Slack. Після розповсюдження застосунку ви можете скористатися Socialite, щоб отримувати Slack Bot токени від імені користувачів вашого застосунку.
Форматування сповіщень Slack
Якщо сповіщення підтримує надсилання як повідомлення у Slack, визначте метод toSlack у класі сповіщення. Цей метод отримує сутність $notifiable і має повертати екземпляр Illuminate\Notifications\Slack\SlackMessage. Насичені сповіщення можна конструювати за допомогою Block Kit API від Slack. Наступний приклад можна переглянути в Block Kit builder від Slack:
use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;
use Illuminate\Notifications\Slack\SlackMessage;
/**
* Отримати представлення сповіщення для Slack.
*/
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->contextBlock(function (ContextBlock $block) {
$block->text('Customer #1234');
})
->sectionBlock(function (SectionBlock $block) {
$block->text('An invoice has been paid.');
$block->field("*Invoice No:*\n1000")->markdown();
$block->field("*Invoice Recipient:*\[email protected]")->markdown();
})
->dividerBlock()
->sectionBlock(function (SectionBlock $block) {
$block->text('Congratulations!');
});
}
Використання шаблону Block Kit Builder від Slack
Замість fluent-методів конструктора повідомлень ви можете передати сирий JSON-payload, згенерований у Block Kit Builder від Slack, у метод usingBlockKitTemplate:
use Illuminate\Notifications\Slack\SlackMessage;
use Illuminate\Support\Str;
/**
* Отримати представлення сповіщення для Slack.
*/
public function toSlack(object $notifiable): SlackMessage
{
$template = <<<JSON
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Team Announcement"
}
},
{
"type": "section",
"text": {
"type": "plain_text",
"text": "We are hiring!"
}
}
]
}
JSON;
return (new SlackMessage)
->usingBlockKitTemplate($template);
}
Інтерактивність Slack
Система сповіщень Block Kit від Slack дає потужні можливості для обробки взаємодії з користувачем. Щоб ними скористатися, у вашому Slack App має бути увімкнено «Interactivity» і налаштовано «Request URL», який вказує на URL, що обслуговує ваш застосунок. Ці налаштування доступні на вкладці керування застосунком «Interactivity & Shortcuts» у Slack.
У наступному прикладі, який використовує метод actionsBlock, Slack надішле POST-запит на ваш «Request URL» із payload, що містить користувача Slack, який натиснув кнопку, ID натиснутої кнопки тощо. Далі ваш застосунок може визначити, яку дію виконати, на основі payload. Вам також слід перевірити, що запит надійшов саме від Slack:
use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;
use Illuminate\Notifications\Slack\SlackMessage;
/**
* Отримати представлення сповіщення для Slack.
*/
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->contextBlock(function (ContextBlock $block) {
$block->text('Customer #1234');
})
->sectionBlock(function (SectionBlock $block) {
$block->text('An invoice has been paid.');
})
->actionsBlock(function (ActionsBlock $block) {
// ID за замовчуванням - "button_acknowledge_invoice"...
$block->button('Acknowledge Invoice')->primary();
// Налаштувати ID вручну...
$block->button('Deny')->danger()->id('deny_invoice');
});
}
Модальні вікна підтвердження
Якщо ви хочете, щоб користувачі підтверджували дію перед її виконанням, викличте метод confirm під час визначення кнопки. Метод confirm приймає повідомлення і замикання, яке отримує екземпляр ConfirmObject:
use Illuminate\Notifications\Slack\BlockKit\Blocks\ActionsBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\ContextBlock;
use Illuminate\Notifications\Slack\BlockKit\Blocks\SectionBlock;
use Illuminate\Notifications\Slack\BlockKit\Composites\ConfirmObject;
use Illuminate\Notifications\Slack\SlackMessage;
/**
* Отримати представлення сповіщення для Slack.
*/
public function toSlack(object $notifiable): SlackMessage
{
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->contextBlock(function (ContextBlock $block) {
$block->text('Customer #1234');
})
->sectionBlock(function (SectionBlock $block) {
$block->text('An invoice has been paid.');
})
->actionsBlock(function (ActionsBlock $block) {
$block->button('Acknowledge Invoice')
->primary()
->confirm(
'Acknowledge the payment and send a thank you email?',
function (ConfirmObject $dialog) {
$dialog->confirm('Yes');
$dialog->deny('No');
}
);
});
}
Перевірка блоків Slack
Якщо ви хочете швидко перевірити блоки, які створюєте, викличте метод dd на екземплярі SlackMessage. Метод dd згенерує і виведе URL на Block Kit Builder від Slack, який показує попередній перегляд payload і сповіщення у вашому браузері. Щоб вивести сирий payload, передайте в метод dd значення true:
return (new SlackMessage)
->text('One of your invoices has been paid!')
->headerBlock('Invoice Paid')
->dd();
Маршрутизація сповіщень Slack
Щоб спрямувати сповіщення Slack до потрібної команди та каналу, визначте метод routeNotificationForSlack у вашій моделі-отримувачі. Цей метод може повертати одне з трьох значень:
null- у цьому разі маршрутизація делегується каналу, налаштованому в самому сповіщенні. Ви можете скористатися методомtoпід час побудовиSlackMessage, щоб налаштувати канал усередині сповіщення.- Рядок із назвою каналу Slack, до якого надсилати сповіщення, наприклад
#support-channel. - Екземпляр
SlackRoute, який дозволяє вказати OAuth-токен і назву каналу, наприкладSlackRoute::make($this->slack_channel, $this->slack_token). Цей спосіб слід використовувати для надсилання сповіщень до зовнішніх робочих просторів.
Наприклад, повернення #support-channel з методу routeNotificationForSlack надішле сповіщення до каналу #support-channel у робочому просторі, повʼязаному з Bot User OAuth токеном із файлу конфігурації services.php вашого застосунку:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class User extends Authenticatable
{
use Notifiable;
/**
* Маршрутизація сповіщень для каналу Slack.
*/
public function routeNotificationForSlack(Notification $notification): mixed
{
return '#support-channel';
}
}
Сповіщення зовнішніх робочих просторів Slack
[!NOTE] Перед надсиланням сповіщень до зовнішніх робочих просторів Slack ваш Slack App має бути розповсюджений.
Часто вам потрібно надсилати сповіщення до робочих просторів Slack, якими володіють користувачі вашого застосунку. Для цього спершу треба отримати Slack OAuth токен для користувача. На щастя, Laravel Socialite містить драйвер Slack, який дозволяє легко автентифікувати користувачів вашого застосунку через Slack і отримати bot-токен.
Отримавши bot-токен і зберігши його в базі даних застосунку, ви можете скористатися методом SlackRoute::make, щоб спрямувати сповіщення до робочого простору користувача. Крім того, вашому застосунку, ймовірно, знадобиться дати користувачу можливість вказати, до якого каналу надсилати сповіщення:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Slack\SlackRoute;
class User extends Authenticatable
{
use Notifiable;
/**
* Маршрутизація сповіщень для каналу Slack.
*/
public function routeNotificationForSlack(Notification $notification): mixed
{
return SlackRoute::make($this->slack_channel, $this->slack_token);
}
}
Локалізація сповіщень
Laravel дозволяє надсилати сповіщення локаллю, відмінною від поточної локалі HTTP-запиту, і навіть памʼятає цю локаль, якщо сповіщення поставлено в чергу.
Для цього клас Illuminate\Notifications\Notification пропонує метод locale, що задає потрібну мову. Застосунок перемкнеться на цю локаль на час обчислення сповіщення, а потім повернеться до попередньої локалі:
$user->notify((new InvoicePaid($invoice))->locale('es'));
Локалізацію для кількох отримувачів також можна зробити через фасад Notification:
Notification::locale('es')->send(
$users, new InvoicePaid($invoice)
);
Бажані локалі користувачів
Іноді застосунки зберігають бажану локаль кожного користувача. Реалізувавши контракт HasLocalePreference у вашій моделі-отримувачі, ви можете вказати Laravel використовувати цю збережену локаль під час надсилання сповіщення:
use Illuminate\Contracts\Translation\HasLocalePreference;
class User extends Model implements HasLocalePreference
{
/**
* Отримати бажану локаль користувача.
*/
public function preferredLocale(): string
{
return $this->locale;
}
}
Після реалізації інтерфейсу Laravel автоматично використовуватиме бажану локаль під час надсилання сповіщень і mailable-обʼєктів цій моделі. Тому викликати метод locale вже не потрібно:
$user->notify(new InvoicePaid($invoice));
Тестування
Щоб запобігти фактичному надсиланню сповіщень, скористайтеся методом fake фасаду Notification. Зазвичай надсилання сповіщень не стосується того коду, який ви насправді тестуєте. Найімовірніше, достатньо просто перевірити, що Laravel отримав вказівку надіслати певне сповіщення.
Після виклику методу fake фасаду Notification ви можете перевіряти, що сповіщення мали бути надіслані користувачам, і навіть досліджувати дані, які отримали сповіщення:
<?php
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
test('orders can be shipped', function () {
Notification::fake();
// Виконати відвантаження замовлення...
// Перевірити, що жодного сповіщення не надіслано...
Notification::assertNothingSent();
// Перевірити, що сповіщення надіслано вказаним користувачам...
Notification::assertSentTo(
[$user], OrderShipped::class
);
// Перевірити, що сповіщення не надіслано...
Notification::assertNotSentTo(
[$user], AnotherNotification::class
);
// Перевірити, що сповіщення надіслано двічі...
Notification::assertSentTimes(WeeklyReminder::class, 2);
// Перевірити, що сповіщення надіслано користувачу рівно один раз...
Notification::assertSentToOnce($user, OrderShipped::class);
// Перевірити, що надіслано вказану кількість сповіщень...
Notification::assertCount(3);
});
<?php
namespace Tests\Feature;
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_orders_can_be_shipped(): void
{
Notification::fake();
// Виконати відвантаження замовлення...
// Перевірити, що жодного сповіщення не надіслано...
Notification::assertNothingSent();
// Перевірити, що сповіщення надіслано вказаним користувачам...
Notification::assertSentTo(
[$user], OrderShipped::class
);
// Перевірити, що сповіщення не надіслано...
Notification::assertNotSentTo(
[$user], AnotherNotification::class
);
// Перевірити, що сповіщення надіслано двічі...
Notification::assertSentTimes(WeeklyReminder::class, 2);
// Перевірити, що сповіщення надіслано користувачу рівно один раз...
Notification::assertSentToOnce($user, OrderShipped::class);
// Перевірити, що надіслано вказану кількість сповіщень...
Notification::assertCount(3);
}
}
У методи assertSentTo або assertNotSentTo можна передати замикання, щоб перевірити, що було надіслано сповіщення, яке проходить заданий «тест на істинність». Якщо хоча б одне надіслане сповіщення проходить цей тест, перевірка буде успішною:
Notification::assertSentTo(
$user,
function (OrderShipped $notification, array $channels) use ($order) {
return $notification->order->id === $order->id;
}
);
Сповіщення on-demand
Якщо код, який ви тестуєте, надсилає сповіщення on-demand, ви можете перевірити факт надсилання такого сповіщення методом assertSentOnDemand:
Notification::assertSentOnDemand(OrderShipped::class);
Notification::assertSentOnDemandOnce(OrderShipped::class);
Передавши замикання другим аргументом у метод assertSentOnDemand, ви можете визначити, чи було сповіщення on-demand надіслано на правильну адресу «маршруту»:
Notification::assertSentOnDemand(
OrderShipped::class,
function (OrderShipped $notification, array $channels, object $notifiable) use ($user) {
return $notifiable->routes['mail'] === $user->email;
}
);
Події сповіщень
Подія надсилання сповіщення
Коли сповіщення надсилається, система сповіщень диспатчить подію Illuminate\Notifications\Events\NotificationSending. Вона містить сутність-отримувача і сам екземпляр сповіщення. Ви можете створити слухачів подій для цієї події у своєму застосунку:
use Illuminate\Notifications\Events\NotificationSending;
class CheckNotificationStatus
{
/**
* Обробити подію.
*/
public function handle(NotificationSending $event): void
{
// ...
}
}
Сповіщення не буде надіслано, якщо слухач події NotificationSending повертає false зі свого методу handle:
/**
* Обробити подію.
*/
public function handle(NotificationSending $event): bool
{
return false;
}
Усередині слухача події ви можете звертатися до властивостей notifiable, notification і channel, щоб дізнатися більше про отримувача або саме сповіщення:
/**
* Обробити подію.
*/
public function handle(NotificationSending $event): void
{
// $event->channel
// $event->notifiable
// $event->notification
}
Подія надісланого сповіщення
Коли сповіщення надіслано, система сповіщень диспатчить подію Illuminate\Notifications\Events\NotificationSent. Вона містить сутність-отримувача і сам екземпляр сповіщення. Ви можете створити слухачів подій для цієї події у своєму застосунку:
use Illuminate\Notifications\Events\NotificationSent;
class LogNotification
{
/**
* Обробити подію.
*/
public function handle(NotificationSent $event): void
{
// ...
}
}
Усередині слухача події ви можете звертатися до властивостей notifiable, notification, channel і response, щоб дізнатися більше про отримувача або саме сповіщення:
/**
* Обробити подію.
*/
public function handle(NotificationSent $event): void
{
// $event->channel
// $event->notifiable
// $event->notification
// $event->response
}
Власні канали
Laravel постачається з невеликим набором каналів сповіщень, але ви можете написати власні драйвери для доставки сповіщень іншими каналами. Laravel робить це просто. Для початку визначте клас із методом send. Метод має приймати два аргументи: $notifiable і $notification.
Усередині методу send ви можете викликати методи сповіщення, щоб отримати обʼєкт повідомлення, зрозумілий вашому каналу, а потім надіслати сповіщення екземпляру $notifiable у будь-який потрібний вам спосіб:
<?php
namespace App\Notifications;
use Illuminate\Notifications\Notification;
class VoiceChannel
{
/**
* Надіслати вказане сповіщення.
*/
public function send(object $notifiable, Notification $notification): void
{
$message = $notification->toVoice($notifiable);
// Надіслати сповіщення екземпляру $notifiable...
}
}
Після визначення класу каналу сповіщень ви можете повертати його імʼя з методу via будь-якого зі своїх сповіщень. У цьому прикладі метод toVoice вашого сповіщення може повертати будь-який обʼєкт, який ви оберете для представлення голосових повідомлень. Наприклад, ви можете визначити власний клас VoiceMessage для таких повідомлень:
<?php
namespace App\Notifications;
use App\Notifications\Messages\VoiceMessage;
use App\Notifications\VoiceChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification
{
use Queueable;
/**
* Отримати канали сповіщення.
*/
public function via(object $notifiable): string
{
return VoiceChannel::class;
}
/**
* Отримати голосове представлення сповіщення.
*/
public function toVoice(object $notifiable): VoiceMessage
{
// ...
}
}
Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.