Привет! Я что-то запутался с разработкой уведомлений на сайте. Нашел у симфонии готовый компонент symfony/notifier. Необходимо отправлять сообщения по разным каналам, при этом подписчики сами выбирают по каким каналам им присылать сообщения, т.е. информация о подписках хранится в базе данных. В данный момент нужны уведомления по каналам: сервис, email, sms. Сервис это по сути таблица в базе данных, для вывода в списке на сервисе, например, как у Яндекс блок уведомлений или подобных систем.
Я реализовал у себя систему подписок на Разные каналы: сервис, почта, смс. Она работает и в ней всё хорошо. Пользователи подписываются на созданные типы уведомлений. Но теперь надо всё связать как-то с этим компонентом используя Event Dispatcher и Messanger от Symfony.
1. Как я понимаю — я должен опубликовать событие через EventDispathcher, например, «пользователь зарегистрирован». Это доменное событие, которое публикуется через агрегат.
// Событие
class UserRegistered extends Event
{
public const NAME = 'user.registered';
protected $user;
public function __construct(User $user)
{
$this-> user = $user;
}
public function getUser()
{
return $this->user;
}
}
use Symfony\Component\EventDispatcher\EventDispatcher;
$dispatcher = new EventDispatcher();
$user = new User();
$event = new UserRegistered($user);
/ Публикация
$dispatcher->dispatch($event, UserRegistered::NAME);
2. На это событие я вешаю слушателя/подписчика и в этом подписчике реализовываю отправку в Messanger.
class NotificationSubscriber implements EventSubscriberInterface
{
private $twig;
private $bus;
public function __construct(Environment $twig, MessageBusInterface $bus)
{
$this->twig = $twig;
$this->bus = $bus;
}
public static function getSubscribedEvents()
{
return [
UserRegistered::NAME => 'onNotification',
];
}
public function onNotification(UserRegistered $event)
{
$notification = new NotificationMessage(
UserRegistered::NAME,
sprintf('Пользователь %s зарегистрирован', $event->getUser()->getName()),
$this->twig->render('notification/user-created.twig')//Шаблон User Created
);
$this->bus->dispatch($notification);
}
}
3. После чего мы создаём NotificationMessage, который опубликует событие в шину
class NotificationMessage
{
private $content;
private $type;
private $subject;
public function __construct(string $type, $subject, string $content)
{
$this->type = $type;
$this->content = $content;
$this->subject = $subject;
}
public function getType(): string
{
return $this->type;
}
public function getSubject(): string
{
return $this->subject;
}
public function getContent(): string
{
return $this->content;
}
}
4. И делаем для него обработчик NotificationHandler
use App\Model\Notification\Entity\Subscriber\SubscriberRepository;
use App\Model\Notification\Entity\Subscriber\Subscriber;
use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\NotifierInterface;
use Symfony\Component\Notifier\Recipient\Recipient;
use Twig\Environment;
class NotificationHandler implements MessageHandlerInterface
{
private $subscribers;
private $notifier;
private $texter;
public function __construct(SubscriberRepository $subscribers, NotifierInterface $notifier, TexterInterface $texter)
{
$this->subscribers = $subscribers;
$this->notifier = $notifier;
$this->texter = $texter;
}
public function __invoke(NotificationMessage $message)
{
/** @var Subscriber[] $subscribers */
$subscribers = $this->subscribers->getAllActiveForType($message->getType());
foreach ($subscribers as $subscriber) {
foreach ($subscriber->getChannels() as $channel) {
if ($channel->isForChannel('email')) {
$notification = (new Notification($message->getSubject()))
->content('You got a new invoice for 15 EUR.');
// The receiver of the Notification
$recipient = new Recipient(
$subscriber->getEmail(),
$subscriber->getPhone()
);
// Send the notification to the recipient
$this->notifier->send($notification, $recipient);
}
if ($channel->isForChannel('sms')) {
$sms = new SmsMessage(
$subscriber->getPhone(),
$message->getContent()
);
$this->texter->send($sms);
}
if ($channel->isForChannel('service')) {
$service = new ServiceMessage(
$recipient,
$message->getSubject(),
$message->getContent()
);
$this->servicer->send($service);
}
}
}
}
}
В итоге у меня появились такие вопросы:
- Нужно ли мне публиковать событие сначала в Event Dispatcher, а затем в Messanger через слушателя. Либо мне напрямую публиковать в Messanger? И в чём тогда различие Event Dispather от Messanger?
- Стоит ли мне реализовывать свои NotificationMessage и NotificationHandler? И так же не могу понять нужно ли разделять по каналам эти NotificationMessage сообщения, например, как в бибилиотеке EmailMessage, SmsMessabe?
- Здесь он получился очень странным, думаю? Или он должен быть таким? Может быть я наворотил слишком много и Symfony Notifier имеет уже всё, что мне нужно?
- Как мне добавить канал уведомления в базу данных, чтобы отображать это уведомление в базе?
В общем и целом я никак не могу додуматься как по событию правильно. Отправлять сообщения по разным каналам, показывать их в сервисе и как правильно публиковать эти сообщения. Подскажите, пожалуйста в этом вопросе. Как вы используете этот компонент на крупных проектах? Я что-то запутался. Если есть какие-то хорошие примеры - с радостью их изучу. Если что-то не понятно описал - скажите в комментариях, исправлюсь.