Skip to content

Commit

Permalink
(experimental) Move Cache instance to Adapter impl
Browse files Browse the repository at this point in the history
  • Loading branch information
sasezaki committed Jan 17, 2016
1 parent 5ef2ea7 commit dc34b7e
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 31 deletions.
93 changes: 93 additions & 0 deletions src/Adapter/CacheAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Zend\Paginator\Adapter;

use Zend\Cache\Storage\StorageInterface as CacheStorage;

class CacheAdapter implements AdapterInterface
{
/**
* The cache tag prefix used to namespace Paginator results in the cache
*
*/
const CACHE_TAG_PREFIX = 'Zend_Paginator_';

/**
* @var AdapterInterface
*/
private $adapter;

/**
* @var CacheStorage;
*/
private $cache;

public function __construct(AdapterInterface $adapter, CacheStorage $cache)
{
$this->adapter = $adapter;
$this->cache = $cache;
}

public function getItems($offset, $itemCountPerPage)
{
$pageNumber = ($offset === 0 ) ? 1 : $offset / $itemCountPerPage + 1;

$cacheId = $this->getCacheId($pageNumber, $itemCountPerPage);

if ($this->cache->hasItem($cacheId)) {
return $this->cache->getItem($cacheId);
}

$items = $this->adapter->getItems($offset, $itemCountPerPage);

if (!$items instanceof \Traversable) {
$items = new \ArrayIterator($items);
}

$this->cache->setItem($cacheId, $items);

return $items;
}

public function count()
{
return $this->adapter->count();
}

public function clearCache($pageNumber, $itemCountPerPage)
{
$cacheId = $this->getCacheId($pageNumber, $itemCountPerPage);

if ($this->cache->hasItem($cacheId)) {
return $this->cache->removeItem($cacheId);
}
}

protected function getCacheId($pageNumber, $itemCountPerPage)
{
return static::CACHE_TAG_PREFIX . $pageNumber . '_' . $this->getCacheInternalId($itemCountPerPage);
}

/**
* Get the internal cache id
* Depends on the adapter and the item count per page
*
* Used to tag that unique Paginator instance in cache
*
* @return string
*/
protected function getCacheInternalId($itemCountPerPage)
{
return md5(serialize([
spl_object_hash($this->adapter),
$itemCountPerPage
]));
}
}
34 changes: 34 additions & 0 deletions src/Adapter/FilterAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
namespace Zend\Paginator\Adapter;

use Zend\Filter\FilterInterface;

class FilterAdapter implements AdapterInterface
{
/**
* @var AdapterInterface
*/
private $adapter;

/**
* @var FilterInterface;
*/
private $filter;

public function __construct(AdapterInterface $adapter, FilterInterface $filter)
{
$this->adapter = $adapter;
$this->filter = $filter;
}

public function getItems($offset, $itemCountPerPage)
{
$items = $this->adapter->getItems($offset, $itemCountPerPage);
return $this->filter->filter($items);
}

public function count()
{
return $this->adapter->count();
}
}
121 changes: 121 additions & 0 deletions src/CacheTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace Zend\Paginator;

use Zend\Cache\Storage\IteratorInterface as CacheIterator;
use Zend\Cache\Storage\StorageInterface as CacheStorage;

use Zend\Paginator\Adapter\CacheAdapter;

trait CacheTrait
{

/**
* Enable or disable the cache by Zend\Paginator\Paginator instance
*
* @var bool
*/
protected $cacheEnabled = true;

/**
* Cache object
*
* @var CacheStorage
*/
protected $cache;

/**
* Sets a cache object
*
* @param CacheStorage $cache
*/
public function setCache(CacheStorage $cache)
{
$this->cache = $cache;
}

/**
* Enables/Disables the cache for this instance
*
* @param bool $enable
* @return Paginator
*/
public function setCacheEnabled($enable)
{
$this->cacheEnabled = (bool) $enable;
return $this;
}

/**
* Tells if there is an active cache object
* and if the cache has not been disabled
*
* @return bool
*/
protected function cacheEnabled()
{
return (($this->cache instanceof CacheStorage) && $this->cacheEnabled);
}

/**
* Returns the page item cache.
*
* @return array
*/
public function getPageItemCache()
{
$data = [];
if ($this->cacheEnabled()) {
$prefixLength = strlen(CacheAdapter::CACHE_TAG_PREFIX);
$cacheIterator = $this->cache->getIterator();
$cacheIterator->setMode(CacheIterator::CURRENT_AS_VALUE);
foreach ($cacheIterator as $key => $value) {
if (substr($key, 0, $prefixLength) == CacheAdapter::CACHE_TAG_PREFIX) {
$pageNumber = (int)substr($key, $prefixLength);
$data[$pageNumber] = $value;
}
}
}
return $data;
}

/**
* Clear the page item cache.
*
* @param int $pageNumber
* @return Paginator
*/
public function clearPageItemCache($pageNumber = null)
{
if (!$this->cacheEnabled()) {
return $this;
}

$cacheAdapter = new CacheAdapter($this->adapter, $this->cache);

if (null === $pageNumber) {
$prefixLength = strlen(CacheAdapter::CACHE_TAG_PREFIX);
$cacheIterator = $this->cache->getIterator();
$cacheIterator->setMode(CacheIterator::CURRENT_AS_KEY);
foreach ($cacheIterator as $key) {
if (substr($key, 0, $prefixLength) == CacheAdapter::CACHE_TAG_PREFIX) {
$pageNumber = (int)substr($key, $prefixLength);
$cacheAdapter->clearCache($pageNumber, $this->getItemCountPerPage());
}
}
} else {
$pageNumber = $this->normalizePageNumber($pageNumber);

$cacheAdapter->clearCache($pageNumber, $this->getItemCountPerPage());
}
return $this;
}
}
38 changes: 13 additions & 25 deletions src/Paginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,17 @@

