Size: a a a

2020 October 03

AD

Alexander Danilov in symfony
Можно не использовать ни одной библиотеки, ни одного фреймворка, все писать самому. В чем проблема? Если так не нравится опенсорс.
источник

DD

Dima Denisov in symfony
Приветствую, какой есть механизм (если есть) в доктрине для кеширования запросов, мне нужно чтобы и все релейшены также кешировались?
источник

D

Dmitry in symfony
источник

D

Dmitry in symfony
Думаю должно помочь
источник
2020 October 04

D

Dos in symfony
Всем привет!

Использую Notifier. Прочитал документацию, но не увидел для себя два важных нюанса, качаемых использования этого компонента:

1. Управление подписками на разные каналы и типы событий из базы данных. Т.е. пользователь сам должен выбирать по какому каналу что доставлять используя UI. В данный момент требуются каналы: в сервис, mail, sms. В принципе кое-как реализовал систему подписок на топики. Но как теперь связать это с текущим компонентом?
2. Трансфер в базу данных для вывода в списке уведомлений в UI.

И ещё есть вопрос
Для чего есть общий класс Notification, когда есть отдельные типы сообщений по транспортам: SmsMessage, EmailMessage. Когда использовать Notification, а когда отдельные типы?

Можете подсказать как можно реализовать данный функционал или поделиться готовыми примерами? Уже вторую ночь не сплю) Буду очень благодарен вам!
источник

D

Dos in symfony
Я создал свой ОБЩИЙ Hendler, но не думаю, что это правильно. Выглядит это так:

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

               }
           }
       }
   }
}
источник

ПГ

Павел Г. in symfony
Dos
Я создал свой ОБЩИЙ Hendler, но не думаю, что это правильно. Выглядит это так:

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

               }
           }
       }
   }
}
Ну ifы тут отчасти неверно, так как при появлении нового чанела, нужно будет менять этот класс, а в идеале нужно добавлять фичи, не меняя старый функционал.
источник

VK

Vladyslav Kopaihorod... in symfony
Павел Г.
Ну ifы тут отчасти неверно, так как при появлении нового чанела, нужно будет менять этот класс, а в идеале нужно добавлять фичи, не меняя старый функционал.
И пользоваться gistом
источник

D

Dos in symfony
Павел Г.
Ну ifы тут отчасти неверно, так как при появлении нового чанела, нужно будет менять этот класс, а в идеале нужно добавлять фичи, не меняя старый функционал.
Получается нужно под каждый транспорт свой handler? SmsHandler, EmailHandler... А не общий класс NotificationHandler? Верно?)
источник

D

Dos in symfony
Vladyslav Kopaihorodskyi
И пользоваться gistом
Извиняюсь) Нужно продублировать а Gist?
источник

VK

Vladyslav Kopaihorod... in symfony
удалить и использовать gist
источник

ПГ

Павел Г. in symfony
Dos
Получается нужно под каждый транспорт свой handler? SmsHandler, EmailHandler... А не общий класс NotificationHandler? Верно?)
Можно разные хандлеры или один хандлер подтягивающий разные месенджеры. Посмотрите паттерн цепочка.
источник

IG

Ivan Grigoriev in symfony
Тут больше мост должен подойти. Разные сообщения и разные транспорта.
источник

IG

Ivan Grigoriev in symfony
С другой стороны, приведённый код намекает, что мессаджи - это внутренний dto конкретного сервиса, и никто кроме него о них знать не должен. И нужен какой-нибудь gateway у каждого сервиса, который честно просит нужный набор данных.
источник

D

Dmitry in symfony
если я правильно понял задумку автора, то имхо стоит сменить идею
может стоит попробовать просто бросать событие (Publisher->publish(SomethingHasHappenedEvent($userData, $messageData)))

а потом некий потребитель, консьюмер, коих должно быть по числу каналов, ловит каждое сообщение и делает проверку по каналам юзера (тип сообщения есть, каналы юзера прилетели с UserData - можем сделать вывод "наше" ли сообщение)

это позволит отвязать сообщения от их отсылки, не забудем поменять свитч или ифы где-то там когда создадим новый канал (новый тип просто подпишется на ивенты и будет мониторить свой тип)
источник

IG

Ivan Grigoriev in symfony
Dmitry
если я правильно понял задумку автора, то имхо стоит сменить идею
может стоит попробовать просто бросать событие (Publisher->publish(SomethingHasHappenedEvent($userData, $messageData)))

а потом некий потребитель, консьюмер, коих должно быть по числу каналов, ловит каждое сообщение и делает проверку по каналам юзера (тип сообщения есть, каналы юзера прилетели с UserData - можем сделать вывод "наше" ли сообщение)

это позволит отвязать сообщения от их отсылки, не забудем поменять свитч или ифы где-то там когда создадим новый канал (новый тип просто подпишется на ивенты и будет мониторить свой тип)
Кстати, да. В основном именно так и делаю. Благо symfony со своей событийной архитектурой поощряет загружать шину всевозможными событиями, отделяя функционал над сущностями и с ними.

Единственное, приходится писать функциональные тесты, проверяющие, что после обработки сущности дёргается нужный сервисный функционал.
источник

D

Dmitry in symfony
Ivan Grigoriev
Кстати, да. В основном именно так и делаю. Благо symfony со своей событийной архитектурой поощряет загружать шину всевозможными событиями, отделяя функционал над сущностями и с ними.

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

D

Dmitry in symfony
хотя, возможно хватить и интеграционных, а не функциональных
источник

IG

Ivan Grigoriev in symfony
И ещё  момент, что если так разделять функционал, то нужно либо явно флашить стейт доктрины,  либо делать это в шине до и после диспатча сообщения.
источник

D

Dmitry in symfony
не понял, зачем ?
флаш был до публикации события, т.е в событие попадут уже последние данные юзера
источник