<?php
// api/src/EventSubscriber/BookMailSubscriber.php
namespace App\EventSubscriber;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\Action;
use App\Entity\Demande;
use App\Entity\Profile;
use App\Entity\Valideur;
use App\Service\NotificationMailFlow;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Doctrine\ORM\EntityManagerInterface;
final class DemandeValidationFlowSubscriber implements EventSubscriberInterface
{
private $security;
private $em;
private $notifier;
public function __construct(Security $security, EntityManagerInterface $em, NotificationMailFlow $notifier)
{
$this->security = $security;
$this->em = $em;
$this->notifier = $notifier;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['validationFlow', EventPriorities::POST_VALIDATE],
];
}
public function validationFlow(ViewEvent $event)
{
$demande = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$demande instanceof Demande || (Request::METHOD_POST !== $method && Request::METHOD_PUT !== $method && Request::METHOD_PATCH != $method)) {
return;
}
$this->checkDemande($demande);
}
protected function checkDemande(Demande $demande)
{
$currentUserHasValidated = $demande->getValidated();
/**
* @var $user User
*/
$user = $this->security->getUser();
//on regarde si il y a un nouveau commentaire
$lastComment = $demande->getNewComment();
if ($lastComment && !$lastComment->getId()) {
$lastComment->setProfile($user->getProfile());
$lastComment->setCreatedAt(new \DateTime());
if ($lastComment->getStatus() === Demande::WAITTING) {
$demande->setStatus(Demande::WAITTING);
$currentUserHasValidated = false;
$newValideur = $this->em->getRepository(Valideur::class)->findOneById($lastComment->getValideurId());
// $newValideur->setValidated(false);
$demande->setCurrentValidator($newValideur->getProfile());
} elseif ($lastComment->getStatus() === Demande::REFUSED) {
$demande->setStatus(Demande::REFUSED);
$demande->setRefusedAt(new \DateTime());
$currentUserHasValidated = false;
$this->refuseDemande($demande, $user->getProfile());
}
// si l'utilisateur courant a validé
// qu'il est l'auteur
// et que la demande est en attente
elseif (
$demande->getStatus() == Demande::WAITTING
&& $user->getProfile() == $demande->getCurrentValidator()
) {
if ($lastComment->getStatus() == Demande::TO_VALIDATE || $currentUserHasValidated) {
$demande->setStatus(Demande::TO_VALIDATE);
} elseif ($lastComment->getStatus() == Demande::REFUSED) {
$demande->setStatus(Demande::REFUSED);
$demande->setRefusedAt(new \DateTime());
$currentUserHasValidated = false;
$this->refuseDemande($demande, $user->getProfile());
}
$currentUserHasValidated = false;
// il faut peut-être révoir de dé-valider tous les valideurs
}
$demande->addComment($lastComment);
}
//si l'utilisateur courant a validé
if ($currentUserHasValidated && $demande->getStatus() == Demande::TO_VALIDATE) {
if ($user->getProfile() == $demande->getCurrentValidator()) {
$this->validateDemande($demande, $user->getProfile());
} elseif ($demande->getCurrentValidator() == null) {
//On lance le flux de validation
$this->setCurrentValidator($demande);
}
} elseif ($currentUserHasValidated && $demande->getStatus() == Demande::WAITTING) {
$demande->setStatus(Demande::TO_VALIDATE);
} elseif ($currentUserHasValidated && $demande->getStatus() == Demande::DRAFT && $demande->getAuthor() == $user->getProfile()) {
$demande->setStatus(Demande::TO_VALIDATE);
$demande->setCreatedAt(new \DateTime());
}
//on set le valideur
if ($demande->getStatus() == Demande::TO_VALIDATE) {
$this->setCurrentValidator($demande);
}
while (
$currentUserHasValidated
&& $demande->getStatus() == Demande::TO_VALIDATE
&& $demande->getCurrentValidator() == $user->getProfile()
) {
$this->setCurrentValidator($demande);
$this->validateDemande($demande, $user->getProfile());
}
//$this->em->merge($demande);
$this->notifier->notify($demande);
}
protected function validateDemande(Demande $demande, Profile $profile)
{
$index = 0;
$valideurs = $demande->getValideurs()->toArray();
usort($valideurs, function ($first, $second) {
return $first->getWeight() <=> $second->getWeight();
});
while ($index < count($valideurs)) {
$currentValideur = $valideurs[$index];
if (!$currentValideur->getValidated()) {
// On est au premier valideur qui a une action à faire
// Si il s'agit de l'utilisateur courant, on change le status
if ($currentValideur->getProfile() === $profile) {
$currentValideur->setValidated(true);
$currentValideur->setValidationDate(new \DateTime());
if($demande->getCurrentValidator()->getId() <> $demande->getInitialValidator()->getId() ) {
$action = new Action();
$action->setProfile($profile);
$action->setDescription("Validation en remplacement de {$demande->getInitialValidator()->getFirstName()} {$demande->getInitialValidator()->getLastName()}");
$action->setDate(new \DateTime());
if($demande->getNextDemande() !== null){
// $action->setComeFromNextDemande(true);
$action->setDemande($demande->getNextDemande());
}
else{
$action->setDemande($demande);
}
$this->em->persist($action);}
}
// je retire le return parce que si le validateur intervient plusieurs fois dans le workflow
// alors il ne doit valider la demande qu'une seule fois
if($demande->getUnitaryValidation()){
return;
}
//return;
}
$index++;
}
return;
}
protected function refuseDemande(Demande $demande, Profile $profile)
{
$index = 0;
$valideurs = $demande->getValideurs()->toArray();
usort($valideurs, function ($first, $second) {
return $first->getWeight() <=> $second->getWeight();
});
while ($index < count($valideurs)) {
$currentValideur = $valideurs[$index];
if (!$currentValideur->getValidated()) {
// On est au premier valideur qui a une action à faire
// Si il s'agit de l'utilisateur courant, on change le status
if ($currentValideur->getProfile() === $profile) {
$currentValideur->setRefused(true);
$currentValideur->setRefusedAt(new \DateTime());
}
// je retire le return parce que si le validateur intervient plusieurs fois dans le workflow
// alors il ne doit valider la demande qu'une seule fois
if($demande->getUnitaryValidation()){
return;
}
//return;
}
$index++;
}
return;
}
protected function setCurrentValidator(Demande $demande)
{
$index = 0;
$valideurs = $demande->getValideurs()->toArray();
usort($valideurs, function ($first, $second) {
return $first->getWeight() <=> $second->getWeight();
});
while ($index < count($valideurs)) {
$currentValideur = $valideurs[$index];
if (!$currentValideur->getValidated()) {
$demande->setCurrentValidator($currentValideur->getProfile());
// save initial validator in case of backup ...
$demande->setInitialValidator($currentValideur->getProfile());
return;
}
$index++;
}
//ou la demande est clôturée
$demande->setStatus(Demande::CLOSED);
$demande->setCurrentValidator(null);
$demande->setInitialValidator(null);
}
}