improve task list

This commit is contained in:
Julien Fastré 2018-04-20 21:55:56 +02:00
parent 9dfa39ff07
commit 196fc2c38f
4 changed files with 250 additions and 91 deletions

View File

@ -9,29 +9,68 @@ use Chill\PersonBundle\Entity\Person;
use Chill\TaskBundle\Entity\SingleTask;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\TaskBundle\Repository\SingleTaskRepository;
use Symfony\Component\HttpFoundation\Response;
class TaskController extends Controller
{
/**
* @Route("/{_locale}/task/task/list/{personId}")
* @Route(
* "/{_locale}/task/task/list/{personId}",
* name="chill_task_task_list"
* )
*/
public function listAction(Request $request, Person $personId)
{
$person = $personId;
$em = $this->getDoctrine()
->getManager();
// collect parameters for filter
$params = [];
/* @var $taskRepository SingleTaskRepository */
$taskRepository = $this->get('chill_task.single_task_repository');
/* @var $paginatorFactory \Chill\MainBundle\Pagination\PaginatorFactory */
$paginatorFactory = $this->get('chill_main.paginator_factory');
/* @var $viewParams array The parameters for the view */
$viewParams['person'] = $person;
// collect parameters for filter
$params['person'] = $person;
$singleTasks = $this->get('chill_task.single_task_repository')
->findByParameters($params, $this->getUser());
if ($request->query->has('date_status')) {
$statuses = $request->query->get('date_status');
$singleStatus = count($statuses) === 1;
// check for invalid parameters
$diff = \array_diff(
$statuses,
SingleTaskRepository::DATE_STATUSES)
;
if (count($diff) > 0) {
return new Response(
'date_status not allowed: '. \implode(', ', $diff),
Response::HTTP_BAD_REQUEST
);
}
}
foreach(SingleTaskRepository::DATE_STATUSES as $type) {
if($request->query->has('date_status')
&& FALSE === \in_array($type, $statuses ?? [])) {
continue;
}
$params['date_status'] = $type;
$count = $taskRepository
->countByParameters($params, $this->getUser())
;
$paginator = $paginatorFactory->create($count);
$viewParams['single_task_'.$type.'_count'] = $count;
$viewParams['single_task_'.$type.'_paginator'] = $paginator;
$viewParams['single_task_'.$type.'_tasks'] = $taskRepository
->findByParameters($params, $this->getUser(),
$singleStatus ? $paginator->getCurrentPage()->getFirstItemNumber() : 0,
$singleStatus ? $paginator->getItemsPerPage() : 10)
;
}
return $this->render('ChillTaskBundle:Task:index.html.twig', [
'single_tasks' => $singleTasks,
'person' => $person
]);
return $this->render('ChillTaskBundle:Task:index.html.twig', $viewParams);
}
protected function getPersonParam(Request $request, EntityManagerInterface $em)

View File

@ -7,12 +7,26 @@ use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Role\Role;
use Chill\TaskBundle\Security\Authorization\TaskVoter;
use Doctrine\DBAL\Types\Type;
/**
* SingleTaskRepository
*/
class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
{
const DATE_STATUS_ENDED = 'ended';
const DATE_STATUS_WARNING = 'warning';
const DATE_STATUS_CURRENT = 'current';
const DATE_STATUS_NOT_STARTED = 'not_started';
const DATE_STATUSES = [
self::DATE_STATUS_ENDED,
self::DATE_STATUS_WARNING,
self::DATE_STATUS_CURRENT,
self::DATE_STATUS_NOT_STARTED
];
/**
*
* @var AuthorizationHelper
@ -24,6 +38,42 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
$this->authorizationHelper = $authorizationHelper;
}
/**
* Count the tasks for given parameters.
*
* The parameters are describe in @see SingleTaskRepository::filterByParameters.
*
* @see SingleTaskRepository::filterByParameters
* @param array $params
* @param User $currentUser
* @return int
*/
public function countByParameters($params, User $currentUser)
{
$qb = $this->createQueryBuilder('st')
->select('COUNT(st)');
$this->buildQuery($qb, $params, $currentUser);
return (int) $qb
->getQuery()
->getSingleScalarResult()
;
}
/**
* Find task for given parameters.
*
* Available parameters:
*
* - `person` : filter by person associated with the task ;
* - `date_status`: type of task. To choose between :
* `ended`, `warning`, `current`, `not_started`
*
* @param type $params
* @param User $currentUser
* @return type
*/
public function findByParameters($params, User $currentUser)
{
$qb = $this->createQueryBuilder('st');
@ -44,8 +94,110 @@ class SingleTaskRepository extends \Doctrine\ORM\EntityRepository
$qb->andWhere($qb->expr()->eq('st.person', ':person'));
$qb->setParameter('person', $params['person']);
}
if (\array_key_exists('date_status', $params)) {
$this->addTypeFilter($qb, $params);
}
}
protected function addTypeFilter(QueryBuilder $qb, $params)
{
$andWhere = $qb->expr()->andX();
switch ($params['date_status']) {
case self::DATE_STATUS_ENDED:
$andWhere->add($this->buildNowIsAfterEndDate($qb));
break;
case self::DATE_STATUS_WARNING:
$andWhere
->add($this->buildNowIsAfterEndDate($qb, true))
->add($this->buildNowIsAfterWarningDate($qb))
;
break;
case self::DATE_STATUS_CURRENT:
// st.endDate is NULL or (st.endDate is not null and st.endDate < now))
$andWhere
->add($this->buildNowIsAfterEndDate($qb, true))
->add($this->buildNowIsAfterWarningDate($qb, true))
->add($this->buildNowIsAfterStartDate($qb, false))
;
break;
case self::DATE_STATUS_NOT_STARTED:
$andWhere
->add($this->buildNowIsAfterEndDate($qb, true))
->add($this->buildNowIsAfterWarningDate($qb, true))
->add($this->buildNowIsAfterStartDate($qb, true))
;
}
$qb->setParameter('now', new \DateTime('today'), Type::DATE);
$qb->andWhere($andWhere);
}
private function buildNowIsAfterEndDate(QueryBuilder $qb, $negative = false)
{
if ($negative === false) {
return $qb->expr()->andX()
->add($qb->expr()->isNotNull('st.endDate'))
->add($qb->expr()->lt('st.endDate', ':now'))
;
} else {
return $qb->expr()->orX()
->add(
$qb->expr()->andX()
->add($qb->expr()->isNotNull('st.endDate'))
->add($qb->expr()->gt('st.endDate', ':now'))
)
->add($qb->expr()->isNull('st.endDate'))
;
}
}
private function buildNowIsAfterWarningDate(QueryBuilder $qb, $negative = false)
{
if ($negative === false) {
return $qb->expr()->andX()
->add($qb->expr()->lt(
$qb->expr()->diff('st.endDate', 'st.warningInterval'), ':now'
)
);
} else {
return $qb->expr()->orX()
->add(
$qb->expr()->andX()
->add($qb->expr()->isNotNull('st.endDate'))
->add($qb->expr()->isNotNull('st.warningInterval'))
->add($qb->expr()->gt(
$qb->expr()->diff('st.endDate', 'st.warningInterval'),
':now'
)
)
)
->add($qb->expr()->isNull('st.endDate'))
->add($qb->expr()->isNull('st.warningInterval'))
;
}
}
private function buildNowIsAfterStartDate(QueryBuilder $qb, $negative = false)
{
if ($negative === false) {
return $qb->expr()->orX()
->add($qb->expr()->lt('st.startDate', ':now'))
->add($qb->expr()->isNull('st.startDate'))
;
} else {
return
$qb->expr()->andX()
->add($qb->expr()->gt('st.startDate', ':now'))
->add($qb->expr()->isNotNull('st.startDate'))
;
}
}
protected function buildACLQuery(QueryBuilder $qb, User $currentUser)
{
if (NULL === $this->authorizationHelper) {

View File

@ -21,85 +21,70 @@
{% block title %}{{ 'Task list'|trans }}{% endblock %}
{% macro thead() %}
<thead>
<tr>
<th>{{ 'Title'|trans }}</th>
<th>{{ 'Task type'|trans }}</th>
<th>{{ 'Task status'|trans }}</th>
<th>{{ 'Task start date'|trans }}</th>
<th>{{ 'Task warning date'|trans }}</th>
<th>{{ 'Task end date'|trans }}</th>
</tr>
</thead>
{% endmacro %}
{% macro row(task) %}
<tr>
<td>{{ task.title }}</td>
<td>{{ task.type }}</td>
<td>todo</td>
<td>{{ task.startDate|localizeddate('medium', 'none') }}</td>
<td>{{ task.warningDate|localizeddate('medium', 'none') }}</td>
<td>{{ task.endDate|localizeddate('medium', 'none') }}</td>
</tr>
{% endmacro %}
{% macro date_status(title, tasks, count, paginator) %}
{% if tasks|length > 0 %}
<h2>{{ title|trans }}</h2>
<table>
<thead>
<tr>
<th>{{ 'Title'|trans }}</th>
<th>{{ 'Task type'|trans }}</th>
<th>{{ 'Task status'|trans }}</th>
<th>{{ 'Task start date'|trans }}</th>
<th>{{ 'Task warning date'|trans }}</th>
<th>{{ 'Task end date'|trans }}</th>
</tr>
</thead>
<tbody>
{% for task in tasks %}
<tr>
<td>{{ task.title }}</td>
<td>{{ task.type }}</td>
<td>todo</td>
<td>{% if task.startDate is not null %}{{ task.startDate|localizeddate('medium', 'none') }}{% endif %}</td>
<td>{% if task.warningDate is not null %}{{ task.warningDate|localizeddate('medium', 'none') }}{% endif %}</td>
<td>{% if task.endDate is not null %}{{ task.endDate|localizeddate('medium', 'none') }}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if tasks|length > paginator.getTotalItems %}
{{ chill_pagination(paginator) }}
{% endif %}
{% endif %}
{% endmacro %}
{% import _self as helper %}
{# filter tasks #}
{% set ended_tasks = [] %}
{% for task in single_tasks if (task.endDate|date("U") > 'now'|date("U")) %}
{% set ended_tasks = ended_tasks|merge([ task ]) %}
{% endfor %}
{% set warning_tasks = [] %}
{% for task in single_tasks if (task.warningDate|date('U') > 'now'|date("U") and task not in ended_tasks) %}
{% set warning_tasks = warning_tasks|merge([ task ]) %}
{% endfor %}
{% set rest_tasks = [] %}
{% for task in single_tasks if (task not in ended_tasks and task not in warning_tasks) %}
{% set rest_tasks = rest_tasks|merge([ task ]) %}
{% endfor %}
{% block personcontent %}
<h1>{{ 'Task list'|trans }}</h1>
{% if ended_tasks|length > 0 %}
<h2>{{ 'Task with expired deadline'|trans }}</h2>
<table>
{{ helper.thead() }}
<tbody>
{% for task in ended_tasks %}
{{ helper.row(task) }}
{% endfor %}
</tbody>
</table>
{% if single_task_ended_tasks is defined %}
{{ helper.date_status('Tasks with expired deadline', single_task_ended_tasks, single_task_ended_count, single_task_ended_paginator) }}
{% endif %}
{% if warning_tasks|length > 0 %}
<h2>{{ 'Task with warning'|trans }}</h2>
<table>
{{ helper.thead() }}
<tbody>
{% for task in warning_tasks %}
{{ helper.row(task) }}
{% endfor %}
</tbody>
</table>
{% if single_task_warning_tasks is defined %}
{{ helper.date_status('Tasks with warning deadline reached', single_task_warning_tasks, single_task_warning_count, single_task_warning_paginator) }}
{% endif %}
{% if rest_tasks|length > 0 %}
<h2>{{ 'Task '|trans }}</h2>
<table>
{{ helper.thead() }}
<tbody>
{% for task in rest_tasks %}
{{ helper.row(task) }}
{% endfor %}
</tbody>
</table>
{% if single_task_current_tasks is defined %}
{{ helper.date_status('Current tasks', single_task_current_tasks, single_task_current_count, single_task_current_paginator) }}
{% endif %}
{% 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) }}
{% endif %}

View File

@ -1,17 +0,0 @@
<?php
namespace Chill\TaskBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class DefaultControllerTest extends WebTestCase
{
public function testIndex()
{
$client = static::createClient();
$crawler = $client->request('GET', '/');
$this->assertContains('Hello World', $client->getResponse()->getContent());
}
}