diff --git a/Controller/TaskController.php b/Controller/TaskController.php index a24fa9ce9..a54964574 100644 --- a/Controller/TaskController.php +++ b/Controller/TaskController.php @@ -11,6 +11,11 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Chill\TaskBundle\Event\UI\UIEvent; +use Chill\TaskBundle\Entity\AbstractTask; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Workflow\Transition; class TaskController extends Controller @@ -41,7 +46,8 @@ class TaskController extends Controller Registry $registry, EntityManagerInterface $em, Request $request, - TranslatorInterface $translator + TranslatorInterface $translator, + EventDispatcherInterface $eventDispatcher ) { switch ($kind) { case 'single-task': @@ -49,9 +55,12 @@ class TaskController extends Controller ->find($taskId) ; $defaultReturnPath = $this->generateUrl( - 'chill_task_singletask_list', - [ 'person_id' => $task->getPerson() ] - ); + 'chill_task_single_task_show', + [ + 'id' => $task->getId(), + 'list_params' => $request->query->get('list_params', []) + ]); + $defaultTemplate = '@ChillTask/SingleTask/transition.html.twig'; break; default: return new Response("The type '$kind' is not implemented", @@ -59,27 +68,75 @@ class TaskController extends Controller } if (NULL === $task) { - $this->createNotFoundException("task with id '$taskId' and type " + throw $this->createNotFoundException("task with id '$taskId' and type " . "'$type' does not exists"); } + + $workflow = $registry->get($task); + + if (!$workflow->can($task, $transition)) { + throw $this->createAccessDeniedException('You are not allowed to apply this transition'); + } + $transitionInstance = \array_values( // array_values needed to reset keys (array_filter preserves keys) + \array_filter( + $workflow->getEnabledTransitions($task), + function(Transition $t) use ($transition) { + return $t->getName() === $transition; + } + ))[0]; // we simply check that the user can see the task. Other ACL checks // should be performed using `guard` events. $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task); + + $form = $this->createTransitionForm($task); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { - $workflow = $registry->get($task); + if ($workflow->can($task, $transition)) { + $workflow->apply($task, $transition); - if ($workflow->can($task, $transition)) { - $workflow->apply($task, $transition); + $em->flush(); - $em->flush(); - - $this->addFlash('success', $translator->trans('The transition is successfully applied')); + $this->addFlash('success', $translator->trans('The transition is successfully applied')); + } else { + $this->addFlash('error', $translator->trans('The transition could not be applied')); + } + + return $this->redirect($defaultReturnPath); } else { - $this->addFlash('error', $translator->trans('The transition could not be applied')); + $event = (new UIEvent($kind, $task)) + ->setForm($form) + ->setTransition($transitionInstance) + ; + + $eventDispatcher->dispatch(UIEvent::SHOW_TRANSITION_PAGE, $event); + + if ($event->hasResponse()) { + return $event->getResponse(); + } else { + return $this->render($defaultTemplate, [ + 'task' => $task, + 'form' => $form->createView(), + 'transition' => $transitionInstance + ]); + } } - - return $this->redirect($request->query->get('return_path', $defaultReturnPath)); + } + + /** + * + * @param \Chill\TaskBundle\Controller\AbstractTask $task + * @return \Symfony\Component\Form\FormInterface + */ + protected function createTransitionForm(AbstractTask $task) + { + $builder = $this->createFormBuilder($task); + $builder->add('submit', SubmitType::class); + + return $builder->getForm(); } } diff --git a/Event/UI/UIEvent.php b/Event/UI/UIEvent.php new file mode 100644 index 000000000..201c3a265 --- /dev/null +++ b/Event/UI/UIEvent.php @@ -0,0 +1,130 @@ + + */ +class UIEvent extends Event +{ + const SHOW_TRANSITION_PAGE = 'chill_task.show_transition_page'; + + /** + * + * @var string + */ + protected $kind; + + /** + * + * @var AbstractTask + */ + protected $task; + + /** + * + * @var Response|null + */ + protected $response = null; + + /** + * + * @var FormInterface|null + */ + protected $form = null; + + /** + * @var Transition + */ + protected $transition = null; + + public function __construct($kind, AbstractTask $task) + { + $this->kind = $kind; + $this->task = $task; + } + + /** + * + * @return string + */ + public function getKind() + { + return $this->kind; + } + + /** + * + * @return AbstractTask + */ + public function getTask(): AbstractTask + { + return $this->task; + } + + /** + * + * @return FormInterface|null + */ + public function getForm() + { + return $this->form; + } + + public function setForm(FormInterface $form) + { + $this->form = $form; + + return $this; + } + + public function getTransition() + { + return $this->transition; + } + + public function setTransition(Transition $transition) + { + $this->transition = $transition; + + return $this; + } + + /** + * + * @return Response + */ + public function getResponse(): Response + { + return $this->response; + } + + /** + * + * @param Response $response + * @return $this + */ + public function setResponse(Response $response) + { + $this->response = $response; + + return $this; + } + + public function hasResponse() + { + return $this->response instanceof Response; + } + + +} diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index e13e07bda..3ec1f10eb 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -60,7 +60,7 @@ Associated person: Personne associée Default task: Tâche par défaut -# transitions +# transitions - default task definition 'new': 'nouvelle' 'in_progress': 'en cours' 'closed': 'fermée' @@ -68,10 +68,16 @@ Default task: Tâche par défaut start: démarrer close: clotûrer cancel: annuler +Start_verb: Démarrer +Close_verb: Clotûrer +Set this task to cancel state: Marquer cette tâche comme annulée '%user% has closed the task': %user% a fermé la tâche '%user% has canceled the task': %user% a annulé la tâche '%user% has started the task': %user% a commencé la tâche '%user% has created the task': %user% a introduit la tâche +Are you sure you want to close this task ?: Êtes-vous sûrs de vouloir clotûrer cette tâche ? +Are you sure you want to cancel this task ?: Êtes-vous sûrs de vouloir annuler cette tâche ? +Are you sure you want to start this task ?: Êtes-vous sûrs de vouloir démarrer cette tâche ? #Flash messages 'The task is created': 'La tâche a été créée' @@ -88,4 +94,7 @@ cancel: annuler #title My tasks near deadline: Mes tâches à échéance proche -My tasks over deadline: Mes tâches à échéance dépassée \ No newline at end of file +My tasks over deadline: Mes tâches à échéance dépassée + +#transition page +Apply transition on task %title%: Appliquer la transition sur la tâche %title% diff --git a/Resources/views/SingleTask/_list.html.twig b/Resources/views/SingleTask/_list.html.twig index dadf6e248..28b3ddc8b 100644 --- a/Resources/views/SingleTask/_list.html.twig +++ b/Resources/views/SingleTask/_list.html.twig @@ -18,7 +18,7 @@ {% for task in tasks %}
{{ 'Are you sure to apply the transition %name% on this task ?'|trans({ '%name%': task_workflow_metadata(task, 'transition.name', transition)|default(transition.name)|trans }) }}
+{% endif %} + +{{ form_start(form) }} + +