<?php
namespace App\EventSubscriber;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Api\Dto\DeviceTokenInput;
use App\Entity\Alert;
use App\Entity\BaseUser;
use App\Repository\BaseUserRepository;
use App\Services\BaseUserService;
use Doctrine\ORM\EntityManagerInterface;
use ExpoSDK\Expo;
use ExpoSDK\ExpoMessage;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Security\Core\Security;
final class AlertSubscriber implements EventSubscriberInterface
{
private MailerInterface $mailer;
private BaseUserRepository $baseUserRepository;
private Security $security;
private BaseUserService $baseUserService;
private EntityManagerInterface $em;
public function __construct(MailerInterface $mailer, BaseUserRepository $baseUserRepository, Security $security, BaseUserService $baseUserService, EntityManagerInterface $em)
{
$this->mailer = $mailer;
$this->baseUserRepository = $baseUserRepository;
$this->security = $security;
$this->baseUserService = $baseUserService;
$this->em = $em;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => [
['create', EventPriorities::POST_WRITE],
['delete', EventPriorities::POST_WRITE],
],
];
}
public function create(ViewEvent $event): void
{
$alert = $event->getControllerResult();
$request = $event->getRequest();
$method = $request->getMethod();
$createdBy = $this->security->getUser();
$admins = $this->baseUserRepository->findByRole('ROLE_ADMIN');
if (
!$alert instanceof Alert
|| Request::METHOD_POST !== $method
|| $request->get('_route') !== 'api_alerts_post_collection'
) {
return;
}
if ($this->security->isGranted("ROLE_ADMIN")) {
/**
* Mail non cohérent car l'alerte n'est pas reliée à une pharmacie
*/
$this->sendMailCreateByAdmin($alert->getEmail(), $alert);
} else {
$this->sendMailCreate($createdBy, $alert);
$this->sendMailCreateForAdmin(array_map(fn (BaseUser $baseUser) => $baseUser->getEmail(), $admins), $alert);
}
$this->sendPushCreate($this->baseUserService->getDevicesTokenFromRole('ROLE_ADMIN'));
$baseUsersSolidarity = $this->baseUserRepository->findBy(['isSolidarity' => true]);
$mails = [];
$pushs = [];
foreach ($baseUsersSolidarity as $baseUserSolidarity) {
if ($baseUserSolidarity === $createdBy) continue;
switch ($baseUserSolidarity->getNotificationType()) {
case BaseUser::NOTIFICATION_MAIL:
$mails[] = $baseUserSolidarity;
break;
case BaseUser::NOTIFICATION_PUSH:
if ($d = $baseUserSolidarity->getDevicesTokensExpo()) {
$pushs[] = $d;
}
break;
case BaseUser::NOTIFICATION_PUSH_MAIL:
$mails[] = $baseUserSolidarity;
if ($d = $baseUserSolidarity->getDevicesTokensExpo()) {
$pushs[] = $d;
}
break;
}
}
$dateCreatedAt = new \DateTimeImmutable($alert->getCreatedAt()->format('Y-m-d'));
$dateEnd = $dateCreatedAt->modify("+10 day");
if (!$alert->getDateEndAt()) {
$alert->setDateEndAt($dateEnd);
}
$this->em->flush();
$this->sendMailCreateSolidarity($mails, $alert);
$this->sendPushCreate(array_merge(...$pushs));
}
public function delete(ViewEvent $event): void
{
$alert = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$alert instanceof Alert || Request::METHOD_DELETE !== $method) {
return;
}
$this->sendMailRemove($alert->getEmail(), $alert);
}
public function sendMailRemove($to, Alert $alert)
{
/**
* MAIL:BaseUser
*/
$email = (new TemplatedEmail())
->from(new Address('noreply@ores.com', 'ORES'))
->to($to)
->subject('Suppression de votre alerte - ORES BFC')
->htmlTemplate('mails/alert/remove.html.twig')
->context([
'alert' => $alert,
])
;
$this->mailer->send($email);
}
public function sendMailCreateByAdmin($to, Alert $alert)
{
/**
* MAIL:BaseUser
*/
$email = (new TemplatedEmail())
->from(new Address('noreply@ores.com', 'ORES'))
->to($to)
->subject('Une nouvelle alerte a été créée pour vous - ORES BFC')
->htmlTemplate('mails/alert/create_by_admin.html.twig')
->context([
'alert' => $alert,
])
;
$this->mailer->send($email);
}
public function sendMailCreate(BaseUser $baseUser, Alert $alert)
{
/**
* MAIL:BaseUser
*/
$email = (new TemplatedEmail())
->from(new Address('noreply@ores.com', 'ORES'))
->to($baseUser->getEmail())
->subject('Création d’une offre - ORES BFC')
->htmlTemplate('mails/alert/create.html.twig')
->context([
'alert' => $alert,
'user' => $baseUser,
])
;
$this->mailer->send($email);
}
public function sendMailCreateSolidarity(array $baseUsers, Alert $alert)
{
$tos = array_map(fn (BaseUser $baseUser) => $baseUser->getEmail(), $baseUsers);
foreach ($tos as $to) {
/**
* MAIL:BaseUser
*/
$email = (new TemplatedEmail())
->from(new Address('noreply@ores.com', 'ORES'))
->to($to)
->subject('Nouvelle alerte - ORES BFC')
->htmlTemplate('mails/alert/create_solidarity.html.twig')
->context([
'alert' => $alert,
])
;
$this->mailer->send($email);
}
}
public function sendMailCreateForAdmin(array $admins, Alert $alert)
{
/**
* MAIL:Admin
*/
$email = (new TemplatedEmail())
->from(new Address('noreply@ores.com', 'ORES'))
->to(...$admins)
->subject('Nouvelle alerte - ORES BFC')
->htmlTemplate('mails/alert/create_admin.html.twig')
->context([
'alert' => $alert,
])
;
$this->mailer->send($email);
}
public function sendPushCreate(?array $tos)
{
/**
* PUSH:BaseUser PUSH:Admin
*/
$message = (new ExpoMessage([
'title' => 'Nouvelle alerte',
'body' => 'Vous pouvez la consulter directement sur l’application.',
]))
->setChannelId('default')
->setBadge(0)
->playSound()
;
if (!empty($tos)) {
return (new Expo)->send($message)->to($tos)->push();
}
}
}