deferring the sending of notification to kernel.terminate: prepare

This commit is contained in:
Julien Fastré 2022-04-22 11:34:41 +02:00
parent e246ccbcd9
commit 33f93d484d
6 changed files with 137 additions and 13 deletions

View File

@ -0,0 +1,47 @@
<?php
namespace Chill\MainBundle\Notification\EventListener;
use Chill\MainBundle\Notification\NotificationPersisterInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
class PersistNotificationOnTerminateEventSubscriber implements EventSubscriberInterface
{
private EntityManagerInterface $em;
private NotificationPersisterInterface $persister;
public function __construct(EntityManagerInterface $em, NotificationPersisterInterface $persister)
{
$this->em = $em;
$this->persister = $persister;
}
public static function getSubscribedEvents()
{
return [
'kernel.terminate' => [
['onKernelTerminate', 1024], // we must ensure that the priority is before sending email
]
];
}
public function onKernelTerminate(TerminateEvent $event): void
{
if ($event->isMasterRequest()) {
$this->persistNotifications();
}
}
private function persistNotifications(): void
{
foreach ($this->persister->getWaitingNotifications() as $notification) {
$this->em->persist($notification);
}
$this->em->flush();
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Chill\MainBundle\Notification;
use Chill\MainBundle\Entity\Notification;
class NotificationPersister implements NotificationPersisterInterface
{
private array $waitingNotifications = [];
public function persist(Notification $notification): void
{
$this->waitingNotifications[] = $notification;
}
/**
* @return array|Notification[]
*/
public function getWaitingNotifications(): array
{
return $this->waitingNotifications;
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Chill\MainBundle\Notification;
use Chill\MainBundle\Entity\Notification;
/**
* Store the notification
*
* Those notification will be stored into database by the kernel. This
* will also ensure that this happens outside of regular operations
* operated by the entity manager.
*/
interface NotificationPersisterInterface
{
public function persist(Notification $notification): void;
/**
* @return array|Notification[]
*/
public function getWaitingNotifications(): array;
}

View File

@ -0,0 +1,34 @@
<?php
namespace Notification\EventListener;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Notification\EventListener\PersistNotificationOnTerminateEventSubscriber;
use Chill\MainBundle\Notification\NotificationPersister;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
class PersistNotificationOnTerminateEventSubscriberTest extends TestCase
{
use ProphecyTrait;
public function testNotificationIsPersisted()
{
$persister = new NotificationPersister();
$em = $this->prophesize(EntityManagerInterface::class);
$em->persist(Argument::type(Notification::class))->shouldBeCalledTimes(1);
$em->flush()->shouldBeCalledTimes(1);
$event = $this->prophesize(TerminateEvent::class);
$event->isMasterRequest()->willReturn(true);
$eventSubscriber = new PersistNotificationOnTerminateEventSubscriber($em->reveal(), $persister);
$notification = new Notification();
$persister->persist($notification);
$eventSubscriber->onKernelTerminate($event->reveal());
}
}

View File

@ -3,6 +3,11 @@ services:
autowire: true
autoconfigure: true
Chill\MainBundle\Notification\:
resource: ../../Notification/
autoconfigure: true
autowire: true
Chill\MainBundle\Notification\Mailer:
arguments:
$logger: '@Psr\Log\LoggerInterface'
@ -17,12 +22,6 @@ services:
arguments:
$handlers: !tagged_iterator chill_main.notification_handler
Chill\MainBundle\Notification\NotificationPresence: ~
Chill\MainBundle\Notification\Templating\NotificationTwigExtension: ~
Chill\MainBundle\Notification\Templating\NotificationTwigExtensionRuntime: ~
Chill\MainBundle\Notification\Counter\NotificationByUserCounter:
autoconfigure: true
autowire: true

View File

@ -13,6 +13,7 @@ namespace Chill\PersonBundle\AccompanyingPeriod\Events;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Notification\NotificationPersisterInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\Event\LifecycleEventArgs;
@ -24,7 +25,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class UserRefEventSubscriber implements EventSubscriberInterface
{
private EntityManagerInterface $em;
private NotificationPersisterInterface $notificationPersister;
private EngineInterface $engine;
@ -32,12 +34,12 @@ class UserRefEventSubscriber implements EventSubscriberInterface
private TranslatorInterface $translator;
public function __construct(Security $security, TranslatorInterface $translator, EngineInterface $engine, EntityManagerInterface $em)
public function __construct(Security $security, TranslatorInterface $translator, EngineInterface $engine, NotificationPersisterInterface $notificationPersister)
{
$this->security = $security;
$this->translator = $translator;
$this->engine = $engine;
$this->em = $em;
$this->notificationPersister = $notificationPersister;
}
public static function getSubscribedEvents()
@ -65,9 +67,6 @@ class UserRefEventSubscriber implements EventSubscriberInterface
) {
$this->generateNotificationToUser($period);
}
// we are just out of a flush operation. Launch a new one
$this->em->flush();
}
private function generateNotificationToUser(AccompanyingPeriod $period)
@ -89,7 +88,7 @@ class UserRefEventSubscriber implements EventSubscriberInterface
))
->addAddressee($period->getUser());
$this->em->persist($notification);
$this->notificationPersister->persist($notification);
}
private function onPeriodConfirmed(AccompanyingPeriod $period)