add closed tasks

- the entity has a new column / property "closed" (boolean)
- An event listener in created during container compilation, which listen on tasks
  status changed
- The taskworkflow manager and task workflow definition indicate if the tasks is closed ;
- Add list for closed tasks in controller, and change parameter 'date_status' to 'status';
- and change query to allow to filter on closed tasks
This commit is contained in:
Julien Fastré 2018-04-26 12:11:06 +02:00
parent d251074430
commit eadaeaef35
9 changed files with 131 additions and 31 deletions

View File

@ -298,39 +298,42 @@ class SingleTaskController extends Controller
$viewParams['person'] = $person; $viewParams['person'] = $person;
// collect parameters for filter // collect parameters for filter
$params['person'] = $person; $params['person'] = $person;
$statuses = $request->query->get('date_status', []); $possibleStatuses = \array_merge(SingleTaskRepository::DATE_STATUSES, [ 'closed' ]);
$statuses = $request->query->get('status', $possibleStatuses);
if ($statuses) { // check for invalid statuses
// check for invalid parameters $diff = \array_diff($statuses, $possibleStatuses);
$diff = \array_diff( if (count($diff) > 0) {
$statuses, return new Response(
SingleTaskRepository::DATE_STATUSES) 'date_status not allowed: '. \implode(', ', $diff),
; Response::HTTP_BAD_REQUEST
);
if (count($diff) > 0) {
return new Response(
'date_status not allowed: '. \implode(', ', $diff),
Response::HTTP_BAD_REQUEST
);
}
} }
$viewParams['isSingleStatus'] = $singleStatus = count($statuses) === 1; $viewParams['isSingleStatus'] = $singleStatus = count($statuses) === 1;
foreach(SingleTaskRepository::DATE_STATUSES as $type) { foreach($statuses as $status) {
if($request->query->has('date_status') if($request->query->has('status')
&& FALSE === \in_array($type, $statuses ?? [])) { && FALSE === \in_array($status, $statuses)) {
continue; continue;
} }
$params['date_status'] = $type; // different query if regarding to date or 'closed'
if (in_array($status, SingleTaskRepository::DATE_STATUSES)) {
$params['date_status'] = $status;
$params['is_closed'] = false;
} else {
$params['date_status'] = null;
$params['is_closed'] = true;
}
$count = $taskRepository $count = $taskRepository
->countByParameters($params, $this->getUser()) ->countByParameters($params, $this->getUser())
; ;
$paginator = $paginatorFactory->create($count); $paginator = $paginatorFactory->create($count);
$viewParams['single_task_'.$type.'_count'] = $count; $viewParams['single_task_'.$status.'_count'] = $count;
$viewParams['single_task_'.$type.'_paginator'] = $paginator; $viewParams['single_task_'.$status.'_paginator'] = $paginator;
$viewParams['single_task_'.$type.'_tasks'] = $taskRepository $viewParams['single_task_'.$status.'_tasks'] = $taskRepository
->findByParameters($params, $this->getUser(), ->findByParameters($params, $this->getUser(),
$singleStatus ? $paginator->getCurrentPage()->getFirstItemNumber() : 0, $singleStatus ? $paginator->getCurrentPage()->getFirstItemNumber() : 0,
$singleStatus ? $paginator->getItemsPerPage() : 10) $singleStatus ? $paginator->getItemsPerPage() : 10)

View File

@ -71,10 +71,10 @@ class TaskController extends Controller
$em->flush(); $em->flush();
$this->addFlash('success', 'The transition is sucessfully applyed'); $this->addFlash('success', 'The transition is sucessfully appliyed');
} else { } else {
$this->addFlash('error', 'The transition could not be applyed'); $this->addFlash('error', 'The transition could not be appliyed');
} }
return $this->redirect($request->query->get('return_path', $defaultReturnPath)); return $this->redirect($request->query->get('return_path', $defaultReturnPath));

View File

