mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
The validation is processed at the form step, so before the transition is processed
425 lines
16 KiB
PHP
425 lines
16 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Chill\MainBundle\Controller;
|
|
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflowComment;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep;
|
|
use Chill\MainBundle\Form\EntityWorkflowCommentType;
|
|
use Chill\MainBundle\Form\WorkflowStepType;
|
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
|
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
|
|
use Chill\MainBundle\Security\Authorization\EntityWorkflowVoter;
|
|
use Chill\MainBundle\Workflow\EntityWorkflowManager;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
|
use Symfony\Component\Routing\Annotation\Route;
|
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
|
use Symfony\Component\Security\Core\Security;
|
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|
use Symfony\Component\Workflow\Registry;
|
|
use Symfony\Component\Workflow\TransitionBlocker;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
use function count;
|
|
|
|
class WorkflowController extends AbstractController
|
|
{
|
|
private EntityManagerInterface $entityManager;
|
|
|
|
private EntityWorkflowManager $entityWorkflowManager;
|
|
|
|
private EntityWorkflowRepository $entityWorkflowRepository;
|
|
|
|
private PaginatorFactory $paginatorFactory;
|
|
|
|
private Registry $registry;
|
|
|
|
private Security $security;
|
|
|
|
private TranslatorInterface $translator;
|
|
|
|
private ValidatorInterface $validator;
|
|
|
|
public function __construct(EntityWorkflowManager $entityWorkflowManager, EntityWorkflowRepository $entityWorkflowRepository, ValidatorInterface $validator, PaginatorFactory $paginatorFactory, Registry $registry, EntityManagerInterface $entityManager, TranslatorInterface $translator, Security $security)
|
|
{
|
|
$this->entityWorkflowManager = $entityWorkflowManager;
|
|
$this->entityWorkflowRepository = $entityWorkflowRepository;
|
|
$this->validator = $validator;
|
|
$this->paginatorFactory = $paginatorFactory;
|
|
$this->registry = $registry;
|
|
$this->entityManager = $entityManager;
|
|
$this->translator = $translator;
|
|
$this->security = $security;
|
|
}
|
|
|
|
/**
|
|
* @Route("/{_locale}/main/workflow/create", name="chill_main_workflow_create")
|
|
*/
|
|
public function create(Request $request): Response
|
|
{
|
|
if (!$request->query->has('entityClass')) {
|
|
throw new BadRequestHttpException('Missing entityClass parameter');
|
|
}
|
|
|
|
if (!$request->query->has('entityId')) {
|
|
throw new BadRequestHttpException('missing entityId parameter');
|
|
}
|
|
|
|
if (!$request->query->has('workflow')) {
|
|
throw new BadRequestHttpException('missing workflow parameter');
|
|
}
|
|
|
|
$entityWorkflow = new EntityWorkflow();
|
|
$entityWorkflow
|
|
->setRelatedEntityClass($request->query->get('entityClass'))
|
|
->setRelatedEntityId($request->query->getInt('entityId'))
|
|
->setWorkflowName($request->query->get('workflow'))
|
|
->addSubscriberToFinal($this->getUser());
|
|
|
|
$errors = $this->validator->validate($entityWorkflow, null, ['creation']);
|
|
|
|
if (count($errors) > 0) {
|
|
$msg = [];
|
|
|
|
foreach ($errors as $error) {
|
|
/** @var \Symfony\Component\Validator\ConstraintViolationInterface $error */
|
|
$msg[] = $error->getMessage();
|
|
}
|
|
|
|
return new Response(implode("\n", $msg), Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
|
|
$this->denyAccessUnlessGranted(EntityWorkflowVoter::CREATE, $entityWorkflow);
|
|
|
|
$em = $this->getDoctrine()->getManager();
|
|
$em->persist($entityWorkflow);
|
|
$em->flush();
|
|
|
|
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{_locale}/main/workflow/{id}/delete", name="chill_main_workflow_delete")
|
|
*/
|
|
public function delete(EntityWorkflow $entityWorkflow, Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted(EntityWorkflowVoter::DELETE, $entityWorkflow);
|
|
|
|
$form = $this->createForm(FormType::class);
|
|
$form->add('submit', SubmitType::class, ['label' => 'workflow.Delete workflow']);
|
|
$form->handleRequest($request);
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
$this->entityManager->remove($entityWorkflow);
|
|
$this->entityManager->flush();
|
|
|
|
$this->addFlash('success', $this->translator->trans('workflow.Workflow deleted with success'));
|
|
|
|
return $this->redirectToRoute('chill_main_homepage');
|
|
}
|
|
|
|
return $this->render('@ChillMain/Workflow/delete.html.twig', [
|
|
'entityWorkflow' => $entityWorkflow,
|
|
'delete_form' => $form->createView(),
|
|
'handler' => $this->entityWorkflowManager->getHandler($entityWorkflow),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{_locale}/main/workflow-step/{id}/access_key", name="chill_main_workflow_grant_access_by_key")
|
|
*/
|
|
public function getAccessByAccessKey(EntityWorkflowStep $entityWorkflowStep, Request $request): Response
|
|
{
|
|
if (null === $accessKey = $request->query->get('accessKey', null)) {
|
|
throw new BadRequestHttpException('accessKey is missing');
|
|
}
|
|
|
|
if (!$this->getUser() instanceof User) {
|
|
throw new AccessDeniedException('Not a valid user');
|
|
}
|
|
|
|
if ($entityWorkflowStep->getAccessKey() !== $accessKey) {
|
|
throw new AccessDeniedException('Access key is invalid');
|
|
}
|
|
|
|
if (!$entityWorkflowStep->isWaitingForTransition()) {
|
|
$this->addFlash('error', $this->translator->trans('workflow.Steps is not waiting for transition. Maybe someone apply the transition before you ?'));
|
|
} else {
|
|
$entityWorkflowStep->addDestUserByAccessKey($this->getUser());
|
|
$this->entityManager->flush();
|
|
$this->addFlash('success', $this->translator->trans('workflow.You get access to this step'));
|
|
}
|
|
|
|
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflowStep->getEntityWorkflow()->getId()]);
|
|
}
|
|
|
|
/**
|
|
* Previous workflows where the user has applyed a transition.
|
|
*
|
|
* @Route("/{_locale}/main/workflow/list/previous_transitionned", name="chill_main_workflow_list_previous_transitionned")
|
|
*/
|
|
public function myPreviousWorkflowsTransitionned(Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
|
|
$total = $this->entityWorkflowRepository->countByPreviousTransitionned($this->getUser());
|
|
$paginator = $this->paginatorFactory->create($total);
|
|
|
|
$workflows = $this->entityWorkflowRepository->findByPreviousTransitionned(
|
|
$this->getUser(),
|
|
['createdAt' => 'DESC'],
|
|
$paginator->getItemsPerPage(),
|
|
$paginator->getCurrentPageFirstItemNumber()
|
|
);
|
|
|
|
return $this->render(
|
|
'@ChillMain/Workflow/list.html.twig',
|
|
[
|
|
'help' => 'workflow.Previous workflow transitionned help',
|
|
'workflows' => $this->buildHandler($workflows),
|
|
'paginator' => $paginator,
|
|
'step' => 'previous_transitionned',
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Previous workflows where the user was mentioned, but did not give any reaction.
|
|
*
|
|
* @Route("/{_locale}/main/workflow/list/previous_without_reaction", name="chill_main_workflow_list_previous_without_reaction")
|
|
*/
|
|
public function myPreviousWorkflowsWithoutReaction(Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
|
|
$total = $this->entityWorkflowRepository->countByPreviousDestWithoutReaction($this->getUser());
|
|
$paginator = $this->paginatorFactory->create($total);
|
|
|
|
$workflows = $this->entityWorkflowRepository->findByPreviousDestWithoutReaction(
|
|
$this->getUser(),
|
|
['createdAt' => 'DESC'],
|
|
$paginator->getItemsPerPage(),
|
|
$paginator->getCurrentPageFirstItemNumber()
|
|
);
|
|
|
|
return $this->render(
|
|
'@ChillMain/Workflow/list.html.twig',
|
|
[
|
|
'help' => 'workflow.Previous workflow without reaction help',
|
|
'workflows' => $this->buildHandler($workflows),
|
|
'paginator' => $paginator,
|
|
'step' => 'previous_without_reaction',
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{_locale}/main/workflow/list/cc", name="chill_main_workflow_list_cc")
|
|
*/
|
|
public function myWorkflowsCc(Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
|
|
$total = $this->entityWorkflowRepository->countByDest($this->getUser());
|
|
$paginator = $this->paginatorFactory->create($total);
|
|
|
|
$workflows = $this->entityWorkflowRepository->findByCc(
|
|
$this->getUser(),
|
|
['createdAt' => 'DESC'],
|
|
$paginator->getItemsPerPage(),
|
|
$paginator->getCurrentPageFirstItemNumber()
|
|
);
|
|
|
|
return $this->render(
|
|
'@ChillMain/Workflow/list.html.twig',
|
|
[
|
|
'workflows' => $this->buildHandler($workflows),
|
|
'paginator' => $paginator,
|
|
'step' => 'cc',
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{_locale}/main/workflow/list/dest", name="chill_main_workflow_list_dest")
|
|
*/
|
|
public function myWorkflowsDest(Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
|
|
$total = $this->entityWorkflowRepository->countByDest($this->getUser());
|
|
$paginator = $this->paginatorFactory->create($total);
|
|
|
|
$workflows = $this->entityWorkflowRepository->findByDest(
|
|
$this->getUser(),
|
|
['createdAt' => 'DESC'],
|
|
$paginator->getItemsPerPage(),
|
|
$paginator->getCurrentPageFirstItemNumber()
|
|
);
|
|
|
|
return $this->render(
|
|
'@ChillMain/Workflow/list.html.twig',
|
|
[
|
|
'workflows' => $this->buildHandler($workflows),
|
|
'paginator' => $paginator,
|
|
'step' => 'dest',
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{_locale}/main/workflow/list/subscribed", name="chill_main_workflow_list_subscribed")
|
|
*/
|
|
public function myWorkflowsSubscribed(Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
|
|
$total = $this->entityWorkflowRepository->countBySubscriber($this->getUser());
|
|
$paginator = $this->paginatorFactory->create($total);
|
|
|
|
$workflows = $this->entityWorkflowRepository->findBySubscriber(
|
|
$this->getUser(),
|
|
['createdAt' => 'DESC'],
|
|
$paginator->getItemsPerPage(),
|
|
$paginator->getCurrentPageFirstItemNumber()
|
|
);
|
|
|
|
return $this->render(
|
|
'@ChillMain/Workflow/list.html.twig',
|
|
[
|
|
'workflows' => $this->buildHandler($workflows),
|
|
'paginator' => $paginator,
|
|
'step' => 'subscribed',
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{_locale}/main/workflow/{id}/show", name="chill_main_workflow_show")
|
|
*/
|
|
public function show(EntityWorkflow $entityWorkflow, Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted(EntityWorkflowVoter::SEE, $entityWorkflow);
|
|
|
|
$handler = $this->entityWorkflowManager->getHandler($entityWorkflow);
|
|
$workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
|
|
$errors = [];
|
|
|
|
if (count($workflow->getEnabledTransitions($entityWorkflow)) > 0) {
|
|
// possible transition
|
|
|
|
$usersInvolved = $entityWorkflow->getUsersInvolved();
|
|
$currentUserFound = array_search($this->security->getUser(), $usersInvolved, true);
|
|
|
|
if (false !== $currentUserFound) {
|
|
unset($usersInvolved[$currentUserFound]);
|
|
}
|
|
|
|
$transitionForm = $this->createForm(
|
|
WorkflowStepType::class,
|
|
$entityWorkflow->getCurrentStep(),
|
|
[
|
|
'transition' => true,
|
|
'entity_workflow' => $entityWorkflow,
|
|
'suggested_users' => $usersInvolved
|
|
]
|
|
);
|
|
|
|
$transitionForm->handleRequest($request);
|
|
|
|
if ($transitionForm->isSubmitted() && $transitionForm->isValid()) {
|
|
if (!$workflow->can($entityWorkflow, $transition = $transitionForm['transition']->getData()->getName())) {
|
|
$blockers = $workflow->buildTransitionBlockerList($entityWorkflow, $transition);
|
|
$msgs = array_map(function (TransitionBlocker $tb) {
|
|
return $this->translator->trans(
|
|
$tb->getMessage(),
|
|
$tb->getParameters()
|
|
);
|
|
}, iterator_to_array($blockers));
|
|
|
|
throw $this->createAccessDeniedException(
|
|
sprintf(
|
|
"not allowed to apply transition {$transition}: %s",
|
|
implode(', ', $msgs)
|
|
)
|
|
);
|
|
}
|
|
|
|
// TODO symfony 5: add those "future" on context ($workflow->apply($entityWorkflow, $transition, $context)
|
|
$entityWorkflow->futureCcUsers = $transitionForm['future_cc_users']->getData();
|
|
$entityWorkflow->futureDestUsers = $transitionForm['future_dest_users']->getData();
|
|
$entityWorkflow->futureDestEmails = $transitionForm['future_dest_emails']->getData();
|
|
|
|
$workflow->apply($entityWorkflow, $transition);
|
|
|
|
$this->entityManager->flush();
|
|
|
|
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
|
|
}
|
|
|
|
if ($transitionForm->isSubmitted() && !$transitionForm->isValid()) {
|
|
$this->addFlash('error', $this->translator->trans('This form contains errors'));
|
|
}
|
|
}
|
|
|
|
/*
|
|
$commentForm = $this->createForm(EntityWorkflowCommentType::class, $newComment = new EntityWorkflowComment());
|
|
$commentForm->handleRequest($request);
|
|
|
|
if ($commentForm->isSubmitted() && $commentForm->isValid()) {
|
|
$this->entityManager->persist($newComment);
|
|
$this->entityManager->flush();
|
|
|
|
$this->addFlash('success', $this->translator->trans('workflow.Comment added'));
|
|
|
|
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
|
|
} elseif ($commentForm->isSubmitted() && !$commentForm->isValid()) {
|
|
$this->addFlash('error', $this->translator->trans('This form contains errors'));
|
|
}
|
|
*/
|
|
|
|
return $this->render(
|
|
'@ChillMain/Workflow/index.html.twig',
|
|
[
|
|
'handler' => $handler,
|
|
'handler_template' => $handler->getTemplate($entityWorkflow),
|
|
'handler_template_data' => $handler->getTemplateData($entityWorkflow),
|
|
'transition_form' => isset($transitionForm) ? $transitionForm->createView() : null,
|
|
'entity_workflow' => $entityWorkflow,
|
|
'transition_form_errors' => $errors,
|
|
//'comment_form' => $commentForm->createView(),
|
|
]
|
|
);
|
|
}
|
|
|
|
private function buildHandler(array $workflows): array
|
|
{
|
|
$lines = [];
|
|
|
|
foreach ($workflows as $workflow) {
|
|
$handler = $this->entityWorkflowManager->getHandler($workflow);
|
|
$lines[] = [
|
|
'handler' => $handler,
|
|
'entity_workflow' => $workflow,
|
|
];
|
|
}
|
|
|
|
return $lines;
|
|
}
|
|
}
|