<?php
namespace App\EventSubscriber;
use App\Entity\Adult;
use App\Entity\Notification;
use App\Entity\NotificationMessage;
use App\Entity\NotificationReceipt;
use App\Entity\Referral;
use App\Entity\User;
use App\Event\NotificationEvent;
use App\Event\ReferralEvent;
use App\Event\UserEvent;
use App\Service\SESService;
use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Twig\Environment;
class NotificationSubscriber implements EventSubscriberInterface
{
protected $accessor;
/** @var ManagerRegistry*/
protected $doctrine;
/** @var LoggerInterface */
protected $logger;
/** @var SESService */
protected $sesService;
/** @var Environment */
protected $twig;
/** @var RouterInterface */
protected $router;
protected $resetTtl;
public function __construct(LoggerInterface $logger, SESService $sesService, ManagerRegistry $doctrine, Environment $twig, RouterInterface $router, $resetTtl)
{
$this->accessor = PropertyAccess::createPropertyAccessor();
$this->doctrine = $doctrine;
$this->logger = $logger;
$this->sesService = $sesService;
$this->twig = $twig;
$this->router = $router;
$this->resetTtl = $resetTtl;
}
public function getSubscribedEvents()
{
return [
UserEvent::class => 'onUserEvent',
ReferralEvent::class => 'onReferralEvent'
];
}
public function onUserEvent(UserEvent $event)
{
$notifications = $this->getNotifications($event);
$this->logger->debug("****** NotificationSubscriber onUserEvent " . $event->getTimestamp()->format('Y-m-d H:i:s'));
foreach($notifications as $notification) {
/** @var Notification $notification */
$messages = $notification->getNotificationMessages();
$this->logger->debug("****** Found notification: " . $notification->getId());
// Create NotificationReceipts for each Targeted User
foreach ($messages as $message) {
$this->logger->debug("****** Found notification message: " . $message->getId());
switch ($message->getTarget()) {
case NotificationMessage::TARGET_USER_SELF:
$user = $event->getEntity();
$this->createNotificationReceipt($notification, $message, [
'target' => $this->getTargetContextUser($user),
'properties' => $event->getAdditionalContext()
], $user);
break;
default:
$this->logger->error("Invalid target '" . $message->getTarget() . "' for notification with id: " . $notification->getId());
continue 2;
}
}
}
}
public function onReferralEvent(ReferralEvent $event)
{
$notifications = $this->getNotifications($event);
$this->logger->debug("****** NotificationSubscriber onReferralEvent");
foreach($notifications as $notification) {
/** @var Notification $notification */
$messages = $notification->getNotificationMessages();
$this->logger->debug("****** Found notification: " . $notification->getId());
// Create NotificationReceipts for each Targeted User
foreach ($messages as $message) {
$this->logger->debug("****** Found notification message: " . $message->getId());
switch ($message->getTarget()) {
case NotificationMessage::TARGET_REFERRAL_AUTHOR:
$referral = $event->getReferral();
$user = $referral->getCreatedBy();
$this->createNotificationReceipt($notification, $message, [
'target' => $this->getTargetContextUser($user),
'properties' => $event->getAdditionalContext()
], $user);
break;
case NotificationMessage::TARGET_REFERRAL_PARENTS:
$referral = $event->getReferral();
/** @var Adult $adult */
foreach ( $referral->getAdults() as $adult ) {
$this->createNotificationReceipt($notification, $message, [
'target' => $this->getTargetContextAdult($adult),
'properties' => $event->getAdditionalContext()
], null);
}
break;
default:
$this->logger->error("Invalid target '" . $message->getTarget() . "' for notification with id: " . $notification->getId());
continue 2;
}
}
}
}
protected function createNotificationReceipt(Notification $notification, NotificationMessage $message, array $context, ?User $user) {
$this->logger->debug("****** NotificationSubscriber createNotificationReceipt(" . $notification->getId() . ", " . $message->getId() . ", " . $context['target']['email'] . ")");
$receipt = new NotificationReceipt();
$receipt->setNotificationMessage($message);
$receipt->setRecipient($user);
$receipt->setCreatedAt(new \DateTime());
$receipt->setContext($context);
$this->doctrine->getManager()->persist($receipt);
if ( $message->getEmailEnabled() ) {
$this->logger->debug("****** NotificationSubscriber creating template from variables: " . json_encode($context));
$subject = $message->getEmailSubject();
$body = $message->getEmailBody();
$template = $this->twig->createTemplate($body);
$body = $template->render($context);
$this->logger->debug("****** TEST createNotificationReceipt(" . $notification->getId() . ", " . $message->getId() . ", " . $context['target']['email'] . ") attempting to send email (" . $subject . " => " . $body . ")");
try {
$this->sesService->send($user->getEmail(), $subject, $body);
} catch ( \Exception $ex ) {
$this->logger->error("NotificationSubscriber.createNotificationReceipt receieved an error when attempting to send an email: " . $ex->getMessage());
}
}
if ( $message->getSmsEnabled() ) {
// TODO: Implement SMS handling
}
if ( $message->getAlertEnabled() ) {
// TODO: Implement in-app alert handling
}
}
protected function getTargetContext($entity) {
switch (get_class($entity)) {
case User::class:
return $this->getTargetContextUser($entity);
case Adult::class:
return $this->getTargetContextAdult($entity);
default:
return [];
}
}
protected function getTargetContextUser(User $user)
{
// User $user
$token = $user->getConfirmationToken() ?: '';
// RouterInterface $router
$confirmationUrl = str_replace('http:', 'https:', $this->router->generate('app_confirm_user', [
'token' => $token
], UrlGeneratorInterface::ABSOLUTE_URL));
$resetUrl = str_replace('http:', 'https:', $this->router->generate('app_reset_user', [
'token' => $token
], UrlGeneratorInterface::ABSOLUTE_URL));
// int $resetTtl
$passwordExpiresAt = (new \DateTime())->add(\DateInterval::createFromDateString($this->resetTtl . ' seconds'));
date_timezone_set($passwordExpiresAt, timezone_open('America/New_York'));
return [
'id' => $user->getId(),
'type' => 'User',
'prefix' => ($user->prefix) ? $user->prefix->getDescription() : '',
'prefixES' => ($user->prefix) ? $user->prefix->getDescriptionEs() : '',
'firstName' => $user->firstName,
'lastName' => $user->lastName,
'suffix' => ($user->suffix) ? $user->suffix->getDescription() : '',
'suffixES' => ($user->suffix) ? $user->suffix->getDescriptionEs() : '',
'homePhone' => ($user->homePhoneNumber) ? implode("-", [$user->homePhoneNumber->getAreaCode(), $user->homePhoneNumber->getPrefix(), $user->homePhoneNumber->getSuffix()]) : '',
'mobilePhone' => ($user->mobilePhoneNumber) ? implode("-", [$user->mobilePhoneNumber->getAreaCode(), $user->mobilePhoneNumber->getPrefix(), $user->mobilePhoneNumber->getSuffix()]) : '',
'workPhone' => ($user->workPhoneNumber) ? implode("-", [$user->workPhoneNumber->getAreaCode(), $user->workPhoneNumber->getPrefix(), $user->workPhoneNumber->getSuffix()]) : '',
'email' => $user->getEmail(),
'confirmationUrl' => $confirmationUrl,
'resetUrl' => $resetUrl,
'expirationTimeUS' => $passwordExpiresAt->format('m-d-Y g:ia'),
'expirationTimeSTD' => $passwordExpiresAt->format('d-m-Y g:ia')
];
}
protected function getTargetContextAdult(Adult $adult) {
return [
'id' => $adult->getId(),
'type' => 'Adult',
'firstName' => $adult->getFirstName(),
'lastName' => $adult->getLastName(),
'homePhone' => ($adult->getHomePhoneNumber()) ? implode("-", [$adult->getHomePhoneNumber()->getAreaCode(), $adult->getHomePhoneNumber()->getPrefix(), $adult->getHomePhoneNumber()->getSuffix()]) : '',
'mobilePhone' => ($adult->getMobilePhoneNumber()) ? implode("-", [$adult->getMobilePhoneNumber()->getAreaCode(), $adult->getMobilePhoneNumber()->getPrefix(), $adult->getMobilePhoneNumber()->getSuffix()]) : '',
'workPhone' => ($adult->getWorkPhoneNumber()) ? implode("-", [$adult->getWorkPhoneNumber()->getAreaCode(), $adult->getWorkPhoneNumber()->getPrefix(), $adult->getWorkPhoneNumber()->getSuffix()]) : '',
'email' => $adult->getEmail(),
];
}
protected function getNotifications(NotificationEvent $event) : array {
$notificationRepository = $this->doctrine->getRepository(Notification::class);
$notifications = $notificationRepository->findBy([
'entity' => $event->getEntityType(),
'field' => $event->getField(),
'checkLogic' => $event->getCheck()
]);
$this->logger->debug("****** searching for notifications matching: " . json_encode([
'entity' => $event->getEntityType(),
'field' => $event->getField(),
'checkLogic' => $event->getCheck()
]));
$resultList = [];
$this->logger->debug("****** found notifications: " . count($notifications));
foreach($notifications as $notification) {
/** @var Notification $notification */
if ($notification->getDisabled()) {
continue;
}
if ($notification->getCheckValue() !== Notification::VALUE_ANY) {
if ($this->accessor->getValue($event->getEntity(), $notification->getField()) !== $notification->getCheckValue()) {
continue;
};
}
$resultList []= $notification;
}
return $resultList;
}
}