@ -39,8 +39,17 @@ class TaskWorkflowDefinitionCompilerPass implements CompilerPassInterface
$workflowManagerDefinition = $container->getDefinition(TaskWorkflowManager::class); $workflowManagerDefinition = $container->getDefinition(TaskWorkflowManager::class);
foreach ($container->findTaggedServiceIds('chill_task.workflow_definition') as $id => $tags) { foreach ($container->findTaggedServiceIds('chill_task.workflow_definition') as $id => $tags) {
// registering the definition to manager
$workflowManagerDefinition $workflowManagerDefinition
->addMethodCall('addDefinition', [new Reference($id)]); ->addMethodCall('addDefinition', [new Reference($id)]);
// adding a listener for currentStatus changes
$definition = $container->getDefinition($id);
$workflowManagerDefinition
->addTag('kernel.event_listener', [
'event' => sprintf('workflow.%s.entered', $definition->getClass()::getAssociatedWorkflowName()),
'method' => 'onTaskStateEntered',
'priority' => -255
]);
} }
} }
} }

View File

@ -80,6 +80,12 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface
* @Assert\NotNull() * @Assert\NotNull()
*/ */
private $circle; private $circle;
/**
* @var boolean
* @ORM\Column(name="closed", type="boolean", options={ "default"=false })
*/
private $closed = false;
/** /**
* Set type * Set type
@ -229,6 +235,21 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface
return $this->getCircle(); return $this->getCircle();
} }
/**
* @return bool
*/
public function isClosed(): bool
{
return $this->closed;
}
/**
*
* @param bool $closed
*/
public function setClosed(bool $closed)
{
$this->closed = $closed;
}
} }

View File

@ -69,6 +69,8 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
* - `person` : filter by person associated with the task ; * - `person` : filter by person associated with the task ;
* - `date_status`: type of task. To choose between : * - `date_status`: type of task. To choose between :
* `ended`, `warning`, `current`, `not_started` * `ended`, `warning`, `current`, `not_started`
* - `is_closed`: boolean. Indicate if the tasks must be closed (true) or
* opened
* *
* @param type $params * @param type $params
* @param User $currentUser * @param User $currentUser
@ -90,14 +92,18 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
{ {
$this->buildACLQuery($qb, $currentUser); $this->buildACLQuery($qb, $currentUser);
if (\array_key_exists('person', $params)) { if (\array_key_exists('person', $params) and !empty($params['person'])) {
$qb->andWhere($qb->expr()->eq('st.person', ':person')); $qb->andWhere($qb->expr()->eq('st.person', ':person'));
$qb->setParameter('person', $params['person']); $qb->setParameter('person', $params['person']);
} }
if (\array_key_exists('date_status', $params)) { if (\array_key_exists('date_status', $params) and !empty($params['date_status'])) {
$this->addTypeFilter($qb, $params); $this->addTypeFilter($qb, $params);
} }
if (\array_key_exists('is_closed', $params)) {
$qb->andWhere($this->buildIsClosed($qb, !$params['is_closed']));
}
} }
protected function addTypeFilter(QueryBuilder $qb, $params) protected function addTypeFilter(QueryBuilder $qb, $params)
@ -106,7 +112,9 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
switch ($params['date_status']) { switch ($params['date_status']) {
case self::DATE_STATUS_ENDED: case self::DATE_STATUS_ENDED:
$andWhere->add($this->buildNowIsAfterEndDate($qb)); $andWhere
->add($this->buildNowIsAfterEndDate($qb))
;
break; break;
case self::DATE_STATUS_WARNING: case self::DATE_STATUS_WARNING:
@ -155,7 +163,7 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
} }
} }
private function buildNowIsAfterWarningDate(QueryBuilder $qb, $negative = false) private function buildNowIsAfterWarningDate(QueryBuilder $qb, bool $negative = false)
{ {
if ($negative === false) { if ($negative === false) {
return $qb->expr()->andX() return $qb->expr()->andX()
@ -181,7 +189,7 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
} }
} }
private function buildNowIsAfterStartDate(QueryBuilder $qb, $negative = false) private function buildNowIsAfterStartDate(QueryBuilder $qb, bool $negative = false)
{ {
if ($negative === false) { if ($negative === false) {
return $qb->expr()->orX() return $qb->expr()->orX()
@ -197,6 +205,15 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
} }
} }
private function buildIsClosed(QueryBuilder $qb, bool $negative = false)
{
if ($negative === false) {
return $qb->expr()->eq('st.closed', "'TRUE'");
} else {
return $qb->expr()->eq('st.closed', "'FALSE'");
}
}
protected function buildACLQuery(QueryBuilder $qb, User $currentUser) protected function buildACLQuery(QueryBuilder $qb, User $currentUser)
{ {

View File

@ -0,0 +1,28 @@
<?php declare(strict_types = 1);
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Add a column 'closed' on tasks
*/
class Version20180426093011 extends AbstractMigration
{
public function up(Schema $schema)
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE chill_task.single_task ADD closed BOOLEAN DEFAULT \'false\' NOT NULL');
$this->addSql('ALTER TABLE chill_task.recurring_task ADD closed BOOLEAN DEFAULT \'false\' NOT NULL');
}
public function down(Schema $schema)
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE chill_task.recurring_task DROP closed');
$this->addSql('ALTER TABLE chill_task.single_task DROP closed');
}
}

