<?php
namespace App\EventSubscriber;
use App\Entity\Article;
use App\Entity\ArticleWorkflowStep;
use App\Entity\ArticleWorkflowStepAlert;
use App\Entity\MajDossier;
use App\Entity\Message;
use App\Entity\PracticalFile;
use App\Entity\Step;
use App\Entity\StepAlertConfiguration;
use App\Entity\Template;
use App\Entity\User;
use App\Event\AppEvents;
use App\Event\ArticleWorkflowStepEvent;
use App\Service\EzPublishZipImportService;
use App\Service\EzTitaneService;
use App\Service\MailerService;
use App\Service\MajDossierService;
use App\Service\PracticalFileGoogleDriveService;
use Doctrine\ORM\EntityManagerInterface;
use FOS\UserBundle\Model\UserInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
/**
* Ecoute les événements déclenchés lors d'un changement d'étape du workflow
*/
class ArticleWorkflowStepSubscriber implements EventSubscriberInterface
{
/**
* Gestionnaire d'envoi d'emails
*
* @var MailerService
*/
private $mailerService;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var TokenStorageInterface
*/
private $storage;
/**
* @var EzTitaneService
*/
private $ezTitaneService;
/**
* @var PracticalFileGoogleDriveService
*/
private $practicalFileGoogleDriveService;
/**
* @var KernelInterface
*/
private $kernel;
/**
* @var EzPublishZipImportService
*/
private $ezPublishZipImportService;
/**
* @var MajDossierService
*/
private $majDossierService;
/**
* @var FlashBagInterface
*/
private $flashBag;
/**
* @var LoggerInterface
*/
private $logger;
/**
* RegistrationSubscriber constructor
*
* @param MailerService $mailerService Gestionnaire d'envoi d'emails
* @param EntityManagerInterface $manager
* @param TokenStorageInterface $storage
* @param EzTitaneService $ezTitaneService
* @param PracticalFileGoogleDriveService $practicalFileGoogleDriveService
* @param KernelInterface $kernel
* @param EzPublishZipImportService $ezPublishZipImportService
* @param MajDossierService $majDossierService
*/
public function __construct(
MailerService $mailerService,
EntityManagerInterface $manager,
TokenStorageInterface $storage,
EzTitaneService $ezTitaneService,
PracticalFileGoogleDriveService $practicalFileGoogleDriveService,
KernelInterface $kernel,
EzPublishZipImportService $ezPublishZipImportService,
MajDossierService $majDossierService,
FlashBagInterface $flashBag,
LoggerInterface $logger
) {
$this->mailerService = $mailerService;
$this->entityManager = $manager;
$this->storage = $storage;
$this->ezTitaneService = $ezTitaneService;
$this->practicalFileGoogleDriveService = $practicalFileGoogleDriveService;
$this->kernel = $kernel;
$this->ezPublishZipImportService = $ezPublishZipImportService;
$this->majDossierService = $majDossierService;
$this->flashBag = $flashBag;
$this->logger = $logger;
}
/**
* Returns an array of event names this subscriber wants to listen to
*
* @return array
*/
public static function getSubscribedEvents()
{
return array(
AppEvents::STEP_CHANGED => [
['onFicheEnFabricationStep', 30],
['notifyArticleStepChange', 40],
['notifyPracticalFileStepChange', 50],
['markAsOnline', 60],
//['EzTitaneXmlExport', 70],
['setStepAlert', 80],
['onChangeStep', 90]
],
);
}
/**
* Archivage du manuscrit lorsqu'une fiche passe à l'étape fiche_en_fabrication
*/
public function onFicheEnFabricationStep(ArticleWorkflowStepEvent $event): void
{
$entity = $event->getCurrentArticleWorkflowStep()->getRelatedEntity()->getRelatedEntity();
if (!($entity instanceof PracticalFile) || $entity->getCurrentStep()->getCode() !== 'fiche_en_fabrication') {
return;
}
$practicalFile = $entity;
// Attachement en PJ du manuscrit
if ($practicalFile->getGoogleDocId()) {
$this->practicalFileGoogleDriveService->getDriveService()->initClient();
$result = $this->practicalFileGoogleDriveService->addDriveFileToAttachment($practicalFile);
if ($result === false) {
$this->flashBag->add('error', "Fiche {$practicalFile->getNumber()} : erreur lors de la récupération du fichier dans Google Drive");
$this->logger->error("Fiche {$practicalFile->getNumber()} : erreur lors de la récupération du fichier dans Google Drive");
}
}
}
/**
* Créer les alertes de la nouvelle étape
*
* @param ArticleWorkflowStepEvent $event
*/
public function setStepAlert(ArticleWorkflowStepEvent $event)
{
$newArticleWorkflowStep = $event->getCurrentArticleWorkflowStep();
$stepAlertConfigurations = $this->entityManager->getRepository(StepAlertConfiguration::class)->findBy(
[
'step' => $newArticleWorkflowStep->getWorkflowStep()->getStep()
]
);
foreach ($stepAlertConfigurations as $stepAlertConfiguration) {
$articleWorkflowStepAlert = new ArticleWorkflowStepAlert();
$articleWorkflowStepAlert->setArticleWorkflowStep($event->getCurrentArticleWorkflowStep());
$articleWorkflowStepAlert->setStepAlertConfiguration($stepAlertConfiguration);
$this->entityManager->persist($articleWorkflowStepAlert);
}
$this->entityManager->flush();
}
/**
* Export XML de l'article s'il s'agit de la validation de l'étape "A exporter sur TITANE"
*
* @param ArticleWorkflowStepEvent $event
*/
public function EzTitaneXmlExport(ArticleWorkflowStepEvent $event)
{
$oldStep = $event->getOldArticleWorkflowStep()->getWorkflowStep()->getStep();
$entity = $event->getCurrentArticleWorkflowStep()->getRelatedEntity()->getRelatedEntity();
if ($entity instanceof Article && $oldStep->getLabel() == 'A exporter sur TITANE') {
$this->ezTitaneService->generateXml($entity);
}
}
/**
* La fiche pratique est tagguée en "ligne" lorsqu'on est à la dernière étape
*
* @param ArticleWorkflowStepEvent $event
*/
public function markAsOnline(ArticleWorkflowStepEvent $event)
{
// S'il ne s'agit pas du workflow principal
if (!$event->getCurrentArticleWorkflowStep()->getArticleWorkflow()) {
return;
}
$entity = $event->getCurrentArticleWorkflowStep()->getRelatedEntity()->getRelatedEntity();
$newStep = $event->getCurrentArticleWorkflowStep()->getWorkflowStep();
if ($entity instanceof PracticalFile && $newStep->isFinalist()) {
$entity->setOnline(true);
}
$this->entityManager->flush();
}
/**
* Récupération du Docx et des outils d'une fiche pratique depuis le site EzPublish et génération du Google Doc de la fiche
*
* @param ArticleWorkflowStepEvent $event
* @throws \Exception
*/
public function onChangeStep(ArticleWorkflowStepEvent $event)
{
$entity = $event->getCurrentArticleWorkflowStep()->getRelatedEntity()->getRelatedEntity();
if ($entity instanceof PracticalFile) {
/** @var MajDossier $majDossier */
foreach ($entity->getMajDossiers() as $majDossier) {
if ($majDossier->getStatus() == MajDossier::STATUS_IN_PROGRESS) {
$this->majDossierService->updateStatusFinish($majDossier);
}
}
if ($event->getCurrentArticleWorkflowStep()->getWorkflowStep()->getStep()->getLabel() === "En ligne") {
$practicalFile = $entity;
$this->ezPublishZipImportService->importEzveilleFiles($practicalFile);
}
}
}
/**
* Retourne l'utilisateur loggué ou l'utilisateur "system" dans le cas d'un traitement automatique
*
* @return UserInterface
*/
protected function getUser(): UserInterface
{
return $this->storage->getToken() ? $this->storage->getToken()->getUser() : $this->entityManager->getRepository(User::class)->findOneBy(['username' => 'system']);
}
/**
* Envoi d'un email de notification de changement d'étape d'une fiche pratique
*/
public function notifyPracticalFileStepChange(ArticleWorkflowStepEvent $event): void
{
$entity = $event->getCurrentArticleWorkflowStep()->getRelatedEntity()->getRelatedEntity();
if (!$entity instanceof PracticalFile || !$event->getArgument('notify')) {
return;
}
$newStep = $event->getCurrentArticleWorkflowStep()->getWorkflowStep()->getStep();
if (!$newStep->getWithNotification()) {
return;
}
$practicalFile = $entity;
$vars = [
'practical_file' => $practicalFile,
];
$this->mailerService->sendMail(
$this->getRecipientsEmails($newStep, $practicalFile),
$this->getEmailTemplatePath($newStep, $practicalFile),
$vars
);
}
/**
* Retourne le chemin du template de notification d'une étape donnée selon l'étape et la société concernées
*/
protected function getEmailTemplatePath(Step $newStep, PracticalFile $practicalFile): string
{
if (!$this->mailerService->templateExists("email/notification_{$newStep->getCode()}_{$practicalFile->getEditionPrefix()}.html.twig")) {
return "email/notification_{$newStep->getCode()}.html.twig";
} else {
return "email/notification_{$newStep->getCode()}_{$practicalFile->getEditionPrefix()}.html.twig";
}
}
/**
* Retourne les mails des destinataires des notifications d'une étape donnée
*
* @param Step $step
* @param $entity Article|PracticalFile
* @return array
*/
protected function getRecipientsEmails(Step $step, $entity): array
{
$recipientsRoles = $step->getAlertsDestinationRoles();
$users = array_filter($entity->getUsersByRoles($recipientsRoles), function ($user) {
return !$user->getStopEmail();
});
$recipientsEmails = array_map(
function (?User $user) {
if (null === $user) {
throw new \Exception("Attention, un utilisateur supposé se charger de cette étape n'a pas été désigné, aucune notification n'a été envoyée.");
}
return $user ? $user->getEmail() : null;
},
$users
);
if ($step->notifyCompositeurOnStepChange()) {
$compositeurUser = $this->entityManager->getRepository(User::class)->findOneBy(['username' => 'compositeur']);
$recipientsEmails[] = $compositeurUser->getEmail();
}
return $recipientsEmails;
}
/**
* Envoi d'un email de notification pour un changement d'étape d'un article
*
* @param ArticleWorkflowStepEvent $event
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
public function notifyArticleStepChange(ArticleWorkflowStepEvent $event)
{
$entity = $event->getCurrentArticleWorkflowStep()->getRelatedEntity()->getRelatedEntity();
if (!$entity instanceof Article || !$event->getArgument('notify')) {
return;
}
$entity = $event->getCurrentArticleWorkflowStep()->getRelatedEntity()->getRelatedEntity();
$oldStep = $event->getOldArticleWorkflowStep()->getWorkflowStep()->getStep();
$newStep = $event->getCurrentArticleWorkflowStep()->getWorkflowStep()->getStep();
$newStepLabel = $newStep->getLabel();
$oldStepLabel = $oldStep->getLabel();
if ( $entity === null || !$newStep->getWithNotification() ) {
return;
}
$senderRole = $oldStep->getSignatureRole();
if ($senderRole !== null) {
$senderUser = $entity->getIntervenorByRole($senderRole);
} else {
$senderUser = $this->getUser();
}
if (array_key_exists(($newStepLabel), ArticleWorkflowStep::NOTIFICATION_ARTICLE_STEPS_LABEL)) {
$template = $this->entityManager->getRepository(Template::class)->findOneByTitle($newStepLabel);
} else {
$template = $this->entityManager->getRepository(Template::class)->findOneByTitle("Changement d'étape workflow");
}
if (is_null($template)) {
return;
}
$message = new Message();
$message->setTemplate($template);
$message->setType(Message::TYPE_NOTIFICATION);
$reflectionClass = new \ReflectionClass($entity);
$entitySetter = 'set' . $reflectionClass->getShortName();
$message->$entitySetter($entity);
$this->entityManager->persist($message);
$this->entityManager->flush();
$subjectParam = [];
$to = $this->getRecipientsEmails($newStep, $entity);
$bodyParam = [
'%oldStep%' => $oldStepLabel,
'%newStep%' => $newStepLabel,
'%responsible%' => $entity->getResponsible(),
'%type%' => $entity instanceof PracticalFile ? "la fiche" : "l'article",
'%number%' => $entity->getNumber(),
];
$signatureParam = [
'%senderName%' => $senderUser->getFullname(),
'%senderRole%' => !empty($senderRole) ? $senderRole->getLabel() : '',
];
$this->mailerService->sendMessage(
$to,
$message,
"email/message.html.twig",
$subjectParam,
$bodyParam,
$signatureParam
);
}
}