mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
record single task states transition and add them in timeline
This commit is contained in:
parent
57169b3148
commit
86f7188d4a
@ -20,6 +20,8 @@ use Chill\MainBundle\Entity\User;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Chill\PersonBundle\Entity\PersonRepository;
|
||||
use Chill\MainBundle\Entity\UserRepository;
|
||||
use Chill\TaskBundle\Event\TaskEvent;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class SingleTaskController extends Controller
|
||||
{
|
||||
@ -30,8 +32,10 @@ class SingleTaskController extends Controller
|
||||
* name="chill_task_single_task_new"
|
||||
* )
|
||||
*/
|
||||
public function newAction(Request $request)
|
||||
{
|
||||
public function newAction(
|
||||
Request $request,
|
||||
EventDispatcherInterface $dispatcher
|
||||
) {
|
||||
|
||||
$task = (new SingleTask())
|
||||
->setAssignee($this->getUser())
|
||||
@ -67,6 +71,8 @@ class SingleTaskController extends Controller
|
||||
if ($form->isValid()) {
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->persist($task);
|
||||
|
||||
$dispatcher->dispatch(TaskEvent::PERSIST, new TaskEvent($task));
|
||||
|
||||
$em->flush();
|
||||
|
||||
|
@ -32,6 +32,8 @@ class ChillTaskExtension extends Extension implements PrependExtensionInterface
|
||||
$loader->load('services/workflow.yml');
|
||||
$loader->load('services/templating.yml');
|
||||
$loader->load('services/menu.yml');
|
||||
$loader->load('services/event.yml');
|
||||
$loader->load('services/timeline.yml');
|
||||
}
|
||||
|
||||
public function prepend(ContainerBuilder $container)
|
||||
|
@ -22,6 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Chill\TaskBundle\Workflow\TaskWorkflowManager;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Chill\TaskBundle\Templating\UI\CountNotificationTask;
|
||||
use Chill\TaskBundle\Event\Lifecycle\TaskLifecycleEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -39,6 +40,7 @@ class TaskWorkflowDefinitionCompilerPass implements CompilerPassInterface
|
||||
|
||||
$workflowManagerDefinition = $container->getDefinition(TaskWorkflowManager::class);
|
||||
$counterDefinition = $container->getDefinition(CountNotificationTask::class);
|
||||
$lifecycleDefinition = $container->getDefinition(TaskLifecycleEvent::class);
|
||||
|
||||
foreach ($container->findTaggedServiceIds('chill_task.workflow_definition') as $id => $tags) {
|
||||
// registering the definition to manager
|
||||
@ -58,6 +60,12 @@ class TaskWorkflowDefinitionCompilerPass implements CompilerPassInterface
|
||||
'method' => 'resetCacheOnNewStates',
|
||||
'priority' => 0
|
||||
]);
|
||||
$lifecycleDefinition
|
||||
->addTag('kernel.event_listener', [
|
||||
'event' => sprintf('workflow.%s.transition', $definition->getClass()::getAssociatedWorkflowName()),
|
||||
'method' => 'onTransition',
|
||||
'priority' => 0
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,11 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface
|
||||
* @ORM\Column(name="closed", type="boolean", options={ "default"=false })
|
||||
*/
|
||||
private $closed = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set type
|
||||
|
@ -4,6 +4,7 @@ namespace Chill\TaskBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
/**
|
||||
* SingleTask
|
||||
@ -58,8 +59,25 @@ class SingleTask extends AbstractTask
|
||||
* )
|
||||
*/
|
||||
private $recurringTask;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var \Doctrine\Common\Collections\Collection
|
||||
* @ORM\OneToMany(
|
||||
* targetEntity="\Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent",
|
||||
* mappedBy="task"
|
||||
* )
|
||||
*/
|
||||
private $taskPlaceEvents;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->taskPlaceEvents = $events = new \Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get id
|
||||
*
|
||||
@ -174,6 +192,16 @@ class SingleTask extends AbstractTask
|
||||
$this->recurringTask = $recurringTask;
|
||||
}
|
||||
|
||||
public function getTaskPlaceEvents(): Collection
|
||||
{
|
||||
return $this->taskPlaceEvents;
|
||||
}
|
||||
|
||||
public function setTaskPlaceEvents(Collection $taskPlaceEvents)
|
||||
{
|
||||
$this->taskPlaceEvents = $taskPlaceEvents;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
|
154
Entity/Task/AbstractTaskPlaceEvent.php
Normal file
154
Entity/Task/AbstractTaskPlaceEvent.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\TaskBundle\Entity\Task;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
|
||||
/**
|
||||
* AbstractTaskPlaceEvent
|
||||
*
|
||||
* @ORM\MappedSuperclass()
|
||||
*/
|
||||
class AbstractTaskPlaceEvent
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @ORM\Column(name="id", type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var datetime_immutable
|
||||
*
|
||||
* @ORM\Column(name="datetime", type="datetime_immutable")
|
||||
*/
|
||||
private $datetime;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="transition", type="string", length=255)
|
||||
*/
|
||||
private $transition = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="data", type="json")
|
||||
*/
|
||||
private $data = [];
|
||||
|
||||
/**
|
||||
*
|
||||
* @var User
|
||||
* @ORM\ManyToOne(
|
||||
* targetEntity="\Chill\MainBundle\Entity\User"
|
||||
* )
|
||||
*/
|
||||
private $author;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->datetime = new \DateTimeImmutable('now');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set datetime.
|
||||
*
|
||||
* @param datetime_immutable $datetime
|
||||
*
|
||||
* @return AbstractTaskPlaceEvent
|
||||
*/
|
||||
public function setDatetime($datetime)
|
||||
{
|
||||
$this->datetime = $datetime;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get datetime.
|
||||
*
|
||||
* @return datetime_immutable
|
||||
*/
|
||||
public function getDatetime()
|
||||
{
|
||||
return $this->datetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set transition.
|
||||
*
|
||||
* @param string $transition
|
||||
*
|
||||
* @return AbstractTaskPlaceEvent
|
||||
*/
|
||||
public function setTransition($transition)
|
||||
{
|
||||
$this->transition = $transition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transition.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTransition()
|
||||
{
|
||||
return $this->transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data.
|
||||
*
|
||||
* @param string $data
|
||||
*
|
||||
* @return AbstractTaskPlaceEvent
|
||||
*/
|
||||
public function setData($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getAuthor(): User
|
||||
{
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
public function setAuthor(User $author)
|
||||
{
|
||||
$this->author = $author;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
56
Entity/Task/SingleTaskPlaceEvent.php
Normal file
56
Entity/Task/SingleTaskPlaceEvent.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\TaskBundle\Entity\Task;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\TaskBundle\Entity\SingleTask;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @ORM\Table("chill_task.single_task_place_event")
|
||||
* @ORM\Entity()
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class SingleTaskPlaceEvent extends AbstractTaskPlaceEvent
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var SingleTask
|
||||
* @ORM\ManyToOne(
|
||||
* targetEntity="\Chill\TaskBundle\Entity\SingleTask",
|
||||
* inversedBy="taskPlaceEvents"
|
||||
* )
|
||||
*/
|
||||
protected $task;
|
||||
|
||||
public function getTask(): SingleTask
|
||||
{
|
||||
return $this->task;
|
||||
}
|
||||
|
||||
public function setTask(SingleTask $task)
|
||||
{
|
||||
$this->task = $task;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
104
Event/Lifecycle/TaskLifecycleEvent.php
Normal file
104
Event/Lifecycle/TaskLifecycleEvent.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\TaskBundle\Event\Lifecycle;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Chill\TaskBundle\Event\TaskEvent;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent;
|
||||
use Symfony\Component\Workflow\Event\Event as WorkflowEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class TaskLifecycleEvent implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var TokenStorageInterface
|
||||
*/
|
||||
protected $tokenStorage;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
public function __construct(
|
||||
TokenStorageInterface $tokenStorage,
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
TaskEvent::PERSIST => [
|
||||
'onTaskPersist'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function onTaskPersist(TaskEvent $e)
|
||||
{
|
||||
$task = $e->getTask();
|
||||
$user = $this->tokenStorage->getToken()->getUser();
|
||||
|
||||
$event = (new SingleTaskPlaceEvent())
|
||||
->setTask($task)
|
||||
->setAuthor($user)
|
||||
->setTransition('_creation')
|
||||
->setData([
|
||||
'new_states' => $task->getCurrentStates()
|
||||
])
|
||||
;
|
||||
|
||||
$task->getTaskPlaceEvents()->add($event);
|
||||
|
||||
$this->em->persist($event);
|
||||
}
|
||||
|
||||
public function onTransition(WorkflowEvent $e)
|
||||
{
|
||||
$task = $e->getSubject();
|
||||
$user = $this->tokenStorage->getToken()->getUser();
|
||||
|
||||
$event = (new SingleTaskPlaceEvent())
|
||||
->setTask($task)
|
||||
->setAuthor($user)
|
||||
->setTransition($e->getTransition()->getName())
|
||||
->setData([
|
||||
'old_states' => $e->getTransition()->getFroms(),
|
||||
'new_states' => $e->getTransition()->getTos(),
|
||||
'workflow' => $e->getWorkflowName()
|
||||
])
|
||||
;
|
||||
|
||||
$task->getTaskPlaceEvents()->add($event);
|
||||
|
||||
$this->em->persist($event);
|
||||
}
|
||||
|
||||
}
|
55
Event/TaskEvent.php
Normal file
55
Event/TaskEvent.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\TaskBundle\Event;
|
||||
|
||||
use Chill\TaskBundle\Entity\AbstractTask;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class TaskEvent extends Event
|
||||
{
|
||||
const PERSIST = 'chill_task.task_persist';
|
||||
|
||||
/**
|
||||
*
|
||||
* @var AbstractTask
|
||||
*/
|
||||
protected $task;
|
||||
|
||||
public function __construct(AbstractTask $task)
|
||||
{
|
||||
$this->task = $task;
|
||||
}
|
||||
|
||||
public function getTask(): AbstractTask
|
||||
{
|
||||
return $this->task;
|
||||
}
|
||||
|
||||
public function setTask(AbstractTask $task)
|
||||
{
|
||||
$this->task = $task;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
7
Resources/config/services/event.yml
Normal file
7
Resources/config/services/event.yml
Normal file
@ -0,0 +1,7 @@
|
||||
services:
|
||||
Chill\TaskBundle\Event\Lifecycle\TaskLifecycleEvent:
|
||||
arguments:
|
||||
$em: '@Doctrine\ORM\EntityManagerInterface'
|
||||
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
|
||||
tags:
|
||||
- { name: kernel.event_subscriber }
|
8
Resources/config/services/timeline.yml
Normal file
8
Resources/config/services/timeline.yml
Normal file
@ -0,0 +1,8 @@
|
||||
services:
|
||||
Chill\TaskBundle\Timeline\TaskLifeCycleEventTimelineProvider:
|
||||
arguments:
|
||||
$em: '@Doctrine\ORM\EntityManagerInterface'
|
||||
$registry: '@Symfony\Component\Workflow\Registry'
|
||||
tags:
|
||||
- { name: 'chill.timeline', context: 'person' }
|
||||
|
34
Resources/migrations/Version20180502194119.php
Normal file
34
Resources/migrations/Version20180502194119.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace Application\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Migrations\AbstractMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
/**
|
||||
* Create task place events table.
|
||||
*/
|
||||
class Version20180502194119 extends AbstractMigration
|
||||
{
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||
|
||||
$this->addSql('CREATE SEQUENCE chill_task.single_task_place_event_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||
$this->addSql('CREATE TABLE chill_task.single_task_place_event (id INT NOT NULL, author_id INT DEFAULT NULL, task_id INT DEFAULT NULL, datetime TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, transition VARCHAR(255) NOT NULL, data JSONB NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_D459EBEEF675F31B ON chill_task.single_task_place_event (author_id)');
|
||||
$this->addSql('CREATE INDEX IDX_D459EBEE8DB60186 ON chill_task.single_task_place_event (task_id)');
|
||||
$this->addSql('COMMENT ON COLUMN chill_task.single_task_place_event.datetime IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE chill_task.single_task_place_event ADD CONSTRAINT FK_D459EBEEF675F31B FOREIGN KEY (author_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE chill_task.single_task_place_event ADD CONSTRAINT FK_D459EBEE8DB60186 FOREIGN KEY (task_id) REFERENCES chill_task.single_task (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||
|
||||
$this->addSql('DROP SEQUENCE chill_task.single_task_place_event_id_seq CASCADE');
|
||||
$this->addSql('DROP TABLE chill_task.single_task_place_event');
|
||||
|
||||
}
|
||||
}
|
@ -59,6 +59,10 @@ Year: Année(s)
|
||||
start: démarrer
|
||||
close: clotûrer
|
||||
cancel: annuler
|
||||
'%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 débuté la tâche
|
||||
'%user% has created the task': %user% a introduit la tâche
|
||||
|
||||
#Flash messages
|
||||
'The task is created': 'La tâche a été créée'
|
||||
|
@ -57,7 +57,7 @@
|
||||
<a href="" class="sc-button bt-task-exchange"> </a>
|
||||
<div class="bt-dropdown-content">
|
||||
{% for transition in workflow_transitions(task) %}
|
||||
<a href="{{ path('chill_task_task_transition', { 'taskId': task.id, 'transition': transition.name|trans, 'kind': 'single-task', 'return_path': app.request.uri }) }}" class="{{ task_workflow_metadata(task, 'transition.class', transition)|e('html_attr') }}">{{ task_workflow_metadata(task, 'transition.verb', transition)|trans }}</a>
|
||||
<a href="{{ path('chill_task_task_transition', { 'taskId': task.id, 'transition': transition.name, 'kind': 'single-task', 'return_path': app.request.uri }) }}" class="{{ task_workflow_metadata(task, 'transition.class', transition)|e('html_attr') }}">{{ task_workflow_metadata(task, 'transition.verb', transition)|trans }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,33 @@
|
||||
<div>
|
||||
<h3 class="single-line">
|
||||
{{ event.datetime|localizeddate('long', 'none') }}
|
||||
<span class="task"> / {{ 'Task'|trans }}</span> /
|
||||
{% if transition is not null %}
|
||||
<span class="statement">{{ task_workflow_metadata(event.task, 'transition.sentence', transition)|trans({ '%user%': event.author.username }) }}</span>
|
||||
{% else %}
|
||||
<span class="statement">{{ '%user% has created the task'|trans({ '%user%': event.author.username }) }}</span>
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
||||
<div class="statement">
|
||||
<dl class="chill_view_data">
|
||||
<dt class="inline">{{ 'title'|trans }}</dt>
|
||||
<dd>{{ event.task.title }}</dd>
|
||||
|
||||
{% if event.task.description is not empty %}
|
||||
<dt class="inline">{{ 'Description'|trans }}</dt>
|
||||
<dd>
|
||||
<blockquote class="chill-user-quote">
|
||||
{{ event.task.description }}
|
||||
</blockquote>
|
||||
</dd>
|
||||
{% endif %}
|
||||
|
||||
{% if event.task.endDate is not empty %}
|
||||
<dt class="inline">{{ 'Task end date'|trans }}</dt>
|
||||
<dd>{{ event.task.endDate|localizeddate('medium', 'none') }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
</div>
|
131
Timeline/TaskLifeCycleEventTimelineProvider.php
Normal file
131
Timeline/TaskLifeCycleEventTimelineProvider.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\TaskBundle\Timeline;
|
||||
|
||||
use Chill\MainBundle\Timeline\TimelineProviderInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent;
|
||||
use Chill\TaskBundle\Entity\SingleTask;
|
||||
use Symfony\Component\Workflow\Registry;
|
||||
use Symfony\Component\Workflow\Workflow;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Registry
|
||||
*/
|
||||
protected $registry;
|
||||
|
||||
const TYPE = 'chill_task.transition';
|
||||
|
||||
public function __construct(EntityManagerInterface $em, Registry $registry)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->registry = $registry;
|
||||
}
|
||||
|
||||
public function fetchQuery($context, $args)
|
||||
{
|
||||
if ($context !== 'person') {
|
||||
throw new \LogicException(sprintf('%s is not able '
|
||||
. 'to render context %s', self::class, $context));
|
||||
}
|
||||
|
||||
$metadata = $this->em
|
||||
->getClassMetadata(SingleTaskPlaceEvent::class);
|
||||
$singleTaskMetadata = $this->em
|
||||
->getClassMetadata(SingleTask::class);
|
||||
|
||||
return [
|
||||
'id' => sprintf('%s.%s.%s', $metadata->getSchemaName(), $metadata->getTableName(), $metadata->getColumnName('id')),
|
||||
'type' => self::TYPE,
|
||||
'date' => $metadata->getColumnName('datetime'),
|
||||
'FROM' => sprintf('%s JOIN %s ON %s = %s',
|
||||
sprintf('%s.%s', $metadata->getSchemaName(), $metadata->getTableName()),
|
||||
sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()),
|
||||
$metadata->getAssociationMapping('task')['joinColumns'][0]['name'],
|
||||
sprintf('%s.%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName(), $singleTaskMetadata->getColumnName('id'))
|
||||
),
|
||||
'WHERE' => sprintf('%s.%s = %d',
|
||||
sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()),
|
||||
$singleTaskMetadata->getAssociationMapping('person')['joinColumns'][0]['name'],
|
||||
$args['person']->getId()
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
public function getEntities(array $ids)
|
||||
{
|
||||
$events = $this->em
|
||||
->getRepository(SingleTaskPlaceEvent::class)
|
||||
->findBy([ 'id' => $ids ])
|
||||
;
|
||||
|
||||
return \array_combine(
|
||||
\array_map(function($e) { return $e->getId(); }, $events ),
|
||||
$events
|
||||
);
|
||||
}
|
||||
|
||||
public function getEntityTemplate($entity, $context, array $args)
|
||||
{
|
||||
$workflow = $this->registry->get($entity->getTask(), $entity->getData['workflow']);
|
||||
$transition = $this->getTransitionByName($entity->getTransition(), $workflow);
|
||||
|
||||
return [
|
||||
'template' => 'ChillTaskBundle:Timeline:single_task_transition_person_context.html.twig',
|
||||
'template_data' => [
|
||||
'person' => $args['person'],
|
||||
'event' => $entity,
|
||||
'transition' => $transition
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $name
|
||||
* @param Workflow $workflow
|
||||
* @return \Symfony\Component\Workflow\Transition
|
||||
*/
|
||||
protected function getTransitionByName($name, Workflow $workflow)
|
||||
{
|
||||
foreach ($workflow->getDefinition()->getTransitions() as $transition) {
|
||||
if ($transition->getName() === $name) {
|
||||
return $transition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function supportsType($type): bool
|
||||
{
|
||||
return $type === self::TYPE;
|
||||
}
|
||||
}
|
@ -31,15 +31,18 @@ class DefaultTaskDefinition implements \Chill\TaskBundle\Workflow\TaskWorkflowDe
|
||||
const TRANSITION_METADATA = [
|
||||
'close' => [
|
||||
'verb' => 'close',
|
||||
'class' => 'sc-button bt-task-label bt-task-close'
|
||||
'class' => 'sc-button bt-task-label bt-task-close',
|
||||
'sentence' => '%user% has closed the task'
|
||||
],
|
||||
'cancel' => [
|
||||
'verb' => 'cancel',
|
||||
'class' => 'sc-button bt-task-label bt-task-cancel'
|
||||
'class' => 'sc-button bt-task-label bt-task-cancel',
|
||||
'sentence' => '%user% has canceled the task'
|
||||
],
|
||||
'start' => [
|
||||
'verb' => 'start',
|
||||
'class' => 'sc-button bt-task-label bt-task-start'
|
||||
'class' => 'sc-button bt-task-label bt-task-start',
|
||||
'sentence' => '%user% has started the task'
|
||||
]
|
||||
];
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user