3
2

More than 5 years have passed since last update.

laravel3:Eloquentのデータをキャッシュ(未完全)

Last updated at Posted at 2012-12-26

Perl の DBIC みたいに cache_for とかで データをキャッシュしたいな~と思ったので Eloquentを拡張してみました。

つまりこんな感じでキャッシュできるといいなー
$books = Books::with('Authors')
->where('is_enabled','=',1)
->cache_for(100)
->get();

eloquent_plugin_model.php
class EloquentPluginQuery extends Laravel\Database\Eloquent\Query {
  protected function query()
  {
    return new EloquentPluginQuery($this); 
  }
}
eloquent_plugin_query.php
class EloquentPluginQuery extends Laravel\Database\Eloquent\Query {
    private $cache_time = 30;
    private $is_cached = 0;

    public function get($columns = array('*'))
    {
        if (is_null($columns)) $columns = array('*');
        $cached_key = $this->generate_cached_key(__FUNCTION__,$columns);

        if ( $this->is_cached and Cache::has( $cached_key ) ) 
            return unserialize( Cache::get( $cached_key ) );

        $value =  parent::get($columns);
        Cache::put( $cached_key ,serialize($value) ,$this->cache_time ) ;
        return $value;
    }

    public function paginate($per_page = null, $columns = array('*'))
    {
        if (is_null($columns)) $columns = array('*');
        $cached_key = $this->generate_cached_key(__FUNCTION__,$columns,$per_page);

        if ( $this->is_cached and Cache::has( $cached_key ) )
             return unserialize( Cache::get( $cached_key ) );

        $value =  parent::paginate($per_page,$columns);
        Cache::put( $cached_key ,serialize($value) ,$this->cache_time ) ;
        return $value;
    }

    public function first($columns = array('*'))
    {
        if (is_null($columns)) $columns = array('*');
        $cached_key = $this->generate_cached_key(__FUNCTION__,$columns); 

        if ( $this->is_cached and Cache::has( $cached_key ) )
            return unserialize( Cache::get( $cached_key ) );


        $value =  parent::first($columns);
        Cache::put( $cached_key ,serialize($value) ,$this->cache_time ) ;
        return $value;
    }

    private function generate_cached_key( $method , $columns,$per_page=0 )
    {

        $t          = $this->table;
        $t->select($columns);
        $sql        = $t->grammar->select($t);
        $bindings   = serialize($t->bindings);
        $page       = Input::get('page', 1);
        $cached_key = "$method|$sql|$bindings|$page|$per_page";
        return md5($cached_key);

       }
    public function cache_for($time=null)
    {
          if ($time) $this->cache_time = $time;
          $this->is_cached = 1;
      return $this;
    }

}

モデルを以下に変更
class Books extends Eloquent {....}

class Books extends EloquentPluginModel {....}

これで cache_for()を使えるようになるので キャッシュがあれば そちからか なければ SQLを発行するようになります。

ただ、withでrelationテーブルを指定するとデータ自体はリレーション先までキャッシュされてるけど、実際 テンプレート上で $book->author->first()->author_name とかするとSQL発行されちゃうので キャッシュされたデータは $books['relationships']を参照する必要がでてきちゃう。

$book->author->first()->author_name できるように relation関連のソースも拡張すれば可能かもしれないけど 今回は面倒なのでやめちゃいました。

どなたかもっとよい方法あれば教えてください<(_ _)>

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2