<?php
namespace FlexApp\EventSubscriber;
use Exception;
use FlexApp\Classes\Constants;
use FlexApp\Entity\CommentablePage;
use FlexApp\Entity\CommentablePageSubscriberEntity;
use FlexApp\Entity\CommentEntity;
use FlexApp\Events\CommentEvent;
use FlexApp\Events\Style43\CommentErrorEvent;
use FlexApp\Events\Style43\NewCommentSavedEvent;
use FlexApp\Exceptions\SourceByCommentTypeDefinerException;
use FlexApp\Repository\CommentablePageRepository;
use FlexApp\Repository\ConsultantRepository;
use FlexApp\Repository\CountryAndLangSpecificDataRepository;
use FlexApp\Service\ChangedUnreadCountHandler;
use FlexApp\Service\ConsDefiner;
use FlexApp\Service\EmailCanonicalizer;
use FlexApp\Service\ManagerContactsProvider;
use FlexApp\Service\ParametersProvider;
use FlexApp\Service\SourceByCommentTypeDefiner;
use FlexApp\Service\SystemChatNotificationService;
use FlexApp\Service\TranslatorWrapper;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Twig\Environment as Twig;
use WebBundle\Entity\ListEmail;
use WebBundle\Helper\App;
use WebBundle\Helper\Mailer;
use WebBundle\Helper\UserHelper;
use WebBundle\Repository\ListCountryRepository;
use WebBundle\Repository\ListEmailRepository;
use WebBundle\Repository\UserRepository;
/**
* Слушает событие - сохранение нового коммента. По событию:
* Рассылает email-уведомления пользователям-подписчикам текущей страницы
*/
class CommentNotifyClientsSubscriber implements EventSubscriberInterface
{
const UNSUB_SALT = 'gPYfrxdQyHiQ';
/**
* @var SourceByCommentTypeDefiner
*/
private $sourceByCommentTypeDefiner;
/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;
/**
* @var Twig
*/
private $twig;
/**
* @var \FlexApp\Repository\CommentablePageRepository
*/
private $commentablePageRepository;
/**
* @var Mailer
*/
private $mailer;
/**
* @var ParametersProvider
*/
private $parametersProvider;
/**
* @var EmailCanonicalizer
*/
private $emailCanonicalizer;
/**
* @var ListEmailRepository
*/
private $listEmailRepository;
/**
* @var RouterInterface
*/
private $router;
/**
* @var UserRepository
*/
private $userRepository;
/**
* @var SystemChatNotificationService
*/
private $systemChatNotificationService;
/**
* @var \FlexApp\Service\TranslatorWrapper
*/
private $translatorWrapper;
/**
* @var ChangedUnreadCountHandler
*/
private $changedUnreadCountHandler;
/** @required */
public ConsultantRepository $consultantRepository;
/** @required */
public ConsDefiner $consDefiner;
/** @required */
public ListCountryRepository $listCountryRepository;
/** @required */
public CountryAndLangSpecificDataRepository $countryAndLangSpecificDataRepository;
/** @required */
public ManagerContactsProvider $contactsProvider;
public function __construct(
SourceByCommentTypeDefiner $sourceByCommentTypeDefiner,
EventDispatcherInterface $eventDispatcher,
Twig $twig,
CommentablePageRepository $commentablePageRepository,
Mailer $mailer,
ParametersProvider $parametersProvider,
EmailCanonicalizer $emailCanonicalizer,
ListEmailRepository $listEmailRepository,
RouterInterface $router,
UserRepository $userRepository,
SystemChatNotificationService $systemChatNotificationService,
TranslatorWrapper $translatorWrapper,
ChangedUnreadCountHandler $changedUnreadCountHandler
) {
$this->sourceByCommentTypeDefiner = $sourceByCommentTypeDefiner;
$this->eventDispatcher = $eventDispatcher;
$this->twig = $twig;
$this->commentablePageRepository = $commentablePageRepository;
$this->mailer = $mailer;
$this->parametersProvider = $parametersProvider;
$this->emailCanonicalizer = $emailCanonicalizer;
$this->listEmailRepository = $listEmailRepository;
$this->router = $router;
$this->userRepository = $userRepository;
$this->systemChatNotificationService = $systemChatNotificationService;
$this->translatorWrapper = $translatorWrapper;
$this->changedUnreadCountHandler = $changedUnreadCountHandler;
}
public static function getSubscribedEvents()
{
return [
NewCommentSavedEvent::class => [
['notifyUsers', 10],
],
];
}
public function notifyUsers(CommentEvent $commentEvent)
{
if ('test' === $this->parametersProvider->getParameter('kernel.environment')) {
return;
}
$comment = $commentEvent->getComment();
$currentUserEmail = $comment->getEmail();
try {
$pageUrl = $this->sourceByCommentTypeDefiner->getSourceByCommentEntity($comment);
} catch (SourceByCommentTypeDefinerException $e) {
$this->eventDispatcher->dispatch(new CommentErrorEvent(new Exception("Уведомления о новом комменте не будут разосланы: Не удалось сгенерировать ссылку для страницы коммента {$comment->getId()}: {$e->getMessage()}")));
return;
}
/** @var \FlexApp\Entity\CommentablePage $commentablePage */
$commentablePage = $this->commentablePageRepository->findOneBy([
'unid' => $comment->getCommentableUnid(),
'locale' => $comment->getLocale(),
'type' => $comment->getType(),
]);
if (!$commentablePage) {
return;
}
/** @var ListEmail $pattern */
$pattern = $this->listEmailRepository->findOneBy(['keyEmail' => 'notification_about_new_comment']);
$theme = (string)$pattern->getTitleCur($comment->getLocale());
$this->sendEmailsAndChatNotificationsToSubscribersOfCurrentPage($commentablePage, $currentUserEmail, $pageUrl, $comment, $theme, $pattern);
}
private function sendEmail(string $email, string $theme, string $body)
{
try {
$this->mailer->sendEmail($theme, $this->parametersProvider->getParameter('mailer_email_from'), $email, $body);
} catch (Exception $e) {
$this->eventDispatcher->dispatch(new CommentErrorEvent(new Exception("Не удалось отправить письмо на '$email'")));
}
}
protected function sendEmailsAndChatNotificationsToSubscribersOfCurrentPage(
CommentablePage $commentablePage,
?string $currentUserEmail,
string $pageUrl,
CommentEntity $comment,
string $theme,
ListEmail $pattern
): void {
$this->consDefiner->setUseCache(false);
//Отправка уведомлений в чат
foreach ($commentablePage->getSubscribers() as $subscriber) {
/** @var CommentablePageSubscriberEntity $subscriber */
if (null === $subscriber->getToken()) {
continue;
}
//Юзеру, который отправил текущий коммент, не отправляем уведомление в чат
if ($subscriber->getToken() !== UserHelper::getInstance()->getToken()) {
$this->sendNotificationToChat($subscriber->getToken(), $comment);
}
}
//Отправка уведомлений на email
foreach ($commentablePage->getSubscribers() as $subscriber) {
/** @var CommentablePageSubscriberEntity $subscriber */
if (null === $subscriber->getEmailCanonical()) {
continue;
}
$body = (string) $pattern->getBodyCur($comment->getLocale());
$body = $pattern->removeMailSignature($body);
$subscriberEmail = $subscriber->getEmailCanonical();
//Юзеру, который оставил текущий коммент, не отправляем уведомление о новом комментарии (т.е. о его же комментарии), т.к. он и так знает.
if ($subscriberEmail !== $this->emailCanonicalizer->canonicalize($currentUserEmail)) {
$this->replaceVars($theme, $body, $comment, $subscriber, $pageUrl);
$this->sendEmail($subscriberEmail, $theme, $body);
}
}
}
private function replaceVars(string &$theme, string &$body, CommentEntity $comment, CommentablePageSubscriberEntity $subscriber, string $pageUrl)
{
$routeParameters = [
'token' => md5($subscriber->getEmailCanonical() . self::UNSUB_SALT),
'email' => $subscriber->getEmailCanonical(),
'_locale' => $comment->getLocale(),
];
/** @var \FlexApp\Entity\ConsultantEntity $consultant */
if ($comment->getAuthorLogin()) {
$contacts = $this->contactsProvider->getContacts($comment->getAuthorLogin(), $comment->getLocale());
} else {
$contacts = $this->contactsProvider->getContacts();
}
$managerName = $contacts->managerName;
$managerEmail = $contacts->managerEmail;
$managerPhone = $contacts->managerPhone;
$htmlLinkToPage = "<a target='_blank' href='$pageUrl'>$pageUrl</a>";
$urlForUnsubscribe = $this->router->generate('app_comment_unsubscribe_from_notifications', $routeParameters,
UrlGeneratorInterface::ABSOLUTE_URL);
$theme = str_replace('%site%', $this->parametersProvider->getParameter('site'), $theme);
$body = str_replace('%htmlLinkToPage%', $htmlLinkToPage, $body);
$body = str_replace('%commentText%', $comment->getBody(), $body);
$body = str_replace('%urlForUnsubscribe%', $urlForUnsubscribe, $body);
$body = str_replace('%managerName%', $managerName, $body);
$body = str_replace('%managerEmail%', $managerEmail, $body);
$body = str_replace('%managerPhone%', $managerPhone, $body);
}
private function sendNotificationToChat(string $token, CommentEntity $comment): bool
{
try {
$pageUrl = $this->sourceByCommentTypeDefiner->getSourceByCommentEntity($comment);
} catch (SourceByCommentTypeDefinerException $e) {
return false;
}
$word = CommentEntity::QA === $comment->getCategory() ? 'qa' : 'comment';
$pageUrl .= "#$word{$comment->getId()}";
$pageLink = "<a target='_blank' href='$pageUrl'>$pageUrl</a>";
$message = json_encode([
'key' => 'new_comment_chat_notification',
'parameters' => [
'%url%' => $pageLink,
],
], JSON_UNESCAPED_UNICODE);
$message = Constants::NEED_TO_BE_TRANSLATED_MARKER . $message;
return $this->systemChatNotificationService->addSystemMessageToChat($token, $message, null, App::getCurLocale(), App::getCurCountry(),
App::getCountryByIp());
}
}