refactoring. added redis drivers.
This commit is contained in:
@@ -3,92 +3,87 @@
|
||||
class Redis {
|
||||
|
||||
/**
|
||||
* The name of the Redis connection.
|
||||
* The address for the Redis host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
protected $host;
|
||||
|
||||
/**
|
||||
* The configuration array for the Redis connection.
|
||||
* The port on which Redis can be accessed on the host.
|
||||
*
|
||||
* @var array
|
||||
* @var int
|
||||
*/
|
||||
public $config = array();
|
||||
protected $port;
|
||||
|
||||
/**
|
||||
* The connection to the Redis database.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected static $connection;
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The active Redis database instances.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $databases = array();
|
||||
|
||||
/**
|
||||
* Create a new Redis connection instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $config
|
||||
* @param string $host
|
||||
* @param string $port
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name, $config)
|
||||
public function __construct($host, $port)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->config = $config;
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Redis connection instance.
|
||||
* Get a Redis database connection instance.
|
||||
*
|
||||
* @param string $connection
|
||||
* @param array $config
|
||||
* The given name should correspond to a Redis database in the configuration file.
|
||||
*
|
||||
* <code>
|
||||
* // Get the default Redis database instance
|
||||
* $redis = Redis::db();
|
||||
*
|
||||
* // Get a specified Redis database instance
|
||||
* $reids = Redis::db('redis_2');
|
||||
* </code>
|
||||
*
|
||||
* @param string $name
|
||||
* @return Redis
|
||||
*/
|
||||
public static function make($name, $config)
|
||||
public static function db($name = 'default')
|
||||
{
|
||||
return new static($name, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Redis connection instance.
|
||||
*
|
||||
* The Redis connection is managed as a singleton, so if the connection has
|
||||
* already been established, that same connection instance will be returned
|
||||
* on subsequent requests for the connection.
|
||||
*
|
||||
* @param string $connection
|
||||
* @return Redis
|
||||
*/
|
||||
public static function connection()
|
||||
{
|
||||
if (is_null(static::$connection))
|
||||
if (is_null(static::$databases[$name]))
|
||||
{
|
||||
static::$connection = static::make($name, Config::get('database.redis'))->connect();
|
||||
if (is_null($config = Config::get("database.redis.{$name}")))
|
||||
{
|
||||
throw new \Exception("Redis database [$name] is not defined.");
|
||||
}
|
||||
|
||||
static::$databases[$name] = new static($config['host'], $config['port']);
|
||||
}
|
||||
|
||||
return static::$connection;
|
||||
return static::$databases[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the Redis database.
|
||||
* Execute a command against the Redis database.
|
||||
*
|
||||
* The Redis instance itself will be returned by the method.
|
||||
* <code>
|
||||
* // Execute the GET command for the "name" key
|
||||
* $name = Redis::db()->run('get', array('name'));
|
||||
*
|
||||
* @return Redis
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
static::$connection = @fsockopen($this->config['host'], $this->config['port'], $error, $message);
|
||||
|
||||
if (static::$connection === false)
|
||||
{
|
||||
throw new \Exception("Error establishing Redis connection [{$this->name}]: {$error} - {$message}");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command agaisnt the Redis database.
|
||||
* // Execute the LRANGE command for the "list" key
|
||||
* $list = Redis::db()->run('lrange', array(0, 5));
|
||||
* </code>
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
@@ -96,21 +91,74 @@ class Redis {
|
||||
*/
|
||||
public function run($method, $parameters)
|
||||
{
|
||||
fwrite(static::$connection, $this->command($method, $parameters));
|
||||
fwrite($this->connect(), $this->command($method, (array) $parameters));
|
||||
|
||||
$reply = trim(fgets(static::$connection, 512));
|
||||
$ersponse = trim(fgets($this->connection, 512));
|
||||
|
||||
switch (substr($ersponse, 0, 1))
|
||||
{
|
||||
case '-':
|
||||
throw new \Exception('Redis error: '.substr(trim($ersponse), 4));
|
||||
|
||||
case '+':
|
||||
case ':':
|
||||
return $this->inline($ersponse);
|
||||
|
||||
case '$':
|
||||
return $this->bulk($ersponse);
|
||||
|
||||
case '*':
|
||||
return $this->multibulk($ersponse);
|
||||
|
||||
default:
|
||||
throw new \Exception("Unknown response from Redis server: ".substr($ersponse, 0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the connection to the Redis database.
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
protected function connect()
|
||||
{
|
||||
if ( ! is_null($this->connection)) return $this->connection;
|
||||
|
||||
$this->connection = @fsockopen($this->host, $this->port, $error, $message);
|
||||
|
||||
if ($this->connection === false)
|
||||
{
|
||||
throw new \Exception("Error making Redis connection: {$error} - {$message}");
|
||||
}
|
||||
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Redis command based from a given method and parameters.
|
||||
*
|
||||
* Redis protocol states that a command should conform to the following format:
|
||||
*
|
||||
* *<number of arguments> CR LF
|
||||
* $<number of bytes of argument 1> CR LF
|
||||
* <argument data> CR LF
|
||||
* ...
|
||||
* $<number of bytes of argument N> CR LF
|
||||
* <argument data> CR LF
|
||||
*
|
||||
* More information regarding the Redis protocol: http://redis.io/topics/protocol
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return string
|
||||
*/
|
||||
protected function command($method, $parameters)
|
||||
{
|
||||
$command = '*'.(count($parameters) + 1).CRLF.'$'.strlen($method).CRLF.strtoupper($method).CRLF;
|
||||
$command = '*'.(count($parameters) + 1).CRLF;
|
||||
|
||||
$command .= '$'.strlen($method).CRLF;
|
||||
|
||||
$command .= strtoupper($method).CRLF;
|
||||
|
||||
foreach ($parameters as $parameter)
|
||||
{
|
||||
@@ -120,6 +168,73 @@ class Redis {
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and handle an inline response from the Redis database.
|
||||
*
|
||||
* @param string $response
|
||||
* @return string
|
||||
*/
|
||||
protected function inline($response)
|
||||
{
|
||||
return substr(trim($response), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and handle a bulk response from the Redis database.
|
||||
*
|
||||
* @param string $head
|
||||
* @return string
|
||||
*/
|
||||
protected function bulk($head)
|
||||
{
|
||||
if ($head == '$-1') return;
|
||||
|
||||
list($read, $response, $size) = array(0, '', substr($head, 1));
|
||||
|
||||
do
|
||||
{
|
||||
// Calculate and read the appropriate bytes off of the Redis response.
|
||||
// We'll read off the response in 1024 byte chunks until the entire
|
||||
// response has been read from the database.
|
||||
$block = (($remaining = $size - $read) < 1024) ? $remaining : 1024;
|
||||
|
||||
$response .= fread($this->connection, $block);
|
||||
|
||||
$read += $block;
|
||||
|
||||
} while ($read < $size);
|
||||
|
||||
// The response ends with a trailing CRLF. So, we need to read that off
|
||||
// of the end of the file stream to get it out of the way of the next
|
||||
// command that is issued to the database.
|
||||
fread($this->connection, 2);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and handle a multi-bulk reply from the Redis database.
|
||||
*
|
||||
* @param string $head
|
||||
* @return array
|
||||
*/
|
||||
protected function multibulk($head)
|
||||
{
|
||||
if (($count = substr($head, 1)) == '-1') return;
|
||||
|
||||
$response = array();
|
||||
|
||||
// Iterate through each bulk response in the multi-bulk and parse it out
|
||||
// using the "bulk" method since a multi-bulk response is just a list of
|
||||
// plain old bulk responses.
|
||||
for ($i = 0; $i < $count; $i++)
|
||||
{
|
||||
$response[] = $this->bulk(trim(fgets($this->connection, 512)));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically make calls to the Redis database.
|
||||
*/
|
||||
@@ -128,6 +243,14 @@ class Redis {
|
||||
return $this->run($method, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically pass static method calls to the Redis instance.
|
||||
*/
|
||||
public static function __callStatic($method, $parameters)
|
||||
{
|
||||
return static::db()->run($method, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection to the Redis database.
|
||||
*
|
||||
@@ -135,7 +258,7 @@ class Redis {
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
fclose(static::$connection);
|
||||
fclose($this->connection);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user