Added knp paginator support

Bug fix: no
Feature addition: yes
Backwards compatibility break: no

Encapsulated Pagerfanta dependency for pagination and added support for knp pagination component
This commit is contained in:
Francisco Facioni 2012-05-22 10:23:51 -03:00
parent 2b858f0e42
commit 0d9e0f1172
13 changed files with 307 additions and 75 deletions

View file

@ -2,7 +2,9 @@
namespace FOQ\ElasticaBundle\Finder;
use FOQ\ElasticaBundle\Paginator\PaginatorAdapterInterface;
use Pagerfanta\Pagerfanta;
use Elastica_Query;
interface PaginatedFinderInterface
{
@ -13,4 +15,12 @@ interface PaginatedFinderInterface
* @return Pagerfanta paginated results
*/
function findPaginated($query);
/**
* Creates a paginator adapter for this query
*
* @param Elastica_Query $query
* @return PaginatorAdapterInterface
*/
function createPaginatorAdapter(Elastica_Query $query);
}

View file

@ -3,6 +3,7 @@
namespace FOQ\ElasticaBundle\Finder;
use FOQ\ElasticaBundle\Paginator\RawPaginatorAdapter;
use FOQ\ElasticaBundle\Paginator\FantaPaginatorAdapter;
use Pagerfanta\Pagerfanta;
use Elastica_Searchable;
use Elastica_Query;
@ -42,7 +43,7 @@ class RawFinder implements FinderInterface, PaginatedFinderInterface
$queryObject = Elastica_Query::create($query);
$paginatorAdapter = $this->createPaginatorAdapter($queryObject);
return new Pagerfanta($paginatorAdapter);
return new Pagerfanta(new FantaPaginatorAdapter($paginatorAdapter));
}
/**
@ -51,7 +52,7 @@ class RawFinder implements FinderInterface, PaginatedFinderInterface
* @param Elastica_Query $query
* @return RawPaginatorAdapter
*/
protected function createPaginatorAdapter(Elastica_Query $query)
public function createPaginatorAdapter(Elastica_Query $query)
{
return new RawPaginatorAdapter($this->searchable, $query);
}

View file

@ -6,6 +6,7 @@ use FOQ\ElasticaBundle\Finder\FinderInterface;
use FOQ\ElasticaBundle\Finder\PaginatedFinderInterface;
use FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
use FOQ\ElasticaBundle\Paginator\TransformedPaginatorAdapter;
use FOQ\ElasticaBundle\Paginator\FantaPaginatorAdapter;
use Pagerfanta\Pagerfanta;
use Elastica_Searchable;
use Elastica_Query;
@ -67,7 +68,7 @@ class TransformedFinder implements FinderInterface, PaginatedFinderInterface
$queryObject = Elastica_Query::create($query);
$paginatorAdapter = $this->createPaginatorAdapter($queryObject);
return new Pagerfanta($paginatorAdapter);
return new Pagerfanta(new FantaPaginatorAdapter($paginatorAdapter));
}
/**
@ -76,7 +77,7 @@ class TransformedFinder implements FinderInterface, PaginatedFinderInterface
* @param Elastica_Query $query
* @return TransformedPaginatorAdapter
*/
protected function createPaginatorAdapter(Elastica_Query $query)
public function createPaginatorAdapter(Elastica_Query $query)
{
return new TransformedPaginatorAdapter($this->searchable, $query, $this->transformer);
}

View file

