我已经创建了一个基础存储库,现在正在扩展它以添加缓存,但我似乎遇到的问题多于pagination
在我的all()
方法中,我执行以下操作而不进行缓存:
public function all($pagination = 20)
{
try
{
$query = $this->model->newQuery();
return $this->handlePagination($query, $pagination);
}
catch (Exception $e)
{
throw $e;
}
}
protected function handlePagination($query, $pagination)
{
if (is_null($pagination))
{
return $query;
}
$collection = $query->paginate($pagination);
return $collection;
}
这很好用,但是当我尝试实现缓存时,我想单独缓存每个模型并存储每个集合的密钥,因此,如果我对所有条目进行分页,我会将每个分页集合存储在一个缓存:
cache set.1 [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
cache set.2 [21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40]
等...
问题是,由于您只对id
我可以单独返回数据和分页符,但这看起来非常hacky。
有没有办法用模型数据重新填充Paginator
类而不会覆盖整个事物?
修改
我在考虑这样的事情:
public function all($pagination = 20)
{
try
{
$cache_key = $this->cache_key . '.all';
$ids = Cache::get($cache_key);
if (! $ids)
{
$query = $this->model->newQuery();
$ids = $query->pluck('id');
Cache::put($cache_key, $ids, $this->cache_ttl);
}
$ids = $this->handlePagination($ids, $pagination);
$collection = new Collection();
foreach ($ids as $id)
{
if ($model = $this->find($id))
{
$collection->put($id, $model);
}
}
return $collection;
}
catch (Exception $e)
{
throw $e;
}
}
/**
* @var \Illuminate\Pagination\Paginator
*/
protected $paginator;
public function handlePagination($array, $pagination = 20)
{
if (!is_null($pagination))
{
$this->paginator = Paginator::make($array, count($array), $pagination);
return $this->paginator->getItems();
}
return $array;
}
public function getPaginator()
{
return $this->paginator;
}
答案 0 :(得分:1)
同时传递页码以进行缓存。像这样的Sonething
$currentPg = Input::get('page') ? Input::get('page') : '1';
$boards = Cache::remember('boards'.$currentPg, 60, function(){ return WhatEverModel::paginate(15); });

答案 1 :(得分:0)
我必须在我工作的项目中实现缓存,我遇到了类似的问题但没有分页。但方法应该是一样的。
如果告知模型,Laravel会在内部默认处理查询缓存。
我所做的是创建一个类,我想要缓存的所有对象都应该以某种方式扩展。然后你可以在不考虑缓存的情况下使用分页。
在下面的代码中,请特别注意以下方法覆盖:
CacheModel类如下所示:
<?php
class CacheModel extends Eloquent
{
/**
* Holds the query builder from which this model was fetched from.
*
* @var Illuminate\Database\Query\Builder
*/
protected $queryBuilder;
/**
* Overrides Illuminate\Database\Eloquent\Model's newQuery().
* We need to do this to store the query builder in our class for caching purpuses.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function newQuery($excludeDeleted = true)
{
$eloquentBuilder = parent::newQuery($excludeDeleted);
return $eloquentBuilder->rememberForever();
}
/**
* Overrides Illuminate\Database\Eloquent\Model's newBaseQueryBuilder().
* We need to do this to store the query builder in our class for caching purpuses.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function newBaseQueryBuilder()
{
$queryBuilder = parent::newBaseQueryBuilder();
$this->queryBuilder = $queryBuilder;
return $queryBuilder;
}
/**
* Overrides Illuminate\Database\Eloquent\Model's newFromBuilder().
* We need to do this to update the cache.
*
* @return an instance of the specified resource
*/
public function newFromBuilder($attributes = array())
{
$object = parent::newFromBuilder($attributes);
$that = $this;
$referencedCacheKeysFromObject = Cache::rememberForever($object->getCacheIdKey(), function() use ($that){
return array( $that->getQueryBuilder()->getCacheKey() => true );
});
if ( !isset($referencedCacheKeysFromObject[$this->getQueryBuilder()->getCacheKey()] ))
{
# Update the cache entries that hold the object
$referencedCacheKeysFromObject[$this->getQueryBuilder()->getCacheKey()] = true;
Cache::forget($object->getCacheIdKey());
Cache::forever($object->getCacheIdKey(), $referencedCacheKeysFromObject);
}
$referencedCacheKeysFromObjectTable = Cache::rememberForever($object->getCacheTableKey(), function() use ($that){
return array( $that->getQueryBuilder()->getCacheKey() => true );
});
if ( !isset( $referencedCacheKeysFromObjectTable[$this->getQueryBuilder()->getCacheKey()] ))
{
# Udate the cache entries that hold objects from the object's table.
$referencedCacheKeysFromObjectTable[$this->getQueryBuilder()->getCacheKey()] = true;
Cache::forget($object->getCacheTableKey());
Cache::forever($object->getCacheTableKey(), $referencedCacheKeysFromObjectTable);
}
return $object;
}
/**
* Overrides Illuminate\Database\Eloquent\Model's save().
* We need to do this to clean up the cache entries related to this object.
*
* @return \Illuminate\Database\Query\Builder
*/
public function save(array $attributes = array())
{
if (!$this->exists)
{
# If the object doesn't exists, it means that the object is gonna be created. So refresh all queries involving the object table.
# This is needed because the new created object might fell within one of the cache entries holding references to objects of this type.
$this->cleanUpCacheQueriesOfObjectTable();
}
$this->cleanUpCacheQueriesOfObject();
return parent::save();
}
/**
* Overrides Illuminate\Database\Eloquent\Model's delete().
* We need to do this to clean up the cache entries related to this object.
*
*/
public function delete()
{
$this->cleanUpCacheQueriesOfObject();
return parent::delete();
}
/**
* Overrides Illuminate\Database\Eloquent\Model's delete().
* We need to do this to clean up the cache entries related to this object.
*
*/
public static function destroy($id)
{
$this->find($id)->cleanUpCacheQueriesOfObject();
Cache::forget($this->getCacheIdKey($id));
return parent::destroy($id);
}
/**
* Returns the asociated query builder from which the model was created
*
* @return \Illuminate\Database\Query\Builder
*/
public function getQueryBuilder()
{
return $this->queryBuilder;
}
/**
* Cleans up all the cache queries that involve this object, if any.
*
*/
private function cleanUpCacheQueriesOfObject()
{
# Clean up the cache entries referencing the object as we need to re-fetch them.
if ( $referencedCacheKeys = Cache::get($this->getCacheIdKey()) )
{
foreach ($referencedCacheKeys as $cacheKey => $dummy)
{
Cache::forget($cacheKey);
}
}
}
/**
* Cleans up all the cache queries that involve this object table, if any.
* Needed when a a new object of this type is created.
* The cache needs to be refreshed just in case the object fells into
* one of the cache queries holding entries from the same type of the object.
*
*/
private function cleanUpCacheQueriesOfObjectTable()
{
# Clean up the cache entries referencing the object TABLE as we need to re-fetch them.
if ( $referencedCacheKeys = Cache::get($this->getCacheTableKey()) )
{
foreach ($referencedCacheKeys as $cacheKey => $dummy)
{
Cache::forget($cacheKey);
}
}
}
/**
* Returns a string containing a key for the table cache
*
*/
private function getCacheTableKey()
{
return '_' . $this->getTable();
}
/**
* Returns a string containing a key for the object cache
*
*/
private function getCacheIdKey($id = null)
{
if (!isset($id))
{
if (isset($this->id))
$id = $this->id;
else
$id = md5(serialize($this->getAttributes()));
}
return $this->getCacheTableKey() . '_' . $id;
}
}
然后你可以做另一个扩展这个可以被称为PaginateModel的CacheModel的类,你可以做你想做的任何分页操作。 当然其余的对象应该扩展这个PaginateModel类。
编辑:在方法newFromBuilder中添加了一些if条件,因为我刚刚发现自3.1.3以来APC中存在一个错误。
答案 2 :(得分:0)
您需要按照Laravel documentation中的说明手动创建分页器。所以基本上你需要从你的存储库返回paginator对象,这些对象可以很容易地缓存。其他选项是根据缓存/查询参数动态生成分页器。