diff --git a/src/Bundle/ChillEventBundle/config/services/timeline.yaml b/src/Bundle/ChillEventBundle/config/services/timeline.yaml
index 7a8eb366d..82f758d15 100644
--- a/src/Bundle/ChillEventBundle/config/services/timeline.yaml
+++ b/src/Bundle/ChillEventBundle/config/services/timeline.yaml
@@ -6,5 +6,5 @@ services:
- '@chill.main.security.authorization.helper'
- '@security.token_storage'
public: true
- tags:
- - { name: chill.timeline, context: 'person' }
+ # tags:
+ # - { name: chill.timeline, context: 'person' }
diff --git a/src/Bundle/ChillReportBundle/Resources/views/Timeline/report_person_context.html.twig b/src/Bundle/ChillReportBundle/Resources/views/Timeline/report.html.twig
similarity index 71%
rename from src/Bundle/ChillReportBundle/Resources/views/Timeline/report_person_context.html.twig
rename to src/Bundle/ChillReportBundle/Resources/views/Timeline/report.html.twig
index e9bcba85b..7929fed9e 100644
--- a/src/Bundle/ChillReportBundle/Resources/views/Timeline/report_person_context.html.twig
+++ b/src/Bundle/ChillReportBundle/Resources/views/Timeline/report.html.twig
@@ -1,9 +1,9 @@
-
{{ report.date|format_date('long') }} / {{ 'Report'|trans }}
+
{{ report.date|format_date('long') }} / {{ 'Report'|trans }}{% if 'person' != context %} / {{ report.person|chill_entity_render_box }}{% endif %}
{{ '%user% has filled a %report_label% report'|trans(
{
- '%user%' : user,
+ '%user%' : report.user,
'%report_label%': report.CFGroup.name|localize_translatable_string,
'%date%' : report.date|format_date('long') }
) }}
@@ -25,13 +25,13 @@
-
-
+
{{ 'View the report'|trans }}
{% if is_granted('CHILL_REPORT_UPDATE', report) %}
-
-
+
{{ 'Update the report'|trans }}
diff --git a/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php b/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php
index c6c13173a..49e237d87 100644
--- a/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php
+++ b/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php
@@ -30,71 +30,34 @@ use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Entity\Scope;
use Chill\CustomFieldsBundle\Service\CustomFieldsHelper;
use Chill\ReportBundle\Entity\Report;
+use Symfony\Component\Security\Core\Security;
+use Chill\MainBundle\Timeline\TimelineSingleQuery;
/**
* Provide report for inclusion in timeline
- *
- * @author Julien Fastré
- * @author Champs Libres
*/
class TimelineReportProvider implements TimelineProviderInterface
{
- /**
- *
- * @var EntityManager
- */
- protected $em;
+ protected EntityManager $em;
- /**
- *
- * @var AuthorizationHelper
- */
- protected $helper;
+ protected AuthorizationHelper $helper;
- /**
- *
- * @var \Chill\MainBundle\Entity\User
- */
- protected $user;
+ protected CustomFieldsHelper $customFieldsHelper;
- /**
- *
- * @var CustomFieldsHelper
- */
- protected $customFieldsHelper;
-
- /**
- * @var
- */
protected $showEmptyValues;
- /**
- * TimelineReportProvider constructor.
- *
- * @param EntityManager $em
- * @param AuthorizationHelper $helper
- * @param TokenStorageInterface $storage
- * @param CustomFieldsHelper $customFieldsHelper
- * @param $showEmptyValues
- */
public function __construct(
EntityManager $em,
AuthorizationHelper $helper,
- TokenStorageInterface $storage,
+ Security $security,
CustomFieldsHelper $customFieldsHelper,
$showEmptyValues
)
{
$this->em = $em;
$this->helper = $helper;
-
- if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User)
- {
- throw new \RuntimeException('A user should be authenticated !');
- }
-
- $this->user = $storage->getToken()->getUser();
+ $this->security = $security;
$this->customFieldsHelper = $customFieldsHelper;
$this->showEmptyValues = $showEmptyValues;
}
@@ -107,70 +70,162 @@ class TimelineReportProvider implements TimelineProviderInterface
{
$this->checkContext($context);
- $metadataReport = $this->em->getClassMetadata('ChillReportBundle:Report');
- $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
-
- return array(
- 'id' => $metadataReport->getTableName()
- .'.'.$metadataReport->getColumnName('id'),
+ $report = $this->em->getClassMetadata(Report::class);
+ [$where, $parameters] = $this->getWhereClause($context, $args);
+
+ return TimelineSingleQuery::fromArray([
+ 'id' => $report->getTableName()
+ .'.'.$report->getColumnName('id'),
'type' => 'report',
- 'date' => $metadataReport->getTableName()
- .'.'.$metadataReport->getColumnName('date'),
- 'FROM' => $this->getFromClause($metadataReport, $metadataPerson),
- 'WHERE' => $this->getWhereClause($metadataReport, $metadataPerson,
- $args['person'])
- );
+ 'date' => $report->getTableName()
+ .'.'.$report->getColumnName('date'),
+ 'FROM' => $this->getFromClause($context),
+ 'WHERE' => $where,
+ 'parameters' => $parameters
+ ]);
}
- private function getWhereClause(ClassMetadata $metadataReport,
- ClassMetadata $metadataPerson, Person $person)
+ private function getWhereClause(string $context, array $args): array
{
- $role = new Role('CHILL_REPORT_SEE');
- $reachableCenters = $this->helper->getReachableCenters($this->user,
- $role);
- $associationMapping = $metadataReport->getAssociationMapping('person');
-
- // we start with reports having the person_id linked to person
- // (currently only context "person" is supported)
- $whereClause = sprintf('%s = %d',
- $associationMapping['joinColumns'][0]['name'],
- $person->getId());
-
- // we add acl (reachable center and scopes)
- $centerAndScopeLines = array();
- foreach ($reachableCenters as $center) {
- $reachablesScopesId = array_map(
- function(Scope $scope) { return $scope->getId(); },
- $this->helper->getReachableScopes($this->user, $role,
- $person->getCenter())
- );
-
- $centerAndScopeLines[] = sprintf('(%s = %d AND %s IN (%s))',
- $metadataPerson->getTableName().'.'.
- $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'],
- $center->getId(),
- $metadataReport->getTableName().'.'.
- $metadataReport->getAssociationMapping('scope')['joinColumns'][0]['name'],
- implode(',', $reachablesScopesId));
-
+ switch ($context) {
+ case 'person':
+ return $this->getWhereClauseForPerson($context, $args);
+ case 'center':
+ return $this->getWhereClauseForCenter($context, $args);
+ default:
+ throw new \UnexpectedValueException("This context $context is not implemented");
}
- $whereClause .= ' AND ('.implode(' OR ', $centerAndScopeLines).')';
-
- return $whereClause;
+ }
+
+ private function getWhereClauseForCenter(string $context, array $args): array
+ {
+ $report = $this->em->getClassMetadata(Report::class);
+ $person = $this->em->getClassMetadata(Person::class);
+ $role = new Role('CHILL_REPORT_SEE');
+ $reachableCenters = $this->helper->getReachableCenters($this->security->getUser(),
+ $role);
+ $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name'];
+ $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name'];
+ $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name'];
+ // parameters for the query, will be filled later
+ $parameters = [];
+
+ // the clause, that will be joined with an "OR"
+ $centerScopesClause = "({person}.{center_id} = ? ".
+ "AND {report}.{scopes_id} IN ({scopes_ids}))";
+ // container for formatted clauses
+ $formattedClauses = [];
+
+ $askedCenters = $args['centers'];
+ foreach ($reachableCenters as $center) {
+ if (FALSE === \in_array($center, $askedCenters)) {
+ continue;
+ }
+
+ // add the center id to the parameters
+ $parameters[] = $center->getId();
+ // loop over scopes
+ $scopeIds = [];
+ foreach ($this->helper->getReachableScopes($this->security->getUser(),
+ $role, $center) as $scope) {
+ if (\in_array($scope->getId(), $scopeIds)) {
+ continue;
+ }
+ $scopeIds[] = $scope->getId();
+ }
+
+ $formattedClauses[] = \strtr($centerScopesClause, [
+ '{scopes_ids}' => \implode(', ', \array_fill(0, \count($scopeIds), '?'))
+ ]);
+ // append $scopeIds to parameters
+ $parameters = \array_merge($parameters, $scopeIds);
+ }
+
+ if (0 === count($formattedClauses)) {
+ return [ 'FALSE = TRUE', [] ];
+ }
+
+ return [
+ \strtr(
+ \implode(' OR ', $formattedClauses),
+ [
+ '{person}' => $person->getTableName(),
+ '{center_id}' => $personCenterId,
+ '{report}' => $report->getTableName(),
+ '{scopes_id}' => $reportScopeId,
+ ]
+ ),
+ $parameters
+ ];
+ }
+
+ private function getWhereClauseForPerson(string $context, array $args): array
+ {
+ $report = $this->em->getClassMetadata(Report::class);
+ $person = $this->em->getClassMetadata(Person::class);
+ $role = new Role('CHILL_REPORT_SEE');
+ $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name'];
+ $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name'];
+ $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name'];
+ // parameters for the query, will be filled later
+ $parameters = [ $args['person']->getId() ];
+
+ // this is the final clause that we are going to fill
+ $clause = "{report}.{person_id} = ? AND {report}.{scopes_id} IN ({scopes_ids})";
+ // iterate over reachable scopes
+ $scopes = $this->helper->getReachableScopes($this->security->getUser(), $role,
+ $args['person']->getCenter());
+
+ foreach ($scopes as $scope) {
+ if (\in_array($scope->getId(), $parameters)) {
+ continue;
+ }
+
+ $parameters[] = $scope->getId();
+ }
+
+ if (1 === count($parameters)) {
+ // nothing change, we simplify the clause
+ $clause = "{report}.{person_id} = ? AND FALSE = TRUE";
+ }
+
+ return [
+ \strtr(
+ $clause,
+ [
+ '{report}' => $report->getTableName(),
+ '{person_id}' => $reportPersonId,
+ '{scopes_id}' => $reportScopeId,
+ '{scopes_ids}' => \implode(', ',
+ \array_fill(0, \count($parameters)-1, '?'))
+ ]
+ ),
+ $parameters
+ ];
}
- private function getFromClause(ClassMetadata $metadataReport,
- ClassMetadata $metadataPerson)
+ private function getFromClause(string $context): string
{
- $associationMapping = $metadataReport->getAssociationMapping('person');
-
- return $metadataReport->getTableName().' JOIN '
- .$metadataPerson->getTableName().' ON '
- .$metadataPerson->getTableName().'.'.
- $associationMapping['joinColumns'][0]['referencedColumnName']
- .' = '
- .$associationMapping['joinColumns'][0]['name']
+ $report = $this->em->getClassMetadata(Report::class);
+ $person = $this->em->getClassMetadata(Person::class);
+ $reportPersonId = $report
+ ->getAssociationMapping('person')['joinColumns'][0]['name']
;
+ $personId = $report
+ ->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']
+ ;
+
+ $clause = "{report} ".
+ "JOIN {person} ON {report}.{person_id} = {person}.{id_person} ";
+
+ return \strtr($clause,
+ [
+ '{report}' => $report->getTableName(),
+ '{person}' => $person->getTableName(),
+ '{person_id}' => $reportPersonId,
+ '{id_person}' => $personId
+ ]
+ );
}
/**
@@ -199,12 +254,11 @@ class TimelineReportProvider implements TimelineProviderInterface
$this->checkContext($context);
return array(
- 'template' => 'ChillReportBundle:Timeline:report_person_context.html.twig',
+ 'template' => 'ChillReportBundle:Timeline:report.html.twig',
'template_data' => array(
- 'report' => $entity,
- 'custom_fields_in_summary' => $this->getFieldsToRender($entity, $context),
- 'person' => $args['person'],
- 'user' => $entity->getUser()
+ 'report' => $entity,
+ 'context' => $context,
+ 'custom_fields_in_summary' => $this->getFieldsToRender($entity, $context),
)
);
}
@@ -272,9 +326,9 @@ class TimelineReportProvider implements TimelineProviderInterface
*/
private function checkContext($context)
{
- if ($context !== 'person') {
+ if ($context !== 'person' && $context !== 'center') {
throw new \LogicException("The context '$context' is not "
- . "supported. Currently only 'person' is supported");
+ . "supported. Currently only 'person' and 'center' is supported");
}
}
diff --git a/src/Bundle/ChillReportBundle/config/services.yaml b/src/Bundle/ChillReportBundle/config/services.yaml
index fec944ff5..477a94746 100644
--- a/src/Bundle/ChillReportBundle/config/services.yaml
+++ b/src/Bundle/ChillReportBundle/config/services.yaml
@@ -20,11 +20,12 @@ services:
arguments:
- '@doctrine.orm.entity_manager'
- '@chill.main.security.authorization.helper'
- - '@security.token_storage'
+ - '@Symfony\Component\Security\Core\Security'
- '@chill.custom_field.helper'
- '%chill_custom_fields.show_empty_values%'
tags:
- { name: chill.timeline, context: 'person' }
+ - { name: chill.timeline, context: 'center' }
chill.report.security.authorization.report_voter:
class: Chill\ReportBundle\Security\Authorization\ReportVoter
@@ -43,4 +44,4 @@ services:
- "@doctrine.orm.entity_manager"
tags:
- { name: form.type, alias: chill_reportbundle_report }
-
\ No newline at end of file
+
diff --git a/src/Bundle/ChillTaskBundle/config/services/timeline.yaml b/src/Bundle/ChillTaskBundle/config/services/timeline.yaml
index d6ca33606..0962866be 100644
--- a/src/Bundle/ChillTaskBundle/config/services/timeline.yaml
+++ b/src/Bundle/ChillTaskBundle/config/services/timeline.yaml
@@ -6,12 +6,12 @@ services:
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
public: true
- tags:
- - { name: 'chill.timeline', context: 'person' }
+ # tags:
+ # - { name: 'chill.timeline', context: 'person' }
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' }