mirror of
https://github.com/predis/predis.git
synced 2026-08-21 13:10:55 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c0498a893 | |||
| aba24d0f6f | |||
| a1df4f20da | |||
| 116eaba75e | |||
| de4bae3f9b | |||
| b50a5975ac | |||
| 1c1b4096f6 | |||
| f8e4ba152f | |||
| 6b6b73f5f4 | |||
| 729e40d6c0 | |||
| fbcfdc343e | |||
| 8cbcb09c4c | |||
| 2781bd780f | |||
| 9675626aac | |||
| f8829985f7 | |||
| e2e809c9d4 | |||
| ef0067e1a4 | |||
| da343046e5 | |||
| 76d6681f68 | |||
| 8d01be388d | |||
| c38376dcc4 | |||
| c354d02105 | |||
| d6685a424a | |||
| 05ef62ff97 | |||
| b76e876b73 | |||
| ebd895a67d | |||
| 923e7ed5fd | |||
| 9e0fe7bdc7 | |||
| 5d774dc581 | |||
| dffbb8b042 | |||
| 06d5475129 | |||
| 1536455fea |
@@ -1,3 +1,32 @@
|
||||
v0.8.3 (2013-02-18)
|
||||
===============================================================================
|
||||
|
||||
- Added `CLIENT SETNAME` and `CLIENT GETNAME` (ISSUE #102).
|
||||
|
||||
- Implemented the `Predis\Connection\PhpiredisStreamConnection` class using the
|
||||
`phpiredis` extension like `Predis\Connection\PhpiredisStreamConnection`, but
|
||||
without requiring the `socket` extension since it relies on PHP's streams.
|
||||
|
||||
- Added support for the TCP_NODELAY flag via the `tcp_nodelay` parameter for
|
||||
stream-based connections, namely `Predis\Connection\StreamConnection` and
|
||||
`Predis\Connection\PhpiredisStreamConnection` (requires PHP >= 5.4.0).
|
||||
|
||||
- Updated the aggregated connection class for redis-cluster to work with 16384
|
||||
hash slots instead of 4096 to reflect the recent change from redis unstable
|
||||
([see this commit](https://github.com/antirez/redis/commit/ebd666d)).
|
||||
|
||||
- The constructor of `Predis\Client` now accepts a callable as first argument
|
||||
returning `Predis\Connection\ConnectionInterface`. Users can create their
|
||||
own self-contained strategies to create and set up the underlying connection.
|
||||
|
||||
- Users should return `0` from `Predis\Command\ScriptedCommand::getKeysCount()`
|
||||
instead of `FALSE` to indicate that all of the arguments of a Lua script must
|
||||
be used to populate `ARGV[]`. This does not represent a breaking change.
|
||||
|
||||
- The `Predis\Helpers` class has been deprecated and it will be removed in
|
||||
future releases.
|
||||
|
||||
|
||||
v0.8.2 (2013-02-03)
|
||||
===============================================================================
|
||||
|
||||
|
||||
@@ -126,12 +126,17 @@ to how your application will use Redis.
|
||||
Fair enough, but there is actually an option for you if you need even more speed and it consists on
|
||||
installing __[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name)
|
||||
and let Predis using it. __phpiredis__ is a C-based extension that wraps __hiredis__ (the official
|
||||
Redis C client library) with a thin layer that exposes its features to PHP. You will now get the
|
||||
benefits of a faster protocol parser just by adding a single line of code in your application:
|
||||
Redis C client library) with a thin layer that exposes its features to PHP. You can choose between
|
||||
two different connection backend classes: `Predis\Connection\PhpiredisConnection` (it depends on the
|
||||
`socket` extension) and `Predis\Connection\PhpiredisStreamConnection` (it uses PHP's native streams).
|
||||
You will now get the benefits of a faster protocol parser just by adding a couple of lines of code:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array('tcp' => 'Predis\Connection\PhpiredisConnection')
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisConnection',
|
||||
),
|
||||
));
|
||||
```
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ serializing and parsing the Redis protocol. Predis is also available in an async
|
||||
through the experimental client provided by the [Predis\Async](http://github.com/nrk/predis-async)
|
||||
library.
|
||||
|
||||
For a list of frequently asked questions about Predis, see __FAQ.md__ in the root of the repository.
|
||||
For a list of frequently asked questions about Predis see our [FAQ](FAQ.md).
|
||||
More details are available on the [official wiki](http://wiki.github.com/nrk/predis) of the project.
|
||||
|
||||
|
||||
@@ -113,13 +113,19 @@ $replies = $redis->pipeline(function ($pipe) {
|
||||
|
||||
### Multiple and customizable connection backends ###
|
||||
|
||||
Predis can optionally use different connection backends to connect to Redis. One of them leverages
|
||||
Predis can optionally use different connection backends to connect to Redis. Two of them leverage
|
||||
the [phpiredis](http://github.com/nrk/phpiredis) C-based extension resulting in a major speed bump
|
||||
especially when dealing with long multibulk replies (the `socket` extension is also required):
|
||||
especially when dealing with long multibulk replies, namely `Predis\Connection\PhpiredisConnection`
|
||||
(the `socket` extension is also required) and `Predis\Connection\StreamPhpiredisConnection` (it
|
||||
does not require additional extensions since it relies on PHP's native streams). Both of them can
|
||||
connect to Redis using standard TCP/IP connections or UNIX domain sockets:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array('tcp' => 'Predis\Connection\PhpiredisConnection')
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisStreamConnection',
|
||||
)
|
||||
));
|
||||
```
|
||||
|
||||
|
||||
+23
-12
@@ -33,12 +33,11 @@ use Predis\Transaction\MultiExecContext;
|
||||
*/
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
const VERSION = '0.8.2';
|
||||
const VERSION = '0.8.3';
|
||||
|
||||
private $options;
|
||||
private $profile;
|
||||
private $connection;
|
||||
private $connections;
|
||||
|
||||
/**
|
||||
* Initializes a new client with optional connection parameters and client options.
|
||||
@@ -50,7 +49,6 @@ class Client implements ClientInterface
|
||||
{
|
||||
$this->options = $this->filterOptions($options);
|
||||
$this->profile = $this->options->profile;
|
||||
$this->connections = $this->options->connections;
|
||||
$this->connection = $this->initializeConnection($parameters);
|
||||
}
|
||||
|
||||
@@ -64,7 +62,7 @@ class Client implements ClientInterface
|
||||
*/
|
||||
protected function filterOptions($options)
|
||||
{
|
||||
if ($options === null) {
|
||||
if (!isset($options)) {
|
||||
return new ClientOptions();
|
||||
}
|
||||
|
||||
@@ -94,13 +92,26 @@ class Client implements ClientInterface
|
||||
}
|
||||
|
||||
if (is_array($parameters) && isset($parameters[0])) {
|
||||
$replication = isset($this->options->replication) && $this->options->replication;
|
||||
$connection = $this->options->{$replication ? 'replication' : 'cluster'};
|
||||
$options = $this->options;
|
||||
$replication = isset($options->replication) && $options->replication;
|
||||
$connection = $options->{$replication ? 'replication' : 'cluster'};
|
||||
|
||||
return $this->connections->createAggregated($connection, $parameters);
|
||||
return $options->connections->createAggregated($connection, $parameters);
|
||||
}
|
||||
|
||||
return $this->connections->create($parameters);
|
||||
if (is_callable($parameters)) {
|
||||
$connection = call_user_func($parameters, $this->options);
|
||||
|
||||
if (!$connection instanceof ConnectionInterface) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Callable parameters must return instances of Predis\Connection\ConnectionInterface'
|
||||
);
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
return $this->options->connections->create($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +137,7 @@ class Client implements ClientInterface
|
||||
*/
|
||||
public function getConnectionFactory()
|
||||
{
|
||||
return $this->connections;
|
||||
return $this->options->connections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +149,7 @@ class Client implements ClientInterface
|
||||
*/
|
||||
public function getClientFor($connectionID)
|
||||
{
|
||||
if (($connection = $this->getConnectionById($connectionID)) === null) {
|
||||
if (!$connection = $this->getConnectionById($connectionID)) {
|
||||
throw new \InvalidArgumentException("Invalid connection ID: '$connectionID'");
|
||||
}
|
||||
|
||||
@@ -269,14 +280,14 @@ class Client implements ClientInterface
|
||||
|
||||
$response = $this->executeCommand($eval);
|
||||
|
||||
if (false === $response instanceof ResponseObjectInterface) {
|
||||
if (!$response instanceof ResponseObjectInterface) {
|
||||
$response = $command->parseResponse($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ($this->options->exceptions === true) {
|
||||
if ($this->options->exceptions) {
|
||||
throw new ServerException($response->getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
return;
|
||||
}
|
||||
|
||||
if (count($this->nodes) === 0) {
|
||||
if (!$this->nodes) {
|
||||
throw new EmptyRingException('Cannot initialize empty hashring');
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class CRC16HashGenerator implements HashGeneratorInterface
|
||||
$strlen = strlen($value);
|
||||
|
||||
for ($i = 0; $i < $strlen; $i++) {
|
||||
$crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 65535; // 0xFFFF
|
||||
$crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 0xFFFF;
|
||||
}
|
||||
|
||||
return $crc;
|
||||
|
||||
@@ -294,9 +294,11 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function getKeyFromScriptingCommands(CommandInterface $command)
|
||||
{
|
||||
$keys = $command instanceof ScriptedCommand
|
||||
? $command->getKeys()
|
||||
: array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
if ($command instanceof ScriptedCommand) {
|
||||
$keys = $command->getKeys();
|
||||
} else {
|
||||
$keys = array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
}
|
||||
|
||||
if ($keys && $this->checkSameHashForKeys($keys)) {
|
||||
return $keys[0];
|
||||
@@ -341,7 +343,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function checkSameHashForKeys(Array $keys)
|
||||
{
|
||||
if (($count = count($keys)) === 0) {
|
||||
if (!$count = count($keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -246,9 +246,11 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function getKeyFromScriptingCommands(CommandInterface $command)
|
||||
{
|
||||
$keys = $command instanceof ScriptedCommand
|
||||
? $command->getKeys()
|
||||
: array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
if ($command instanceof ScriptedCommand) {
|
||||
$keys = $command->getKeys();
|
||||
} else {
|
||||
$keys = array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
}
|
||||
|
||||
if (count($keys) === 1) {
|
||||
return $keys[0];
|
||||
|
||||
@@ -65,9 +65,9 @@ abstract class AbstractCommand implements CommandInterface
|
||||
*
|
||||
* @param array $arguments Position of the argument.
|
||||
*/
|
||||
public function getArgument($index = 0)
|
||||
public function getArgument($index)
|
||||
{
|
||||
if (isset($this->arguments[$index]) === true) {
|
||||
if (isset($this->arguments[$index])) {
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
}
|
||||
@@ -129,4 +129,34 @@ abstract class AbstractCommand implements CommandInterface
|
||||
$this->getId()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the arguments array passed to a Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeArguments(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 1 && is_array($arguments[0])) {
|
||||
return $arguments[0];
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the arguments array passed to a variadic Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeVariadic(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 2 && is_array($arguments[1])) {
|
||||
return array_merge(array($arguments[0]), $arguments[1]);
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,13 @@ interface CommandInterface
|
||||
*/
|
||||
public function getArguments();
|
||||
|
||||
/**
|
||||
* Gets the argument of the command at the specified index.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArgument($index);
|
||||
|
||||
/**
|
||||
* Parses a reply buffer and returns a PHP object.
|
||||
*
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/hdel
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class HashDelete extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/hmget
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class HashGetMultiple extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/del
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class KeyDelete extends AbstractCommand implements PrefixableCommandInterface
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/rpush
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class ListPushTail extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/subscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class PubSubSubscribe extends AbstractCommand implements PrefixableCommandInterf
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/psubscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/unsubscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class PubSubUnsubscribe extends AbstractCommand implements PrefixableCommandInte
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,19 +30,15 @@ abstract class ScriptedCommand extends ServerEvalSHA
|
||||
/**
|
||||
* Specifies the number of arguments that should be considered as keys.
|
||||
*
|
||||
* The default behaviour for the base class is to return FALSE to indicate that
|
||||
* The default behaviour for the base class is to return 0 to indicate that
|
||||
* all the elements of the arguments array should be considered as keys, but
|
||||
* subclasses can enforce a static number of keys.
|
||||
*
|
||||
* @todo How about returning 1 by default to make scripted commands act like
|
||||
* variadic ones where the first argument is the key (KEYS[1]) and the
|
||||
* rest are values (ARGV)?
|
||||
*
|
||||
* @return int|Boolean
|
||||
* @return int
|
||||
*/
|
||||
protected function getKeysCount()
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,13 +56,11 @@ abstract class ScriptedCommand extends ServerEvalSHA
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
if (false !== $numkeys = $this->getKeysCount()) {
|
||||
$numkeys = $numkeys >= 0 ? $numkeys : count($arguments) + $numkeys;
|
||||
} else {
|
||||
$numkeys = count($arguments);
|
||||
if (($numkeys = $this->getKeysCount()) && $numkeys < 0) {
|
||||
$numkeys = count($arguments) + $numkeys;
|
||||
}
|
||||
|
||||
return array_merge(array(sha1($this->getScript()), $numkeys), $arguments);
|
||||
return array_merge(array(sha1($this->getScript()), (int) $numkeys), $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,8 +35,9 @@ class ServerClient extends AbstractCommand
|
||||
switch (strtoupper($args[0])) {
|
||||
case 'LIST':
|
||||
return $this->parseClientList($data);
|
||||
|
||||
case 'KILL':
|
||||
case 'GETNAME':
|
||||
case 'SETNAME':
|
||||
default:
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/object
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/sadd
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class SetAdd extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/sinter
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class SetIntersection extends AbstractCommand implements PrefixableCommandInterf
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/srem
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class SetRemove extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/mget
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class StringGetMultiple extends AbstractCommand implements PrefixableCommandInte
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zadd
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zrem
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class ZSetRemove extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,23 @@ abstract class CommunicationException extends PredisException
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offers a generic and reusable method to handle exceptions generated by
|
||||
* a connection object.
|
||||
*
|
||||
* @param CommunicationException $exception Exception.
|
||||
*/
|
||||
public static function handle(CommunicationException $exception)
|
||||
{
|
||||
if ($exception->shouldResetConnection()) {
|
||||
$connection = $exception->getConnection();
|
||||
|
||||
if ($connection->isConnected()) {
|
||||
$connection->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
@@ -136,7 +136,7 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
*/
|
||||
protected function onConnectionError($message, $code = null)
|
||||
{
|
||||
Helpers::onCommunicationException(new ConnectionException($this, $message, $code));
|
||||
CommunicationException::handle(new ConnectionException($this, $message, $code));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +146,7 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
*/
|
||||
protected function onProtocolError($message)
|
||||
{
|
||||
Helpers::onCommunicationException(new ProtocolException($this, $message));
|
||||
CommunicationException::handle(new ProtocolException($this, $message));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,12 +31,8 @@ class ComposableStreamConnection extends StreamConnection implements ComposableC
|
||||
*/
|
||||
public function __construct(ConnectionParametersInterface $parameters, ProtocolInterface $protocol = null)
|
||||
{
|
||||
$protocol = $protocol ?: new TextProtocol();
|
||||
$protocol->setOption('iterable_multibulk', $parameters->iterable_multibulk);
|
||||
|
||||
$this->mbiterable = null;
|
||||
$this->protocol = $protocol;
|
||||
$this->parameters = $this->checkParameters($parameters);
|
||||
$this->protocol = $protocol ?: new TextProtocol();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,6 +130,6 @@ class ComposableStreamConnection extends StreamConnection implements ComposableC
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array_merge(parent::__sleep(), array('protocol'));
|
||||
return array_diff(array_merge(parent::__sleep(), array('protocol')), array('mbiterable'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'timeout' => 5.0,
|
||||
'iterable_multibulk' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -37,7 +36,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
public function __construct($parameters = array())
|
||||
{
|
||||
if (!is_array($parameters)) {
|
||||
$parameters = $this->parseURI($parameters);
|
||||
$parameters = self::parseURI($parameters);
|
||||
}
|
||||
|
||||
$this->parameters = $this->filter($parameters) + $this->getDefaults();
|
||||
@@ -109,14 +108,14 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
* @param string $uri Connection string.
|
||||
* @return array
|
||||
*/
|
||||
private function parseURI($uri)
|
||||
public static function parseURI($uri)
|
||||
{
|
||||
if (stripos($uri, 'unix') === 0) {
|
||||
// Hack to support URIs for UNIX sockets with minimal effort.
|
||||
$uri = str_ireplace('unix:///', 'unix://localhost/', $uri);
|
||||
}
|
||||
|
||||
if (($parsed = @parse_url($uri)) === false || !isset($parsed['host'])) {
|
||||
if (!($parsed = @parse_url($uri)) || !isset($parsed['host'])) {
|
||||
throw new ClientException("Invalid URI: $uri");
|
||||
}
|
||||
|
||||
@@ -140,7 +139,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
*/
|
||||
private function filter(Array $parameters)
|
||||
{
|
||||
if (count($parameters) > 0) {
|
||||
if ($parameters) {
|
||||
$casters = array_intersect_key($this->getValueCasters(), $parameters);
|
||||
|
||||
foreach ($casters as $parameter => $caster) {
|
||||
|
||||
@@ -41,7 +41,7 @@ use Predis\Command\CommandInterface;
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
*
|
||||
* @link http://github.com/seppo0010/phpiredis
|
||||
* @link http://github.com/nrk/phpiredis
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PhpiredisConnection extends AbstractConnection
|
||||
@@ -90,10 +90,10 @@ class PhpiredisConnection extends AbstractConnection
|
||||
*/
|
||||
protected function checkParameters(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
if ($parameters->iterable_multibulk === true) {
|
||||
if (isset($parameters->iterable_multibulk)) {
|
||||
$this->onInvalidOption('iterable_multibulk', $parameters);
|
||||
}
|
||||
if ($parameters->persistent === true) {
|
||||
if (isset($parameters->persistent)) {
|
||||
$this->onInvalidOption('persistent', $parameters);
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ class PhpiredisConnection extends AbstractConnection
|
||||
|
||||
$this->connectWithTimeout($this->parameters);
|
||||
|
||||
if (count($this->initCmds) > 0) {
|
||||
if ($this->initCmds) {
|
||||
$this->sendInitializationCommands();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
<?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\Connection;
|
||||
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\ResponseError;
|
||||
use Predis\ResponseQueued;
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
* This class provides the implementation of a Predis connection that uses PHP's
|
||||
* streams for network communication and wraps the phpiredis C extension (PHP
|
||||
* bindings for hiredis) to parse and serialize the Redis protocol. Everything
|
||||
* is highly experimental (even the very same phpiredis since it is quite new),
|
||||
* so use it at your own risk.
|
||||
*
|
||||
* This class is mainly intended to provide an optional low-overhead alternative
|
||||
* for processing replies from Redis compared to the standard pure-PHP classes.
|
||||
* Differences in speed when dealing with short inline replies are practically
|
||||
* nonexistent, the actual speed boost is for long multibulk replies when this
|
||||
* protocol processor can parse and return replies very fast.
|
||||
*
|
||||
* For instructions on how to build and install the phpiredis extension, please
|
||||
* consult the repository of the project.
|
||||
*
|
||||
* The connection parameters supported by this class are:
|
||||
*
|
||||
* - scheme: it can be either 'tcp' or 'unix'.
|
||||
* - host: hostname or IP address of the server.
|
||||
* - port: TCP port of the server.
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
* - async_connect: performs the connection asynchronously.
|
||||
* - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
|
||||
* - persistent: the connection is left intact after a GC collection.
|
||||
*
|
||||
* @link https://github.com/nrk/phpiredis
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PhpiredisStreamConnection extends StreamConnection
|
||||
{
|
||||
private $reader;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
$this->checkExtensions();
|
||||
$this->initializeReader();
|
||||
|
||||
parent::__construct($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
phpiredis_reader_destroy($this->reader);
|
||||
|
||||
parent::__destruct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the phpiredis extension is loaded in PHP.
|
||||
*/
|
||||
protected function checkExtensions()
|
||||
{
|
||||
if (!function_exists('phpiredis_reader_create')) {
|
||||
throw new NotSupportedException(
|
||||
'The phpiredis extension must be loaded in order to be able to use this connection class'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkParameters(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
if (isset($parameters->iterable_multibulk)) {
|
||||
$this->onInvalidOption('iterable_multibulk', $parameters);
|
||||
}
|
||||
|
||||
return parent::checkParameters($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the protocol reader resource.
|
||||
*/
|
||||
protected function initializeReader()
|
||||
{
|
||||
$reader = phpiredis_reader_create();
|
||||
|
||||
phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
|
||||
phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());
|
||||
|
||||
$this->reader = $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the handler used by the protocol reader to handle status replies.
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getStatusHandler()
|
||||
{
|
||||
return function ($payload) {
|
||||
switch ($payload) {
|
||||
case 'OK':
|
||||
return true;
|
||||
|
||||
case 'QUEUED':
|
||||
return new ResponseQueued();
|
||||
|
||||
default:
|
||||
return $payload;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the handler used by the protocol reader to handle Redis errors.
|
||||
*
|
||||
* @param Boolean $throw_errors Specify if Redis errors throw exceptions.
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getErrorHandler()
|
||||
{
|
||||
return function ($errorMessage) {
|
||||
return new ResponseError($errorMessage);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read()
|
||||
{
|
||||
$socket = $this->getResource();
|
||||
$reader = $this->reader;
|
||||
|
||||
while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
|
||||
$buffer = fread($socket, 4096);
|
||||
|
||||
if ($buffer === false || $buffer === '') {
|
||||
$this->onConnectionError('Error while reading bytes from the server');
|
||||
return;
|
||||
}
|
||||
|
||||
phpiredis_reader_feed($reader, $buffer);
|
||||
}
|
||||
|
||||
if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
|
||||
return phpiredis_reader_get_reply($reader);
|
||||
} else {
|
||||
$this->onProtocolError(phpiredis_reader_get_error($reader));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function writeCommand(CommandInterface $command)
|
||||
{
|
||||
$cmdargs = $command->getArguments();
|
||||
array_unshift($cmdargs, $command->getId());
|
||||
$this->writeBytes(phpiredis_format_command($cmdargs));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array_diff(parent::__sleep(), array('mbiterable'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->checkExtensions();
|
||||
$this->initializeReader();
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
public function buildSlotsMap()
|
||||
{
|
||||
$this->slotsMap = array();
|
||||
$this->slotsPerNode = (int) (4096 / count($this->pool));
|
||||
$this->slotsPerNode = (int) (16384 / count($this->pool));
|
||||
|
||||
foreach ($this->pool as $connectionID => $connection) {
|
||||
$parameters = $connection->getParameters();
|
||||
@@ -177,7 +177,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
*/
|
||||
public function setSlots($first, $last, $connection)
|
||||
{
|
||||
if ($first < 0 || $first > 4095 || $last < 0 || $last > 4095 || $last < $first) {
|
||||
if ($first < 0x0000 || $first > 0x3FFF || $last < 0x0000 || $last > 0x3FFF || $last < $first) {
|
||||
throw new \OutOfBoundsException("Invalid slot values for $connection: [$first-$last]");
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
throw new NotSupportedException("Cannot use {$command->getId()} with redis-cluster");
|
||||
}
|
||||
|
||||
$slot = $hash & 4095; // 0x0FFF
|
||||
$slot = $hash & 0x3FFF;
|
||||
|
||||
if (isset($this->slots[$slot])) {
|
||||
return $this->slots[$slot];
|
||||
@@ -214,7 +214,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
*/
|
||||
public function getConnectionBySlot($slot)
|
||||
{
|
||||
if ($slot < 0 || $slot > 4095) {
|
||||
if ($slot < 0x0000 || $slot > 0x3FFF) {
|
||||
throw new \OutOfBoundsException("Invalid slot value [$slot]");
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ use Predis\Iterator\MultiBulkResponseSimple;
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
* - async_connect: performs the connection asynchronously.
|
||||
* - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
|
||||
* - persistent: the connection is left intact after a GC collection.
|
||||
* - iterable_multibulk: multibulk replies treated as iterable objects.
|
||||
*
|
||||
@@ -53,7 +54,7 @@ class StreamConnection extends AbstractConnection
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (!$this->parameters->persistent) {
|
||||
if (isset($this->parameters) && !$this->parameters->persistent) {
|
||||
$this->disconnect();
|
||||
}
|
||||
}
|
||||
@@ -80,10 +81,10 @@ class StreamConnection extends AbstractConnection
|
||||
$uri = "tcp://{$parameters->host}:{$parameters->port}/";
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
|
||||
if (isset($parameters->async_connect) && $parameters->async_connect === true) {
|
||||
if (isset($parameters->async_connect) && $parameters->async_connect) {
|
||||
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
|
||||
}
|
||||
if (isset($parameters->persistent) && $parameters->persistent === true) {
|
||||
if (isset($parameters->persistent) && $parameters->persistent) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
}
|
||||
|
||||
@@ -101,6 +102,11 @@ class StreamConnection extends AbstractConnection
|
||||
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
|
||||
}
|
||||
|
||||
if (isset($parameters->tcp_nodelay) && version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
$socket = socket_import_stream($resource);
|
||||
socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
@@ -115,7 +121,7 @@ class StreamConnection extends AbstractConnection
|
||||
$uri = "unix://{$parameters->path}";
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
|
||||
if ($parameters->persistent === true) {
|
||||
if ($parameters->persistent) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
}
|
||||
|
||||
@@ -135,7 +141,7 @@ class StreamConnection extends AbstractConnection
|
||||
{
|
||||
parent::connect();
|
||||
|
||||
if (count($this->initCmds) > 0){
|
||||
if ($this->initCmds) {
|
||||
$this->sendInitializationCommands();
|
||||
}
|
||||
}
|
||||
@@ -244,7 +250,7 @@ class StreamConnection extends AbstractConnection
|
||||
if ($count === -1) {
|
||||
return null;
|
||||
}
|
||||
if ($this->mbiterable === true) {
|
||||
if ($this->mbiterable) {
|
||||
return new MultiBulkResponseSimple($this, $count);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ use Predis\Connection\ConnectionInterface;
|
||||
* Defines a few helper methods.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
* @deprecated Deprecated since v0.8.3.
|
||||
*/
|
||||
class Helpers
|
||||
{
|
||||
@@ -26,6 +27,7 @@ class Helpers
|
||||
* Offers a generic and reusable method to handle exceptions generated by
|
||||
* a connection object.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\CommunicationException::handle()
|
||||
* @param CommunicationException $exception Exception.
|
||||
*/
|
||||
public static function onCommunicationException(CommunicationException $exception)
|
||||
@@ -44,6 +46,7 @@ class Helpers
|
||||
/**
|
||||
* Normalizes the arguments array passed to a Redis command.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeArguments()
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
@@ -59,6 +62,7 @@ class Helpers
|
||||
/**
|
||||
* Normalizes the arguments array passed to a variadic Redis command.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeVariadic()
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,6 @@ use Predis\BasicClientInterface;
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\ExecutableContextInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
|
||||
@@ -130,7 +130,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
public function supportsCommands(Array $commands)
|
||||
{
|
||||
foreach ($commands as $command) {
|
||||
if ($this->supportsCommand($command) === false) {
|
||||
if (!$this->supportsCommand($command)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -37,7 +37,7 @@ class ResponseBulkHandler implements ResponseHandlerInterface
|
||||
$length = (int) $lengthString;
|
||||
|
||||
if ("$length" !== $lengthString) {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$lengthString' as bulk length"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -39,7 +39,7 @@ class ResponseIntegerHandler implements ResponseHandlerInterface
|
||||
}
|
||||
|
||||
if ($number !== 'nil') {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$number' as numeric response"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -37,7 +37,7 @@ class ResponseMultiBulkHandler implements ResponseHandlerInterface
|
||||
$length = (int) $lengthString;
|
||||
|
||||
if ("$length" !== $lengthString) {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$lengthString' as multi-bulk length"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Iterator\MultiBulkResponseSimple;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
@@ -38,7 +38,7 @@ class ResponseMultiBulkStreamHandler implements ResponseHandlerInterface
|
||||
$length = (int) $lengthString;
|
||||
|
||||
if ("$length" != $lengthString) {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$lengthString' as multi-bulk length"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\ResponseError;
|
||||
use Predis\ResponseQueued;
|
||||
use Predis\ServerException;
|
||||
@@ -98,7 +98,7 @@ class TextProtocol implements ProtocolInterface
|
||||
if ($count === -1) {
|
||||
return null;
|
||||
}
|
||||
if ($this->mbiterable == true) {
|
||||
if ($this->mbiterable) {
|
||||
return new MultiBulkResponseSimple($connection, $count);
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ class TextProtocol implements ProtocolInterface
|
||||
return new ResponseError($payload);
|
||||
|
||||
default:
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Unknown prefix: '$prefix'"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -108,6 +108,6 @@ class TextResponseReader implements ResponseReaderInterface
|
||||
*/
|
||||
private function protocolError(ComposableConnectionInterface $connection, $message)
|
||||
{
|
||||
Helpers::onCommunicationException(new ProtocolException($connection, $message));
|
||||
CommunicationException::handle(new ProtocolException($connection, $message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace Predis\PubSub;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\NotSupportedException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Predis\PubSub;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\Command\AbstractCommand as Command;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\Connection\AggregatedConnectionInterface;
|
||||
|
||||
@@ -77,7 +77,7 @@ class PubSubContext extends AbstractPubSubContext
|
||||
*/
|
||||
protected function writeCommand($method, $arguments)
|
||||
{
|
||||
$arguments = Helpers::filterArrayArguments($arguments);
|
||||
$arguments = Command::normalizeArguments($arguments);
|
||||
$command = $this->client->createCommand($method, $arguments);
|
||||
$this->client->getConnection()->writeCommand($command);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\ExecutableContextInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\ResponseErrorInterface;
|
||||
use Predis\ResponseQueued;
|
||||
@@ -443,7 +442,7 @@ class MultiExecContext implements BasicClientInterface, ExecutableContextInterfa
|
||||
// Since a MULTI/EXEC block cannot be initialized when using aggregated
|
||||
// connections, we can safely assume that Predis\Client::getConnection()
|
||||
// will always return an instance of Predis\Connection\SingleConnectionInterface.
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$this->client->getConnection(), $message
|
||||
));
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ name = "Predis"
|
||||
desc = "Flexible and feature-complete PHP client library for Redis"
|
||||
homepage = "http://github.com/nrk/predis"
|
||||
license = "MIT"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
stability = "stable"
|
||||
channel = "pear.nrk.io"
|
||||
|
||||
|
||||
@@ -159,6 +159,32 @@ abstract class CommandTestCase extends StandardTestCase
|
||||
$this->assertEquals($this->getExpectedId(), $command->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $expectedVersion
|
||||
* @param string $message Optional message.
|
||||
* @throws \RuntimeException when unable to retrieve server info or redis version
|
||||
* @throws \PHPUnit_Framework_SkippedTestError when expected redis version is not met
|
||||
*/
|
||||
protected function markTestSkippedOnRedisVersionBelow($expectedVersion, $message = '')
|
||||
{
|
||||
$client = $this->getClient();
|
||||
$info = array_change_key_case($client->info());
|
||||
|
||||
if (isset($info['server']['redis_version'])) {
|
||||
// Redis >= 2.6
|
||||
$version = $info['server']['redis_version'];
|
||||
} else if (isset($info['redis_version'])) {
|
||||
// Redis < 2.6
|
||||
$version = $info['redis_version'];
|
||||
} else {
|
||||
throw new \RuntimeException('Unable to retrieve server info');
|
||||
}
|
||||
|
||||
if (version_compare($version, $expectedVersion) <= -1) {
|
||||
$this->markTestSkipped($message ?: "Test requires Redis $expectedVersion, current is $version.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -197,6 +197,42 @@ class ClientTest extends StandardTestCase
|
||||
$this->assertSame($replication, $client->getConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testConstructorWithCallableArgument()
|
||||
{
|
||||
$connection = $this->getMock('Predis\Connection\ConnectionInterface');
|
||||
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
$callable->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($this->isInstanceOf('Predis\Option\ClientOptions'))
|
||||
->will($this->returnValue($connection));
|
||||
|
||||
$client = new Client($callable);
|
||||
|
||||
$this->assertSame($connection, $client->getConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Callable parameters must return instances of Predis\Connection\ConnectionInterface
|
||||
*/
|
||||
public function testConstructorWithCallableArgumentButInvalidReturnType()
|
||||
{
|
||||
$wrongType = $this->getMock('stdClass');
|
||||
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
$callable->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($this->isInstanceOf('Predis\Option\ClientOptions'))
|
||||
->will($this->returnValue($wrongType));
|
||||
|
||||
$client = new Client($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,9 @@ class PredisClusterHashStrategyTest extends StandardTestCase
|
||||
*/
|
||||
public function testSupportsKeyTags()
|
||||
{
|
||||
$expected = -1938594527;
|
||||
// NOTE: 32 and 64 bits PHP runtimes can produce different hash values.
|
||||
$expected = PHP_INT_SIZE == 4 ? -1938594527 : 2356372769;
|
||||
|
||||
$strategy = $this->getHashStrategy();
|
||||
|
||||
$this->assertSame($expected, $strategy->getKeyHash('{foo}'));
|
||||
|
||||
@@ -140,4 +140,35 @@ class CommandTest extends StandardTestCase
|
||||
|
||||
$this->assertEquals($expected, (string) $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testNormalizeArguments()
|
||||
{
|
||||
$arguments = array('arg1', 'arg2', 'arg3', 'arg4');
|
||||
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments));
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments(array($arguments)));
|
||||
|
||||
$arguments = array(array(), array());
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments));
|
||||
|
||||
$arguments = array(new \stdClass());
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testNormalizeVariadic()
|
||||
{
|
||||
$arguments = array('key', 'value1', 'value2', 'value3');
|
||||
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeVariadic($arguments));
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeVariadic(array('key', array('value1', 'value2', 'value3'))));
|
||||
|
||||
$arguments = array(new \stdClass());
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeVariadic($arguments));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,25 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame(array_merge(array(self::LUA_SCRIPT_SHA1, 2), $arguments), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetArgumentsWithZeroKeysCount()
|
||||
{
|
||||
$arguments = array('value1', 'value2', 'value3');
|
||||
|
||||
$command = $this->getMock('Predis\Command\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(0));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame(array_merge(array(self::LUA_SCRIPT_SHA1, 0), $arguments), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -79,6 +98,25 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame(array('key1', 'key2'), $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetKeysWithZeroKeysCount()
|
||||
{
|
||||
$arguments = array('value1', 'value2', 'value3');
|
||||
|
||||
$command = $this->getMock('Predis\Command\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(0));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame(array(), $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -63,6 +63,32 @@ class ServerClientTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArgumentsOfClientGetname()
|
||||
{
|
||||
$arguments = $expected = array('getname');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArgumentsOfClientSetname()
|
||||
{
|
||||
$arguments = $expected = array('setname', 'connection-a');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -117,6 +143,61 @@ BUFFER;
|
||||
$this->assertArrayHasKey('psub', $clients[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testGetsNameOfConnection()
|
||||
{
|
||||
$this->markTestSkippedOnRedisVersionBelow('2.6.9');
|
||||
|
||||
$redis = $this->getClient();
|
||||
$clientName = $redis->client('GETNAME');
|
||||
$this->assertNull($clientName);
|
||||
|
||||
$expectedConnectionName = 'foo-bar';
|
||||
$this->assertTrue($redis->client('SETNAME', $expectedConnectionName));
|
||||
$this->assertEquals($expectedConnectionName, $redis->client('GETNAME'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testSetsNameOfConnection()
|
||||
{
|
||||
$this->markTestSkippedOnRedisVersionBelow('2.6.9');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$expectedConnectionName = 'foo-baz';
|
||||
$this->assertTrue($redis->client('SETNAME', $expectedConnectionName));
|
||||
$this->assertEquals($expectedConnectionName, $redis->client('GETNAME'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function invalidConnectionNameProvider()
|
||||
{
|
||||
return array(
|
||||
array('foo space'),
|
||||
array('foo \n'),
|
||||
array('foo $'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @dataProvider invalidConnectionNameProvider
|
||||
*/
|
||||
public function testInvalidSetNameOfConnection($invalidConnectionName)
|
||||
{
|
||||
$this->markTestSkippedOnRedisVersionBelow('2.6.9');
|
||||
|
||||
$redis = $this->getClient();
|
||||
$redis->client('SETNAME', $invalidConnectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
|
||||
@@ -56,6 +56,22 @@ class CommunicationExceptionTest extends StandardTestCase
|
||||
$this->assertTrue($exception->shouldResetConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException Predis\CommunicationException
|
||||
* @expectedExceptionMessage Communication error
|
||||
*/
|
||||
public function testCommunicationExceptionHandling()
|
||||
{
|
||||
$connection = $this->getMock('Predis\Connection\SingleConnectionInterface');
|
||||
$connection->expects($this->once())->method('isConnected')->will($this->returnValue(true));
|
||||
$connection->expects($this->once())->method('disconnect');
|
||||
|
||||
$exception = $this->getException($connection, 'Communication error');
|
||||
|
||||
CommunicationException::handle($exception);
|
||||
}
|
||||
|
||||
// ******************************************************************** //
|
||||
// ---- HELPER METHODS ------------------------------------------------ //
|
||||
// ******************************************************************** //
|
||||
|
||||
@@ -74,7 +74,8 @@ class ComposableStreamConnectionTest extends ConnectionTestCase
|
||||
*/
|
||||
public function testReadsMultibulkRepliesAsIterators()
|
||||
{
|
||||
$connection = $this->getConnection($profile, true, array('iterable_multibulk' => true));
|
||||
$connection = $this->getConnection($profile, true);
|
||||
$connection->getProtocol()->setOption('iterable_multibulk', true);
|
||||
|
||||
$connection->executeCommand($profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol')));
|
||||
$connection->writeCommand($profile->createCommand('lrange', array('metavars', 0, -1)));
|
||||
|
||||
@@ -30,7 +30,6 @@ class ParametersTest extends StandardTestCase
|
||||
$this->assertEquals($defaults['scheme'], $parameters->scheme);
|
||||
$this->assertEquals($defaults['host'], $parameters->host);
|
||||
$this->assertEquals($defaults['port'], $parameters->port);
|
||||
$this->assertEquals($defaults['iterable_multibulk'], $parameters->iterable_multibulk);
|
||||
$this->assertEquals($defaults['timeout'], $parameters->timeout);
|
||||
}
|
||||
|
||||
@@ -124,6 +123,52 @@ class ParametersTest extends StandardTestCase
|
||||
$this->assertNull($unserialized->unknown);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParsingURI()
|
||||
{
|
||||
$uri = 'tcp://10.10.10.10:6400?timeout=0.5&persistent=1';
|
||||
|
||||
$expected = array(
|
||||
'scheme' => 'tcp',
|
||||
'host' => '10.10.10.10',
|
||||
'port' => 6400,
|
||||
'timeout' => '0.5',
|
||||
'persistent' => '1',
|
||||
);
|
||||
|
||||
$this->assertSame($expected, ConnectionParameters::parseURI($uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParsingUnixDomainURI()
|
||||
{
|
||||
$uri = 'unix:///tmp/redis.sock?timeout=0.5&persistent=1';
|
||||
|
||||
$expected = array(
|
||||
'scheme' => 'unix',
|
||||
'host' => 'localhost',
|
||||
'path' => '/tmp/redis.sock',
|
||||
'timeout' => '0.5',
|
||||
'persistent' => '1',
|
||||
);
|
||||
|
||||
$this->assertSame($expected, ConnectionParameters::parseURI($uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException Predis\ClientException
|
||||
* @expectedExceptionMessage Invalid URI: tcp://invalid:uri
|
||||
*/
|
||||
public function testParsingURIThrowOnInvalidURI()
|
||||
{
|
||||
ConnectionParameters::parseURI('tcp://invalid:uri');
|
||||
}
|
||||
|
||||
// ******************************************************************** //
|
||||
// ---- HELPER METHODS ------------------------------------------------ //
|
||||
// ******************************************************************** //
|
||||
@@ -140,7 +185,6 @@ class ParametersTest extends StandardTestCase
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'timeout' => 5.0,
|
||||
'iterable_multibulk' => false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
<?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\Connection;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
use Predis\Profile\ServerProfile;
|
||||
|
||||
/**
|
||||
* @group ext-phpiredis
|
||||
*/
|
||||
class PhpiredisStreamConnectionTest extends ConnectionTestCase
|
||||
{
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testConstructorDoesNotOpenConnection()
|
||||
{
|
||||
$connection = new PhpiredisStreamConnection($this->getParameters());
|
||||
|
||||
$this->assertFalse($connection->isConnected());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testExposesParameters()
|
||||
{
|
||||
$parameters = $this->getParameters();
|
||||
$connection = new PhpiredisStreamConnection($parameters);
|
||||
|
||||
$this->assertSame($parameters, $connection->getParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Invalid scheme: udp
|
||||
*/
|
||||
public function testThrowsExceptionOnInvalidScheme()
|
||||
{
|
||||
$parameters = $this->getParameters(array('scheme' => 'udp'));
|
||||
$connection = new PhpiredisStreamConnection($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testCanBeSerialized()
|
||||
{
|
||||
$parameters = $this->getParameters(array('alias' => 'redis', 'read_write_timeout' => 10));
|
||||
$connection = new PhpiredisStreamConnection($parameters);
|
||||
|
||||
$unserialized = unserialize(serialize($connection));
|
||||
|
||||
$this->assertInstanceOf('Predis\Connection\PhpiredisStreamConnection', $unserialized);
|
||||
$this->assertEquals($parameters, $unserialized->getParameters());
|
||||
}
|
||||
|
||||
// ******************************************************************** //
|
||||
// ---- INTEGRATION TESTS --------------------------------------------- //
|
||||
// ******************************************************************** //
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testAcceptsTcpNodelayParameter()
|
||||
{
|
||||
if (!version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$this->markTestSkipped('Setting TCP_NODELAY on PHP socket streams works on PHP >= 5.4.0');
|
||||
}
|
||||
|
||||
$connection = new PhpiredisStreamConnection($this->getParameters(array('tcp_nodelay' => false)));
|
||||
$connection->connect();
|
||||
$this->assertTrue($connection->isConnected());
|
||||
|
||||
$connection = new PhpiredisStreamConnection($this->getParameters(array('tcp_nodelay' => true)));
|
||||
$connection->connect();
|
||||
$this->assertTrue($connection->isConnected());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testExecutesCommandsOnServer()
|
||||
{
|
||||
$connection = $this->getConnection($profile, true);
|
||||
|
||||
$cmdPing = $profile->createCommand('ping');
|
||||
$cmdEcho = $profile->createCommand('echo', array('echoed'));
|
||||
$cmdGet = $profile->createCommand('get', array('foobar'));
|
||||
$cmdRpush = $profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol'));
|
||||
$cmdLrange = $profile->createCommand('lrange', array('metavars', 0, -1));
|
||||
|
||||
$this->assertSame('PONG', $connection->executeCommand($cmdPing));
|
||||
$this->assertSame('echoed', $connection->executeCommand($cmdEcho));
|
||||
$this->assertNull($connection->executeCommand($cmdGet));
|
||||
$this->assertSame(3, $connection->executeCommand($cmdRpush));
|
||||
$this->assertSame(array('foo', 'hoge', 'lol'), $connection->executeCommand($cmdLrange));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\Protocol\ProtocolException
|
||||
* @expectedExceptionMessage Protocol error, got "P" as reply type byte
|
||||
*/
|
||||
public function testThrowsExceptionOnProtocolDesynchronizationErrors()
|
||||
{
|
||||
$connection = $this->getConnection($profile);
|
||||
$socket = $connection->getResource();
|
||||
|
||||
$connection->writeCommand($profile->createCommand('ping'));
|
||||
fread($socket, 1);
|
||||
|
||||
$connection->read();
|
||||
}
|
||||
|
||||
// ******************************************************************** //
|
||||
// ---- HELPER METHODS ------------------------------------------------ //
|
||||
// ******************************************************************** //
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getConnection(&$profile = null, $initialize = false, Array $parameters = array())
|
||||
{
|
||||
$parameters = $this->getParameters($parameters);
|
||||
$profile = $this->getProfile();
|
||||
|
||||
$connection = new PhpiredisStreamConnection($parameters);
|
||||
|
||||
if ($initialize) {
|
||||
$connection->pushInitCommand($profile->createCommand('select', array($parameters->database)));
|
||||
$connection->pushInitCommand($profile->createCommand('flushdb'));
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
}
|
||||
@@ -279,9 +279,9 @@ class RedisClusterTest extends StandardTestCase
|
||||
*/
|
||||
public function testCanAssignConnectionsToCustomSlotsFromParameters()
|
||||
{
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-1364');
|
||||
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=1365-2729');
|
||||
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=2730-4095');
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-5460');
|
||||
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=5461-10921');
|
||||
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=10922-16383');
|
||||
|
||||
$cluster = new RedisCluster();
|
||||
$cluster->add($connection1);
|
||||
@@ -289,9 +289,9 @@ class RedisClusterTest extends StandardTestCase
|
||||
$cluster->add($connection3);
|
||||
|
||||
$expectedMap = array_merge(
|
||||
array_fill(0, 1365, '127.0.0.1:6379'),
|
||||
array_fill(1364, 1365, '127.0.0.1:6380'),
|
||||
array_fill(2729, 1366, '127.0.0.1:6381')
|
||||
array_fill(0, 5461, '127.0.0.1:6379'),
|
||||
array_fill(5460, 5461, '127.0.0.1:6380'),
|
||||
array_fill(10921, 5462, '127.0.0.1:6381')
|
||||
);
|
||||
|
||||
$cluster->buildSlotsMap();
|
||||
@@ -314,11 +314,11 @@ class RedisClusterTest extends StandardTestCase
|
||||
$cluster->add($connection3);
|
||||
|
||||
$this->assertSame($connection1, $cluster->getConnectionBySlot(0));
|
||||
$this->assertSame($connection2, $cluster->getConnectionBySlot(1365));
|
||||
$this->assertSame($connection3, $cluster->getConnectionBySlot(2730));
|
||||
$this->assertSame($connection2, $cluster->getConnectionBySlot(5461));
|
||||
$this->assertSame($connection3, $cluster->getConnectionBySlot(10922));
|
||||
|
||||
$cluster->setSlots(1365, 3000, '127.0.0.1:6380');
|
||||
$this->assertSame($connection2, $cluster->getConnectionBySlot(2730));
|
||||
$cluster->setSlots(5461, 7096, '127.0.0.1:6380');
|
||||
$this->assertSame($connection2, $cluster->getConnectionBySlot(5461));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -337,8 +337,8 @@ class RedisClusterTest extends StandardTestCase
|
||||
$cluster->add($connection2);
|
||||
$cluster->add($connection3);
|
||||
|
||||
$set = $profile->createCommand('set', array('node:1024', 'foobar'));
|
||||
$get = $profile->createCommand('get', array('node:1024'));
|
||||
$set = $profile->createCommand('set', array('node:1001', 'foobar'));
|
||||
$get = $profile->createCommand('get', array('node:1001'));
|
||||
$this->assertSame($connection1, $cluster->getConnection($set));
|
||||
$this->assertSame($connection1, $cluster->getConnection($get));
|
||||
|
||||
@@ -358,7 +358,7 @@ class RedisClusterTest extends StandardTestCase
|
||||
*/
|
||||
public function testWritesCommandToCorrectConnection()
|
||||
{
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1024'));
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1001'));
|
||||
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379');
|
||||
$connection1->expects($this->once())->method('writeCommand')->with($command);
|
||||
@@ -378,7 +378,7 @@ class RedisClusterTest extends StandardTestCase
|
||||
*/
|
||||
public function testReadsCommandFromCorrectConnection()
|
||||
{
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1048'));
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1050'));
|
||||
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379');
|
||||
$connection1->expects($this->never())->method('readResponse');
|
||||
@@ -407,13 +407,13 @@ class RedisClusterTest extends StandardTestCase
|
||||
$cluster->add($connection1);
|
||||
$cluster->add($connection2);
|
||||
|
||||
$set = $profile->createCommand('set', array('{node:1024}:foo', 'foobar'));
|
||||
$get = $profile->createCommand('get', array('{node:1024}:foo'));
|
||||
$set = $profile->createCommand('set', array('{node:1001}:foo', 'foobar'));
|
||||
$get = $profile->createCommand('get', array('{node:1001}:foo'));
|
||||
$this->assertSame($connection1, $cluster->getConnection($set));
|
||||
$this->assertSame($connection1, $cluster->getConnection($get));
|
||||
|
||||
$set = $profile->createCommand('set', array('{node:1024}:bar', 'foobar'));
|
||||
$get = $profile->createCommand('get', array('{node:1024}:bar'));
|
||||
$set = $profile->createCommand('set', array('{node:1001}:bar', 'foobar'));
|
||||
$get = $profile->createCommand('get', array('{node:1001}:bar'));
|
||||
$this->assertSame($connection2, $cluster->getConnection($set));
|
||||
$this->assertSame($connection2, $cluster->getConnection($get));
|
||||
}
|
||||
@@ -423,9 +423,9 @@ class RedisClusterTest extends StandardTestCase
|
||||
*/
|
||||
public function testAskResponseWithConnectionInPool()
|
||||
{
|
||||
$askResponse = new ResponseError('ASK 373 127.0.0.1:6380');
|
||||
$askResponse = new ResponseError('ASK 1970 127.0.0.1:6380');
|
||||
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1024'));
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1001'));
|
||||
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379');
|
||||
$connection1->expects($this->exactly(2))
|
||||
@@ -456,9 +456,9 @@ class RedisClusterTest extends StandardTestCase
|
||||
*/
|
||||
public function testAskResponseWithConnectionNotInPool()
|
||||
{
|
||||
$askResponse = new ResponseError('ASK 373 127.0.0.1:6381');
|
||||
$askResponse = new ResponseError('ASK 1970 127.0.0.1:6381');
|
||||
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1024'));
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1001'));
|
||||
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379');
|
||||
$connection1->expects($this->exactly(2))
|
||||
@@ -496,9 +496,9 @@ class RedisClusterTest extends StandardTestCase
|
||||
*/
|
||||
public function testMovedResponseWithConnectionInPool()
|
||||
{
|
||||
$movedResponse = new ResponseError('MOVED 373 127.0.0.1:6380');
|
||||
$movedResponse = new ResponseError('MOVED 1970 127.0.0.1:6380');
|
||||
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1024'));
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1001'));
|
||||
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379');
|
||||
$connection1->expects($this->exactly(1))
|
||||
@@ -530,9 +530,9 @@ class RedisClusterTest extends StandardTestCase
|
||||
*/
|
||||
public function testMovedResponseWithConnectionNotInPool()
|
||||
{
|
||||
$movedResponse = new ResponseError('MOVED 373 127.0.0.1:6381');
|
||||
$movedResponse = new ResponseError('MOVED 1970 127.0.0.1:6381');
|
||||
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1024'));
|
||||
$command = ServerProfile::getDefault()->createCommand('get', array('node:1001'));
|
||||
|
||||
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379');
|
||||
$connection1->expects($this->once())
|
||||
|
||||
@@ -69,6 +69,24 @@ class StreamConnectionTest extends ConnectionTestCase
|
||||
// ---- INTEGRATION TESTS --------------------------------------------- //
|
||||
// ******************************************************************** //
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testAcceptsTcpNodelayParameter()
|
||||
{
|
||||
if (!version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$this->markTestSkipped('Setting TCP_NODELAY on PHP socket streams works on PHP >= 5.4.0');
|
||||
}
|
||||
|
||||
$connection = new StreamConnection($this->getParameters(array('tcp_nodelay' => false)));
|
||||
$connection->connect();
|
||||
$this->assertTrue($connection->isConnected());
|
||||
|
||||
$connection = new StreamConnection($this->getParameters(array('tcp_nodelay' => true)));
|
||||
$connection->connect();
|
||||
$this->assertTrue($connection->isConnected());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user