@ -1,54 +0,0 @@
<?php
namespace FOQ\ElasticaBundle\Paginator;
use Pagerfanta\Adapter\AdapterInterface;
use Elastica_Searchable;
use Elastica_Query;
/**
* Implements the Pagerfanta\Adapter\AdapterInterface for use with Pagerfanta\Pagerfanta
*
* Allows pagination of Elastica_Query. Does not map results
*/
abstract class AbstractPaginatorAdapter implements AdapterInterface
{
/**
* @var Elastica_SearchableInterface the object to search in
*/
protected $searchable = null;
/**
* @var Elastica_Query the query to search
*/
protected $query = null;
/**
* @see PaginatorAdapterInterface::__construct
*
* @param Elastica_SearchableInterface the object to search in
* @param Elastica_Query the query to search
*/
public function __construct(Elastica_Searchable $searchable, Elastica_Query $query)
{
$this->searchable = $searchable;
$this->query = $query;
}
protected function getElasticaResults($offset, $itemCountPerPage)
{
$query = clone $this->query;
$query->setFrom($offset);
$query->setLimit($itemCountPerPage);
return $this->searchable->search($query)->getResults();
}
/**
* @see Pagerfanta\Adapter\AdapterInterface::getNbResults
*/
public function getNbResults()
{
return $this->searchable->count($this->query);
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace FOQ\ElasticaBundle\Paginator;
use Pagerfanta\Adapter\AdapterInterface;
use FOQ\ElasticaBundle\Paginator\PaginatorAdapterInterface;
class FantaPaginatorAdapter implements AdapterInterface
{
private $adapter;
/**
* @param PaginatorAdapterInterface $adapter
*/
public function __construct(PaginatorAdapterInterface $adapter)
{
$this->adapter = $adapter;
}
/**
* Returns the number of results.
*
* @return integer The number of results.
*
* @api
*/
public function getNbResults()
{
return $this->adapter->getTotalHits();
}
/**
* Returns an slice of the results.
*
* @param integer $offset The offset.
* @param integer $length The length.
*
* @return array|\Traversable The slice.
*
* @api
*/
public function getSlice($offset, $length)
{
return $this->adapter->getResults($offset,$length)->toArray();
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace FOQ\ElasticaBundle\Paginator;
interface PaginatorAdapterInterface
{
/**
* Returns the number of results.
*
* @return integer The number of results.
*
* @api
*/
function getTotalHits();
/**
* Returns an slice of the results.
*
* @param integer $offset The offset.
* @param integer $length The length.
*
* @return FOQ\ElasticaBundle\Paginator\PartialResults
*
* @api
*/
function getResults($offset, $length);
}

View file

@ -0,0 +1,32 @@
<?php
namespace FOQ\ElasticaBundle\Paginator;
interface PartialResultsInterface
{
/**
* Returns the paginated results.
*
* @return array
*
* @api
*/
function toArray();
/**
* Returns the number of results.
*
* @return integer The number of results.
*
* @api
*/
function getTotalHits();
/**
* Returns the facets
*
* @return array
*/
function getFacets();
}

View file

@ -2,20 +2,69 @@
namespace FOQ\ElasticaBundle\Paginator;
use Elastica_Searchable;
use Elastica_Query;
use FOQ\ElasticaBundle\Paginator\PaginatorAdapterInterface;
use FOQ\ElasticaBundle\Paginator\RawPartialResults;
/**
* Implements the Pagerfanta\Adapter\AdapterInterface for use with Zend\Paginator\Paginator
*
* Allows pagination of Elastica_Query. Does not map results
*/
class RawPaginatorAdapter extends AbstractPaginatorAdapter
class RawPaginatorAdapter implements PaginatorAdapterInterface
{
/**
* @see Pagerfanta\Adapter\AdapterInterface::getSlice
* @var Elastica_SearchableInterface the object to search in
*/
public function getSlice($offset, $length)
{
$results = $this->getElasticaResults($offset, $length);
private $searchable = null;
return array_map(function($result) { return $result->getSource(); }, $results);
/**
* @var Elastica_Query the query to search
*/
private $query = null;
/**
* @see PaginatorAdapterInterface::__construct
*
* @param Elastica_SearchableInterface the object to search in
* @param Elastica_Query the query to search
*/
public function __construct(Elastica_Searchable $searchable, Elastica_Query $query)
{
$this->searchable = $searchable;
$this->query = $query;
}
/**
* Returns the paginated results.
*
* @return Elastica_ResultSet
*/
protected function getElasticaResults($offset, $itemCountPerPage)
{
$query = clone $this->query;
$query->setFrom($offset);
$query->setLimit($itemCountPerPage);
return $this->searchable->search($query);
}
/**
* Returns the paginated results.
*
* @return FOQ\ElasticaBundle\Paginator\PartialResultInterface
*/
public function getResults($offset, $itemCountPerPage)
{
return new RawPartialResults($this->getElasticaResults($offset,$itemCountPerPage));
}
/**
* Returns the number of results.
*
* @return integer The number of results.
*/
public function getTotalHits()
{
return $this->searchable->count($this->query);
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace FOQ\ElasticaBundle\Paginator;
use FOQ\ElasticaBundle\Paginator\PartialResultsInterface;
use Elastica_ResultSet;
/**
* Raw partial results transforms to a simple array
*/
class RawPartialResults implements PartialResultsInterface
{
protected $resultSet;
/**
* @param \Elastica_ResultSet $resultSet
*/
public function __construct(Elastica_ResultSet $resultSet)
{
$this->resultSet = $resultSet;
}
/**
* {@inheritDoc}
*/
public function toArray()
{
return array_map(function($result) {
return $result->getSource();
}, $this->resultSet->getResults());
}
/**
* {@inheritDoc}
*/
public function getTotalHits()
{
return $this->resultSet->getTotalHits();
}
/**
* {@inheritDoc}
*/
public function getFacets()
{
if ($this->resultSet->hasFacets()) {
return $this->resultSet->getFacets();
}
return null;
}
}

View file

@ -3,17 +3,16 @@
namespace FOQ\ElasticaBundle\Paginator;
use FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
use FOQ\ElasticaBundle\Paginator\TransformedPartialResults;
use Elastica_Searchable;
use Elastica_Query;
/**
* Implements the Pagerfanta\Adapter\AdapterInterface Interface for use with Zend\Paginator\Paginator
*
* Allows pagination of Elastica_Query
*/
class TransformedPaginatorAdapter extends AbstractPaginatorAdapter
class TransformedPaginatorAdapter extends RawPaginatorAdapter
{
protected $transformer;
private $transformer;
/**
* @param Elastica_SearchableInterface the object to search in
@ -28,12 +27,10 @@ class TransformedPaginatorAdapter extends AbstractPaginatorAdapter
}
/**
* @see Pagerfanta\Adapter\AdapterInterface::getSlice
* {@inheritDoc}
*/
public function getSlice($offset, $length)
public function getResults($offset, $length)
{
$results = $this->getElasticaResults($offset, $length);
return $this->transformer->transform($results);
return new TransformedPartialResults($this->getElasticaResults($offset,$length),$this->transformer);
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace FOQ\ElasticaBundle\Paginator;
use FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface;
use FOQ\ElasticaBundle\Paginator\RawPartialResults;
use Elastica_ResultSet;
/**
* Partial transformed result set
*/
class TransformedPartialResults extends RawPartialResults
{
protected $transformer;
/**
* @param \Elastica_ResultSet $resultSet
* @param \FOQ\ElasticaBundle\Transformer\ElasticaToModelTransformerInterface $transformer
*/
public function __construct(Elastica_ResultSet $resultSet, ElasticaToModelTransformerInterface $transformer)
{
parent::__construct($resultSet);
$this->transformer = $transformer;
}
/**
* {@inheritDoc}
*/
public function toArray()
{
return $this->transformer->transform($this->resultSet->getResults());
}
}

View file

@ -68,6 +68,10 @@
<argument type="service" id="service_container" />
</call>
</service>
<service id="foq_elastica.paginator.subscriber" class="FOQ\ElasticaBundle\Subscriber\PaginateElasticaQuerySubscriber">
<tag name="knp_paginator.subscriber" />
</service>
</services>
</container>

View file

@ -0,0 +1,33 @@
<?php
namespace FOQ\ElasticaBundle\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Knp\Component\Pager\Event\ItemsEvent;
use FOQ\ElasticaBundle\Paginator\PaginatorAdapterInterface;
class PaginateElasticaQuerySubscriber implements EventSubscriberInterface
{
public function items(ItemsEvent $event)
{
if ($event->target instanceof PaginatorAdapterInterface) {
$results = $event->target->getResults($event->getOffset(), $event->getLimit());
$event->count = $results->getTotalHits();
$event->items = $results->toArray();
$facets = $results->getFacets();
if (null != $facets) {
$event->setCustomPaginationParameter('facets', $facets);
}
$event->stopPropagation();
}
}
public static function getSubscribedEvents()
{
return array(
'knp_pager.items' => array('items', 1)
);
}
}