Документация Laravel 10.x
Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.
Помимо поддержки отправки электронной почты, Laravel поддерживает отправку уведомлений через различные каналы доставки, включая электронную почту, SMS (через Vonage, ранее известный как Nexmo), и Slack. Кроме того, существует множество каналов уведомлений, созданных сообществом, для отправки уведомлений по десяткам различных каналов! Уведомления также могут быть сохранены в базе данных, чтобы их можно было отображать в вашем веб-интерфейсе.
Как правило, уведомления должны быть короткими информационными сообщениями, уведомляющими пользователей о чем-то, что произошло в вашем приложении. Например, если вы пишете биллинговое приложение, вы можете отправить уведомление "Оплачен счет" вашим пользователям через каналы электронной почты и SMS.
В Laravel каждое уведомление представлено отдельным классом, который обычно хранится в каталоге app/Notifications
. Не волнуйтесь, если вы не видите этот каталог в своем приложении - он будет создан для вас при запуске команды Artisan make:notification
:
php artisan make:notification InvoicePaid
Эта команда поместит новый класс уведомления в ваш каталог app/Notifications
. Каждый класс уведомления содержит метод via
и переменное количество методов построения сообщений, таких как toMail
или toDatabase
, которые преобразуют уведомление в сообщение, настроенное для этого конкретного канала.
Уведомления можно отправлять двумя способами: с использованием метода 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));
Примечание Помните, что вы можете использовать трейт
Notifiable
в любых ваших моделях. Вы не ограничены только включением его в вашу модельUser
.
В качестве альтернативы вы можете отправлять уведомления через фасад Notification
. Этот подход полезен, когда вам нужно отправить уведомление нескольким сущностям, таким как коллекция пользователей. Чтобы отправить уведомления с использованием фасада, передайте все сущности и экземпляр уведомления методу 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
.
Примечание Если вы хотите использовать другие каналы доставки, такие как 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'];}
Внимание Прежде чем поставить уведомления в очередь, вы должны настроить свою очередь и запустить рабочего.
Отправка уведомлений может занять время, особенно если каналу требуется внешний вызов 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()->addMinutes(10); $user->notify((new InvoicePaid($invoice))->delay($delay));
Вы можете передать массив методу delay
, чтобы указать задержку для конкретных каналов:
$user->notify((new InvoicePaid($invoice))->delay([ 'mail' => now()->addMinutes(5), 'sms' => now()->addMinutes(10),]));
Кроме того, вы можете определить метод withDelay
непосредственно в классе уведомления. Метод withDelay
должен возвращать массив с именами каналов и значениями задержки:
/** * Определить задержку доставки уведомления. * * @return array<string, \Illuminate\Support\Carbon> */public function withDelay(object $notifiable): array{ return [ 'mail' => now()->addMinutes(5), 'sms' => now()->addMinutes(10), ];}
По умолчанию уведомления в очереди будут помещены в очередь с использованием конфигурации очереди по умолчанию вашего приложения. Если вы хотите указать другое соединение, которое следует использовать для конкретного уведомления, вы можете вызвать метод onConnection
из конструктора вашего уведомления:
<?phpnamespace 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', ];}
Когда уведомления в очереди отправляются в пределах транзакций базы данных, они могут быть обработаны очередью до того, как транзакция базы данных будет зафиксирована. Когда это происходит, любые обновления, сделанные вами в моделях или записях базы данных в транзакции, могут еще не отразиться в базе данных. Кроме того, любые модели или записи базы данных, созданные в транзакции, могут не существовать в базе данных. Если ваше уведомление зависит от этих моделей, при обработке задания, отправляющего уведомление в очередь, могут возникнуть непредвиденные ошибки.
Если параметр after_commit
вашего соединения с очередью установлен в false
, вы можете все равно указать, что конкретное уведомление в очереди должно быть отправлено после того, как все открытые транзакции базы данных будут зафиксированы, вызвав метод afterCommit
при отправке уведомления:
use App\Notifications\InvoicePaid; $user->notify((new InvoicePaid($invoice))->afterCommit());
Кроме того, вы можете вызвать метод afterCommit
из конструктора вашего уведомления:
<?phpnamespace 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(); }}
Примечание Чтобы узнать больше о работе с этими проблемами, ознакомьтесь с документацией по очередям и транзакциям базы данных.
После того как уведомление в очереди было отправлено в очередь для обработки в фоновом режиме, оно обычно будет принято рабочим процессом очереди и отправлено своему предполагаемому получателю.
Однако, если вы хотите окончательно решить, должно ли уведомление в очереди быть отправлено после обработки рабочим процессом очереди, вы можете определить метод shouldSend
в классе уведомления. Если этот метод возвращает false
, уведомление не будет отправлено:
/** * Определить, должно ли быть отправлено уведомление. */public function shouldSend(object $notifiable, string $channel): bool{ return $this->invoice->isPaid();}
Иногда вам может потребоваться отправить уведомление кому-то, кто не хранится как "пользователь" вашего приложения. Используя метод route
фасада Notification
, вы можете указать информацию маршрутизации уведомлений перед отправкой уведомления:
use Illuminate\Broadcasting\Channel;use Illuminate\Support\Facades\Notification; ->route('vonage', '5555555555') ->route('slack', '#slack-channel') ->route('broadcast', [new Channel('channel-name')]) ->notify(new InvoicePaid($invoice));
Если вы хотите указать имя получателя при отправке уведомления по требованию по маршруту mail
, вы можете предоставить массив, содержащий адрес электронной почты в качестве ключа и имя в качестве значения первого элемента массива:
Notification::route('mail', [])->notify(new InvoicePaid($invoice));
Если уведомление поддерживает отправку по электронной почте, вы должны определить метод toMail
в классе уведомления. Этот метод принимает сущность $notifiable
и должен возвращать экземпляр Illuminate\Notifications\Messages\MailMessage
.
Класс MailMessage
содержит несколько простых методов, чтобы помочь вам создавать транзакционные сообщения электронной почты. Письменные сообщения могут содержать строки текста, а также "призыв к действию". Давайте рассмотрим пример метода toMail
:
/** * Получить почтовое представление уведомления. */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!');}
Примечание Обратите внимание, что мы используем
$this->invoice->id
в нашем методеtoMail
. Вы можете передавать любые данные, необходимые вашему уведомлению для создания его сообщения, в конструктор уведомления.
В этом примере мы регистрируем приветствие, строку текста, призыв к действию, а затем еще одну строку текста. Эти методы, предоставленные объектом MailMessage
, делают простым и быстрым форматирование небольших транзакционных электронных писем. Затем канал электронной почты преобразует компоненты сообщения в красивый, адаптивный HTML-шаблон электронной почты с партнером в виде обычного текста. Вот пример электронного письма, сгенерированного каналом электронной почты mail
:
Примечание При отправке почтовых уведомлений убедитесь, что установлен параметр конфигурации
name
в вашем файле конфигурацииconfig/app.php
. Это значение будет использоваться в заголовке и подвале сообщений почтового уведомления.
Некоторые уведомления информируют пользователей об ошибках, таких как неудачная оплата счета. Вы можете указать, что сообщение по электронной почте относится к ошибке, вызвав метод error
при построении вашего сообщения. При использовании метода error
в письме, кнопка призыва к действию будет красной, а не черной:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->error() ->subject('Invoice Payment Failed') ->line('...');}
Вместо определения "строк" текста в классе уведомления вы можете использовать метод view
, чтобы указать пользовательский шаблон, который должен использоваться для отображения электронного сообщения:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage)->view( 'emails.name', ['invoice' => $this->invoice] );}
Вы можете указать вид обычного текста для сообщения электронной почты, передав имя вида вторым элементом массива, передаваемого методу view
:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage)->view( ['emails.name.html', 'emails.name.plain'], ['invoice' => $this->invoice] );}
По умолчанию адрес отправителя/отправителя электронной почты определен в конфигурационном файле config/mail.php
. Однако вы можете указать адрес отправителя для конкретного уведомления, используя метод from
:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->from('[email protected]', 'Barrett Blair') ->line('...');}
При отправке уведомлений через канал mail
система уведомлений автоматически будет искать свойство email
в вашей сущности-получателе. Вы можете настроить, какой адрес электронной почты используется для доставки уведомления, определив метод routeNotificationForMail
в сущности-получателе:
<?phpnamespace App\Models;use Illuminate\Foundation\Auth\User as Authenticatable;use Illuminate\Notifications\Notifiable;use Illuminate\Notifications\Notification;class User extends Authenticatable{ use Notifiable; /** * Маршрутизировать уведомления для канала почты. * * @return array<string, string>|string */ public function routeNotificationForMail(Notification $notification): array|string { // Вернуть только адрес электронной почты... return $this->email_address; // Вернуть адрес электронной почты и имя... return [$this->email_address => $this->name]; }}
По умолчанию тема электронной почты - это имя класса уведомления, форматированное как "заглавные буквы". Таким образом, если ваш класс уведомления назван InvoicePaid
, тема электронного письма будет Invoice Paid
. Если вы хотите указать другую тему для сообщения, вы можете вызвать метод subject
при построении вашего сообщения:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->subject('Notification Subject') ->line('...');}
По умолчанию уведомление по электронной почте будет отправлено с использованием почтового клиента, определенного в конфигурационном файле config/mail.php
. Однако вы можете указать другой почтовый клиент во время выполнения, вызвав метод mailer
при построении вашего сообщения:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->mailer('postmark') ->line('...');}
Вы можете изменить шаблон HTML и обычного текста, используемый для электронных уведомлений, публикуя ресурсы пакета уведомлений. После выполнения этой команды шаблоны электронных уведомлений будут находиться в каталоге resources/views/vendor/notifications
:
php artisan vendor:publish --tag=laravel-notifications
Для добавления вложений в уведомление по электронной почте используйте метод attach
при построении вашего сообщения. Метод attach
принимает абсолютный путь к файлу в качестве своего первого аргумента:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->greeting('Hello!') ->attach('/path/to/file');}
Примечание Метод
attach
, предлагаемый почтовыми сообщениями уведомлений, также принимает объекты, которые можно прикрепить. Пожалуйста, ознакомьтесь с обширной документацией по объектам, которые можно прикрепить, чтобы узнать больше.
Прикрепляя файлы к сообщению, вы также можете указать отображаемое имя и/или тип MIME, передав массив вторым аргументом методу attach
:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->greeting('Hello!') ->attach('/path/to/file', [ 'as' => 'name.pdf', 'mime' => 'application/pdf', ]);}
В отличие от прикрепления файлов в объектах отправляемых сообщений, вы не можете прикрепить файл напрямую с хранилища, используя attachFromStorage
. Вы должны вместо этого использовать метод attach
с абсолютным путем к файлу на диске хранилища. В противном случае вы можете вернуть отправляемое сообщение из метода toMail
:
use App\Mail\InvoicePaid as InvoicePaidMailable;/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): Mailable{ return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email) ->attachFromStorage('/path/to/file');}
При необходимости к сообщению можно прикрепить несколько файлов с использованием метода attachMany
:
/** * Получить почтовое представление уведомления. */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', ], ]);}
Метод attachData
можно использовать для прикрепления сырой строки байтов в качестве вложения. При вызове метода attachData
вы должны указать имя файла, которое должно быть присвоено вложению:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->greeting('Hello!') ->attachData($this->pdf, 'name.pdf', [ 'mime' => 'application/pdf', ]);}
Некоторые поставщики сторонней электронной почты, такие как Mailgun и Postmark, поддерживают "теги" и "метаданные" сообщений, которые могут использоваться для группировки и отслеживания электронных писем, отправленных вашим приложением. Вы можете добавить теги и метаданные к сообщению электронной почты с помощью методов tag
и metadata
:
/** * Получить почтовое представление уведомления. */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 к сообщению.
Метод withSymfonyMessage
класса MailMessage
позволяет зарегистрировать замыкание, которое будет вызвано с экземпляром Symfony Message перед отправкой сообщения. Это дает вам возможность полностью настроить сообщение перед его доставкой:
use Symfony\Component\Mime\Email;/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->withSymfonyMessage(function (Email $message) { $message->getHeaders()->addTextHeader( 'Custom-Header', 'Header Value' ); });}
При необходимости вы можете вернуть полноценный объект отправляемого сообщения из метода toMail
вашего уведомления. При возвращении Mailable
вместо MailMessage
вам нужно будет указать получателя сообщения, используя метод to
объекта отправляемого сообщения:
use App\Mail\InvoicePaid as InvoicePaidMailable;use Illuminate\Mail\Mailable;/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): Mailable{ return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email);}
Если вы отправляете уведомление по требованию, переданный экземпляр $notifiable
методу toMail
будет экземпляром Illuminate\Notifications\AnonymousNotifiable
, который предлагает метод routeNotificationFor
, который может быть использован для получения адреса электронной почты, на который должно быть отправлено уведомление по требованию:
use App\Mail\InvoicePaid as InvoicePaidMailable;use Illuminate\Notifications\AnonymousNotifiable;use Illuminate\Mail\Mailable;/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): Mailable{ $address = $notifiable instanceof AnonymousNotifiable ? $notifiable->routeNotificationFor('mail') : $notifiable->email; return (new InvoicePaidMailable($this->invoice)) ->to($address);}
При проектировании шаблона уведомления по электронной почте удобно быстро просматривать отрендеренное электронное сообщение в вашем браузере, как типичный шаблон Blade. По этой причине Laravel позволяет вам возвращать любое электронное сообщение, сгенерированное уведомлением по электронной почте, напрямую из замыкания маршрута или контроллера. Когда возвращается 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, Laravel может отображать красивые, адаптивные HTML-шаблоны для сообщений, а также автоматически создавать их обычные текстовые аналоги.
Для создания уведомления с соответствующим шаблоном Markdown вы можете использовать опцию --markdown
команды Artisan make:notification
:
php artisan make:notification InvoicePaid --markdown=mail.invoice.paid
Как и все другие уведомления по электронной почте, уведомления, использующие шаблоны Markdown, должны определять метод toMail
в классе уведомления. Однако вместо использования методов line
и action
для построения уведомления используйте метод markdown
для указания имени шаблона Markdown, который следует использовать. Вторым аргументом метода можно передать массив данных, который вы хотели бы сделать доступным для шаблона:
/** * Получить почтовое представление уведомления. */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>
Компонент кнопки отображает центрированную кнопку-ссылку. Компонент принимает два аргумента: url
и необязательный color
. Поддерживаемые цвета: primary
, green
и red
. Вы можете добавлять столько компонентов кнопок к уведомлению, сколько вам нужно:
<x-mail::button :url="$url" color="green">View Invoice</x-mail::button>
Компонент панели отображает данный блок текста в панели с немного другим цветом фона по сравнению с остальной частью уведомления. Это позволяет выделить данный блок текста:
<x-mail::panel>This is the panel content.</x-mail::panel>
Компонент таблицы позволяет преобразовать таблицу 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
, каждый из которых содержит соответствующие представления каждого доступного компонента. Вы можете настроить эти компоненты так, как вам угодно.
После экспорта компонентов в каталоге resources/views/vendor/mail/html/themes
будет содержаться файл default.css
. Вы можете настраивать CSS в этом файле, и ваши стили будут автоматически встроены в HTML-представления уведомлений Markdown.
Если вы хотите создать совершенно новую тему для компонентов Markdown Laravel, вы можете разместить файл CSS в каталоге html/themes
. После названия и сохранения вашего файла CSS обновите опцию theme
файла конфигурации mail
, чтобы она соответствовала имени вашей новой темы.
Для настройки темы для отдельного уведомления вы можете вызвать метод theme
при построении сообщения электронной почты уведомления. Метод theme
принимает имя темы, которую следует использовать при отправке уведомления:
/** * Получить почтовое представление уведомления. */public function toMail(object $notifiable): MailMessage{ return (new MailMessage) ->theme('invoice') ->subject('Invoice Paid') ->markdown('mail.invoice.paid', ['url' => $url]);}
Канал уведомлений database
сохраняет информацию об уведомлении в таблице базы данных. Эта таблица будет содержать информацию, такую как тип уведомления, а также структуру данных JSON, описывающую уведомление.
Вы можете запросить таблицу для отображения уведомлений в пользовательском интерфейсе вашего приложения. Но прежде чем вы сможете это сделать, вам нужно создать таблицу базы данных для хранения ваших уведомлений. Вы можете использовать команду notifications:table
для генерации миграции с правильной схемой таблицы:
php artisan notifications:table php artisan migrate
Примечание Если ваши модели, которые могут быть уведомлены, используют UUID или ULID в качестве первичных ключей, вы должны заменить метод
morphs
наuuidMorphs
илиulidMorphs
в миграции таблицы уведомлений.
Если уведомление поддерживает хранение в таблице базы данных, вы должны определить метод toDatabase
или toArray
в классе уведомления. Этот метод получит сущность $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, ];}
toDatabase
Vs. toArray
Метод toArray
также используется каналом broadcast
для определения данных, которые следует транслировать на ваш веб-интерфейс, работающий на JavaScript. Если вы хотите иметь два разных представления массива для каналов database
и broadcast
, вы должны определить метод toDatabase
вместо метода toArray
.
Как только уведомления сохранены в базе данных, вам нужен удобный способ получения к ним доступа из ваших сущностей, поддерживающих уведомления. Трейт Illuminate\Notifications\Notifiable
, включенный в модель App\Models\User
по умолчанию в Laravel, включает в себя отношение notifications
Eloquent, возвращающее уведомления для сущности. Чтобы получить уведомления, вы можете получить доступ к этому методу, как к любому другому отношению 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;}
Примечание Чтобы получить доступ к уведомлениям из вашего клиента JavaScript, вы должны определить контроллер уведомлений для вашего приложения, который возвращает уведомления для объекта, который может быть уведомлен, такого как текущий пользователь. Затем вы можете сделать 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();
Перед тем как транслировать уведомления, вы должны настроить и быть знакомыми с сервисами трансляции событий Laravel. Событийная трансляция предоставляет способ реагировать на события Laravel на стороне сервера из вашего веб-интерфейса, работающего на JavaScript.
Канал broadcast
транслирует уведомления с использованием сервисов трансляции событий Laravel, что позволяет вашему веб-интерфейсу на JavaScript ловить уведомления в реальном времени. Если уведомление поддерживает трансляцию, вы можете определить метод toBroadcast
в классе уведомления. Этот метод будет получать сущность $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, ]);}
Все транслируемые уведомления поставляются в очередь на трансляцию. Если вы хотите настроить соединение с очередью или имя очереди, используемое для постановки трансляционной операции в очередь, вы можете использовать методы onConnection
и onQueue
в BroadcastMessage
:
return (new BroadcastMessage($data)) ->onConnection('sqs') ->onQueue('broadcasts');
Помимо указанных вами данных, все транслируемые уведомления также имеют поле type
, содержащее полное имя класса уведомления. Если вы хотите настроить type
уведомления, вы можете определить метод broadcastType
в классе уведомления:
/** * Получить тип транслируемого уведомления. */public function broadcastType(): string{ return 'broadcast.message';}
Уведомления будут транслироваться на частный канал, форматированный с использованием соглашения {notifiable}.{id}
. Таким образом, если вы отправляете уведомление экземпляру App\Models\User
с идентификатором 1
, уведомление будет транслировано на частном канале App.Models.User.1
. При использовании Laravel Echo вы можете легко слушать уведомления на канале, используя метод notification
:
Echo.private('App.Models.User.' + userId) .notification((notification) => { console.log(notification.type); });
Если вы хотите настроить канал, на который будут транслироваться трансляции уведомлений для сущности, вы можете определить метод receivesBroadcastNotificationsOn
в сущности, которая поддерживает уведомления:
<?phpnamespace 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 { }}
Отправка уведомлений по 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, вы должны определить метод 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');}
Если ваше SMS-сообщение будет содержать символы Unicode, вы должны вызвать метод unicode
при построении экземпляра VonageMessage
:
use Illuminate\Notifications\Messages\VonageMessage;/** * Получить Vonage / SMS представление уведомления. */public function toVonage(object $notifiable): VonageMessage{ return (new VonageMessage) ->content('Your unicode message') ->unicode();}
Если вы хотите отправить некоторые уведомления с номера телефона, отличного от номера телефона, указанного в вашей переменной среды 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');}
Если вы хотите отслеживать затраты на каждого пользователя, команду или клиента, вы можете добавить "клиентскую ссылку" к уведомлению. 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');}
Чтобы маршрутизировать уведомления Vonage на правильный номер телефона, определите метод routeNotificationForVonage
в вашей сущности, которую можно уведомить:
<?phpnamespace 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 через Composer:
composer require laravel/slack-notification-channel
Кроме того, вы должны создать приложение Slack для вашего рабочего пространства Slack.
Если вам нужно отправлять уведомления только в то же рабочее пространство Slack, в котором создано приложение, убедитесь, что ваше приложение имеет области видимости chat:write
, chat:write.public
и chat:write.customize
. Эти области видимости можно добавить в разделе управления приложением "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, которые принадлежат пользователям вашего приложения, вам нужно "распространить" ваше приложение через Slack. Распределение приложения можно управлять на вкладке "Управление распространением" вашего приложения в Slack. После распространения вашего приложения вы можете использовать Socialite для получения токенов Slack Bot от имени пользователей вашего приложения.
Если уведомление поддерживает отправку в виде сообщения в Slack, вы должны определить метод toSlack
в классе уведомления. Этот метод будет получать сущность $notifiable
и должен возвращать экземпляр Illuminate\Notifications\Slack\SlackMessage
. Вы можете создавать насыщенные уведомления с использованием Block Kit API Slack. В следующем примере можно предварительно просмотреть в конструкторе Block Kit для Slack:
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.'); $block->field("*Invoice No:*\n1000")->markdown(); $block->field("*Invoice Recipient:*\[email protected]")->markdown(); }) ->dividerBlock() ->sectionBlock(function (SectionBlock $block) { $block->text('Congratulations!'); });}
Система уведомлений Block Kit Slack предоставляет мощные функции для обработки взаимодействия с пользователем. Чтобы использовать эти функции, ваше приложение Slack должно иметь включенную "Интерактивность" и настроенный "URL запроса", указывающий на URL, обслуживаемый вашим приложением. Эти настройки можно управлять на вкладке "Интерактивность и ярлыки" в управлении приложением Slack.
В следующем примере, использующем метод actionsBlock
, Slack отправит запрос POST
на ваш "URL запроса" с полезной нагрузкой, содержащей Slack-пользователя, который нажал кнопку, идентификатор нажатой кнопки и другие данные. Ваше приложение затем может определить действие на основе полезной нагрузки. Вы также должны проверить запрос был сделан 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'); } ); });}
Если вы хотите быстро проверить блоки, которые вы создали, вы можете вызвать метод dd
на экземпляре SlackMessage
. Метод dd
создаст и выведет URL в Конструктор Block Kit для Slack, который отобразит предварительный просмотр полезной нагрузки и уведомления в вашем браузере. Вы можете передать true
методу dd
, чтобы вывести сырую полезную нагрузку:
return (new SlackMessage) ->text('One of your invoices has been paid!') ->headerBlock('Invoice Paid') ->dd();
Чтобы направлять уведомления Slack в соответствующую рабочую область Slack и канал, определите метод routeNotificationForSlack
в вашей модели, для которой рассылаются уведомления. Этот метод может вернуть одно из трех значений:
null
- что откладывает маршрутизацию на канал, настроенный в самом уведомлении. Вы можете использовать метод to
при построении вашего SlackMessage
, чтобы настроить канал внутри уведомления.#support-channel
.SlackRoute
, который позволяет указать токен OAuth и имя канала, например, SlackRoute::make($this->slack_channel, $this->slack_token)
. Этот метод следует использовать для отправки уведомлений во внешние рабочие пространства.Например, возврат #support-channel
из метода routeNotificationForSlack
отправит уведомление на канал #support-channel
в рабочей области, связанной с токеном Bot User OAuth, указанным в файле конфигурации вашего приложения services.php
:
<?phpnamespace 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, ваше Slack-приложение должно быть распространено.
Конечно, вы часто захотите отправлять уведомления в рабочие области Slack, принадлежащие пользователям вашего приложения. Для этого сначала вам нужно получить токен Slack OAuth для пользователя. К счастью, Laravel Socialite включает в себя драйвер Slack, который позволит вам легко аутентифицировать пользователей вашего приложения в Slack и получать токен бота.
После получения токена бота и сохранения его в базе данных вашего приложения вы можете использовать метод SlackRoute::make
для направления уведомления в рабочую область пользователя. Кроме того, ваше приложение, скорее всего, должно предоставить возможность пользователю указать, на какой канал следует отправлять уведомления:
<?phpnamespace 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 автоматически будет использовать предпочтительный язык при отправке уведомлений и почтовых сообщений модели. Следовательно, нет необходимости вызывать метод locale
при использовании этого интерфейса:
$user->notify(new InvoicePaid($invoice));
Вы можете использовать метод fake
фасада Notification
, чтобы предотвратить отправку уведомлений. Обычно отправка уведомлений не связана с кодом, который вы фактически тестируете. Вероятно, будет достаточно просто утверждать, что Laravel был настроен отправить данное уведомление.
После вызова метода fake
фасада Notification
вы можете утверждать, что было настроено отправить уведомления пользователям, и даже проверять данные, которые уведомления получили:
<?phpnamespace 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::assertCount(3); }}
Вы можете передать замыкание в методы assertSentTo
или assertNotSentTo
, чтобы утверждать, что уведомление было отправлено и прошло заданный "тест истины". Если хотя бы одно уведомление было отправлено и прошло данный тест истины, утверждение будет успешным:
Notification::assertSentTo( $user, function (OrderShipped $notification, array $channels) use ($order) { return $notification->order->id === $order->id; });
Если код, который вы тестируете, отправляет уведомления по требованию, вы можете проверить, что уведомление по требованию было отправлено с помощью метода assertSentOnDemand
:
Notification::assertSentOnDemand(OrderShipped::class);
Передачей замыкания вторым аргументом метода assertSentOnDemand
вы можете определить, было ли уведомление по требованию отправлено по правильному "адресу" маршрута:
Notification::assertSentOnDemand( OrderShipped::class, function (OrderShipped $notification, array $channels, object $notifiable) use ($user) { return $notifiable->routes['mail'] === $user->email; });
Когда уведомление отправляется, система уведомлений отправляет событие Illuminate\Notifications\Events\NotificationSending
event. В нем содержится сущность "notifiable" и сам экземпляр уведомления. Вы можете зарегистрировать прослушивателей для этого события в провайдере событий вашего приложения EventServiceProvider
:
use App\Listeners\CheckNotificationStatus;use Illuminate\Notifications\Events\NotificationSending;/** * Сопоставления слушателей событий для приложения. * * @var array */protected $listen = [ NotificationSending::class => [ CheckNotificationStatus::class, ],];
Уведомление не будет отправлено, если прослушиватель события NotificationSending
возвращает false
из своего метода handle
:
use Illuminate\Notifications\Events\NotificationSending; /** * Handle the event. */public function handle(NotificationSending $event): bool{ return false;}
В пределах прослушивателя событий вы можете получить доступ к свойствам notifiable
, notification
и channel
события для получения дополнительной информации о получателе уведомления или самом уведомлении:
/** * Handle the event. */public function handle(NotificationSending $event): void{ // $event->channel // $event->notifiable // $event->notification}
Когда уведомление отправляется, событие Illuminate\Notifications\Events\NotificationSent
event вызывается системой уведомлений. В нем содержится сущность "notifiable" и сам экземпляр уведомления. Вы можете зарегистрировать прослушивателей для этого события в вашем EventServiceProvider
:
use App\Listeners\LogNotification;use Illuminate\Notifications\Events\NotificationSent;/** * Сопоставления слушателей событий для приложения. * * @var array */protected $listen = [ NotificationSent::class => [ LogNotification::class, ],];
Примечание После регистрации слушателей в вашем
EventServiceProvider
используйте команду Artisanevent:generate
, чтобы быстро создать классы слушателей.
В пределах прослушивателя событий вы можете получить доступ к свойствам notifiable
, notification
, channel
и response
события для получения дополнительной информации о получателе уведомления или самом уведомлении:
/** * Handle the event. */public function handle(NotificationSent $event): void{ // $event->channel // $event->notifiable // $event->notification // $event->response}
Laravel поставляется с несколькими каналами уведомлений, но вам может захотеться написать свои драйверы для доставки уведомлений через другие каналы. Laravel делает это простым. Чтобы начать, определите класс, содержащий метод send
. Метод должен принимать два аргумента: $notifiable
и $notification
.
В пределах метода send
вы можете вызывать методы уведомления для получения объекта сообщения, понятного вашему каналу, а затем отправить уведомление в экземпляр $notifiable
так, как вам угодно:
<?phpnamespace App\Notifications;use Illuminate\Notifications\Notification;class VoiceChannel{ /** * Отправить указанное уведомление. */ public function send(object $notifiable, Notification $notification): void { $message = $notification->toVoice($notifiable); // Отправить уведомление для экземпляра $notifiable... }}
После определения класса канала уведомлений вы можете вернуть имя класса из метода via
любого из ваших уведомлений. В этом примере метод toVoice
вашего уведомления может возвращать любой объект, который вы выберете для представления голосовых сообщений. Например, вы можете определить собственный класс VoiceMessage
для представления этих сообщений:
<?phpnamespace 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 { // ... }}