{{TOC}} {{DOCVER 5.3=c06d6a2352ed8c767633aab9c20f2bf7d880c967 28.01.2017 5:00:51}} == Введение == Вдобавок к поддержке ((//docs/v5/mail отправки email)) Laravel поддерживает отправку уведомлений по разным каналам доставки, включая почту, SMS (через ((https://www.nexmo.com/ Nexmo))) и ((https://slack.com Slack)). Уведомления также можно сохранять в БД, чтобы выводить их в вашем веб-интерфейсе. Обычно уведомления - это короткие информационные сообщения для пользователей о том, что в приложении что-то произошло. Например, при создании биллингового приложения вы можете посылать пользователям уведомления "Счёт оплачен" по email и SMS каналам. == Создание уведомлений == В Laravel каждое уведомление представлено одним классом (обычно хранящимся в папке %%(t)app/Notifications%%). Если у вас в приложении нет такой папки - не беда, она будет создана для вас при выполнении Artisan-команды %%(sh)make:notification%%: %%(sh) php artisan make:notification InvoicePaid %% Эта команда поместит новый класс уведомления в папку %%(t)app/Notifications%%. Класс каждого уведомления содержит метод %%via()%% и разное число методов создания сообщения (таких как %%toMail()%% и %%toDatabase()%%), которые конвертируют уведомление в сообщение, оптимизированное под определённый канал. == Отправка уведомлений == === С помощью типажа %%(t)Notifiable%% === Уведомления можно отправлять двумя способами: используя метод %%notify()%% типажа %%(t)Notifiable%%, или используя ((//docs/v5/facades фасад)) %%(t)Notification%%. Сначала попробуем типаж %%(t)Notifiable%%. Этот типаж использует стандартной моделью %%(t)App\User%% и содержит один метод, который можно использовать для отправки уведомлений - %%notify()%%. Этот метод принимает экземпляр уведомления: %% use App\Notifications\InvoicePaid; $user->notify(new InvoicePaid($invoice)); %% .(alert) Запомните, вы можете использовать типаж %%(t)Illuminate\Notifications\Notifiable%% на любой из ваших моделей. Никто не принуждает вас включать его только в модель %%(t)User%%. === С помощью фасада %%(t)Notification%% === Или вы можете отправлять уведомления через ((//docs/v5/facades фасад)) %%(t)Notification%%. Это особенно полезно при необходимости отправки уведомления нескольким уведомляемым сущностям, таким как коллекция пользователей. Для отправки уведомлений через фасад передайте все уведомляемые сущности и экземпляр уведомления в метод %%send()%%: %% Notification::send($users, new InvoicePaid($invoice)); %% === Указание каналов доставки === Класс каждого уведомления содержит метод %%via()%%, который определяет, по каким каналам будет доставляться уведомление. Изначально уведомления можно отправлять через каналы %%(t)mail%%, %%(t)database%%, %%(t)broadcast%%, %%(t)nexmo%% и %%(t)slack%%. .(alert) Если вы хотите использовать другие каналы доставки, такие как Telegram или Pusher, зайдите на созданный сообществом ((http://laravel-notification-channels.com сайт каналов уведомлений Laravel)). Метод %%via()%% получает экземпляр %%$notifiable%%, который будет экземпляром класса, которому посылается уведомление. Вы можете использовать %%$notifiable%% для определения того, по каким каналам должно доставляться уведомление: %% /** * Получить каналы доставки уведомления. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database']; } %% === Постановка уведомлений в очередь === .(alert) Перед использованием очереди для уведомлений вам надо настроить вашу очередь и ((//docs/v5/queues запустить обработчика)). Отправка уведомлений может занять какое-то время, особенно если каналу необходим вызов внешнего API для доставки уведомления. Для ускорения отклика вашего приложения позвольте вашим уведомлениям вставать в очередь, добавив в их классы интерфейс %%(t)ShouldQueue%% и типаж %%(t)Queueable%%. Эти интерфейс и типаж уже импортированы во все уведомления, создаваемые при помощи команды %%(sh)make:notification%%, поэтому вы можете сразу добавить их в класс своего уведомления: %% notify(new InvoicePaid($invoice)); %% Если вы хотите отложить доставку уведомления, вы можете прицепить метод %%delay()%% к созданию экземпляра уведомления: %% $when = Carbon::now()->addMinutes(10); $user->notify((new InvoicePaid($invoice))->delay($when)); %% == Почтовые уведомления == === Форматирование почтовых сообщений === Чтобы уведомление поддерживало отправку по email, вам надо определить метод %%toMail()%% в классе уведомления. Этот метод получает сущность %%$notifiable%% и должен возвращать экземпляр %%(t)Illuminate\Notifications\Messages\MailMessage%%. Почтовые сообщения могут содержать строки текста, а также "вызовы действий". Давайте посмотрим на пример метода %%toMail()%%: %% /** * Получить представление уведомления в виде письма. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { $url = url('/invoice/'.$this->invoice->id); return (new MailMessage) ->greeting('Привет!') ->line('Один из ваших счетов оплачен!') ->action('Посмотреть счёт', $url) ->line('Спасибо за использование нашего приложения!'); } %% .(alert) Обратите внимание, мы используем %%$this->invoice->id%% в нашем методе %%message()%%. Вы можете передать любые данные, необходимые вашему уведомлению для генерирования его сообщения, в конструктор уведомления. В этом примере мы регистрируем приветствие, строку с текстом, вызов действия, а затем ещё одну строку с текстом. Эти методы, предоставляемые объектом %%(t)MailMessage%%, позволяют легко и быстро форматировать небольшие транзакционные письма. Затем почтовый канал переведёт компоненты сообщения в приятный, удобный HTML-шаблон email с копией в виде простого текста. Вот пример письма, сгенерированного каналом %%(t)mail%%: {{Image /packages/proger/habravel/uploads/756-notification-example.png, height=500px}} .(alert) При отправке почтовых уведомлений не забудьте задать значение %%(t)name%% в файле %%(t)config/app.php%%. Это значение будет использоваться в заголовке и подвале сообщений ваших почтовых уведомлений. === Изменение получателя === При отправке уведомлений по каналу %%(t)mail%% система уведомлений будет автоматически искать свойство %%email%% в уведомляемой сущности. Вы можете изменить адрес email, используемый для доставки уведомления, определив метод %%routeNotificationForMail()%% на сущности: %% email_address; } } %% === Изменение темы === По умолчанию тема письма - имя класса уведомления в формате "Title Case". Например, если класс вашего уведомления называется %%(t)InvoicePaid%%, тема письма будет %%(t)Invoice Paid%%. Если вы хотите указать тему письма сами, вызовите метод %%subject()%% при создании вашего сообщения: %% /** * Получить представление уведомления в виде письма. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage) ->subject('Тема уведомления') ->line('...'); } %% === Изменение шаблонов === Вы можете изменить HTML-шаблоны и шаблоны в виде простого текста, используемые почтовыми уведомлениями, опубликовав ресурсы пакета уведомлений. После выполнения этой команды шаблоны почтовых уведомлений будут помещены в папку %%(t)resources/views/vendor/notifications%%: %%(sh) php artisan vendor:publish --tag=laravel-notifications %% === Сообщения об ошибках === Некоторые уведомления информирую пользователей об ошибках, таких как неудачная оплата счёта. Вы можете отметить, что почтовое сообщение связано с ошибкой, вызвав метод %%error()%% при создании сообщения. При использовании метода %%error()%% на почтовом сообщении кнопка вызова действия будет красной, а не синей: %% /** * Получить представление уведомления в виде письма. * * @param mixed $notifiable * @return \Illuminate\Notifications\Message */ public function toMail($notifiable) { return (new MailMessage) ->error() ->subject('Тема уведомления') ->line('...'); } %% == Уведомления для БД == === Требования === Канал уведомлений %%(t)database%% сохраняет информацию уведомлений в таблицу БД. Эта таблица будет содержать такую информацию, как тип уведомления и JSON-данные, описывающие уведомление. Вы можете сделать запрос к таблице, чтобы вывести уведомления в пользовательском интерфейсе приложения. Но перед этим вам надо создать таблицу для хранения ваших уведомлений. Вы можете использовать команду %%(sh)notifications:table%% для создания миграции с необходимой схемой таблицы: %%(sh) php artisan notifications:table php artisan migrate %% === Форматирование уведомлений для БД === Чтобы уведомление поддерживало сохранение в БД, вам надо определить метод %%toDatabase()%% или метод %%toArray()%% в классе уведомления. Этот метод получает сущность %%$notifiable%% и должен возвращать простой PHP-массив. Возвращённый массив будет закодирован в JSON и сохранён в столбец %%(t)data%% вашей таблицы %%(t)notifications%%. Давайте посмотрим на пример метода %%toArray()%%: %% /** * Получить представление уведомления в виде массива. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]; } %% **%%toDatabase()%% или %%toArray()%%** Метод %%toArray()%% также используется каналом %%(t)broadcast%% для определения того, какие данные вещать вашему JavaScript-клиенту. Если вы хотите иметь два разных представления в виде массива для каналов %%(t)database%% и %%(t)broadcast%%, вам надо определить метод %%toDatabase()%% вместо метода %%toArray()%%. === Обращение к уведомлениям === Когда уведомления сохранены в БД, вам нужен удобный способ для доступа к ним из вашей уведомляемой сущности. Типаж %%(t)Illuminate\Notifications\Notifiable%%, включённый в стандартную модель Laravel %%(t)App\User%%, содержит Eloquent-отношение %%(t)notifications%%, которое возвращает уведомления для сущности. Для получения уведомлений вы можете обратиться к этому методу, как к любому другому Eloquent-отношению. По умолчанию уведомления будут отсортированы по отметке времени %%(t)created_at%%: %% $user = App\User::find(1); foreach ($user->notifications as $notification) { echo $notification->type; } %% Если вы хотите получить только "непрочитанные" уведомления, используйте отношение %%(t)unreadNotifications%%. Эти уведомления так же будут отсортированы по отметке времени %%(t)created_at%%: %% $user = App\User::find(1); foreach ($user->unreadNotifications as $notification) { echo $notification->type; } %% .(alert) Для доступа к вашим уведомлениям из вашего JavaScript-клиента вам надо определить контроллер уведомлений для вашего приложения, который возвращает уведомления для уведомляемой сущности, такой как текущий пользователь. Затем вы можете сделать HTTP-запрос к URI этого контроллера из вашего JavaScript-клиента. === Пометка прочитанного уведомления === Обычно надо отметить уведомление "прочитанным", когда пользователь просмотрел его. Типаж %%(t)Illuminate\Notifications\Notifiable%% предоставляет метод %%markAsRead()%%, который изменяет поле %%(t)read_at%% записи уведомления в БД: %% $user = App\User::find(1); foreach ($user->unreadNotifications as $notification) { $notification->markAsRead(); } %% Но вместо перебора всех уведомлений вы можете использовать метод %%markAsRead()%% прямо на коллекции уведомлений: %% $user->unreadNotifications->markAsRead(); %% Также вы можете использовать массовый запрос на изменение, чтобы отметить все уведомления прочитанными, не получая их из БД: %% $user = App\User::find(1); $user->unreadNotifications()->update(['read_at' => Carbon::now()]); %% Само собой, вы можете удалить уведомления из таблицы целиком: %% $user->notifications()->delete(); %% == Вещание уведомлений == === Требования === Перед вещанием уведомлений вам надо познакомиться со службами ((//docs/v5/broadcasting вещания событий)) Laravel и настроить их. Вещание событий предоставляет способ реагировать на события серверной части Laravel в вашем JavaScript-клиенте. === Форматирование уведомлений для вещания === Канал %%(t)broadcast%% вещает уведомления с помощью сервисов ((//docs/v5/broadcasting вещания событий)) Laravel, позволяя вашему JavaScript-клиенту получать уведомления в реальном времени. Чтобы уведомление поддерживало вещание, вам надо определить метод %%()toBroadcast%% или метод %%()toArray%% в классе уведомления. Этот метод принимает сущность %%$notifiable%% и должен возвращать простой PHP-массив. Возвращённый массив будет закодирован в JSON и будет вещаться JavaScript-клиенту. Давайте посмотрим на пример метода %%toArray()%%: %% /** * Получить представление уведомления в виде массива. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ 'invoice_id' => $this->invoice->id, 'amount' => $this->invoice->amount, ]; } %% .(alert) В добавок к указанным вами данным вещание уведомлений будет также содержать поле %%(t)type%%, содержащее имя класса уведомления. **%%toBroadcast()%% или %%toArray()%%** Метод %%toArray()%% также используется каналом %%(t)database%% для определения того, какие данные сохранять в таблицу БД. Если вы хотите иметь два разных представления в виде массива для каналов %%(t)database%% и %%(t)broadcast%%, вам надо определить метод %%toBroadcast()%% вместо метода %%toArray()%%. === Прослушивание уведомлений === Уведомления будут вещаться в приватный канал в формате %%(t){notifiable}.{id}%%. Например, если вы посылаете уведомление экземпляру %%(t)App\User%% c ID равным %%(t)1%%, то уведомление будет вещаться в приватный канал %%(t)App.User.1%%. При использовании ((//docs/v5/broadcasting Laravel Echo)) вы легко можете слушать уведомления на канале вспомогательным методом %%notification()%%: %% Echo.private('App.User.' + userId) .notification((notification) => { console.log(notification.type); }); %% == SMS уведомления == === Требования === Отправка SMS уведомлений в Laravel обеспечивается с помощью ((https://www.nexmo.com/ Nexmo)). Перед отправкой уведомлений через Nexmo, вам надо установить Composer-пакет %%(t)nexmo/client%% и добавить несколько параметров в файл настроек %%(t)config/services.php%%. Вы можете скопировать этот пример настройки: %%(conf) 'nexmo' => [ 'key' => env('NEXMO_KEY'), 'secret' => env('NEXMO_SECRET'), 'sms_from' => '15556666666', ], %% Параметр %%(t)sms_from%% - телефонный номер, с которого будут отправляться ваши SMS сообщения. Вам надо сгенерировать этот номер для своего приложения в панели управления Nexmo. === Форматирование SMS уведомлений === Чтобы уведомление поддерживало отправку по SMS, вам надо определить метод %%()toNexmo%% в классе уведомления. Этот метод принимает сущность %%$notifiable%% и должен возвращать экземпляр %%(t)Illuminate\Notifications\Messages\NexmoMessage%%: %% /** * Получить представления уведомления в виде Nexmo / SMS. * * @param mixed $notifiable * @return NexmoMessage */ public function toNexmo($notifiable) { return (new NexmoMessage) ->content('Содержимое вашего SMS сообщения'); } %% === Изменение номера "From" === Если вы хотите отправлять некоторые уведомления с номера, отличающегося от указанного в вашем файле %%(t)config/services.php%%, вы можете использовать метод %%from()%% на экземпляре %%(t)NexmoMessage%%: %% /** * Получить представления уведомления в виде Nexmo / SMS. * * @param mixed $notifiable * @return NexmoMessage */ public function toNexmo($notifiable) { return (new NexmoMessage) ->content('Содержимое вашего SMS сообщения') ->from('15554443333'); } %% === Изменение получателя SMS === При отправке уведомлений по каналу %%(t)nexmo%% система уведомлений автоматически будет искать атрибут %%(t)phone_number%% в уведомляемой сущности. Если вы хотите изменить телефонный номер для доставки уведомления, определите метод %%routeNotificationForNexmo()%% на сущности: %% phone; } } %% == Уведомления Slack == === Требования === Перед отправкой уведомлений через Slack, вы должны установить HTTP-библиотеку Guzzle через Composer: %%(sh) composer require guzzlehttp/guzzle %% Также вам надо настроить интеграцию с "Входящим Webhook" для вашей Slack-команды. Эта интеграция предоставит вам URL, который можно использовать при ((#routing-slack-notifications направлении уведомлений Slack)). === Форматирование уведомлений Slack === Чтобы уведомление поддерживало отправку в виде Slack-сообщения, вам надо определить метод %%()toSlack%% в классе уведомления. Этот метод принимает сущность %%$notifiable%% и должен возвращать экземпляр %%(t)Illuminate\Notifications\Messages\SlackMessage%%. В Slack-сообщении может быть текстовое содержимое, а также "attachment" (вложение), которое форматирует дополнительный текст или массив полей. Давайте посмотрим на пример метода %%toSlack()%%: %% /** * Получить представление уведомления для Slack. * * @param mixed $notifiable * @return SlackMessage */ public function toSlack($notifiable) { return (new SlackMessage) ->content('Один из ваших счетов оплачен!'); } %% В этом примере мы просто отправляем одну строку текста в Slack, при этом будет создано сообщение, выглядящее вот так: {{Image /packages/proger/habravel/uploads/756-basic-slack-notification.png, height=55px}} **Вложения Slack** Также вы можете добавлять вложения в Slack-сообщения. Вложения обеспечивают более широкие возможности форматирования, чем простые текстовые сообщения. В этом примере мы отправим уведомление об ошибке - об исключении в приложении со ссылкой для просмотра подробной информации об исключении: %% /** * Получить представление уведомления для Slack. * * @param mixed $notifiable * @return SlackMessage */ public function toSlack($notifiable) { $url = url('/exceptions/'.$this->exception->id); return (new SlackMessage) ->error() ->content('Упс! Что-то пошло не так.') ->attachment(function ($attachment) use ($url) { $attachment->title('Исключение: файл не найден', $url) ->content('Файл [background.jpg] не найден.'); }); } %% Этот пример создаст такое Slack-сообщение: {{Image /packages/proger/habravel/uploads/756-basic-slack-attachment.png, height=114px}} Вложения также позволяют вам указать массив данных, который будет предоставлен пользователю. Эти данные будут представлены в виде таблицы для удобства чтения: %% /** * Получить представление уведомления для Slack. * * @param mixed $notifiable * @return SlackMessage */ public function toSlack($notifiable) { $url = url('/invoices/'.$this->invoice->id); return (new SlackMessage) ->success() ->content('Один из ваших счетов оплачен!') ->attachment(function ($attachment) use ($url) { $attachment->title('Счёт 1322', $url) ->fields([ 'Title' => 'Оплата сервера', 'Amount' => '$1,234', 'Via' => 'American Express', 'Was Overdue' => ':-1:', ]); }); } %% Этот пример создаст такое Slack-сообщение: {{Image /packages/proger/habravel/uploads/756-slack-fields-attachment.png, height=193px}} **Изменение отправителя и получателя** Вы можете использовать методы %%from()%% и %%to()%% для изменения отправителя и получателя. Метод %%from()%% принимает имя пользователя и идентификатор emoji, а метод %%to()%% принимает имя канала или пользователя: %% /** * Получить представление уведомления для Slack. * * @param mixed $notifiable * @return SlackMessage */ public function toSlack($notifiable) { return (new SlackMessage) ->from('Призрак', ':ghost:') ->to('#other') ->content('Это будет отправлено #other'); } %% ((#routing-slack-notifications)) === Изменение получателя уведомлений Slack === Для направления уведомлений Slack в нужное место определите метод %%routeNotificationForSlack()%% на уведомляемой сущности. Он должен возвращать URL того webhook, которому должно быть доставлено уведомление. Webhook URL можно генерировать с помощью добавления сервиса "Входящий Webhook" в вашу Slack-команду: %% slack_webhook_url; } } %% == События уведомлений == Когда отправляется уведомление, система уведомлений создаёт событие %%(t)Illuminate\Notifications\Events\NotificationSent%%. Оно содержит "уведомляемую" сущность и экземпляр самого уведомления. Вы можете зарегистрировать слушателей этого события в своём %%(t)EventServiceProvider%%: %% /** * Привязка слушателей события для приложения. * * @var array */ protected $listen = [ 'Illuminate\Notifications\Events\NotificationSent' => [ 'App\Listeners\LogNotification', ], ]; %% .(alert) После регистрации слушателей в %%(t)EventServiceProvider%% используйте Artisan-команду %%(sh)event:generate%%, чтобы быстро сгенерировать классы слушателей. В слушателе событий вы можете обращаться к свойствам события %%(t)notifiable%%, %%(t)notification%% и %%(t)channel%%, чтобы узнать больше о получателе или о самом уведомлении: %% /** * Обработка события. * * @param NotificationSent $event * @return void */ public function handle(NotificationSent $event) { // $event->channel // $event->notifiable // $event->notification } %% == Другие каналы == Laravel поставляется с набором каналов для уведомлений, но вы можете написать свой собственный драйвер для доставки уведомлений по другим каналам. В Laravel это делается просто. Сначала определите класс с методом %%send()%%. Метод должен получать два аргумента: %%$notifiable%% и %%$notification%%: %% toVoice($notifiable); // Send notification to the $notifiable instance... } } %% После определения класса канала уведомлений вы можете просто вернуть имя класса из метода %%via()%% любого из ваших уведомлений: %%