Created
April 27, 2012 21:36
-
-
Save kemo/2513471 to your computer and use it in GitHub Desktop.
Cache-powered ORM model extension (Kohana 3.3) - [!!] Not tested
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php defined('SYSPATH') or die('No direct script access.'); | |
/** | |
* Extend this class if you want your model cached. Example usage: | |
* | |
* 1. Model | |
* class Model_User extends ORM_Cached {} | |
* | |
* 2. Usage | |
* | |
* // This will either retrieve the user with specified ID from cache | |
* // or get him from the database and cache him anyways | |
* $user = Model_User::cache($this->request->param('id')); | |
* | |
* // This will get the user with username "Jason" and email "[email protected]" | |
* // and also save him by these params (not the PK) | |
* $user = Model_User::cache(array('username' => 'Jason','email' => '[email protected]')); | |
* | |
* // Now if we update this user, related cache will also be updated | |
* $user->set('password' => 'test')->update(); | |
* | |
* // And if we delete this user, related cache will also be deleted | |
* $user->delete(); | |
* | |
* @package ORM | |
* @author Kemal Delalic <[email protected]> | |
*/ | |
class ORM_Cached extends ORM { | |
/** | |
* @var string Default cache group, e.g. 'file' or 'memcached' | |
*/ | |
protected static $_cacher_driver = 'apc'; | |
/** | |
* @var int For how long should the cache for current model last? | |
*/ | |
protected static $_cacher_lifetime = 60; | |
/** | |
* List of columns to be serialized when going to 'sleep' | |
* | |
* @var array | |
* @see http://php.net/serializable | |
*/ | |
protected static $_serialized_columns = array( | |
'_cache_loader_key', | |
'_primary_key_value', | |
'_object', | |
'_changed', | |
'_loaded', | |
'_saved', | |
'_sorting', | |
'_original_values', | |
); | |
/** | |
* Cached "factory" method | |
* | |
* $post = Model_User::cache($request->param('id')); | |
* | |
* @param mixed $id primary key or array of values to be matched | |
* @return ORM_Cached | |
*/ | |
public static function cache($id) | |
{ | |
$model = get_called_class(); | |
$cache_key = static::cache_key($model, $id); | |
if ( ! $object = static::cacher()->get($cache_key)) | |
{ | |
$object = new $model($id); | |
// Only save the object cache if its' loaded | |
if ($object->loaded()) | |
{ | |
// Save the loader key into the object (to use when deleting the cache) | |
$object->cache_loader_key($cache_key); | |
// Save this objects' cache | |
static::save_cache($object); | |
} | |
} | |
return $object; | |
} | |
/** | |
* Retrieves the cache driver for current model | |
* | |
* @return Cache | |
*/ | |
public static function cacher() | |
{ | |
return Cache::instance(static::$_cacher_driver); | |
} | |
/** | |
* Returns the cache key for ORM_Cached::cache() | |
* | |
* @param string $model | |
* @param mixed $id | |
* @return string | |
*/ | |
public static function cache_key($model, $id) | |
{ | |
if (is_array($id)) | |
{ | |
// Sort the passed array keys for consistency | |
ksort($id); | |
$id = http_build_query($id, '', '::'); | |
} | |
elseif (Valid::digit($id)) | |
{ | |
// Make sure the key is a string to have consistent cache keys | |
$id = (string) $id; | |
} | |
elseif ( ! is_string($id)) | |
{ | |
throw new Kohana_Exception('Unsupported $id type: :type', | |
array(':type' => gettype($id))); | |
} | |
return $model.':::'.$id; | |
} | |
/** | |
* Deletes the cache for passed ORM_Cached object | |
* | |
* @param ORM_Cached $object | |
* @return void | |
*/ | |
public static function delete_cache(ORM_Cached $object) | |
{ | |
if ($key = $object->cache_loader_key()) | |
{ | |
static::cacher()->delete($key); | |
} | |
} | |
/** | |
* Saves the cache for passed ORM object | |
* | |
* @param ORM $object | |
* @return void | |
*/ | |
public static function save_cache(ORM_Cached $object) | |
{ | |
if ($key = $object->cache_loader_key()) | |
{ | |
static::cacher()->set($key, $object, static::$_cacher_lifetime); | |
} | |
} | |
/** | |
* @var string The key current object was loaded with, if any | |
*/ | |
protected $_cache_loader_key; | |
/** | |
* @var boolean Should table columns be reloaded on wakeup? | |
*/ | |
protected $_reload_on_wakeup = FALSE; | |
/** | |
* ORM contructor overloaded to auto-assign a cache key if none provided | |
* | |
* @param mixed $id | |
*/ | |
public function __construct($id = NULL) | |
{ | |
parent::__construct($id); | |
// If the current record has been loaded and no cache key is set, | |
// use the primary key for creating a cache key | |
if ($this->_loaded AND ! $this->cache_loader_key()) | |
{ | |
$this->cache_loader_key(static::cache_key(get_class($this), $this->pk())); | |
} | |
} | |
/** | |
* Cache loader key setter / getter | |
* | |
* @param mixed $key to set | |
* @return string|self | |
* @chainable (on set) | |
*/ | |
public function cache_loader_key($key = NULL) | |
{ | |
if ($key === NULL) | |
return $this->_cache_loader_key; | |
$this->_cache_loader_key = $key; | |
return $this; | |
} | |
/** | |
* Overloaded create method | |
* Once the object is created, cache will be saved | |
* | |
* @param Validation $validation | |
* @return $this (chainable) | |
*/ | |
public function create(Validation $validation = NULL) | |
{ | |
$result = parent::create($validation); | |
// Assign the cache loader key now that we have the primary key | |
$this->cache_loader_key(static::cache_key(get_called_class(), $this->pk())); | |
// Save the cache for this object | |
static::save_cache($this); | |
return $result; | |
} | |
/** | |
* Delete override with cache support | |
* | |
* @chainable | |
* @return $this | |
*/ | |
public function delete() | |
{ | |
static::delete_cache($this); | |
return parent::delete(); | |
} | |
/** | |
* Proxy method to Database list_columns. | |
* | |
* @cached | |
* @return array | |
*/ | |
public function list_columns() | |
{ | |
$cache_key = "{$this->_table_name}::list_columns()"; | |
if ( ! $columns = ORM_Cached::cacher()->get($cache_key)) | |
{ | |
$columns = $this->_db->list_columns($this->_table_name); | |
ORM_Cached::cacher()->set($cache_key, $columns, Date::MINUTE); | |
} | |
return $columns; | |
} | |
/** | |
* Allows serialization of only the object data and state, to prevent | |
* "stale" objects being unserialized, which also requires less memory. | |
* | |
* @return array | |
*/ | |
public function serialize() | |
{ | |
$data = array(); | |
// Store only information about the object | |
foreach (static::$_serialized_columns as $var) | |
{ | |
$data[$var] = $this->{$var}; | |
} | |
return serialize($data); | |
} | |
/** | |
* Update override with cache support | |
* | |
* @param Validation $validation | |
* @return $this | |
* @throws ORM_Validation_Exception | |
*/ | |
public function update(Validation $validation = NULL) | |
{ | |
$result = parent::update($validation); | |
static::save_cache($this); | |
return $result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment