fix activity timeline using TimelineSingleQuery

This commit is contained in:
Julien Fastré 2021-05-24 20:26:33 +02:00
parent ea477a9842
commit 74541f360b
4 changed files with 210 additions and 82 deletions

View File

@ -62,7 +62,7 @@ final class ActivityACLAwareRepository
$metadataActivity = $this->em->getClassMetadata(Activity::class); $metadataActivity = $this->em->getClassMetadata(Activity::class);
$from = $this->getFromClauseCenter($args); $from = $this->getFromClauseCenter($args);
$where = $this->getWhereClause($context, $args); [$where, $parameters] = $this->getWhereClause($context, $args);
return [ return [
'id' => $metadataActivity->getTableName() 'id' => $metadataActivity->getTableName()
@ -71,7 +71,8 @@ final class ActivityACLAwareRepository
'date' => $metadataActivity->getTableName() 'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'), .'.'.$metadataActivity->getColumnName('date'),
'FROM' => $from, 'FROM' => $from,
'WHERE' => $where 'WHERE' => $where,
'parameters' => $parameters
]; ];
} }

View File

@ -29,13 +29,13 @@ use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
/** /**
* Provide activity for inclusion in timeline * Provide activity for inclusion in timeline
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> */
* @author Champs Libres <info@champs-libres.coop>
*/
class TimelineActivityProvider implements TimelineProviderInterface class TimelineActivityProvider implements TimelineProviderInterface
{ {
@ -93,63 +93,37 @@ class TimelineActivityProvider implements TimelineProviderInterface
*/ */
public function fetchQuery($context, array $args) public function fetchQuery($context, array $args)
{ {
//$this->checkContext($context);
//
if ('center' === $context) { if ('center' === $context) {
return $this->aclAwareRepository->queryTimelineIndexer($context, $args); return TimelineSingleQuery::fromArray($this->aclAwareRepository
->queryTimelineIndexer($context, $args));
} }
$metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity'); $metadataActivity = $this->em->getClassMetadata(Activity::class);
return array( [$where, $parameters] = $this->getWhereClauseForPerson($args['person']);
dump($where, $parameters);
return TimelineSingleQuery::fromArray([
'id' => $metadataActivity->getTableName() 'id' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('id'), .'.'.$metadataActivity->getColumnName('id'),
'type' => 'activity', 'type' => 'activity',
'date' => $metadataActivity->getTableName() 'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'), .'.'.$metadataActivity->getColumnName('date'),
'FROM' => $this->getFromClause($metadataActivity, $metadataPerson), 'FROM' => $this->getFromClausePerson($args['person']),
'WHERE' => $this->getWhereClause($metadataActivity, $metadataPerson, 'WHERE' => $where,
$args['person']) 'parameters' => $parameters
); ]);
}
private function getFromClause(string $context)
{
switch ($context) {
case 'person':
return $this->getFromClausePerson($metadataActivity, $metadataPerson);
}
}
private function getWhereClause(string $context, array $args)
{
switch ($context) {
case 'person':
return $this->getWhereClause($args['person']);
}
}
/**
*
* @var $centers array|Center[]
*/
private function getWhereClauseForCenter(array $centers)
{
$clause = "";
$role = new Role('CHILL_ACTIVITY_SEE');
} }
private function getWhereClauseForPerson(Person $person) private function getWhereClauseForPerson(Person $person)
{ {
$parameters = [];
$metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity'); $metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity');
$associationMapping = $metadataActivity->getAssociationMapping('person');
$metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person'); $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
$role = new Role('CHILL_ACTIVITY_SEE'); $role = new Role('CHILL_ACTIVITY_SEE');
$reachableCenters = $this->helper->getReachableCenters($this->user, $reachableCenters = $this->helper->getReachableCenters($this->user,
$role); $role);
$associationMapping = $metadataActivity->getAssociationMapping('person');
if (count($reachableCenters) === 0) { if (count($reachableCenters) === 0) {
return 'FALSE = TRUE'; return 'FALSE = TRUE';
@ -157,31 +131,41 @@ class TimelineActivityProvider implements TimelineProviderInterface
// we start with activities having the person_id linked to person // we start with activities having the person_id linked to person
// (currently only context "person" is supported) // (currently only context "person" is supported)
$whereClause = sprintf('%s = %d', $whereClause = sprintf(' {activity.person_id} = ? ');
$associationMapping['joinColumns'][0]['name'], $parameters[] = $person->getId();
$person->getId());
// we add acl (reachable center and scopes) // we add acl (reachable center and scopes)
$centerAndScopeLines = array(); $centerAndScopeClauses = [];
foreach ($reachableCenters as $center) { foreach ($reachableCenters as $center) {
$reachablesScopesId = array_map( $parameters[] = $center->getId();
function(Scope $scope) { return $scope->getId(); }, $scopes_ids = [];
$this->helper->getReachableScopes($this->user, $role, $reachableScopes = $this->helper->getReachableScopes($this->user, $role, $person->getCenter());
$person->getCenter()) foreach ($reachableScopes as $scope) {
); $scopes_ids[] = '?';
$parameters[] = $scope->getId();
$centerAndScopeLines[] = sprintf('(%s = %d AND %s IN (%s))', }
$metadataPerson->getTableName().'.'. $centerAndScopeClauses[] = \strtr(
$metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'], '( {person.center_id} = ? AND {activity.scope_id} IN ({scopes_ids})) ',
$center->getId(), [
$metadataActivity->getTableName().'.'. '{scopes_ids}' => \implode(", ", $scopes_ids)
$metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], ]
implode(',', $reachablesScopesId)); );
} }
$whereClause .= ' AND ('.implode(' OR ', $centerAndScopeLines).')'; $whereClause .= ' AND ('.\implode(' OR ', $centerAndScopeClauses).' ) ';
return $whereClause; return [
\strtr(
$whereClause,
[
'{activity.person_id}' => $associationMapping['joinColumns'][0]['name'],
'{person.center_id}' => $metadataPerson->getTableName().'.'.
$metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'],
'{activity.scope_id}' => $metadataActivity->getTableName().'.'.
$metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'],
]
),
$parameters
];
} }
private function getFromClausePerson() private function getFromClausePerson()
@ -199,21 +183,6 @@ class TimelineActivityProvider implements TimelineProviderInterface
; ;
} }
private function getFromClauseCenter()
{
$metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity');
$metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
$associationMapping = $metadataActivity->getAssociationMapping('person');
return $metadataActivity->getTableName().' JOIN '
.$metadataPerson->getTableName().' ON '
.$metadataPerson->getTableName().'.'.
$associationMapping['joinColumns'][0]['referencedColumnName']
.' = '
.$associationMapping['joinColumns'][0]['name']
;
}
/** /**
* *
* {@inheritDoc} * {@inheritDoc}

View File

@ -201,10 +201,13 @@ class TimelineBuilder implements ContainerAwareInterface
/** /**
* return the SQL SELECT query as a string, * return the SQL SELECT query as a string,
* *
* @return string * @return array: first parameter is the sql string, second an array with parameters
*/ */
private function buildSelectQuery(array $data): array private function buildSelectQuery($data): array
{ {
return [$data->buildSql(), $data->getParameters()];
// dead code
$parameters = []; $parameters = [];
$sql = sprintf( $sql = sprintf(

View File

@ -0,0 +1,155 @@
<?php
namespace Chill\MainBundle\Timeline;
class TimelineSingleQuery
{
private ?string $id;
private ?string $date;
private ?string $key;
private ?string $from;
private ?string $where;
private array $parameters = [];
private bool $distinct = false;
public function __construct(
string $id = null,
string $date = null,
string $key = null,
string $from = null,
string $where = null,
array $parameters = []
) {
$this->id = $id;
$this->date = $date;
$this->key = $key;
$this->from = $from;
$this->where = $where;
$this->parameters = $parameters;
}
public static function fromArray(array $a)
{
return new TimelineSingleQuery(
$a['id'],
$a['date'],
$a['type'] ?? $a['key'],
$a['FROM'] ?? $a['from'],
$a['WHERE'] ?? $a['where'],
$a['parameters']);
}
public function getId(): string
{
return $this->id;
}
public function setId(string $id): self
{
$this->id = $id;
return $this;
}
public function getDate(): string
{
return $this->date;
}
public function setDate(string $date): self
{
$this->date = $date;
return $this;
}
public function getKey(): string
{
return $this->key;
}
public function setKey(string $key): self
{
$this->key = $key;
return $this;
}
public function getFrom(): string
{
return $this->from;
}
public function setFrom(string $from): self
{
$this->from = $from;
return $this;
}
public function getWhere(): string
{
return $this->where;
}
public function setWhere(string $where): self
{
$this->where = $where;
return $this;
}
public function getParameters(): array
{
return $this->parameters;
}
public function setParameters(array $parameters): self
{
$this->parameters = $parameters;
return $this;
}
public function setDistinct(bool $distinct): self
{
$this->distinct = $distinct;
return $this;
}
public function isDistinct(): bool
{
return $this->distinct;
}
public function buildSql(): string
{
$parameters = [];
$sql = \strtr(
'SELECT {distinct} {id} AS id, '
. '{date} AS "date", '
. "'{key}' AS type "
. 'FROM {from} '
. 'WHERE {where}',
[
'{distinct}' => $this->distinct ? 'DISTINCT' : '',
'{id}' => $this->getId(),
'{date}' => $this->getDate(),
'{key}' => $this->getKey(),
'{from}' => $this->getFrom(),
'{where}' => $this->getWhere(),
]
);
return $sql;
}
}