View File

@ -100,7 +100,7 @@
{% else %} {% else %}
<ul class="record_actions"> <ul class="record_actions">
<li> <li>
<a href="{{ path('chill_task_task_list_by_person', {'personId': person.id, 'date_status' : [ status ] }) }}" class="sc-button bt-cancel"> <a href="{{ path('chill_task_task_list_by_person', {'personId': person.id, 'status' : [ status ] }) }}" class="sc-button bt-cancel">
{{ 'See more' | trans }} {{ 'See more' | trans }}
</a> </a>
</li> </li>
@ -132,6 +132,10 @@
{% if single_task_not_started_tasks is defined %} {% if single_task_not_started_tasks is defined %}
{{ helper.date_status('Tasks not started', single_task_not_started_tasks, single_task_not_started_count, single_task_not_started_paginator, 'not_started', isSingleStatus, person) }} {{ helper.date_status('Tasks not started', single_task_not_started_tasks, single_task_not_started_count, single_task_not_started_paginator, 'not_started', isSingleStatus, person) }}
{% endif %} {% endif %}
{% if single_task_closed_tasks is defined %}
{{ helper.date_status('Closed', single_task_closed_tasks, single_task_closed_count, single_task_closed_paginator, 'closed', isSingleStatus, person) }}
{% endif %}
{% if isSingleStatus == false %} {% if isSingleStatus == false %}
<ul class="record_actions"> <ul class="record_actions">

View File

@ -53,7 +53,7 @@ class DefaultTaskDefinition implements \Chill\TaskBundle\Workflow\TaskWorkflowDe
&& $task->getType() === 'task_default'; && $task->getType() === 'task_default';
} }
public function getAssociatedWorkflowName() public static function getAssociatedWorkflowName()
{ {
return 'task_default'; return 'task_default';
} }
@ -89,4 +89,10 @@ class DefaultTaskDefinition implements \Chill\TaskBundle\Workflow\TaskWorkflowDe
return self::TRANSITION_METADATA[$transition->getName()][$key]; return self::TRANSITION_METADATA[$transition->getName()][$key];
} }
public function isClosed(AbstractTask $task)
{
return \array_key_exists('closed', $task->getCurrentStates())
|| \array_key_exists('canceled', $task->getCurrentStates());
}
} }

View File

@ -20,6 +20,7 @@ namespace Chill\TaskBundle\Workflow;
use Chill\TaskBundle\Entity\AbstractTask; use Chill\TaskBundle\Entity\AbstractTask;
use Symfony\Component\Workflow\SupportStrategy\SupportStrategyInterface; use Symfony\Component\Workflow\SupportStrategy\SupportStrategyInterface;
use Symfony\Component\Workflow\Workflow; use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Workflow\Event\Event;
/** /**
* *
@ -80,4 +81,15 @@ class TaskWorkflowManager implements SupportStrategyInterface
return $this->getTaskWorkflowDefinition($task) return $this->getTaskWorkflowDefinition($task)
->getWorkflowMetadata($key, $metadataSubject); ->getWorkflowMetadata($key, $metadataSubject);
} }
public function onTaskStateEntered(Event $e)
{
$task = $e->getSubject();
$definition = $this->getTaskWorkflowDefinition($task);
$task->setClosed($definition->isClosed($task));
dump($task);
}
} }