From a0074337a3e8f31b8927f7e0698307f6d06f7f63 Mon Sep 17 00:00:00 2001 From: Josh Sherman Date: Thu, 28 Feb 2013 16:26:25 -0500 Subject: [PATCH] Reverted cache layer --- classes/Cache.php | 284 +++++++------------------- jar.php | 500 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 568 insertions(+), 216 deletions(-) diff --git a/classes/Cache.php b/classes/Cache.php index 42630ed..3a847e8 100644 --- a/classes/Cache.php +++ b/classes/Cache.php @@ -9,7 +9,7 @@ * Redistribution of these files must retain the above copyright notice. * * @author Josh Sherman - * @copyright Copyright 2007-2013, Josh Sherman + * @copyright Copyright 2007-2012, Josh Sherman * @license http://www.opensource.org/licenses/mit-license.html * @package PICKLES * @link https://github.com/joshtronic/pickles @@ -18,31 +18,24 @@ /** * Cache Class * - * Wrapper class for interfacing with Redis and Memcached as key/value - * stores for caching data. Wrapper provides graceful failover when a - * caching server is not available. The syntax is designed around the API - * for Memcached() to provide a consistent experience across datastores. - * Support for Memcached is currently using the Memcache() library due to - * some bugginess with Memcached(). The plan is to migrate to Memcached() - * in the future. Redis interaction is done via phpredis. Keys are - * optionally namespaced and keys are forced to lowercase for consistency. - - * @link http://www.memcached.org/ + * Wrapper class for Memcache() to allow for better error handling when the + * Memcached server is unavailable. Designed around the syntax for Memcached() + * to allow for an easier transistion to the aforementioned in the future. I + * don't entirely remember specifics, but the reason for not using Memcached() + * was due to an unexplainable bug in the version in the repository for Ubuntu + * 10.04 LTS. Memcached() does support more of the memcached protocol and will + * eventually be what PICKLES uses. Keys are forced to be uppercase for + * consistencies sake as I've been burned by the case sensitivity due to typos + * in my code. + * + * Requires php5-memcache + * * @link http://us.php.net/manual/en/book.memcache.php * @link http://packages.ubuntu.com/lucid/php5-memcache - * @link http://redis.io - * @link https://github.com/nicolasff/phpredis + * @link http://www.memcached.org/ */ class Cache extends Object { - /** - * Cache handler - * - * @access private - * @var string memcached or redis - */ - private $handler = null; - /** * Hostname for the Memcached Server * @@ -57,15 +50,7 @@ class Cache extends Object * @access private * @var integer */ - private $port = null; - - /** - * Database to use (Redis-only) - * - * @access private - * @var integer - */ - private $database = 0; + private $port = 11211; /** * Namespace (prefix) @@ -86,9 +71,12 @@ class Cache extends Object /** * Constructor * - * Sets up our variables + * Sets up our connection variables. + * + * @param string $hostname optional hostname to connect to + * @param string $database optional port to use */ - public function __construct() + public function __construct($hostname = null, $port = null) { parent::__construct(); @@ -98,37 +86,20 @@ class Cache extends Object { $datasource = $this->config->datasources[$this->config->pickles['cache']]; - if (!isset($datasource['type'])) + foreach (array('hostname', 'port', 'namespace') as $variable) { - throw new Exception('You must specify the datasource\'s type'); - } - - $this->hostname = isset($datasource['hostname']) ? $datasource['hostname'] : 'localhost'; - - switch ($datasource['type']) - { - case 'memcache': - case 'memcached': - $this->handler = 'memcached'; - $this->port = isset($datasource['port']) ? $datasource['port'] : 11211; - break; - - case 'redis': - $this->handler = 'redis'; - $this->port = isset($datasource['port']) ? $datasource['port'] : 6379; - $this->database = isset($datasource['database']) ? $datasource['database'] : 0; - break; - - default: - throw new Exception('The specified datasource type "' . $datasource['type'] . '" is unsupported.'); - } - - if (isset($datasource['namespace']) && $datasource['namespace'] != '') - { - $this->namespace = $datasource['namespace'] . ':'; + if (isset($datasource[$variable])) + { + $this->$variable = $datasource[$variable]; + } } } } + + if ($this->namespace != '') + { + $this->namespace .= '-'; + } } /** @@ -167,62 +138,11 @@ class Cache extends Object { if ($this->connection === null) { - switch ($this->handler) - { - case 'memcached': - $this->connection = new Memcache(); - break; - - case 'redis': - $this->connection = new Redis(); - break; - } + $this->connection = new Memcache(); + $this->connection->connect($this->hostname, $this->port); } - $connected = $this->connection->connect($this->hostname, $this->port); - - if ($connected && $this->database != 0) - { - $this->connection->select($this->database); - } - - return $connected; - } - - /** - * Set Key - * - * Sets key to the specified value. - * - * @param string $key key to set - * @param mixed $value value to set - * @param integer $expiration optional expiration, defaults to 5 minutes - * @return boolean status of writing the data to the key - */ - public function set($key, $value, $expire = 300) - { - $key = strtolower($key); - - if ($this->open()) - { - switch ($this->handler) - { - case 'memcached': - return $this->connection->set(strtolower($this->namespace . $key), $value, 0, $expire); - break; - - case 'redis': - if (is_array($value)) - { - $value = 'JSON:' . json_encode($value); - } - - return $this->connection->set(strtolower($this->namespace . $key), $value, $expire); - break; - } - } - - return false; + return true; } /** @@ -237,53 +157,45 @@ class Cache extends Object { if ($this->open()) { - // Namespaces keys if (is_array($keys)) { foreach ($keys as $index => $key) { - $keys[$index] = strtolower($this->namespace . $key); + $keys[$index] = strtoupper($this->namespace . $key); } } else { - $keys = strtolower($this->namespace . $keys); + $keys = strtoupper($this->namespace . $keys); } - switch ($this->handler) - { - case 'memcached': - return $this->connection->get($keys); - break; + return $this->connection->get($keys); + } - case 'redis': - if (is_array($keys)) - { - $values = $this->connection->mGet($keys); + return false; + } - foreach ($values as $index => $value) - { - if (substr($value, 0, 5) == 'JSON:') - { - $values[$index] = json_decode(substr($value, 5), true); - } - } + /** + * Set Key + * + * Sets key to the specified value. I've found that compression can lead to + * issues with integers and can slow down the storage and retrieval of data + * (defeats the purpose of caching if you ask me) and isn't supported. I've + * also been burned by data inadvertantly being cached for infinity, hence + * the 5 minute default. + * + * @param string $key key to set + * @param mixed $value value to set + * @param integer $expiration optional expiration, defaults to 5 minutes + * @return boolean status of writing the data to the key + */ + public function set($key, $value, $expire = 300) + { + $key = strtoupper($key); - return $values; - } - else - { - $value = $this->connection->get($keys); - - if (substr($value, 0, 5) == 'JSON:') - { - $value = json_decode(substr($value, 5), true); - } - - return $value; - } - break; - } + if ($this->open()) + { + return $this->connection->set(strtoupper($this->namespace . $key), $value, 0, $expire); } return false; @@ -309,7 +221,7 @@ class Cache extends Object // Memcache() doesn't let you pass an array to delete all records the same way you can with get() foreach ($keys as $key) { - $this->connection->delete(strtolower($this->namespace . $key)); + $this->connection->delete(strtoupper($this->namespace . $key)); } return true; @@ -318,83 +230,23 @@ class Cache extends Object return false; } - /** - * Change - * - * Increment / decrement a variable by a value - * - * @param string $direction increment or decrement - * @param string $key key to increment - * @param integer $value increment by value - * @return mixed new value or false if unable to connect - */ - public function change($direction, $key, $value = 1) - { - if ($this->handler == 'redis') - { - switch ($direction) - { - case 'increment': $direction = 'incr'; break; - case 'decrement': $direction = 'decr'; break; - } - - if ($value > 1) - { - $direction .= 'By'; - } - } - - $key = strtolower($this->namespace . $key); - - if ($this->open()) - { - // Memcache::*crement() doesn't create the key - if ($this->handler == 'memcached') - { - if ($this->connection->add($key, $value) === false) - { - return $this->connection->$direction($key, $value); - } - else - { - return $value; - } - } - else - { - return $this->connection->$direction($key, $value); - } - } - - return false; - } - /** * Increment Key * * Increments the value of an existing key. * * @param string $key key to increment - * @param integer $value increment by value - * @return mixed new value or false if unable to connect + * @return boolean status of incrementing the key + * @todo Wondering if I should check the key and set to 1 if it's new */ - public function increment($key, $value = 1) + public function increment($key) { - return $this->change('increment', $key, $value); - } + if ($this->open()) + { + return $this->connection->increment(strtoupper($this->namespace . $key)); + } - /** - * Decrement Key - * - * Decrements the value of an existing key. - * - * @param string $key key to decrement - * @param integer $value decrement by value - * @return mixed new value or false if unable to connect - */ - public function decrement($key, $value = 1) - { - return $this->change('decrement', $key, $value); + return false; } } diff --git a/jar.php b/jar.php index c7e1104..1798b01 100755 --- a/jar.php +++ b/jar.php @@ -579,6 +579,256 @@ class Browser extends Object } } +/** + * Caching System for PICKLES + * + * PHP version 5 + * + * Licensed under The MIT License + * Redistribution of these files must retain the above copyright notice. + * + * @author Josh Sherman + * @copyright Copyright 2007-2012, Josh Sherman + * @license http://www.opensource.org/licenses/mit-license.html + * @package PICKLES + * @link https://github.com/joshtronic/pickles + */ + +/** + * Cache Class + * + * Wrapper class for Memcache() to allow for better error handling when the + * Memcached server is unavailable. Designed around the syntax for Memcached() + * to allow for an easier transistion to the aforementioned in the future. I + * don't entirely remember specifics, but the reason for not using Memcached() + * was due to an unexplainable bug in the version in the repository for Ubuntu + * 10.04 LTS. Memcached() does support more of the memcached protocol and will + * eventually be what PICKLES uses. Keys are forced to be uppercase for + * consistencies sake as I've been burned by the case sensitivity due to typos + * in my code. + * + * Requires php5-memcache + * + * @link http://us.php.net/manual/en/book.memcache.php + * @link http://packages.ubuntu.com/lucid/php5-memcache + * @link http://www.memcached.org/ + */ +class Cache extends Object +{ + /** + * Hostname for the Memcached Server + * + * @access private + * @var string + */ + private $hostname = 'localhost'; + + /** + * Port to use to connect + * + * @access private + * @var integer + */ + private $port = 11211; + + /** + * Namespace (prefix) + * + * @access private + * @var string + */ + private $namespace = ''; + + /** + * Connection resource to Memcached + * + * @access private + * @var object + */ + private $connection = null; + + /** + * Constructor + * + * Sets up our connection variables. + * + * @param string $hostname optional hostname to connect to + * @param string $database optional port to use + */ + public function __construct($hostname = null, $port = null) + { + parent::__construct(); + + if ($this->config->pickles['cache']) + { + if (isset($this->config->datasources[$this->config->pickles['cache']])) + { + $datasource = $this->config->datasources[$this->config->pickles['cache']]; + + foreach (array('hostname', 'port', 'namespace') as $variable) + { + if (isset($datasource[$variable])) + { + $this->$variable = $datasource[$variable]; + } + } + } + } + + if ($this->namespace != '') + { + $this->namespace .= '-'; + } + } + + /** + * Destructor + * + * Closes the connection when the object dies. + */ + public function __destruct() + { + if ($this->connection) + { + $this->connection->close(); + } + } + + /** + * Get Instance + * + * Let's the parent class do all the work. + * + * @static + * @param string $class name of the class to instantiate + * @return object self::$instance instance of the Cache class + */ + public static function getInstance($class = 'Cache') + { + return parent::getInstance($class); + } + + /** + * Opens Connection + * + * Establishes a connection to the memcached server. + */ + public function open() + { + if ($this->connection === null) + { + $this->connection = new Memcache(); + $this->connection->connect($this->hostname, $this->port); + } + + return true; + } + + /** + * Get Key + * + * Gets the value of the key(s) and returns it. + * + * @param mixed $keys key(s) to retrieve + * @return mixed value(s) of the requested key(s), false if not set + */ + public function get($keys) + { + if ($this->open()) + { + if (is_array($keys)) + { + foreach ($keys as $index => $key) + { + $keys[$index] = strtoupper($this->namespace . $key); + } + } + else + { + $keys = strtoupper($this->namespace . $keys); + } + + return $this->connection->get($keys); + } + + return false; + } + + /** + * Set Key + * + * Sets key to the specified value. I've found that compression can lead to + * issues with integers and can slow down the storage and retrieval of data + * (defeats the purpose of caching if you ask me) and isn't supported. I've + * also been burned by data inadvertantly being cached for infinity, hence + * the 5 minute default. + * + * @param string $key key to set + * @param mixed $value value to set + * @param integer $expiration optional expiration, defaults to 5 minutes + * @return boolean status of writing the data to the key + */ + public function set($key, $value, $expire = 300) + { + $key = strtoupper($key); + + if ($this->open()) + { + return $this->connection->set(strtoupper($this->namespace . $key), $value, 0, $expire); + } + + return false; + } + + /** + * Delete Key + * + * Deletes the specified key(s). + * + * @param mixed $keys key(s) to delete + * @return boolean status of deleting the key + */ + public function delete($keys) + { + if ($this->open()) + { + if (!is_array($keys)) + { + $keys = array($keys); + } + + // Memcache() doesn't let you pass an array to delete all records the same way you can with get() + foreach ($keys as $key) + { + $this->connection->delete(strtoupper($this->namespace . $key)); + } + + return true; + } + + return false; + } + + /** + * Increment Key + * + * Increments the value of an existing key. + * + * @param string $key key to increment + * @return boolean status of incrementing the key + * @todo Wondering if I should check the key and set to 1 if it's new + */ + public function increment($key) + { + if ($this->open()) + { + return $this->connection->increment(strtoupper($this->namespace . $key)); + } + + return false; + } +} + /** * Caching System for PICKLES * @@ -977,6 +1227,256 @@ class Cache extends Object } } +/** + * Caching System for PICKLES + * + * PHP version 5 + * + * Licensed under The MIT License + * Redistribution of these files must retain the above copyright notice. + * + * @author Josh Sherman + * @copyright Copyright 2007-2012, Josh Sherman + * @license http://www.opensource.org/licenses/mit-license.html + * @package PICKLES + * @link https://github.com/joshtronic/pickles + */ + +/** + * Cache Class + * + * Wrapper class for Memcache() to allow for better error handling when the + * Memcached server is unavailable. Designed around the syntax for Memcached() + * to allow for an easier transistion to the aforementioned in the future. I + * don't entirely remember specifics, but the reason for not using Memcached() + * was due to an unexplainable bug in the version in the repository for Ubuntu + * 10.04 LTS. Memcached() does support more of the memcached protocol and will + * eventually be what PICKLES uses. Keys are forced to be uppercase for + * consistencies sake as I've been burned by the case sensitivity due to typos + * in my code. + * + * Requires php5-memcache + * + * @link http://us.php.net/manual/en/book.memcache.php + * @link http://packages.ubuntu.com/lucid/php5-memcache + * @link http://www.memcached.org/ + */ +class Cache extends Object +{ + /** + * Hostname for the Memcached Server + * + * @access private + * @var string + */ + private $hostname = 'localhost'; + + /** + * Port to use to connect + * + * @access private + * @var integer + */ + private $port = 11211; + + /** + * Namespace (prefix) + * + * @access private + * @var string + */ + private $namespace = ''; + + /** + * Connection resource to Memcached + * + * @access private + * @var object + */ + private $connection = null; + + /** + * Constructor + * + * Sets up our connection variables. + * + * @param string $hostname optional hostname to connect to + * @param string $database optional port to use + */ + public function __construct($hostname = null, $port = null) + { + parent::__construct(); + + if ($this->config->pickles['cache']) + { + if (isset($this->config->datasources[$this->config->pickles['cache']])) + { + $datasource = $this->config->datasources[$this->config->pickles['cache']]; + + foreach (array('hostname', 'port', 'namespace') as $variable) + { + if (isset($datasource[$variable])) + { + $this->$variable = $datasource[$variable]; + } + } + } + } + + if ($this->namespace != '') + { + $this->namespace .= '-'; + } + } + + /** + * Destructor + * + * Closes the connection when the object dies. + */ + public function __destruct() + { + if ($this->connection) + { + $this->connection->close(); + } + } + + /** + * Get Instance + * + * Let's the parent class do all the work. + * + * @static + * @param string $class name of the class to instantiate + * @return object self::$instance instance of the Cache class + */ + public static function getInstance($class = 'Cache') + { + return parent::getInstance($class); + } + + /** + * Opens Connection + * + * Establishes a connection to the memcached server. + */ + public function open() + { + if ($this->connection === null) + { + $this->connection = new Memcache(); + $this->connection->connect($this->hostname, $this->port); + } + + return true; + } + + /** + * Get Key + * + * Gets the value of the key(s) and returns it. + * + * @param mixed $keys key(s) to retrieve + * @return mixed value(s) of the requested key(s), false if not set + */ + public function get($keys) + { + if ($this->open()) + { + if (is_array($keys)) + { + foreach ($keys as $index => $key) + { + $keys[$index] = strtoupper($this->namespace . $key); + } + } + else + { + $keys = strtoupper($this->namespace . $keys); + } + + return $this->connection->get($keys); + } + + return false; + } + + /** + * Set Key + * + * Sets key to the specified value. I've found that compression can lead to + * issues with integers and can slow down the storage and retrieval of data + * (defeats the purpose of caching if you ask me) and isn't supported. I've + * also been burned by data inadvertantly being cached for infinity, hence + * the 5 minute default. + * + * @param string $key key to set + * @param mixed $value value to set + * @param integer $expiration optional expiration, defaults to 5 minutes + * @return boolean status of writing the data to the key + */ + public function set($key, $value, $expire = 300) + { + $key = strtoupper($key); + + if ($this->open()) + { + return $this->connection->set(strtoupper($this->namespace . $key), $value, 0, $expire); + } + + return false; + } + + /** + * Delete Key + * + * Deletes the specified key(s). + * + * @param mixed $keys key(s) to delete + * @return boolean status of deleting the key + */ + public function delete($keys) + { + if ($this->open()) + { + if (!is_array($keys)) + { + $keys = array($keys); + } + + // Memcache() doesn't let you pass an array to delete all records the same way you can with get() + foreach ($keys as $key) + { + $this->connection->delete(strtoupper($this->namespace . $key)); + } + + return true; + } + + return false; + } + + /** + * Increment Key + * + * Increments the value of an existing key. + * + * @param string $key key to increment + * @return boolean status of incrementing the key + * @todo Wondering if I should check the key and set to 1 if it's new + */ + public function increment($key) + { + if ($this->open()) + { + return $this->connection->increment(strtoupper($this->namespace . $key)); + } + + return false; + } +} + /** * Configuration Class File for PICKLES *