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);
$from = $this->getFromClauseCenter($args);
$where = $this->getWhereClause($context, $args);
[$where, $parameters] = $this->getWhereClause($context, $args);
return [
'id' => $metadataActivity->getTableName()
@ -71,7 +71,8 @@ final class ActivityACLAwareRepository
'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'),
'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 Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
/**
* 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
{
@ -93,63 +93,37 @@ class TimelineActivityProvider implements TimelineProviderInterface
*/
public function fetchQuery($context, array $args)
{
//$this->checkContext($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()
.'.'.$metadataActivity->getColumnName('id'),
'type' => 'activity',
'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'),
'FROM' => $this->getFromClause($metadataActivity, $metadataPerson),
'WHERE' => $this->getWhereClause($metadataActivity, $metadataPerson,
$args['person'])
);
}
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');
'FROM' => $this->getFromClausePerson($args['person']),
'WHERE' => $where,
'parameters' => $parameters
]);
}
private function getWhereClauseForPerson(Person $person)
{
$parameters = [];
$metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity');
$associationMapping = $metadataActivity->getAssociationMapping('person');
$metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
$role = new Role('CHILL_ACTIVITY_SEE');
$reachableCenters = $this->helper->getReachableCenters($this->user,
$role);
$associationMapping = $metadataActivity->getAssociationMapping('person');
if (count($reachableCenters) === 0) {
return 'FALSE = TRUE';
@ -157,31 +131,41 @@ class TimelineActivityProvider implements TimelineProviderInterface
// we start with activities having the person_id linked to person
// (currently only context "person" is supported)
$whereClause = sprintf('%s = %d',
$associationMapping['joinColumns'][0]['name'],
$person->getId());
$whereClause = sprintf(' {activity.person_id} = ? ');
$parameters[] = $person->getId();
// we add acl (reachable center and scopes)
$centerAndScopeLines = array();
$centerAndScopeClauses = [];
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(),
$metadataActivity->getTableName().'.'.
$metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'],
implode(',', $reachablesScopesId));
$parameters[] = $center->getId();
$scopes_ids = [];
$reachableScopes = $this->helper->getReachableScopes($this->user, $role, $person->getCenter());
foreach ($reachableScopes as $scope) {
$scopes_ids[] = '?';
$parameters[] = $scope->getId();
}
$centerAndScopeClauses[] = \strtr(
'( {person.center_id} = ? AND {activity.scope_id} IN ({scopes_ids})) ',
[
'{scopes_ids}' => \implode(", ", $scopes_ids)
]
);
}
$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()
@ -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}

View File

@ -201,10 +201,13 @@ class TimelineBuilder implements ContainerAwareInterface
/**
* 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 = [];
$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;
}
}