2014-02-17 33 views
1

我創建了一個基礎庫,我現在擴展它來添加緩存,但問題我似乎遇到了比大多數是paginationLaravel庫緩存和分頁

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

分別

我可以返回數據和分頁程序但是這看起來很詭異。

有沒有辦法使用模型數據重新填充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

我不得不實施一個項目,我的工作緩存和我遇到類似的問題,但不與分頁。但方法應該是一樣的。

如果模型被告知這樣做,Laravel默認在內部處理查詢緩存。

我所做的是創建一個類,我想要緩存的所有對象應以某種方式擴展。然後你可以使用分頁,而不用考慮緩存。

在下面的代碼,要特別注意以下方法覆蓋:

  • newQuery
  • newBaseQueryBuilder
  • newFromBuilder

的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; 
} 

} 

然後你可以做另一個擴展這個CacheModel的類,它可以被稱爲PaginateModel,你可以做任何你想做的分頁操作。 當然其餘的對象應該擴展這個PaginateModel類。

編輯:添加了一些if方法newFromBuilder中的條件,因爲我剛剛發現自從3.1.3以來有一個錯誤在APC中。

+0

非常有趣的類 - 它充分利用由口才給出的所有功能,併成功緩存的一切嗎? – azngunit81

+0

到目前爲止,我們正在測試這個類。到目前爲止,我們沒有發現重大問題。但是你可以試試看看它是否有效。背後的想法是緩存一個對象和所有將獲取該對象的相關查詢。只要對象得到更新,我們就會使所有這些引用無效,以便緩存得到刷新。 – martin

+0

將緩存嵌入到Eloquent模型中可能不是一個好主意。 Questioner使用了存儲庫設計模式,因此處理緩存的正確方法是存儲庫的緩存修飾器類。 – trm42

0

您需要按照Laravel documentation中的說明手動創建分頁程序。所以基本上你需要從你的倉庫中返回paginator對象,並且可以很容易地緩存這些對象。其他選項是基於緩存/查詢參數即時生成分頁程序。

0

傳遞頁碼以及緩存。 Sonething這樣

$currentPg = Input::get('page') ? Input::get('page') : '1'; 
 
$boards = Cache::remember('boards'.$currentPg, 60, function(){ return WhatEverModel::paginate(15); });