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;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
@ -52,33 +53,60 @@ class TimelineBuilder implements ContainerAwareInterface
/**
* return an HTML string with timeline
*
*
* 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
*
*
* @param string $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
* @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);
$fetched = $this->runQuery($query);
$union = $this->buildUnionQuery($context, $args);
//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);
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
*
*
* @internal This function is called by the TimelineCompilerClass
*
*
* @param string $context the context of the service
* @param string $id the
* @param string $id the
*/
public function addProvider($context, $id)
{
@ -87,7 +115,7 @@ class TimelineBuilder implements ContainerAwareInterface
/**
* Get providers by context
*
*
* @param string $context
* @return TimelineProviderInterface[]
*/
@ -104,9 +132,9 @@ class TimelineBuilder implements ContainerAwareInterface
/**
* build the UNION query with all providers
*
*
* @uses self::buildSelectQuery to build individual SELECT queries
*
*
* @param string $context
* @param mixed $args
* @param int $page
@ -114,7 +142,7 @@ class TimelineBuilder implements ContainerAwareInterface
* @return string
* @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
if (!array_key_exists($context, $this->providers)) {
@ -124,21 +152,18 @@ class TimelineBuilder implements ContainerAwareInterface
//append SELECT queries with UNION keyword between them
$union = '';
foreach($this->getProvidersByContext($context) as $provider) {
$select = $this->buildSelectQuery($provider, $context, $args);
foreach($this->getProvidersByContext($context) as $provider) {
$select = $this->buildSelectQuery($provider, $context, $args);
$append = ($union === '') ? $select : ' UNION '.$select;
$union .= $append;
}
//add ORDER BY clause and LIMIT
$union .= sprintf(' ORDER BY date DESC LIMIT %d OFFSET %d',
$number, $page * $number);
return $union;
}
/**
* return the SQL SELECT query as a string,
*
*
* @uses TimelineProfiderInterface::fetchQuery use the fetchQuery function
* @param \Chill\MainBundle\Timeline\TimelineProviderInterface $provider
* @param string $context
@ -164,11 +189,11 @@ class TimelineBuilder implements ContainerAwareInterface
/**
* run the UNION query and return result as an array
*
*
* @param string $query
* @return array
*/
private function runQuery($query)
private function runUnionQuery($query)
{
$resultSetMapping = (new ResultSetMapping())
->addScalarResult('id', 'id')
@ -180,14 +205,14 @@ class TimelineBuilder implements ContainerAwareInterface
}
/**
*
*
* @param array $queriedIds
* @param string $context
* @return array with the form array($type => [$entity, $entity, $entity])
*/
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();
foreach($queriedIds as $result) {
@ -211,7 +236,7 @@ class TimelineBuilder implements ContainerAwareInterface
/**
* render the timeline as HTML
*
*
* @param array $fetched
* @param array $entitiesByType
* @param string $context
@ -224,7 +249,7 @@ class TimelineBuilder implements ContainerAwareInterface
$timelineEntries = array();
foreach ($fetched as $result) {
$data = $this->getTemplateData(
$result['type'],
$result['type'],
$entitiesByType[$result['type']][$result['id']], //the entity
$context,
$args);
@ -244,7 +269,7 @@ class TimelineBuilder implements ContainerAwareInterface
/**
* get the template data from the provider for the given entity, by type.
*
*
* @param string $type
* @param mixed $entity
* @param string $context