Эта статья представляет собой небольшое руководство о том, как начать транслировать уведомления Laravel с помощью Pusher и получать их в React. У меня были проблемы с поиском всей необходимой документации, когда я сам начинал вещание. Поскольку я одновременно просматривал разные учебные пособия / статьи, мне было трудно отлаживать возникающие проблемы.

У меня есть работающее веб-приложение, созданное с помощью Laravel и React, и теперь мне нужно, чтобы мои пользователи получали уведомления в режиме реального времени.

Laravel предоставляет канал Pusher из коробки, и я решил использовать его. На тот момент я никогда не работал с сокетами (что отчасти печально, поскольку я был разработчиком (Laravel) в течение 4 лет), и я понятия не имел, как к этому подойти.

Я разделил задачу на несколько более мелких:

  • Настроить Pusher и трансляцию в Laravel
  • Создать класс (ы) уведомлений
  • Добавьте Laravel Echo и PusherJS в React
  • Подпишитесь на канал (ы)

Настроить трансляцию Pusher в Laravel

Мы также можем разбить эту задачу на меньшие:

  • Установить Pusher
  • Настройте файлы конфигурации и .env
  • Настроить авторизацию канала
  • Настроить модель пользователя

Прежде всего, нам нужно добавить в проект пакет Pusher composer.

composer require pusher/pusher-php-server "~3.0"

Во-вторых, давайте настроим файлы конфигурации и переменные среды.

В config/broadcasting.php файле должна быть опция толкателя в подключениях:

'default' => env('BROADCAST_DRIVER', 'null'),
'connections' => [
    'pusher' => [
        'driver' => 'pusher',
        'key' => env('PUSHER_APP_KEY'),
        'secret' => env('PUSHER_APP_SECRET'),
        'app_id' => env('PUSHER_APP_ID'),
        'options' => [
            'cluster' => env('PUSHER_APP_CLUSTER'),
        ],
    ],
...
],

Теперь давайте добавим необходимые переменные среды в файл .env.

BROADCAST_DRIVER=pusher
...
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=

Нам нужно раскомментировать App \ Providers \ BroadcastServiceProvider.php в config/app.php

'providers' => [    
    ...
    App\Providers\BroadcastServiceProvider.php,
    ...
]

Теперь давайте посмотрим на файл, который мы только что раскомментировали. Здесь важен метод Broadcast :: routes (), который определяет маршруты для ответа на запросы авторизации канала. Он принимает $options в качестве параметра так же, как Route::group() принимает их, поэтому в моем случае, поскольку я использую токены JWT для аутентификации, мне нужно, чтобы запрос прошел через мое промежуточное ПО auth: api . Вызов метода routes регистрирует broadcasting/auth маршрут для обработки запросов авторизации.

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes(['middleware' => ['auth:api']]);
        
        require base_path('routes/channels.php');
    }
}

Упрощенная версия того, как работает вещание, заключается в том, что события проходят через каналы, и для получения событий мы должны подписаться на канал. Это то, что я делаю в своем приложении React, чтобы получать уведомления. Вы можете узнать больше о каналах в официальной документации Laravel. Я использую частные каналы, поэтому для получения событий требуется авторизация. Вместе с событиями мы можем передавать дополнительные данные.

Нам нужно определить нашу логику авторизации канала. В routes/channels.php файле для нас уже есть пример канала. Я только немного изменил название канала.

Broadcast::channel('App.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

У каждого пользователя есть свой канал, и в этом примере только сам пользователь может подписаться на его канал.

Далее нам нужно настроить нашу модель пользователя. В частности, нам нужно сделать две вещи:

  • Используйте свойство, подлежащее уведомлению
  • Добавить receivesBroadcastNotificationsOn функцию. Здесь мы определяем канал, по которому начинают проходить уведомления пользователей. Убедитесь, что он соответствует каналу, указанному в channels.php.
use Illuminate\Notifications\Notifiable;
/**
 * The channels the user receives notification broadcasts on.
 *
 * @return string
 */
public function receivesBroadcastNotificationsOn()
{
    return 'App.User.' . $this->id;
}

Создать класс (ы) уведомлений

Допустим, у нас есть система, в которой пользователи могут публиковать статьи и комментировать указанные статьи. Если кто-то добавит комментарий к моей статье, я хочу получить уведомление об этом. Итак, наш список TODO выглядит так:

  • Создайте класс уведомлений
  • Уведомить пользователя о добавлении комментария

В классе уведомлений мы должны определить несколько специальных методов вещания, таких как toBroadcast method, где мы можем решить, какие данные передавать с уведомлением. Если вы используете Laravel 5.7, мы можем указать тип широковещательного события, и это сделает привязку к типам событий немного удобнее.

<?php

namespace Guava\Communication\Notifications;

use App\Models\Comment;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\BroadcastMessage;

class NewComment extends Notification implements ShouldQueue
{
    use Queueable;    
    /** @var Comment */
    private $comment;

    public function __construct(Comment $comment)
    {
        $this->comment = $comment;
    }
    public function via($notifiable) 
    {
         return ['database', 'broadcast'];
    }
    public function toArray($notifiable)
    {
         return [
            'post' => [
                'id' => $this->comment->post_id,
            ],
            'author' => [
                'id' => $this->comment->user_id,
                'first_name' => $this->comment->user->first_name,
                'last_name' => $this->comment-user->last_name,
            ],
            'comment' => [
                'id' => $this->comment->id,
                'body' => $this->comment->body,
                'commented_at' => $this->comment->commented_at,
            ],
        ];
     }
    public function toBroadcast($notifiable)
    {
        return new BroadcastMessage($this->toArray($notifiable));
    }
    public function broadcastType()
    {
        return 'new-comment';
    }

}

В моем случае я также хочу использовать уведомления базы данных и хочу, чтобы они были структурно такими же, как и BroadcastMessage, поэтому я использую метод toArray для определения возвращаемых данных. Если вы не хотите этого делать, просто удалите метод database из via и toArray.

Я создал упрощенную конечную точку для хранения комментария и уведомления пользователя.

public function store(Post $post, StoreCommentRequest $request)
{
     $comment = $post->addComment($request->all());
     $post->author()->notify(NewComment($comment));
     return new CommentResource($comment);
}

Чтобы отладить и проверить, все ли работает, установитеBROADCAST_DRIVER=log в файле .env и посмотрите, успешно ли добавление комментария добавляет информацию о транслируемом сообщении в журналы.

Добавить Pusher в React

npm install --save pusher-js laravel-echo

Я представлю упрощенную версию того, как инициализировать экземпляр Echo и как подписаться на каналы.

import Echo from 'laravel-echo';
const options = {
  broadcaster: 'pusher',
  key: config.pusher.key,
  cluster: config.pusher.cluster,
  forceTLS: config.pusher.tls,
  //authEndpoint is your apiUrl + /broadcasting/auth
  authEndpoint: config.pusher.authEndpoint, 
  // As I'm using JWT tokens, I need to manually set up the headers.
  auth: {
    headers: {
      Authorization: `Bearer ${token}`,
      Accept: 'application/json',
    },
  },
};

const echo = new Echo(options);
echo.private(`App.User.${userId}`).notification((data) => {
    console.log(data);
});

Уведомления передаются по частному каналу. Laravel Echo - намного более удобный вариант по сравнению с пакетом PusherJS при использовании уведомлений Laravel для трансляции, потому что есть вспомогательная функция notification, которая упрощает подписку на уведомления. В противном случае вам пришлось бы подписаться на событие под названием Illuminate\Notifications\Events\BroadcastNotificationCreated и продолжить работу.

Надеюсь, это поможет вам, я провел почти весь день, начиная с нуля, без особых предварительных знаний о сокетах, широковещании и уведомлениях Laravel. Большую часть информации здесь можно найти в официальной документации Laravel о вещании уведомлений и вещании в целом.

Я полностью открыт для всех видов обратной связи и способов создания более чистого и эффективного кода. Я использую React всего несколько месяцев, так что мне нужно многому научиться.