adding the paginator to timeline

This commit is contained in:
Julien Fastré 2016-09-02 08:21:42 +02:00
parent 1b674f9141
commit 32f887d71f

View File

@ -20,6 +20,7 @@
namespace Chill\MainBundle\Timeline; namespace Chill\MainBundle\Timeline;
use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface;
@ -52,33 +53,60 @@ class TimelineBuilder implements ContainerAwareInterface
/** /**
* return an HTML string with timeline * return an HTML string with timeline
* *
* This function must be called from controller * This function must be called from controller
* *
* @example https://redmine.champs-libres.coop/projects/chillperson/repository/revisions/bd2e1b1808f73e39532e9538413025df5487cad0/entry/Controller/TimelinePersonController.php#L47 the implementation in person bundle * @example https://redmine.champs-libres.coop/projects/chillperson/repository/revisions/bd2e1b1808f73e39532e9538413025df5487cad0/entry/Controller/TimelinePersonController.php#L47 the implementation in person bundle
* *
* @param string $context * @param string $context
* @param array $args arguments defined by the bundle which create the context * @param array $args arguments defined by the bundle which create the context
* @param int $page first page = 0 * @param int $firstItem first item number
* @param int $number number of items by page * @param int $number number of items by page
* @return string an HTML representation, must be included using `|raw` filter * @return string an HTML representation, must be included using `|raw` filter
*/ */
public function getTimelineHTML($context, array $args, $page = 0, $number = 20) public function getTimelineHTML($context, array $args, $firstItem = 0, $number = 20)
{ {
$query = $this->buildUnionQuery($context, $args, $page, $number); $union = $this->buildUnionQuery($context, $args);
$fetched = $this->runQuery($query);
//add ORDER BY clause and LIMIT
$query = $union . sprintf(' ORDER BY date DESC LIMIT %d OFFSET %d',
$number, $firstItem);
// run query and handle results
$fetched = $this->runUnionQuery($query);
$entitiesByKey = $this->getEntities($fetched, $context); $entitiesByKey = $this->getEntities($fetched, $context);
return $this->render($fetched, $entitiesByKey, $context, $args); return $this->render($fetched, $entitiesByKey, $context, $args);
} }
/**
* Return the number of items for the given context and args
*
* @param unknown $context
* @param array $args
* @return mixed|\Doctrine\DBAL\Driver\Statement|NULL
*/
public function countItems($context, array $args)
{
$union = $this->buildUnionQuery($context, $args);
// embed the union query inside a count query
$count = sprintf('SELECT COUNT(sq.id) AS total FROM (%s) as sq', $union);
$rsm = (new ResultSetMapping())
->addScalarResult('total', 'total', Type::INTEGER);
return $this->em->createNativeQuery($count, $rsm)
->getSingleScalarResult();
}
/** /**
* add a provider id * add a provider id
* *
* @internal This function is called by the TimelineCompilerClass * @internal This function is called by the TimelineCompilerClass
* *
* @param string $context the context of the service * @param string $context the context of the service
* @param string $id the * @param string $id the
*/ */
public function addProvider($context, $id) public function addProvider($context, $id)
{ {
@ -87,7 +115,7 @@ class TimelineBuilder implements ContainerAwareInterface
/** /**
* Get providers by context * Get providers by context
* *
* @param string $context * @param string $context
* @return TimelineProviderInterface[] * @return TimelineProviderInterface[]
*/ */
@ -104,9 +132,9 @@ class TimelineBuilder implements ContainerAwareInterface
/** /**
* build the UNION query with all providers * build the UNION query with all providers
* *
* @uses self::buildSelectQuery to build individual SELECT queries * @uses self::buildSelectQuery to build individual SELECT queries
* *
* @param string $context * @param string $context
* @param mixed $args * @param mixed $args
* @param int $page * @param int $page
@ -114,7 +142,7 @@ class TimelineBuilder implements ContainerAwareInterface
* @return string * @return string
* @throws \LogicException if no builder have been defined for this context * @throws \LogicException if no builder have been defined for this context
*/ */
private function buildUnionQuery($context, array $args, $page, $number) private function buildUnionQuery($context, array $args)
{ {
//throw an exception if no provider have been defined for this context //throw an exception if no provider have been defined for this context
if (!array_key_exists($context, $this->providers)) { if (!array_key_exists($context, $this->providers)) {
@ -124,21 +152,18 @@ class TimelineBuilder implements ContainerAwareInterface
//append SELECT queries with UNION keyword between them //append SELECT queries with UNION keyword between them
$union = ''; $union = '';
foreach($this->getProvidersByContext($context) as $provider) { foreach($this->getProvidersByContext($context) as $provider) {
$select = $this->buildSelectQuery($provider, $context, $args); $select = $this->buildSelectQuery($provider, $context, $args);
$append = ($union === '') ? $select : ' UNION '.$select; $append = ($union === '') ? $select : ' UNION '.$select;
$union .= $append; $union .= $append;
} }
//add ORDER BY clause and LIMIT
$union .= sprintf(' ORDER BY date DESC LIMIT %d OFFSET %d',
$number, $page * $number);
return $union; return $union;
} }
/** /**
* return the SQL SELECT query as a string, * return the SQL SELECT query as a string,
* *
* @uses TimelineProfiderInterface::fetchQuery use the fetchQuery function * @uses TimelineProfiderInterface::fetchQuery use the fetchQuery function
* @param \Chill\MainBundle\Timeline\TimelineProviderInterface $provider * @param \Chill\MainBundle\Timeline\TimelineProviderInterface $provider
* @param string $context * @param string $context
@ -164,11 +189,11 @@ class TimelineBuilder implements ContainerAwareInterface
/** /**
* run the UNION query and return result as an array * run the UNION query and return result as an array
* *
* @param string $query * @param string $query
* @return array * @return array
*/ */
private function runQuery($query) private function runUnionQuery($query)
{ {
$resultSetMapping = (new ResultSetMapping()) $resultSetMapping = (new ResultSetMapping())
->addScalarResult('id', 'id') ->addScalarResult('id', 'id')
@ -180,14 +205,14 @@ class TimelineBuilder implements ContainerAwareInterface
} }
/** /**
* *
* @param array $queriedIds * @param array $queriedIds
* @param string $context * @param string $context
* @return array with the form array($type => [$entity, $entity, $entity]) * @return array with the form array($type => [$entity, $entity, $entity])
*/ */
private function getEntities(array $queriedIds, $context) private function getEntities(array $queriedIds, $context)
{ {
//gather entities by type to pass all id with same type to the TimelineProvider. //gather entities by type to pass all id with same type to the TimelineProvider.
$idsByType = array(); $idsByType = array();
foreach($queriedIds as $result) { foreach($queriedIds as $result) {
@ -211,7 +236,7 @@ class TimelineBuilder implements ContainerAwareInterface
/** /**
* render the timeline as HTML * render the timeline as HTML
* *
* @param array $fetched * @param array $fetched
* @param array $entitiesByType * @param array $entitiesByType
* @param string $context * @param string $context
@ -224,7 +249,7 @@ class TimelineBuilder implements ContainerAwareInterface
$timelineEntries = array(); $timelineEntries = array();
foreach ($fetched as $result) { foreach ($fetched as $result) {
$data = $this->getTemplateData( $data = $this->getTemplateData(
$result['type'], $result['type'],
$entitiesByType[$result['type']][$result['id']], //the entity $entitiesByType[$result['type']][$result['id']], //the entity
$context, $context,
$args); $args);
@ -244,7 +269,7 @@ class TimelineBuilder implements ContainerAwareInterface
/** /**
* get the template data from the provider for the given entity, by type. * get the template data from the provider for the given entity, by type.
* *
* @param string $type * @param string $type
* @param mixed $entity * @param mixed $entity
* @param string $context * @param string $context