D
D
Dos2020-10-03 16:43:17
symfony
Dos, 2020-10-03 16:43:17

How to use notifier?

Hey! I'm confused with the development of notifications on the site. I found a ready-made symfony / notifier component in the symphony. It is necessary to send messages through different channels, while subscribers themselves choose which channels to send messages to them, i.e. subscription information is stored in a database. At the moment, we need notifications by channels: service, email, sms. The service is essentially a table in the database, to be displayed in the list on the service, for example, like Yandex has a notification block or similar systems.

I implemented a system of subscriptions to different channels: service, mail, sms. She works and everything is fine with her. Users subscribe to the created notification types. But now we need to connect everything somehow with this component using Event Dispatcher and Messanger from Symfony.

1. As I understand it, I have to publish an event through the EventDispathcher, for example, "user registered". This is a domain event that is published through an aggregate.

// Событие
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. I hang a listener/subscriber on this event and in this subscriber I implement sending to 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. After that, we create a NotificationMessage that will publish an event to the bus
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. And we make a NotificationHandler handler for it

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);

                }
            }
        }
    }
}


As a result, I had the following questions:
  1. Do I need to post the event first to the Event Dispatcher and then to the Messanger via the listener. Or should I post directly to Messenger? And what is the difference between Event Dispather and Messanger then?
  2. Should I implement my own NotificationMessage and NotificationHandler? And I also can’t understand whether these NotificationMessage messages should be separated by channels, for example, as in the EmailMessage, SmsMessabe library?
  3. Here it turned out very strange, I think? Or should it be? Maybe I did too much and Symfony Notifier already has everything I need?
  4. How do I add a notification channel to the database to display this notification in the database?


In general, I just can not think of how the event is correct. Send messages through different channels, show them in the service and how to properly publish these messages. Please advise on this issue. How do you use this component on large projects? I'm confused about something. If there are any good examples, I will gladly study them. If something is not clear described - tell me in the comments, corrected.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Daria Motorina, 2020-10-03
@glaphire

Flow
1.1. Create a listener/subscriber, catch the event itself (symphonic or custom)
1.2. In the event handler, create a message with notification data (if you need to save data for other processing, then write it to the entity, and duplicate it in the message), throw the message into the bus
2. Create a message handler
3. Set up asynchronous processing of these messages in the messenger configs
Documentation there is a very similar example - creating-a-message-handler
Messenger has a separate configuration for retry.
I didn’t make exactly the same system, I had notifications on a different framework, and in the course on symfonycasts about Messenger there were many examples on setting up this case) I think it’s worth clarifying with the customer / manager the exact flow of all these times of resending, data storage, confirmation of a successful submission, because some may be critical and some may be secondary.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question