<?php
namespace App\Controller;
use App\Entity\Historique;
use App\Entity\Workflow;
use App\Entity\Mission;
use App\Entity\User;
use App\Enum\Manager;
use App\Repository\JobRepository;
use App\Repository\MissionRepository;
use App\Repository\CampaignRepository;
use App\Repository\UserRepository;
use App\Entity\WorkflowAction;
use App\Enum\Role;
use App\Enum\Trigger;
use App\Enum\Operation;
use App\Entity\WorkflowStep;
use App\Event\Workflow\Step\WorkflowStepEditedEvent;
use Symfony\Component\HttpFoundation\JsonResponse;
use App\Event\ClientUpdatedEvent;
use App\Form\WorkflowActionType;
use App\Form\WorkflowStepType;
use App\Form\WorkflowType;
use App\Repository\WorkflowActionRepository;
use App\Repository\WorkflowRepository;
use App\Repository\WorkflowStepRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\EmailTemplate;
use App\Form\EmailTemplateType;
use App\Form\ExteralUserType;
use App\Service\DynamicHostService;
use App\Service\WorkflowService;
use Symfony\Component\Security\Core\Security;
#[Route('/admin/workflows')]
class WorkflowController extends AbstractController
{
private $agencyForUser = null;
public function __construct(private WorkflowService $workflowService,DynamicHostService $dynamicHostService,Security $security)
{
$company = $dynamicHostService->getCompany();
$curentUser = $security?->getUser();
if (!is_null($curentUser) and !is_null($curentUser?->getRoles()) and in_array('ROLE_MANAGER', $curentUser?->getRoles())) {
$company = $curentUser?->getCompany();
}
$this->agencyForUser = $company;
}
#[Route('/checkform', name: 'check-form', methods: ['GET'])]
public function checkform(Request $request): JsonResponse
{
$workflowName = $request->query->get('name');
$productId = $request->query->get('product-id');
$companyId = $request->query->get('company-id');
$worflowId = $request->query->get('worflow-id');
$isNameExist = $this->workflowService->alreadyHaveWorkflowName($workflowName,$worflowId);
$isNameProductWorflowAnCompanyExist = $this->workflowService->alreadyHaveProductAndCompany($productId,$companyId,$worflowId);
return new JsonResponse([
'isNameWorkflowExist'=> $isNameExist,
'isNameProductAndCompanyExist'=> $isNameProductWorflowAnCompanyExist,
]);
}
#[Route('/checkstep/{id}', name: 'check-step', methods: ['GET'])]
public function checkStep(Workflow $workflow): JsonResponse
{
$steps = $workflow->getSteps();
$stepsValidation = [];
$numberSteps = sizeof($steps);
foreach ($steps as $keyStep => $step) {
$actions = $step->getActions();
$actionValidation = 0;
$actionValidationWithStp=0;
$nbrValidatorToValidateStep=0;
$closeAction = 0;
$noEmailTemplate = [];
$noJobStepDescription = !$this->isHaveJobStepDescription($step);
$noJobsInStepForSubcontractor= !$this->isHaveJobsInStepForSubcontractor($step);;
$haveValidatorStepError = false;
$validatorStepError=[];
foreach ($actions as $key => $action) {
$triggers = $action->getTriggers();
$validatorActions = $this->haveValidatorAction($step, $action, $key);
$validatorStepError=$validatorActions;
if(sizeof($validatorStepError) == 0){
$nbrValidatorToValidateStep ++;
}
foreach ($triggers as $key => $trigger) {
if($trigger->getTriggerType()== Trigger::VALIDATION){
$actionValidation++;
}
if($trigger->getTriggerType()== Trigger::VALIDATION && $trigger->getOperation()==Operation::NEXT_STEP ){
$actionValidationWithStp++;
}
if($trigger->getTriggerType()== Trigger::CLOSED_STEP){
$closeAction ++;
}
if((in_array($trigger->getTriggerType(),[Trigger::ENTER_STEP,Trigger::EXIT_STEP]) || $trigger->getOperation()==Operation::EMAIL) && $trigger->getEmailTemplate() == null){
$noEmailTemplate = [...$noEmailTemplate, $action->getName()];
}
}
}
$stepsValidation=[...$stepsValidation,[
'name'=> $step->getName(),
'responsable'=> $step->getManager(),
'job'=>$step->getJob()?->getName(),
'subcontractor_description'=>$step->getSupplierDescription(),
'client_description'=>$step->getCustomerDescription(),
'isLastStep'=> false,
'position'=>$step->getPosition(),
'nbrStep'=>$numberSteps,
'noDescription'=> $noJobStepDescription,
'noJobs'=>$noJobsInStepForSubcontractor,
'validatorStepError'=> $nbrValidatorToValidateStep > 0 ? [] : $validatorStepError,
'actions'=>[
'haveValidationWithAction'=> $actionValidationWithStp > 0 ? true : false,
'haveValidation'=> $actionValidationWithStp == 0 && $actionValidation > 0 ? true : false,
'haveClosedAction'=> $closeAction>0 ? true : false,
'missingEmailTemplate'=>$noEmailTemplate
]
]];
}
$workflowValidation['nameWorflow']= $workflow->getName();
$workflowValidation['nameAlredyExist']= false;
$workflowValidation['productAndClientExiste']= false;
$workflowValidation['steps']= $stepsValidation;
return new JsonResponse($workflowValidation);
}
private function isHaveJobStepDescription(WorkflowStep $step){
$manager = $step->getManager();
$customerDescription = $step->getCustomerDescription();
if($manager == Manager::JOB){
return !empty($step->getCustomerDescription()) && !is_null($step->getCustomerDescription()) && isset($customerDescription);
}
return !empty($step->getSupplierDescription() ) && !is_null($step->getSupplierDescription());
}
private function isHaveJobsInStepForSubcontractor(WorkflowStep $step){
$manager = $step->getManager();
if($manager == Manager::JOB){
return !is_null($step->getJob()) ;
}
return true;
}
private function haveValidatorAction(WorkflowStep $step,WorkflowAction $action, $indexAction){
switch ($step->getManager() ) {
case Manager::CLIENT:
if($action->getRecipient() != Role::ROLE_CLIENT){
return [
'message'=> "client",
'step_position'=>$step->getPosition(),
'action_index'=> $indexAction,
'job_subcontractor'=>''
];
}
break;
case Manager::JOB:
if(!($action->getRecipient() == Role::ROLE_SUBCONTRACTOR && $action->getJob() == $step->getJob())){
return [
'message'=> "sous-traitant",
'step_position'=>$step->getPosition(),
'job_subcontractor'=>$step->getJob()? $step->getJob()->getName() : '-',
'action_index'=> $indexAction
];
}
break;
case Manager::CLIENT_EXTERNAL:
if(!($action->getRecipient() == Role::ROLE_USER_SPECIFIC && sizeof($action->getUser())!=0 && $this->isUserInStepIsInRecipientAtAction($step->getUserResponsable(),$action->getUser()) == true)){
$userResponsables = ($step->getUserResponsable())->toArray();
$userResponsables = array_reduce($userResponsables, function($carry,$item){ return "$carry {$item->getFullName()},";});
return [
'message'=> "utilisateur specifique",
'responsable'=> $userResponsables,
'step_position'=>$step->getPosition(),
'action_index'=> $indexAction,
'job_subcontractor'=>''
];
}
break;
}
return [];
}
private function isUserInStepIsInRecipientAtAction($usersInStep,$usersInAction){
foreach ($usersInStep as $key => $user) {
foreach ($usersInAction as $key => $usr) {
if($user->getId()== $usr->getId()){
return true;
}
}
}
return false;
}
/**
* Displays the index view of the templates
*
* @param WorkflowRepository $workflowRepository
*
* @return Response template /workflow/index.html.twig
*/
#[Route('', name: 'workflow_index')]
public function index(WorkflowRepository $workflowRepository,DynamicHostService $dynamicHostService): Response
{
$isAgency = false;
// $workflow = $workflowRepository->getAll();
$company = $dynamicHostService->getCompany();
$companyOwner = $dynamicHostService->getCompany();
$workflow = $workflowRepository->getWorkflowAdmin($company, $companyOwner);
if ( in_array('ROLE_ADMIN_AGENCY',$this->getUser()->getRoles()) or in_array('ROLE_MANAGER',$this->getUser()->getRoles())) {
$isAgency = true;
}
return $this->render('workflow/index.html.twig', [
'workflows' => $workflow,
'isAgency' => $isAgency,
]);
}
/**
* Displays the handle view for the workflows
*
* @param Workflow|null $workflow if defined, the workflow to edit
* @param Request $request
* @param EntityManagerInterface $entityManager
* @param WorkflowActionRepository $workflowActionRepository
* @param WorkflowStepRepository $workflowStepRepository
*
* @return Response template /workflow/handle.html.twig
*/
#[Route('/ajouter', name: 'workflow_new')]
#[Route('/{id}', name: 'workflow_edit')]
public function handle(Workflow $workflow = null,DynamicHostService $dynamicHostService, Request $request,JobRepository $jobRepository, EntityManagerInterface $entityManager, WorkflowActionRepository $workflowActionRepository, WorkflowStepRepository $workflowStepRepository, EventDispatcherInterface $dispatcher,MissionRepository $missionRepository, WorkflowRepository $workflowRepository,UserRepository $userRepository): Response
{
$workflowExist = true;
if (null === $workflow) {
$workflowExist = false;
$companyOwner = $dynamicHostService->getCompany();
$workflow = (new Workflow())
->setTemplate(true)
->setOwner($companyOwner)
;
}
$allUsers = $userRepository->findAll();
//campaing for workflow
$mission = $missionRepository->findByWorkflow($workflow);
/*
* Handling the workflow informations form
*/
$company = null;
$isadminAgency = false;
$company = $this->getUser()->getCompany() ;
if (in_array("ROLE_ADMIN_AGENCY", $this->getUser()->getRoles()) ) {
$isadminAgency = true;
$company = $this->getUser()->getCompany();
}
$form = $this->createForm(WorkflowType::class, $workflow,['company'=>$company,'user'=>$allUsers,'isadminAgency'=>$isadminAgency]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($workflow->getTemplate() === false && null !== $workflow->getMission()) {
$historique = (new Historique())
->setUser($this->getUser())
->setMission($workflow->getMission())
->setMessage($this->getUser().' a modifié le workflow');
$entityManager->persist($historique);
}
// if(!in_array('ROLE_ADMIN', $this->getUser()->getRoles()) && $company!=null && $workflow->getCompany()==null){
// $workflow->setCompany($company);
// }
$entityManager->persist($workflow);
$entityManager->flush();
//link workflow into all mission if haven't workflow
if (!$workflowExist || $form->getData()->getCompany()) {
$product = $form->getData()->getProduct();
$company = $form->getData()->getCompany();
$sameWorkflow = $workflowRepository->findWorkFlowByCompanyAndProduct($company, $product);
if (sizeof($sameWorkflow) >= 2) {
$this->addFlash(
type: 'error',
message: 'Un workflow a déjà été créé pour ce service. Nous vous invitons à vérifier le processus existant ou en créer un nouveau pour un client en particulier si vous souhaitez activer un processus spécifique',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
}
$missions = $missionRepository->findMissionWorkFlowNullByCompany($company,$product);
$fisrtInsert = true;
foreach ($missions as $mission) {
if ($fisrtInsert) {
$mission->setWorkflow($workflow);
}else{
$newWorkflow = clone $workflow;
$newWorkflow->setTemplate(false);
$mission->setWorkflow($newWorkflow);
$entityManager->persist($newWorkflow);
}
$fisrtInsert = false;
$entityManager->persist($mission);
$entityManager->flush();
}
//end
}
$this->addFlash(
type: 'success',
message: 'Le workflow a bien été enregistré',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
} elseif ($form->isSubmitted()) {
$this->addFlash(
type: 'danger',
message: 'Merci de corriger les erreurs',
);
}
/*
* Handling the new step form
*
* If the form is submitted when editing a step, we load it and throw a bad request exception if the step is not found
* If not, a new step is created
*/
if (null !== $request->request->get('workflow_step') && isset($request->request->get('workflow_step')['stepId']) && !empty($request->request->get('workflow_step')['stepId'])) {
$step = $workflowStepRepository->find($request->request->get('workflow_step')['stepId']);
$newSteps = false;
if (null === $step) {
throw new BadRequestException();
}
} else {
$step = new WorkflowStep();
$newSteps = true;
}
$step->setWorkflow($workflow);
$addStepForm = $this->createForm(WorkflowStepType::class, $step);
$addStepForm->handleRequest($request);
if ($addStepForm->isSubmitted() && $addStepForm->isValid()) {
//if new steps add position
if( $newSteps ){
$step->setPosition(count($workflow->getSteps()));
}
// $userResponsableList = $step->getUserResponsables();
// foreach ($userResponsableList as $key => $userResponsable) {
// $step->removeUserResponsable($userResponsable)
// }
// $newUserResponsable =
// dump($request->request->get('workflow_step')['userResponsable']);
// dd($addStepForm);
$entityManager->persist($step);
$entityManager->flush();
$event = new WorkflowStepEditedEvent($step);
$dispatcher->dispatch($event, WorkflowStepEditedEvent::NAME);
$this->addFlash(
type: 'success',
message: 'L\'étape a bien été enregistrée',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
} elseif ($addStepForm->isSubmitted()) {
$this->addFlash(
type: 'danger',
message: 'Merci de corriger les erreurs',
);
}
/*
* Handling the new action form
*
* If the form is submitted when editing an action, we load it and throw a bad request exception if the action is not found
* If not, a new action is created
*/
if (null !== $request->request->get('workflow_action') && isset($request->request->get('workflow_action')['actionId']) && !empty($request->request->get('workflow_action')['actionId'])) {
$action = $workflowActionRepository->find($request->request->get('workflow_action')['actionId']);
if (null === $action) {
throw new BadRequestException();
}
} else {
$action = new WorkflowAction();
}
$participantsListUserId = [];
if (!is_null($workflow->getCompany())) {
foreach ($allUsers as $user) {
if (!is_null($user->getCompany()) && $user->getCompany()->getId() != $workflow->getCompany()->getId()) {
$participantsListUserId[] = $user;
}
}
}else{
$participantsListUserId = $allUsers;
}
$companyAgency = $dynamicHostService->getCompany();
$addActionForm = $this->createForm(WorkflowActionType::class, $action, ['product' => $workflow->getProduct(),'participantsListUserId'=>$participantsListUserId]);
$addActionForm->handleRequest($request);
if ($addActionForm->isSubmitted() && $addActionForm->isValid()) {
$entityManager->persist($action);
$entityManager->flush();
$this->addFlash(
type: 'success',
message: 'Le workflow a bien été enregistré',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
} elseif ($addStepForm->isSubmitted()) {
$this->addFlash(
type: 'danger',
message: 'Merci de corriger les erreurs',
);
}
$emailTemplate = new EmailTemplate();
$jobs = $jobRepository->findByAgency($this->agencyForUser);
$formEmailTemplate = $this->createForm(EmailTemplateType::class, $emailTemplate);
$externalUser = $this->createForm(ExteralUserType::class);
return $this->renderForm('workflow/handle.html.twig', [
'workflow' => $workflow,
'form' => $form,
'addStepForm' => $addStepForm,
'addActionForm' => $addActionForm,
'formEmailTemplate' => $formEmailTemplate,
'userInAction' => $action->getUser(),
'jobsProduct'=> $jobs
]);
}
/**
* @param Request $request
* @param UserRepository $userRepository
* @param EntityManagerInterface $entityManagerInterface
* @param WorkflowActionRepository $workflowActionRepository
*/
#[Route('/add/external', name: 'workflow_add_user_external')]
public function addUserExternal(Request $request,UserRepository $userRepository,EntityManagerInterface $entityManager, EventDispatcherInterface $dispatcher,WorkflowActionRepository $workflowActionRepository){
// Récupérer une variable POST spécifique
$email = $request->request->get('email');
$role = $request->request->get('role');
$userExist = true;
$idAction = $request->request->get('id_action');
$idWorkflow = $request->request->get('id_workflow');
//verification if user is exist
$user = $userRepository->findOneByEmail($email);
if (is_null($user)) {
$userExist = false;
$user = new User();
$user->setEnabled(false);
}
$user->setEmail($email)
->setRoles(['ROLE_CLIENT'])
->setExternal(true)
;
//liaison action
$action = $workflowActionRepository->findOneById($idAction);
//end validation step
$entityManager->persist($user);
$entityManager->flush();
$role = ($role['role'] == 'ROLE_VALIDATOR_EXTERNAL') ? Role::ROLE_VALIDATOR_EXTERNAL: Role::ROLE_OBSERVER_EXTERNAL;
$action->setRecipient($role);
$action->addUser($user);;
$entityManager->persist($action);
$entityManager->flush();
if (!$userExist) {
$event = new ClientUpdatedEvent($user, true);
$dispatcher->dispatch($event, ClientUpdatedEvent::NAME);
}
$this->addFlash(
type: 'message',
message: 'Le validateur externe est bien ajouté à cette action',
);
return $this->redirectToRoute('workflow_edit', ['id' => $idWorkflow]);
}
/**
* Displays the handle view for the workflows
*
* @param Workflow|null $workflow if defined, the workflow to edit
* @param Request $request
* @param EntityManagerInterface $entityManager
* @param WorkflowActionRepository $workflowActionRepository
* @param WorkflowStepRepository $workflowStepRepository
*
* @return Response template /workflow/handle.html.twig
*/
#[Route('/ajouter', name: 'workflow_new')]
#[Route('/test/{id}', name: 'workflow_edit2')]
public function handle2(Workflow $workflow = null, Request $request, EntityManagerInterface $entityManager, WorkflowActionRepository $workflowActionRepository, WorkflowStepRepository $workflowStepRepository, EventDispatcherInterface $dispatcher,MissionRepository $missionRepository, WorkflowRepository $workflowRepository): Response
{
$workflowExist = true;
if (null === $workflow) {
$workflowExist = false;
$workflow = (new Workflow())
->setTemplate(true);
}
/*
* Handling the workflow informations form
*/
$form = $this->createForm(WorkflowType::class, $workflow);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($workflow->getTemplate() === false && null !== $workflow->getMission()) {
$historique = (new Historique())
->setUser($this->getUser())
->setMission($workflow->getMission())
->setMessage($this->getUser().' a modifié le workflow');
$entityManager->persist($historique);
}
$entityManager->persist($workflow);
$entityManager->flush();
//link workflow into all mission if haven't workflow
if (!$workflowExist || $form->getData()->getCompany()) {
$product = $form->getData()->getProduct();
$company = $form->getData()->getCompany();
$sameWorkflow = $workflowRepository->findWorkFlowByCompanyAndProduct($company, $product);
if (sizeof($sameWorkflow) >= 2) {
$this->addFlash(
type: 'error',
message: 'Un workflow a déjà été créé pour ce service. Nous vous invitons à vérifier le processus existant ou en créer un nouveau pour un client en particulier si vous souhaitez activer un processus spécifique',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
}
$missions = $missionRepository->findMissionWorkFlowNullByCompany($company,$product);
$fisrtInsert = true;
foreach ($missions as $mission) {
if ($fisrtInsert) {
$mission->setWorkflow($workflow);
}else{
$newWorkflow = clone $workflow;
$newWorkflow->setTemplate(false);
$mission->setWorkflow($newWorkflow);
$entityManager->persist($newWorkflow);
}
$fisrtInsert = false;
$entityManager->persist($mission);
$entityManager->flush();
}
//end
}
$this->addFlash(
type: 'success',
message: 'Le workflow a bien été enregistré',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
} elseif ($form->isSubmitted()) {
$this->addFlash(
type: 'danger',
message: 'Merci de corriger les erreurs',
);
}
/*
* Handling the new step form
*
* If the form is submitted when editing a step, we load it and throw a bad request exception if the step is not found
* If not, a new step is created
*/
if (null !== $request->request->get('workflow_step') && isset($request->request->get('workflow_step')['stepId']) && !empty($request->request->get('workflow_step')['stepId'])) {
$step = $workflowStepRepository->find($request->request->get('workflow_step')['stepId']);
if (null === $step) {
throw new BadRequestException();
}
} else {
$step = new WorkflowStep();
}
$step->setWorkflow($workflow);
$addStepForm = $this->createForm(WorkflowStepType::class, $step);
$addStepForm->handleRequest($request);
if ($addStepForm->isSubmitted() && $addStepForm->isValid()) {
$entityManager->persist($step);
$entityManager->flush();
$event = new WorkflowStepEditedEvent($step);
$dispatcher->dispatch($event, WorkflowStepEditedEvent::NAME);
$this->addFlash(
type: 'success',
message: 'L\'étape a bien été enregistrée',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
} elseif ($addStepForm->isSubmitted()) {
$this->addFlash(
type: 'danger',
message: 'Merci de corriger les erreurs',
);
}
/*
* Handling the new action form
*
* If the form is submitted when editing an action, we load it and throw a bad request exception if the action is not found
* If not, a new action is created
*/
if (null !== $request->request->get('workflow_action') && isset($request->request->get('workflow_action')['actionId']) && !empty($request->request->get('workflow_action')['actionId'])) {
$action = $workflowActionRepository->find($request->request->get('workflow_action')['actionId']);
if (null === $action) {
throw new BadRequestException();
}
} else {
$action = new WorkflowAction();
}
$addActionForm = $this->createForm(WorkflowActionType::class, $action, ['product' => $workflow->getProduct()]);
$addActionForm->handleRequest($request);
if ($addActionForm->isSubmitted() && $addActionForm->isValid()) {
$entityManager->persist($action);
$entityManager->flush();
$this->addFlash(
type: 'success',
message: 'Le workflow a bien été enregistré',
);
return $this->redirectToRoute('workflow_edit', ['id' => $workflow->getId()]);
} elseif ($addStepForm->isSubmitted()) {
$this->addFlash(
type: 'danger',
message: 'Merci de corriger les erreurs',
);
}
$emailTemplate = new EmailTemplate();
$formEmailTemplate = $this->createForm(EmailTemplateType::class, $emailTemplate);
return $this->renderForm('workflow/handle2.html.twig', [
'workflow' => $workflow,
'form' => $form,
'addStepForm' => $addStepForm,
'addActionForm' => $addActionForm,
'formEmailTemplate' => $formEmailTemplate,
]);
}
#[Route('/{id}/supprimer', name: 'workflow_delete' , methods: ['GET'])]
public function delete(Workflow $workflow, EntityManagerInterface $entityManager): RedirectResponse
{
$entityManager->remove($workflow);
$entityManager->flush();
$this->addFlash(
type: 'success',
message: 'Le workflow a bien été supprimé',
);
return $this->redirectToRoute('workflow_index');
}
#[Route('/{id}/dupliquer', name: 'workflow_duplicate', methods: ['GET'])]
public function duplicate(Workflow $workflow, EntityManagerInterface $entityManager)
{
$workflowClone = clone $workflow;
$workflowClone->setName($workflowClone->getName().'_clone');
$workflowClone->setCompany(null);
$entityManager->persist($workflowClone);
$entityManager->flush();
$this->addFlash(
type: 'success',
message: 'Le workflow a bien été cloné',
);
return $this->redirectToRoute('workflow_index');
}
}