diff --git a/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition_person_context.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition.html.twig
similarity index 68%
rename from src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition_person_context.html.twig
rename to src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition.html.twig
index 234bbc134..fe65a1f1f 100644
--- a/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition_person_context.html.twig
+++ b/src/Bundle/ChillTaskBundle/Resources/views/Timeline/single_task_transition.html.twig
@@ -7,6 +7,9 @@
{% else %}
{{ '%user% has created the task'|trans({ '%user%': event.author.username }) }}
{% endif %}
+ {% if 'person' != context %}
+ / {{ task.person|chill_entity_render_box({'addLink': true}) }}
+ {% endif %}
@@ -29,5 +32,17 @@
{% endif %}
+
diff --git a/src/Bundle/ChillTaskBundle/Timeline/SingleTaskTaskLifeCycleEventTimelineProvider.php b/src/Bundle/ChillTaskBundle/Timeline/SingleTaskTaskLifeCycleEventTimelineProvider.php
index 6e40cb4a3..57a3832af 100644
--- a/src/Bundle/ChillTaskBundle/Timeline/SingleTaskTaskLifeCycleEventTimelineProvider.php
+++ b/src/Bundle/ChillTaskBundle/Timeline/SingleTaskTaskLifeCycleEventTimelineProvider.php
@@ -18,6 +18,7 @@
namespace Chill\TaskBundle\Timeline;
use Chill\MainBundle\Timeline\TimelineProviderInterface;
+use Chill\MainBundle\Timeline\TimelineSingleQuery;
use Doctrine\ORM\EntityManagerInterface;
use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent;
use Chill\TaskBundle\Entity\SingleTask;
@@ -25,9 +26,8 @@ use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Workflow;
/**
+ * Provide timeline elements related to tasks, in tasks context
*
- *
- * @author Julien Fastré
*/
class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderInterface
{
@@ -63,7 +63,7 @@ class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderIn
$singleTaskMetadata = $this->em
->getClassMetadata(SingleTask::class);
- return [
+ return TimelineSingleQuery::fromArray([
'id' => sprintf('%s.%s.%s', $metadata->getSchemaName(), $metadata->getTableName(), $metadata->getColumnName('id')),
'type' => self::TYPE,
'date' => $metadata->getColumnName('datetime'),
@@ -77,8 +77,9 @@ class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderIn
sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()),
$singleTaskMetadata->getColumnName('id'),
$args['task']->getId()
- )
- ];
+ ),
+ 'parameters' => [],
+ ]);
}
diff --git a/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php b/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php
index db099a3e1..fe5a8f78d 100644
--- a/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php
+++ b/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php
@@ -21,43 +21,30 @@ use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Doctrine\ORM\EntityManagerInterface;
use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent;
use Chill\TaskBundle\Entity\SingleTask;
+use Chill\PersonBundle\Entity\Person;
+use Symfony\Component\Security\Core\Security;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Workflow;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Symfony\Component\Security\Core\Role\Role;
+use Chill\MainBundle\Timeline\TimelineSingleQuery;
/**
- *
+ * Provide element for timeline for 'person' and 'center' context
*
- * @author Julien Fastré
*/
class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface
{
- /**
- *
- * @var EntityManagerInterface
- */
- protected $em;
+ protected EntityManagerInterface $em;
- /**
- *
- * @var Registry
- */
- protected $registry;
+ protected Registry $registry;
- /**
- *
- * @var AuthorizationHelper
- */
- protected $authorizationHelper;
+ protected AuthorizationHelper $authorizationHelper;
+
+ protected Security $security;
- /**
- *
- * @var TokenStorageInterface
- */
- protected $tokenStorage;
const TYPE = 'chill_task.transition';
@@ -65,60 +52,172 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface
EntityManagerInterface $em,
Registry $registry,
AuthorizationHelper $authorizationHelper,
- TokenStorageInterface $tokenStorage
+ Security $security
) {
$this->em = $em;
$this->registry = $registry;
$this->authorizationHelper = $authorizationHelper;
- $this->tokenStorage = $tokenStorage;
+ $this->security = $security;
}
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);
- $user = $this->tokenStorage->getToken()->getUser();
- $circles = $this->authorizationHelper->getReachableCircles(
- $user, new Role(ActivityVoter::SEE_DETAILS), $args['person']->getCenter());
-
- if (count($circles) > 0) {
- $circlesId = \array_map(function($c) { return $c->getId(); }, $circles);
- $circleRestriction = sprintf('%s.%s.%s IN (%s)',
- $singleTaskMetadata->getSchemaName(), // chill_task schema
- $singleTaskMetadata->getTableName(), // single_task table name
- $singleTaskMetadata->getAssociationMapping('circle')['joinColumns'][0]['name'],
- \implode(', ', $circlesId)
- );
- } else {
- $circleRestriction = 'FALSE = TRUE';
+ switch ($context) {
+ case 'person':
+ [ $where, $parameters ] = $this->getWhereClauseForPerson($args['person']);
+ break;
+ case 'center':
+ [ $where, $parameters ] = $this->getWhereClauseForCenter($args['centers']);
+ break;
+ default:
+ throw new \UnexpectedValueException("context {$context} is not supported");
}
-
-
- return [
+
+ return TimelineSingleQuery::fromArray([
'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 and %s',
- sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()),
- $singleTaskMetadata->getAssociationMapping('person')['joinColumns'][0]['name'],
- $args['person']->getId(),
- $circleRestriction
- )
+ 'FROM' => $this->getFromClause($context),
+ 'WHERE' => $where,
+ 'parameters' => $parameters
+ ]);
+ }
+
+ private function getWhereClauseForCenter(array $centers): array
+ {
+ $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class);
+ $singleTask = $this->em->getClassMetadata(SingleTask::class);
+ $person = $this->em->getClassMetadata(Person::class);
+ $personFkCenter = $person->getAssociationMapping('center')['joinColumns'][0]['name'];
+ $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name'];
+
+ // the parameters
+ $parameters = [];
+
+ // the clause that we will repeat for each center, joined by 'OR'
+ $clause = "{person}.{center_id} = ? AND {task}.{circle} IN ({circle_ids})";
+
+ // array to gather clauses
+ $clauses = [];
+
+ // loop over centers
+ foreach ($this->authorizationHelper->getReachableCenters(
+ $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS)) as $center) {
+
+ if (FALSE === \in_array($center, $centers)) {
+ continue;
+ }
+
+ // fill center parameter
+ $parameters[] = $center->getId();
+
+ // we loop over circles
+ $circles = $this->authorizationHelper->getReachableCircles(
+ $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS), $center);
+ $circleIds = [];
+
+ foreach ($circles as $circle) {
+ $parameters[] = $circleIds[] = $circle->getId();
+ }
+
+ $clauses[] = \strtr(
+ $clause,
+ [
+ '{person}' => $person->getTableName(),
+ '{center_id}' => $personFkCenter,
+ '{task}' => $singleTask->getSchemaName().".".$singleTask->getTableName(),
+ '{circle}' => $taskFkCircle,
+ '{circle_ids}' => \implode(', ', \array_fill(0, count($circleIds), '?'))
+ ]
+ );
+ }
+
+ if (0 === \count($clauses)) {
+ return [ 'FALSE = TRUE' , [] ];
+ }
+
+ return [
+ \implode(' OR ', $clauses),
+ $parameters
];
+ }
+
+ private function getWhereClauseForPerson(Person $personArg): array
+ {
+ $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class);
+ $singleTask = $this->em->getClassMetadata(SingleTask::class);
+ $person = $this->em->getClassMetadata(Person::class);
+ $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name'];
+ $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name'];
+ $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName'];
+ $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name'];
+
+
+ // the parameters
+ $parameters = [];
+
+ // the clause that we will fill
+ $clause = "{person}.{person_id} = ? AND {task}.{circle} IN ({circle_ids})";
+
+ // person is the first parameter
+ $parameters[] = $personArg->getId();
+
+ // we loop over circles
+ $circles = $this->authorizationHelper->getReachableCircles(
+ $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS), $personArg->getCenter());
+
+ if (0 === count($circles)) {
+ // go fast to block access to every tasks
+ return [ "FALSE = TRUE", [] ];
+ }
+
+ foreach ($circles as $circle) {
+ $parameters[] = $circleIds[] = $circle->getId();
+ }
+
+ return [
+ \strtr(
+ $clause,
+ [
+ '{person}' => $person->getTableName(),
+ '{person_id}' => $person->getColumnName('id'),
+ '{task}' => $singleTask->getSchemaName().".".$singleTask->getTableName(),
+ '{circle}' => $taskFkCircle,
+ '{circle_ids}' => \implode(', ', \array_fill(0, count($circleIds), '?'))
+ ]
+ ),
+ $parameters
+ ];
+ }
+
+ private function getFromClause(string $context)
+ {
+ $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class);
+ $singleTask = $this->em->getClassMetadata(SingleTask::class);
+ $person = $this->em->getClassMetadata(Person::class);
+ $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name'];
+ $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name'];
+ $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName'];
+
+ $from = "{single_task_event} ".
+ "JOIN {single_task} ON {single_task}.{task_pk} = {single_task_event}.{event_fk_task} ".
+ "JOIN {person} ON {single_task}.{task_person_fk} = {person}.{person_pk}";
+
+ return \strtr(
+ $from,
+ [
+ '{single_task}' => sprintf('%s.%s', $singleTask->getSchemaName(), $singleTask->getTableName()),
+ '{single_task_event}' => sprintf('%s.%s', $taskEvent->getSchemaName(), $taskEvent->getTableName()),
+ '{task_pk}' => $singleTask->getColumnName('id'),
+ '{event_fk_task}' => $eventFkTask,
+ '{person}' => $person->getTableName(),
+ '{task_person_fk}' => $taskFkPerson,
+ '{person_pk}' => $personPk
+ ]
+ );
}
public function getEntities(array $ids)
@@ -147,10 +246,11 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface
$transition = $this->getTransitionByName($entity->getTransition(), $workflow);
return [
- 'template' => 'ChillTaskBundle:Timeline:single_task_transition_person_context.html.twig',
+ 'template' => 'ChillTaskBundle:Timeline:single_task_transition.html.twig',
'template_data' => [
- 'person' => $args['person'],
+ 'context' => $context,
'event' => $entity,
+ 'task' => $entity->getTask(),
'transition' => $transition
]
];
diff --git a/src/Bundle/ChillTaskBundle/config/services/timeline.yaml b/src/Bundle/ChillTaskBundle/config/services/timeline.yaml
index 0962866be..04ef218b5 100644
--- a/src/Bundle/ChillTaskBundle/config/services/timeline.yaml
+++ b/src/Bundle/ChillTaskBundle/config/services/timeline.yaml
@@ -4,14 +4,15 @@ services:
$em: '@Doctrine\ORM\EntityManagerInterface'
$registry: '@Symfony\Component\Workflow\Registry'
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
- $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
+ $security: '@Symfony\Component\Security\Core\Security'
public: true
- # tags:
- # - { name: 'chill.timeline', context: 'person' }
+ tags:
+ - { name: 'chill.timeline', context: 'person' }
+ - { name: 'chill.timeline', context: 'center' }
Chill\TaskBundle\Timeline\SingleTaskTaskLifeCycleEventTimelineProvider:
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
$registry: '@Symfony\Component\Workflow\Registry'
- # tags:
- #- { name: 'chill.timeline', context: 'task' }
+ tags:
+ - { name: 'chill.timeline', context: 'task' }