mirror of
https://github.com/predis/predis.git
synced 2026-08-17 23:24:55 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4bc6f588fc | |||
| 2522a249f3 | |||
| b4e1cfcee7 | |||
| 105bf8a2ee | |||
| 4f16e232a8 | |||
| 703c3ceb90 | |||
| ca2e4aa4a1 | |||
| 477056b862 | |||
| b94e002e90 | |||
| 3aff21f8cc | |||
| 1e142a63e6 | |||
| b67dab9ab1 | |||
| 6ba1890da9 | |||
| ca8ba35fb5 | |||
| 5af2b628f1 | |||
| f4c58b926b | |||
| cb390cf292 | |||
| 74cc0e3225 | |||
| b5ae1b9a2b | |||
| 31c47362fb | |||
| 871f1a3a1d | |||
| ba0338e3d8 | |||
| a7c906ab4c | |||
| 7675bb040a | |||
| 930af24c7f | |||
| 23ed563e45 | |||
| f00bf6443d | |||
| 6d73f4a538 | |||
| f0f3d7814c | |||
| 5c2704c9d4 | |||
| effefcee34 | |||
| 86bf223ec0 |
+29
-2
@@ -1,8 +1,30 @@
|
||||
v0.7.2 (2012-xx-xx)
|
||||
v0.7.3 (2012-06-01)
|
||||
===============================================================================
|
||||
|
||||
- New commands available in the Redis v2.6 profile (dev): `BITOP`, `BITCOUNT`.
|
||||
|
||||
- When the number of keys `Predis\Commands\ScriptedCommand` is negative, Predis
|
||||
will count from the end of the arguments list to calculate the actual number
|
||||
of keys that will be interpreted as elements for `KEYS` by the underlying
|
||||
`EVAL` command.
|
||||
|
||||
- __FIX__: `examples\CustomDistributionStrategy.php` had a mistyped constructor
|
||||
call and produced a bad distribution due to an error as pointed in ISSUE #63.
|
||||
This bug is limited to the above mentioned example and does not affect the
|
||||
classes implemented in the `Predis\Distribution` namespace.
|
||||
|
||||
- __FIX__: `Predis\Commands\ServerEvalSHA::getScriptHash()` was calculating the
|
||||
hash while it just needs to return the first argument of the command.
|
||||
|
||||
- __FIX__: `Predis\Autoloader` has been modified to allow cascading autoloaders
|
||||
for the `Predis` namespace.
|
||||
|
||||
|
||||
v0.7.2 (2012-04-01)
|
||||
===============================================================================
|
||||
|
||||
- Added `2.6` in the server profiles aliases list for the upcoming Redis 2.6.
|
||||
`2.4` is still the default server profile.
|
||||
`2.4` is still the default server profile. `dev` now targets Redis 2.8.
|
||||
|
||||
- Connection instances can be serialized and unserialized using `serialize()`
|
||||
and `unserialize()`. This is handy in certain scenarios such as client-side
|
||||
@@ -10,6 +32,11 @@ v0.7.2 (2012-xx-xx)
|
||||
object with many sub-connections since unserializing them can be up to 5x
|
||||
times faster.
|
||||
|
||||
- Reworked the default autoloader to make it faster. It is also possible to
|
||||
prepend it in PHP's autoload stack.
|
||||
|
||||
- __FIX__: fixed parsing of the payload returned by `MONITOR` with Redis 2.6.
|
||||
|
||||
|
||||
v0.7.1 (2011-12-27)
|
||||
===============================================================================
|
||||
|
||||
@@ -56,3 +56,45 @@ generalized when using Redis because of the many possible access patterns for th
|
||||
mean that it is impossible to have such a feature, you can leverage Predis' extensibility to define your
|
||||
own serialization-aware commands. See [here](http://github.com/nrk/predis/issues/29#issuecomment-1202624)
|
||||
for more details on how to implement such a feature with a practical example.
|
||||
|
||||
|
||||
### How can I force Predis to connect to Redis before sending any command? ###
|
||||
|
||||
Explicitly connecting to Redis is usually not needed since the client library relies on lazily initialized
|
||||
connections to the server, but this behavior can be inconvenient in certain scenarios when you absolutely
|
||||
need to do an upfront check to detect if the server is up and running and eventually catch exceptions on
|
||||
failures. In this case developers can use `Predis\Client::connect()` to explicitly connect to the server:
|
||||
|
||||
```
|
||||
$client = new Predis\Client();
|
||||
|
||||
try {
|
||||
$client->connect();
|
||||
}
|
||||
catch (Predis\Network\ConnectionException $exception) {
|
||||
// We could not connect to Redis! Your handling code goes here.
|
||||
}
|
||||
|
||||
$client->info();
|
||||
```
|
||||
|
||||
|
||||
### How Predis implements abstraction of Redis commands? ###
|
||||
|
||||
The approach used in Predis to implement the abstraction of Redis commands is quite simple. By default
|
||||
every command in the library follows exactly the same argument list as defined in the great online
|
||||
[Redis documentation](http://redis.io/commands) which makes things pretty easy if you already know how
|
||||
Redis works or if you need to look up how to use certain commands. Alternatively, variadic commands can
|
||||
accept an array for keys or values (depending on the command) instead of a list of arguments. See for
|
||||
example how [RPUSH](http://redis.io/commands/rpush) or [HMSET](http://redis.io/commands/hmset) work:
|
||||
|
||||
```
|
||||
$client->rpush('my:list', 'value1', 'value2', 'value3'); // values as arguments
|
||||
$client->rpush('my:list', array('value1', 'value2', 'value3')); // values as single argument array
|
||||
|
||||
$client->hmset('my:hash', 'field1', 'value1', 'field2', 'value2'); // values as arguments
|
||||
$client->hmset('my:hash', array('field1'=>'value1', 'field2'=>'value2'); // values as single named array
|
||||
```
|
||||
|
||||
The only exception to this _rule_ is the [SORT](http://redis.io/commands/sort) command for which modifiers are
|
||||
[passed using a named array](https://github.com/nrk/predis/blob/v0.7.1/tests/Predis/Commands/KeySortTest.php#L56-77).
|
||||
|
||||
@@ -5,13 +5,12 @@ Predis is a flexible and feature-complete PHP (>= 5.3) client library for the Re
|
||||
For a list of frequently asked questions about Predis, see the __FAQ__ file in the root of the repository.
|
||||
For a version compatible with PHP 5.2 you must use the backported version from the latest release in the
|
||||
0.6.x series. More details are available on the [official wiki](http://wiki.github.com/nrk/predis) of the
|
||||
project,
|
||||
project.
|
||||
|
||||
|
||||
## Main features ##
|
||||
|
||||
- Complete support for Redis from __1.2__ to __2.4__ and the current development versions using different
|
||||
server profiles.
|
||||
- Complete support for Redis from __1.2__ to __2.6__ and unstable versions using different server profiles.
|
||||
- Client-side sharding with support for consistent hashing or custom distribution strategies.
|
||||
- Support for master / slave replication configurations (write on master, read from slaves).
|
||||
- Command pipelining on single and aggregated connections.
|
||||
@@ -35,7 +34,7 @@ by browsing the list of [tagged releases](http://github.com/nrk/predis/tags).
|
||||
|
||||
### Loading the library ###
|
||||
|
||||
To automatically load all of its files, Predis relies on the autoloading features of PHP and complies
|
||||
Predis relies on the autoloading features of PHP to automatically load the needed files and complies
|
||||
with the [PSR-0 standard](http://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) for
|
||||
interoperability with most of the major frameworks and libraries. Everything is transparently handled
|
||||
for you when installing the library using Composer, but you can also leverage its own autoloader class
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
* Documentation! The README is obviously not enought to show how to use Predis
|
||||
as it does not cover all of its features.
|
||||
|
||||
* [v0.8] Implement smart and transparent support for redis-cluster.
|
||||
|
||||
@@ -23,7 +23,7 @@ class NaiveDistributionStrategy implements IDistributionStrategy
|
||||
private $nodes;
|
||||
private $nodesCount;
|
||||
|
||||
public function __constructor()
|
||||
public function __construct()
|
||||
{
|
||||
$this->nodes = array();
|
||||
$this->nodesCount = 0;
|
||||
@@ -51,7 +51,7 @@ class NaiveDistributionStrategy implements IDistributionStrategy
|
||||
throw new RuntimeException('No connections');
|
||||
}
|
||||
|
||||
return $this->nodes[$count > 1 ? abs(crc32($key) % $count) : 0];
|
||||
return $this->nodes[$count > 1 ? abs($key % $count) : 0];
|
||||
}
|
||||
|
||||
public function generateKey($value)
|
||||
|
||||
@@ -20,30 +20,47 @@ require 'SharedConfigurations.php';
|
||||
|
||||
use Predis\Commands\ScriptedCommand;
|
||||
|
||||
class IncrementExistingKey extends ScriptedCommand
|
||||
class IncrementExistingKeysBy extends ScriptedCommand
|
||||
{
|
||||
public function getKeysCount()
|
||||
{
|
||||
return 1;
|
||||
// Tell Predis to use all the arguments but the last one as arguments
|
||||
// for KEYS. The last one will be used to populate ARGV.
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function getScript()
|
||||
{
|
||||
return
|
||||
<<<LUA
|
||||
local cmd = redis.call
|
||||
if cmd('exists', KEYS[1]) == 1 then
|
||||
return cmd('incr', KEYS[1])
|
||||
end
|
||||
local cmd, insert = redis.call, table.insert
|
||||
local increment, results = ARGV[1], { }
|
||||
|
||||
for idx, key in ipairs(KEYS) do
|
||||
if cmd('exists', key) == 1 then
|
||||
insert(results, idx, cmd('incrby', key, increment))
|
||||
else
|
||||
insert(results, idx, false)
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
LUA;
|
||||
}
|
||||
}
|
||||
|
||||
$client = new Predis\Client($single_server, '2.6');
|
||||
|
||||
$client->getProfile()->defineCommand('increx', 'IncrementExistingKey');
|
||||
$client->getProfile()->defineCommand('increxby', 'IncrementExistingKeysBy');
|
||||
|
||||
$client->set('foo', 10);
|
||||
$client->mset('foo', 10, 'foobar', 100);
|
||||
|
||||
var_dump($client->increx('foo')); // int(11)
|
||||
var_dump($client->increx('bar')); // NULL
|
||||
var_export($client->increxby('foo', 'foofoo', 'foobar', 50));
|
||||
|
||||
/*
|
||||
array (
|
||||
0 => 60,
|
||||
1 => NULL,
|
||||
2 => 150,
|
||||
)
|
||||
*/
|
||||
|
||||
+16
-12
@@ -15,27 +15,32 @@ namespace Predis;
|
||||
* Implements a lightweight PSR-0 compliant autoloader.
|
||||
*
|
||||
* @author Eric Naeseth <eric@thumbtack.com>
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class Autoloader
|
||||
{
|
||||
private $baseDir;
|
||||
private $directory;
|
||||
private $prefix;
|
||||
private $prefixLength;
|
||||
|
||||
/**
|
||||
* @param string $baseDirectory Base directory where the source files are located.
|
||||
*/
|
||||
public function __construct($baseDirectory = null)
|
||||
public function __construct($baseDirectory = __DIR__)
|
||||
{
|
||||
$this->baseDir = $baseDirectory ?: dirname(__FILE__);
|
||||
$this->directory = $baseDirectory;
|
||||
$this->prefix = __NAMESPACE__ . '\\';
|
||||
$this->prefixLength = strlen($this->prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the autoloader class with the PHP SPL autoloader.
|
||||
*
|
||||
* @param boolean $prepend Prepend the autoloader on the stack instead of appending it.
|
||||
*/
|
||||
public static function register()
|
||||
public static function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array(new self, 'autoload'));
|
||||
spl_autoload_register(array(new self, 'autoload'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,13 +50,12 @@ class Autoloader
|
||||
*/
|
||||
public function autoload($className)
|
||||
{
|
||||
if (0 !== strpos($className, $this->prefix)) {
|
||||
return;
|
||||
if (0 === strpos($className, $this->prefix)) {
|
||||
$parts = explode('\\', substr($className, $this->prefixLength));
|
||||
$filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php';
|
||||
if (is_file($filepath)) {
|
||||
require($filepath);
|
||||
}
|
||||
}
|
||||
|
||||
$relativeClassName = substr($className, strlen($this->prefix));
|
||||
$classNameParts = explode('\\', $relativeClassName);
|
||||
|
||||
require_once $this->baseDir.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $classNameParts).'.php';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ use Predis\Transaction\MultiExecContext;
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
const VERSION = '0.7.2-dev';
|
||||
const VERSION = '0.7.3';
|
||||
|
||||
private $options;
|
||||
private $profile;
|
||||
|
||||
@@ -67,6 +67,24 @@ class PrefixHelpers
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified prefix to all the arguments but the first one.
|
||||
*
|
||||
* @param ICommand $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function skipFirst(ICommand $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$length = count($arguments);
|
||||
|
||||
for ($i = 1; $i < $length; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified prefix to all the arguments but the last one.
|
||||
*
|
||||
|
||||
@@ -60,8 +60,13 @@ abstract class ScriptedCommand extends ServerEval
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
$header = array($this->getScript(), ($keys = $this->getKeysCount()) !== false ? $keys : count($arguments));
|
||||
if (false !== $numkeys = $this->getKeysCount()) {
|
||||
$numkeys = $numkeys >= 0 ? $numkeys : count($arguments) + $numkeys;
|
||||
}
|
||||
else {
|
||||
$numkeys = count($arguments);
|
||||
}
|
||||
|
||||
return array_merge($header, $arguments);
|
||||
return array_merge(array($this->getScript(), $numkeys), $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,14 @@ class ServerEvalSHA extends ServerEval
|
||||
{
|
||||
return 'EVALSHA';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA1 hash of the body of the script.
|
||||
*
|
||||
* @return string SHA1 hash.
|
||||
*/
|
||||
public function getScriptHash()
|
||||
{
|
||||
return $this->getArgument(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/time
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerTime extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'TIME';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return $data instanceof \Iterator ? iterator_to_array($data) : $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/bitcount
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class StringBitCount extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'BITCOUNT';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/bitop
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class StringBitOp extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'BITOP';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 3 && is_array($arguments[2])) {
|
||||
list($operation, $destination, ) = $arguments;
|
||||
$arguments = $arguments[2];
|
||||
array_unshift($arguments, $operation, $destination);
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::skipFirst($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return $this->checkSameHashForKeys(
|
||||
array_slice(($args = $this->getArguments()), 1, count($args))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,16 @@ abstract class MultiBulkResponse implements \Iterator, \Countable
|
||||
return $this->replySize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position of the iterator.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPosition()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ class MultiBulkResponseTuple extends MultiBulkResponse implements \OuterIterator
|
||||
{
|
||||
$virtualSize = count($iterator) / 2;
|
||||
$this->iterator = $iterator;
|
||||
$this->position = 0;
|
||||
$this->position = $iterator->getPosition();
|
||||
$this->current = $virtualSize > 0 ? $this->getValue() : null;
|
||||
$this->replySize = $virtualSize;
|
||||
}
|
||||
|
||||
@@ -132,21 +132,29 @@ class MonitorContext implements \Iterator
|
||||
private function getValue()
|
||||
{
|
||||
$database = 0;
|
||||
$client = null;
|
||||
$event = $this->client->getConnection()->read();
|
||||
|
||||
$callback = function($matches) use (&$database) {
|
||||
if (isset($matches[1])) {
|
||||
$callback = function($matches) use (&$database, &$client) {
|
||||
if (2 === $count = count($matches)) {
|
||||
// Redis <= 2.4
|
||||
$database = (int) $matches[1];
|
||||
}
|
||||
if (4 === $count) {
|
||||
// Redis >= 2.6
|
||||
$database = (int) $matches[2];
|
||||
$client = $matches[3];
|
||||
}
|
||||
return ' ';
|
||||
};
|
||||
|
||||
$event = preg_replace_callback('/ \(db (\d+)\) /', $callback, $event, 1);
|
||||
@list($timestamp, $command, $arguments) = split(' ', $event, 3);
|
||||
$event = preg_replace_callback('/ \(db (\d+)\) | \[(\d+) (.*?)\] /', $callback, $event, 1);
|
||||
@list($timestamp, $command, $arguments) = explode(' ', $event, 3);
|
||||
|
||||
return (object) array(
|
||||
'timestamp' => (float) $timestamp,
|
||||
'database' => $database,
|
||||
'client' => $client,
|
||||
'command' => substr($command, 1, -1),
|
||||
'arguments' => $arguments,
|
||||
);
|
||||
|
||||
@@ -409,6 +409,8 @@ class MasterSlaveReplication implements IConnectionReplication
|
||||
'ECHO' => true,
|
||||
'QUIT' => true,
|
||||
'OBJECT' => true,
|
||||
'BITCOUNT' => true,
|
||||
'TIME' => true,
|
||||
'SORT' => array($this, 'isSortReadOnly'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -257,7 +257,8 @@ class PhpiredisConnection extends ConnectionBase
|
||||
* @param IConnectionParameters $parameters Parameters used to initialize the connection.
|
||||
* @return string
|
||||
*/
|
||||
private function connectWithTimeout(IConnectionParameters $parameters) {
|
||||
private function connectWithTimeout(IConnectionParameters $parameters)
|
||||
{
|
||||
$host = self::getAddress($parameters);
|
||||
$socket = $this->getResource();
|
||||
|
||||
|
||||
@@ -186,7 +186,8 @@ class StreamConnection extends ConnectionBase
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read() {
|
||||
public function read()
|
||||
{
|
||||
$socket = $this->getResource();
|
||||
|
||||
$chunk = fgets($socket);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\Network\IConnection;
|
||||
use Predis\Network\IConnectionReplication;
|
||||
|
||||
/**
|
||||
* Implements a pipeline executor strategy that writes a list of commands to
|
||||
@@ -21,11 +22,27 @@ use Predis\Network\IConnection;
|
||||
*/
|
||||
class FireAndForgetExecutor implements IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* Allows the pipeline executor to perform operations on the
|
||||
* connection before starting to execute the commands stored
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param IConnection Connection instance.
|
||||
*/
|
||||
protected function checkConnection(IConnection $connection)
|
||||
{
|
||||
if ($connection instanceof IConnectionReplication) {
|
||||
$connection->switchTo('master');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(IConnection $connection, &$commands)
|
||||
{
|
||||
$this->checkConnection($connection);
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ use Predis\Client;
|
||||
use Predis\Helpers;
|
||||
use Predis\ClientException;
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Network\IConnectionReplication;
|
||||
|
||||
/**
|
||||
* Abstraction of a pipeline context where write and read operations
|
||||
@@ -121,13 +120,6 @@ class PipelineContext
|
||||
if (count($this->pipeline) > 0) {
|
||||
if ($send) {
|
||||
$connection = $this->client->getConnection();
|
||||
|
||||
// TODO: it would be better to use a dedicated pipeline executor
|
||||
// for classes implementing master/slave replication.
|
||||
if ($connection instanceof IConnectionReplication) {
|
||||
$connection->switchTo('master');
|
||||
}
|
||||
|
||||
$replies = $this->executor->execute($connection, $this->pipeline);
|
||||
$this->replies = array_merge($this->replies, $replies);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Predis\Pipeline;
|
||||
|
||||
use Predis\ServerException;
|
||||
use Predis\Network\IConnection;
|
||||
use Predis\Network\IConnectionReplication;
|
||||
|
||||
/**
|
||||
* Implements the standard pipeline executor strategy used
|
||||
@@ -23,6 +24,20 @@ use Predis\Network\IConnection;
|
||||
*/
|
||||
class StandardExecutor implements IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* Allows the pipeline executor to perform operations on the
|
||||
* connection before starting to execute the commands stored
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param IConnection Connection instance.
|
||||
*/
|
||||
protected function checkConnection(IConnection $connection)
|
||||
{
|
||||
if ($connection instanceof IConnectionReplication) {
|
||||
$connection->switchTo('master');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -31,6 +46,8 @@ class StandardExecutor implements IPipelineExecutor
|
||||
$sizeofPipe = count($commands);
|
||||
$values = array();
|
||||
|
||||
$this->checkConnection($connection);
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ abstract class ServerProfile implements IServerProfile, IProcessingSupport
|
||||
'2.0' => 'Predis\Profiles\ServerVersion20',
|
||||
'2.2' => 'Predis\Profiles\ServerVersion22',
|
||||
'2.4' => 'Predis\Profiles\ServerVersion24',
|
||||
'2.6' => 'Predis\Profiles\ServerVersionNext',
|
||||
'2.6' => 'Predis\Profiles\ServerVersion26',
|
||||
'default' => 'Predis\Profiles\ServerVersion24',
|
||||
'dev' => 'Predis\Profiles\ServerVersionNext',
|
||||
);
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
* Server profile for Redis v2.6.x.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerVersion26 extends ServerProfile
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return '2.6';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSupportedCommands()
|
||||
{
|
||||
return array(
|
||||
/* ---------------- Redis 1.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'exists' => 'Predis\Commands\KeyExists',
|
||||
'del' => 'Predis\Commands\KeyDelete',
|
||||
'type' => 'Predis\Commands\KeyType',
|
||||
'keys' => 'Predis\Commands\KeyKeys',
|
||||
'randomkey' => 'Predis\Commands\KeyRandom',
|
||||
'rename' => 'Predis\Commands\KeyRename',
|
||||
'renamenx' => 'Predis\Commands\KeyRenamePreserve',
|
||||
'expire' => 'Predis\Commands\KeyExpire',
|
||||
'expireat' => 'Predis\Commands\KeyExpireAt',
|
||||
'ttl' => 'Predis\Commands\KeyTimeToLive',
|
||||
'move' => 'Predis\Commands\KeyMove',
|
||||
'sort' => 'Predis\Commands\KeySort',
|
||||
|
||||
/* commands operating on string values */
|
||||
'set' => 'Predis\Commands\StringSet',
|
||||
'setnx' => 'Predis\Commands\StringSetPreserve',
|
||||
'mset' => 'Predis\Commands\StringSetMultiple',
|
||||
'msetnx' => 'Predis\Commands\StringSetMultiplePreserve',
|
||||
'get' => 'Predis\Commands\StringGet',
|
||||
'mget' => 'Predis\Commands\StringGetMultiple',
|
||||
'getset' => 'Predis\Commands\StringGetSet',
|
||||
'incr' => 'Predis\Commands\StringIncrement',
|
||||
'incrby' => 'Predis\Commands\StringIncrementBy',
|
||||
'decr' => 'Predis\Commands\StringDecrement',
|
||||
'decrby' => 'Predis\Commands\StringDecrementBy',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpush' => 'Predis\Commands\ListPushTail',
|
||||
'lpush' => 'Predis\Commands\ListPushHead',
|
||||
'llen' => 'Predis\Commands\ListLength',
|
||||
'lrange' => 'Predis\Commands\ListRange',
|
||||
'ltrim' => 'Predis\Commands\ListTrim',
|
||||
'lindex' => 'Predis\Commands\ListIndex',
|
||||
'lset' => 'Predis\Commands\ListSet',
|
||||
'lrem' => 'Predis\Commands\ListRemove',
|
||||
'lpop' => 'Predis\Commands\ListPopFirst',
|
||||
'rpop' => 'Predis\Commands\ListPopLast',
|
||||
'rpoplpush' => 'Predis\Commands\ListPopLastPushHead',
|
||||
|
||||
/* commands operating on sets */
|
||||
'sadd' => 'Predis\Commands\SetAdd',
|
||||
'srem' => 'Predis\Commands\SetRemove',
|
||||
'spop' => 'Predis\Commands\SetPop',
|
||||
'smove' => 'Predis\Commands\SetMove',
|
||||
'scard' => 'Predis\Commands\SetCardinality',
|
||||
'sismember' => 'Predis\Commands\SetIsMember',
|
||||
'sinter' => 'Predis\Commands\SetIntersection',
|
||||
'sinterstore' => 'Predis\Commands\SetIntersectionStore',
|
||||
'sunion' => 'Predis\Commands\SetUnion',
|
||||
'sunionstore' => 'Predis\Commands\SetUnionStore',
|
||||
'sdiff' => 'Predis\Commands\SetDifference',
|
||||
'sdiffstore' => 'Predis\Commands\SetDifferenceStore',
|
||||
'smembers' => 'Predis\Commands\SetMembers',
|
||||
'srandmember' => 'Predis\Commands\SetRandomMember',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zadd' => 'Predis\Commands\ZSetAdd',
|
||||
'zincrby' => 'Predis\Commands\ZSetIncrementBy',
|
||||
'zrem' => 'Predis\Commands\ZSetRemove',
|
||||
'zrange' => 'Predis\Commands\ZSetRange',
|
||||
'zrevrange' => 'Predis\Commands\ZSetReverseRange',
|
||||
'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore',
|
||||
'zcard' => 'Predis\Commands\ZSetCardinality',
|
||||
'zscore' => 'Predis\Commands\ZSetScore',
|
||||
'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore',
|
||||
|
||||
/* connection related commands */
|
||||
'ping' => 'Predis\Commands\ConnectionPing',
|
||||
'auth' => 'Predis\Commands\ConnectionAuth',
|
||||
'select' => 'Predis\Commands\ConnectionSelect',
|
||||
'echo' => 'Predis\Commands\ConnectionEcho',
|
||||
'quit' => 'Predis\Commands\ConnectionQuit',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfo',
|
||||
'slaveof' => 'Predis\Commands\ServerSlaveOf',
|
||||
'monitor' => 'Predis\Commands\ServerMonitor',
|
||||
'dbsize' => 'Predis\Commands\ServerDatabaseSize',
|
||||
'flushdb' => 'Predis\Commands\ServerFlushDatabase',
|
||||
'flushall' => 'Predis\Commands\ServerFlushAll',
|
||||
'save' => 'Predis\Commands\ServerSave',
|
||||
'bgsave' => 'Predis\Commands\ServerBackgroundSave',
|
||||
'lastsave' => 'Predis\Commands\ServerLastSave',
|
||||
'shutdown' => 'Predis\Commands\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
'setex' => 'Predis\Commands\StringSetExpire',
|
||||
'append' => 'Predis\Commands\StringAppend',
|
||||
'substr' => 'Predis\Commands\StringSubstr',
|
||||
|
||||
/* commands operating on lists */
|
||||
'blpop' => 'Predis\Commands\ListPopFirstBlocking',
|
||||
'brpop' => 'Predis\Commands\ListPopLastBlocking',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zunionstore' => 'Predis\Commands\ZSetUnionStore',
|
||||
'zinterstore' => 'Predis\Commands\ZSetIntersectionStore',
|
||||
'zcount' => 'Predis\Commands\ZSetCount',
|
||||
'zrank' => 'Predis\Commands\ZSetRank',
|
||||
'zrevrank' => 'Predis\Commands\ZSetReverseRank',
|
||||
'zremrangebyrank' => 'Predis\Commands\ZSetRemoveRangeByRank',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hset' => 'Predis\Commands\HashSet',
|
||||
'hsetnx' => 'Predis\Commands\HashSetPreserve',
|
||||
'hmset' => 'Predis\Commands\HashSetMultiple',
|
||||
'hincrby' => 'Predis\Commands\HashIncrementBy',
|
||||
'hget' => 'Predis\Commands\HashGet',
|
||||
'hmget' => 'Predis\Commands\HashGetMultiple',
|
||||
'hdel' => 'Predis\Commands\HashDelete',
|
||||
'hexists' => 'Predis\Commands\HashExists',
|
||||
'hlen' => 'Predis\Commands\HashLength',
|
||||
'hkeys' => 'Predis\Commands\HashKeys',
|
||||
'hvals' => 'Predis\Commands\HashValues',
|
||||
'hgetall' => 'Predis\Commands\HashGetAll',
|
||||
|
||||
/* transactions */
|
||||
'multi' => 'Predis\Commands\TransactionMulti',
|
||||
'exec' => 'Predis\Commands\TransactionExec',
|
||||
'discard' => 'Predis\Commands\TransactionDiscard',
|
||||
|
||||
/* publish - subscribe */
|
||||
'subscribe' => 'Predis\Commands\PubSubSubscribe',
|
||||
'unsubscribe' => 'Predis\Commands\PubSubUnsubscribe',
|
||||
'psubscribe' => 'Predis\Commands\PubSubSubscribeByPattern',
|
||||
'punsubscribe' => 'Predis\Commands\PubSubUnsubscribeByPattern',
|
||||
'publish' => 'Predis\Commands\PubSubPublish',
|
||||
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Commands\ServerConfig',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'persist' => 'Predis\Commands\KeyPersist',
|
||||
|
||||
/* commands operating on string values */
|
||||
'strlen' => 'Predis\Commands\StringStrlen',
|
||||
'setrange' => 'Predis\Commands\StringSetRange',
|
||||
'getrange' => 'Predis\Commands\StringGetRange',
|
||||
'setbit' => 'Predis\Commands\StringSetBit',
|
||||
'getbit' => 'Predis\Commands\StringGetBit',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpushx' => 'Predis\Commands\ListPushTailX',
|
||||
'lpushx' => 'Predis\Commands\ListPushHeadX',
|
||||
'linsert' => 'Predis\Commands\ListInsert',
|
||||
'brpoplpush' => 'Predis\Commands\ListPopLastPushHeadBlocking',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zrevrangebyscore' => 'Predis\Commands\ZSetReverseRangeByScore',
|
||||
|
||||
/* transactions */
|
||||
'watch' => 'Predis\Commands\TransactionWatch',
|
||||
'unwatch' => 'Predis\Commands\TransactionUnwatch',
|
||||
|
||||
/* remote server control commands */
|
||||
'object' => 'Predis\Commands\ServerObject',
|
||||
'slowlog' => 'Predis\Commands\ServerSlowlog',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.4 ---------------- */
|
||||
|
||||
/* remote server control commands */
|
||||
'client' => 'Predis\Commands\ServerClient',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.6 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'pttl' => 'Predis\Commands\KeyPreciseTimeToLive',
|
||||
'pexpire' => 'Predis\Commands\KeyPreciseExpire',
|
||||
'pexpireat' => 'Predis\Commands\KeyPreciseExpireAt',
|
||||
|
||||
/* commands operating on string values */
|
||||
'psetex' => 'Predis\Commands\StringPreciseSetExpire',
|
||||
'incrbyfloat' => 'Predis\Commands\StringIncrementByFloat',
|
||||
'bitop' => 'Predis\Commands\StringBitOp',
|
||||
'bitcount' => 'Predis\Commands\StringBitCount',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hincrbyfloat' => 'Predis\Commands\HashIncrementByFloat',
|
||||
|
||||
/* scripting */
|
||||
'eval' => 'Predis\Commands\ServerEval',
|
||||
'evalsha' => 'Predis\Commands\ServerEvalSHA',
|
||||
'script' => 'Predis\Commands\ServerScript',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfoV26x',
|
||||
'time' => 'Predis\Commands\ServerTime',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,18 +12,18 @@
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
* Server profile for the current development version of Redis.
|
||||
* Server profile for the current unstable version of Redis.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerVersionNext extends ServerVersion24
|
||||
class ServerVersionNext extends ServerVersion26
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return '2.6';
|
||||
return '2.8';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,25 +32,6 @@ class ServerVersionNext extends ServerVersion24
|
||||
public function getSupportedCommands()
|
||||
{
|
||||
return array_merge(parent::getSupportedCommands(), array(
|
||||
/* commands operating on the key space */
|
||||
'pttl' => 'Predis\Commands\KeyPreciseTimeToLive',
|
||||
'pexpire' => 'Predis\Commands\KeyPreciseExpire',
|
||||
'pexpireat' => 'Predis\Commands\KeyPreciseExpireAt',
|
||||
|
||||
/* commands operating on string values */
|
||||
'psetex' => 'Predis\Commands\StringPreciseSetExpire',
|
||||
'incrbyfloat' => 'Predis\Commands\StringIncrementByFloat',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hincrbyfloat' => 'Predis\Commands\HashIncrementByFloat',
|
||||
|
||||
/* scripting */
|
||||
'eval' => 'Predis\Commands\ServerEval',
|
||||
'evalsha' => 'Predis\Commands\ServerEvalSHA',
|
||||
'script' => 'Predis\Commands\ServerScript',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfoV26x',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -1,9 +1,8 @@
|
||||
; This file is meant to be used with Onion http://c9s.github.com/Onion/
|
||||
; In order to be able to build a PEAR package of Predis, open a new terminal
|
||||
; session and follow these two easy steps:
|
||||
; For instructions on how to build a PEAR package of Predis please follow
|
||||
; the instructions at this URL:
|
||||
;
|
||||
; $ wget https://github.com/c9s/Onion/raw/master/onion.phar
|
||||
; $ /usr/bin/env php onion.phar build
|
||||
; https://github.com/c9s/Onion#a-quick-tutorial-for-building-pear-package
|
||||
;
|
||||
|
||||
[package]
|
||||
@@ -11,8 +10,8 @@ name = "Predis"
|
||||
desc = "Flexible and feature-complete PHP client library for Redis"
|
||||
homepage = "http://github.com/nrk/predis"
|
||||
license = "MIT"
|
||||
version = "0.7.2"
|
||||
stability = "beta"
|
||||
version = "0.7.3"
|
||||
stability = "stable"
|
||||
channel = "pear.nrk.io"
|
||||
|
||||
author = "Daniele Alessandri \"nrk\" <suppakilla@gmail.com>"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<group>ext-phpiredis</group>
|
||||
<group>ext-curl</group>
|
||||
<group>realm-webdis</group>
|
||||
<group>connected</group>
|
||||
<!-- <group>connected</group> -->
|
||||
<!-- <group>disconnected</group> -->
|
||||
<!-- <group>commands</group> -->
|
||||
<!-- <group>slow</group> -->
|
||||
|
||||
@@ -39,6 +39,25 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame(array_merge(array(self::LUA_SCRIPT, 2), $arguments), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetArgumentsWithNegativeKeysCount()
|
||||
{
|
||||
$arguments = array('key1', 'key2', 'value1', 'value2');
|
||||
|
||||
$command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue(self::LUA_SCRIPT));
|
||||
$command->expects($this->once())
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(-2));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame(array_merge(array(self::LUA_SCRIPT, 2), $arguments), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -58,6 +77,25 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame(array('key1', 'key2'), $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetKeysWithNegativeKeysCount()
|
||||
{
|
||||
$arguments = array('key1', 'key2', 'value1', 'value2');
|
||||
|
||||
$command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue(self::LUA_SCRIPT));
|
||||
$command->expects($this->exactly(2))
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(-2));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame(array('key1', 'key2'), $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -80,6 +118,28 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame($expected, $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysWithNegativeKeysCount()
|
||||
{
|
||||
$arguments = array('foo', 'hoge', 'bar', 'piyo');
|
||||
$expected = array('prefix:foo', 'prefix:hoge');
|
||||
|
||||
$command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue(self::LUA_SCRIPT));
|
||||
$command->expects($this->exactly(2))
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(-2));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame($expected, $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -75,6 +75,15 @@ class ServerEvalSHATest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetScriptHash()
|
||||
{
|
||||
$command = $this->getCommandWithArgumentsArray(array($sha1 = sha1('return true')), 0);
|
||||
$this->assertSame($sha1, $command->getScriptHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -64,6 +64,11 @@ class ServerMonitorTest extends CommandTestCase
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertTrue($connection->executeCommand($command));
|
||||
$this->assertRegExp('/\d+.\d+(\s?\(db \d+\))? "MONITOR"/', $connection->read());
|
||||
|
||||
// NOTE: Starting with 2.6 Redis does not return the "MONITOR" message after
|
||||
// +OK to the client that issued the MONITOR command.
|
||||
if (version_compare($this->getProfile()->getVersion(), '2.4', '<=')) {
|
||||
$this->assertRegExp('/\d+.\d+(\s?\(db \d+\))? "MONITOR"/', $connection->read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-server
|
||||
*/
|
||||
class ServerTimeTest extends CommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand()
|
||||
{
|
||||
return 'Predis\Commands\ServerTime';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId()
|
||||
{
|
||||
return 'TIME';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments()
|
||||
{
|
||||
$arguments = array();
|
||||
$expected = array();
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse()
|
||||
{
|
||||
$expected = array(1331114908, 453990);
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($expected));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testReturnsServerTime()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->assertInternalType('array', $time = $redis->time());
|
||||
$this->assertInternalType('string', $time[0]);
|
||||
$this->assertInternalType('string', $time[1]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-string
|
||||
*/
|
||||
class StringBitCountTest extends CommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand()
|
||||
{
|
||||
return 'Predis\Commands\StringBitCount';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId()
|
||||
{
|
||||
return 'BITCOUNT';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments()
|
||||
{
|
||||
$arguments = array('key', 0, 10);
|
||||
$expected = array('key', 0, 10);
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse()
|
||||
{
|
||||
$raw = 10;
|
||||
$expected = 10;
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeys()
|
||||
{
|
||||
$arguments = array('key', 0, 10);
|
||||
$expected = array('prefix:key', 0, 10);
|
||||
|
||||
$command = $this->getCommandWithArgumentsArray($arguments);
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testReturnsNumberOfBitsSet()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->setbit('key', 1, 1);
|
||||
$redis->setbit('key', 10, 1);
|
||||
$redis->setbit('key', 16, 1);
|
||||
$redis->setbit('key', 22, 1);
|
||||
$redis->setbit('key', 32, 1);
|
||||
|
||||
$this->assertSame(5, $redis->bitcount('key'), 'Count bits set (without range)');
|
||||
$this->assertSame(3, $redis->bitcount('key', 2, 4), 'Count bits set (with range)');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->lpush('key', 'list');
|
||||
$redis->bitcount('key');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-string
|
||||
*/
|
||||
class StringBitOpTest extends CommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand()
|
||||
{
|
||||
return 'Predis\Commands\StringBitOp';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId()
|
||||
{
|
||||
return 'BITOP';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments()
|
||||
{
|
||||
$arguments = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
$expected = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArgumentsKeysAsSingleArray()
|
||||
{
|
||||
$arguments = array('AND', 'key:dst', array('key:01', 'key:02'));
|
||||
$expected = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse()
|
||||
{
|
||||
$raw = 10;
|
||||
$expected = 10;
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeys()
|
||||
{
|
||||
$arguments = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
$expected = array('AND', 'prefix:key:dst', 'prefix:key:01', 'prefix:key:02');
|
||||
|
||||
$command = $this->getCommandWithArgumentsArray($arguments);
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseAND()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
$redis->set('key:src:2', "R");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2'));
|
||||
$this->assertSame("@\x00", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseOR()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
$redis->set('key:src:2', "R");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('OR', 'key:dst', 'key:src:1', 'key:src:2'));
|
||||
$this->assertSame("z\x80", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseXOR()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
$redis->set('key:src:2', "R");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('XOR', 'key:dst', 'key:src:1', 'key:src:2'));
|
||||
$this->assertSame(":\x80", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseNOT()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('NOT', 'key:dst', 'key:src:1'));
|
||||
$this->assertSame("\x97\x7f", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR BITOP NOT must be called with a single source key.
|
||||
*/
|
||||
public function testBitwiseNOTAcceptsOnlyOneSourceKey()
|
||||
{
|
||||
$this->getClient()->bitop('NOT', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR syntax error
|
||||
*/
|
||||
public function testThrowsExceptionOnInvalidOperation()
|
||||
{
|
||||
$this->getClient()->bitop('NOOP', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnInvalidSourceKey()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->lpush('key:src:1', 'list');
|
||||
$redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testDoesNotThrowExceptionOnInvalidDestinationKey()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->lpush('key:dst', 'list');
|
||||
$redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
|
||||
$this->assertSame('none', $redis->type('key:dst'));
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ class MonitorContextTest extends StandardTestCase
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testCurrentReadsMessageFromConnection()
|
||||
public function testReadsMessageFromConnectionToRedis24()
|
||||
{
|
||||
$message = '1323367530.939137 (db 15) "MONITOR"';
|
||||
|
||||
@@ -120,6 +120,30 @@ class MonitorContextTest extends StandardTestCase
|
||||
$payload = $monitor->current();
|
||||
$this->assertSame(1323367530, (int) $payload->timestamp);
|
||||
$this->assertSame(15, $payload->database);
|
||||
$this->assertNull($payload->client);
|
||||
$this->assertSame('MONITOR', $payload->command);
|
||||
$this->assertNull($payload->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testReadsMessageFromConnectionToRedis26()
|
||||
{
|
||||
$message = '1323367530.939137 [15 127.0.0.1:37265] "MONITOR"';
|
||||
|
||||
$connection = $this->getMock('Predis\Network\IConnectionSingle');
|
||||
$connection->expects($this->once())
|
||||
->method('read')
|
||||
->will($this->returnValue($message));
|
||||
|
||||
$client = new Client($connection);
|
||||
$monitor = new MonitorContext($client);
|
||||
|
||||
$payload = $monitor->current();
|
||||
$this->assertSame(1323367530, (int) $payload->timestamp);
|
||||
$this->assertSame(15, $payload->database);
|
||||
$this->assertSame('127.0.0.1:37265', $payload->client);
|
||||
$this->assertSame('MONITOR', $payload->command);
|
||||
$this->assertNull($payload->arguments);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ use Predis\Commands\Processors\ProcessorChain;
|
||||
class ServerProfileTest extends StandardTestCase
|
||||
{
|
||||
const DEFAULT_PROFILE_VERSION = '2.4';
|
||||
const DEVELOPMENT_PROFILE_VERSION = '2.6';
|
||||
const DEVELOPMENT_PROFILE_VERSION = '2.8';
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
@@ -145,6 +145,34 @@ class ServerProfileTest extends StandardTestCase
|
||||
$this->assertNull($profile->getCommandClass('UNKNOWN'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testDefineCommand()
|
||||
{
|
||||
$profile = ServerProfile::getDefault();
|
||||
$command = $this->getMock('Predis\Commands\ICommand');
|
||||
|
||||
$profile->defineCommand('mock', get_class($command));
|
||||
|
||||
$this->assertTrue($profile->supportsCommand('mock'));
|
||||
$this->assertTrue($profile->supportsCommand('MOCK'));
|
||||
|
||||
$this->assertSame(get_class($command), $profile->getCommandClass('mock'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Cannot register 'stdClass' as it is not a valid Redis command
|
||||
*/
|
||||
public function testDefineInvalidCommand()
|
||||
{
|
||||
$profile = ServerProfile::getDefault();
|
||||
|
||||
$profile->defineCommand('mock', 'stdClass');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class ServerVersion26Test extends ServerVersionTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProfileInstance()
|
||||
{
|
||||
return new ServerVersion26();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getExpectedVersion()
|
||||
{
|
||||
return '2.6';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getExpectedCommands()
|
||||
{
|
||||
return array(
|
||||
0 => 'exists',
|
||||
1 => 'del',
|
||||
2 => 'type',
|
||||
3 => 'keys',
|
||||
4 => 'randomkey',
|
||||
5 => 'rename',
|
||||
6 => 'renamenx',
|
||||
7 => 'expire',
|
||||
8 => 'expireat',
|
||||
9 => 'ttl',
|
||||
10 => 'move',
|
||||
11 => 'sort',
|
||||
12 => 'set',
|
||||
13 => 'setnx',
|
||||
14 => 'mset',
|
||||
15 => 'msetnx',
|
||||
16 => 'get',
|
||||
17 => 'mget',
|
||||
18 => 'getset',
|
||||
19 => 'incr',
|
||||
20 => 'incrby',
|
||||
21 => 'decr',
|
||||
22 => 'decrby',
|
||||
23 => 'rpush',
|
||||
24 => 'lpush',
|
||||
25 => 'llen',
|
||||
26 => 'lrange',
|
||||
27 => 'ltrim',
|
||||
28 => 'lindex',
|
||||
29 => 'lset',
|
||||
30 => 'lrem',
|
||||
31 => 'lpop',
|
||||
32 => 'rpop',
|
||||
33 => 'rpoplpush',
|
||||
34 => 'sadd',
|
||||
35 => 'srem',
|
||||
36 => 'spop',
|
||||
37 => 'smove',
|
||||
38 => 'scard',
|
||||
39 => 'sismember',
|
||||
40 => 'sinter',
|
||||
41 => 'sinterstore',
|
||||
42 => 'sunion',
|
||||
43 => 'sunionstore',
|
||||
44 => 'sdiff',
|
||||
45 => 'sdiffstore',
|
||||
46 => 'smembers',
|
||||
47 => 'srandmember',
|
||||
48 => 'zadd',
|
||||
49 => 'zincrby',
|
||||
50 => 'zrem',
|
||||
51 => 'zrange',
|
||||
52 => 'zrevrange',
|
||||
53 => 'zrangebyscore',
|
||||
54 => 'zcard',
|
||||
55 => 'zscore',
|
||||
56 => 'zremrangebyscore',
|
||||
57 => 'ping',
|
||||
58 => 'auth',
|
||||
59 => 'select',
|
||||
60 => 'echo',
|
||||
61 => 'quit',
|
||||
62 => 'info',
|
||||
63 => 'slaveof',
|
||||
64 => 'monitor',
|
||||
65 => 'dbsize',
|
||||
66 => 'flushdb',
|
||||
67 => 'flushall',
|
||||
68 => 'save',
|
||||
69 => 'bgsave',
|
||||
70 => 'lastsave',
|
||||
71 => 'shutdown',
|
||||
72 => 'bgrewriteaof',
|
||||
73 => 'setex',
|
||||
74 => 'append',
|
||||
75 => 'substr',
|
||||
76 => 'blpop',
|
||||
77 => 'brpop',
|
||||
78 => 'zunionstore',
|
||||
79 => 'zinterstore',
|
||||
80 => 'zcount',
|
||||
81 => 'zrank',
|
||||
82 => 'zrevrank',
|
||||
83 => 'zremrangebyrank',
|
||||
84 => 'hset',
|
||||
85 => 'hsetnx',
|
||||
86 => 'hmset',
|
||||
87 => 'hincrby',
|
||||
88 => 'hget',
|
||||
89 => 'hmget',
|
||||
90 => 'hdel',
|
||||
91 => 'hexists',
|
||||
92 => 'hlen',
|
||||
93 => 'hkeys',
|
||||
94 => 'hvals',
|
||||
95 => 'hgetall',
|
||||
96 => 'multi',
|
||||
97 => 'exec',
|
||||
98 => 'discard',
|
||||
99 => 'subscribe',
|
||||
100 => 'unsubscribe',
|
||||
101 => 'psubscribe',
|
||||
102 => 'punsubscribe',
|
||||
103 => 'publish',
|
||||
104 => 'config',
|
||||
105 => 'persist',
|
||||
106 => 'strlen',
|
||||
107 => 'setrange',
|
||||
108 => 'getrange',
|
||||
109 => 'setbit',
|
||||
110 => 'getbit',
|
||||
111 => 'rpushx',
|
||||
112 => 'lpushx',
|
||||
113 => 'linsert',
|
||||
114 => 'brpoplpush',
|
||||
115 => 'zrevrangebyscore',
|
||||
116 => 'watch',
|
||||
117 => 'unwatch',
|
||||
118 => 'object',
|
||||
119 => 'slowlog',
|
||||
120 => 'client',
|
||||
121 => 'pttl',
|
||||
122 => 'pexpire',
|
||||
123 => 'pexpireat',
|
||||
124 => 'psetex',
|
||||
125 => 'incrbyfloat',
|
||||
126 => 'bitop',
|
||||
127 => 'bitcount',
|
||||
128 => 'hincrbyfloat',
|
||||
129 => 'eval',
|
||||
130 => 'evalsha',
|
||||
131 => 'script',
|
||||
132 => 'time',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ class ServerVersionNextTest extends ServerVersionTestCase
|
||||
*/
|
||||
public function getExpectedVersion()
|
||||
{
|
||||
return '2.6';
|
||||
return '2.8';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,10 +164,13 @@ class ServerVersionNextTest extends ServerVersionTestCase
|
||||
123 => 'pexpireat',
|
||||
124 => 'psetex',
|
||||
125 => 'incrbyfloat',
|
||||
126 => 'hincrbyfloat',
|
||||
127 => 'eval',
|
||||
128 => 'evalsha',
|
||||
129 => 'script',
|
||||
126 => 'bitop',
|
||||
127 => 'bitcount',
|
||||
128 => 'hincrbyfloat',
|
||||
129 => 'eval',
|
||||
130 => 'evalsha',
|
||||
131 => 'script',
|
||||
132 => 'time',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user