namespace Zend\Paginator;

use ArrayIterator;
use Traversable;
use ArrayIterator;
use Zend\Filter\FilterInterface;
use Zend\Paginator\Adapter;

class Paginator extends GlobalPaginator
{
use JsonSerializeTrait,
RenderTrait,
FilterTrait,
CachedTrait;

/**
* The cache tag prefix used to namespace Paginator results in the cache
*
*/
const CACHE_TAG_PREFIX = 'Zend_Paginator_';

CacheTrait;

/**
* @inheritdoc
Expand All @@ -33,32 +28,25 @@ public function getItemsByPage($pageNumber)
{
$pageNumber = $this->normalizePageNumber($pageNumber);

$adapter = $this->adapter;

$filter = $this->getFilter();
if ($filter instanceof FilterInterface) {
$adapter = new Adapter\FilterAdapter($adapter, $filter);
}

if ($this->cacheEnabled()) {
$data = static::$cache->getItem($this->_getCacheId($pageNumber));
if ($data) {
return $data;
}
$adapter = new Adapter\CacheAdapter($adapter, $this->cache);
}

$offset = ($pageNumber - 1) * $this->getItemCountPerPage();

$items = $this->adapter->getItems($offset, $this->getItemCountPerPage());

$filter = $this->getFilter();

if ($filter !== null) {
$items = $filter->filter($items);
}
$items = $adapter->getItems($offset, $this->getItemCountPerPage());

if (!$items instanceof Traversable) {
$items = new ArrayIterator($items);
}

if ($this->cacheEnabled()) {
$cacheId = $this->_getCacheId($pageNumber);
static::$cache->setItem($cacheId, $items);
}

return $items;
}
}
13 changes: 7 additions & 6 deletions test/PaginatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ protected function setUp()
$this->config = Config\Factory::fromFile(__DIR__ . '/_files/config.xml', true);

$this->cache = CacheFactory::adapterFactory('memory', ['memory_limit' => 0]);
Paginator\Paginator::setCache($this->cache);
// Paginator\Paginator::setCache($this->cache);
$this->paginator->setCache($this->cache);

$this->_restorePaginatorDefaults();
}
Expand Down Expand Up @@ -853,14 +854,14 @@ public function testLoadScrollingStyleWithObjectThrowsInvalidArgumentException()
public function testGetCacheId()
{
$adapter = new TestAsset\TestAdapter;
$paginator = new Paginator\Paginator($adapter);
$reflectionGetCacheId = new ReflectionMethod($paginator, '_getCacheId');
$adapter = new Paginator\Adapter\CacheAdapter($adapter, $this->cache);
$reflectionGetCacheId = new ReflectionMethod($adapter, 'getCacheId');
$reflectionGetCacheId->setAccessible(true);
$outputGetCacheId = $reflectionGetCacheId->invoke($paginator, null);
$outputGetCacheId = $reflectionGetCacheId->invoke($adapter, 1, 10);

$reflectionGetCacheInternalId = new ReflectionMethod($paginator, '_getCacheInternalId');
$reflectionGetCacheInternalId = new ReflectionMethod($adapter, 'getCacheInternalId');
$reflectionGetCacheInternalId->setAccessible(true);
$outputGetCacheInternalId = $reflectionGetCacheInternalId->invoke($paginator);
$outputGetCacheInternalId = $reflectionGetCacheInternalId->invoke($adapter, 10);

$this->assertEquals($outputGetCacheId, 'Zend_Paginator_1_' . $outputGetCacheInternalId);
}
Expand Down

0 comments on commit dc34b7e

Please sign in to comment.