mirror of
https://github.com/predis/predis.git
synced 2026-08-20 16:31:47 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cb18d67b6a | |||
| 4576dc029f | |||
| aa458a1922 | |||
| 2d2930d24f | |||
| 7e0ec1a265 | |||
| 04e597ebba | |||
| d681bff4ab | |||
| 3dea41aa66 | |||
| 69c66e157f | |||
| dd50cfe47e | |||
| 8451146d38 | |||
| d45ce35923 | |||
| 6cd124cc59 | |||
| d6fa4a3292 | |||
| 5b771704d3 | |||
| 68d972a1b1 | |||
| 4bf035918d | |||
| 94c4e2ffee | |||
| 6e2fd181f1 | |||
| 1c21fcc5b3 | |||
| 531261b0fc | |||
| 7434a9bd0e | |||
| c4123ce7ce | |||
| 536992e277 | |||
| 5a735aa670 | |||
| 15f2776d77 | |||
| dc1103582e | |||
| 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 | |||
| aa1b070f9b | |||
| 3e125c964c | |||
| e9fdc47d3f | |||
| d3930ea298 | |||
| 0efcbb7992 | |||
| f2af247c63 | |||
| a5cf6d72cd | |||
| 7173f0c80c |
@@ -1,3 +1,71 @@
|
||||
v0.8.4 (2013-07-27)
|
||||
===============================================================================
|
||||
|
||||
- Added `DUMP` and `RESTORE` to the server profile for Redis 2.6.
|
||||
|
||||
- Connection exceptions now report basic host details in their messages.
|
||||
|
||||
- Allow `Predis\Connection\PhpiredisConnection` to use a random IP when a host
|
||||
actually has several IPs (ISSUE #116).
|
||||
|
||||
- __FIX__: allow `HMSET` when using a cluster of Redis nodes with client-side
|
||||
sharding or redis-cluster (ISSUE #106).
|
||||
|
||||
- __FIX__: set `WITHSCORES` modifer for `ZRANGE`, `ZREVRANGE`, `ZRANGEBYSCORE`
|
||||
and `ZREVRANGEBYSCORE` only when the options array passed to these commands
|
||||
has `WITHSCORES` set to `true` (ISSUE #107).
|
||||
|
||||
- __FIX__: scripted commands falling back from `EVALSHA` to `EVAL` resulted in
|
||||
PHP errors when using a prefixed client (ISSUE #109).
|
||||
|
||||
- __FIX__: `Predis\PubSub\DispatcherLoop` now works properly when using key
|
||||
prefixing (ISSUE #114).
|
||||
|
||||
|
||||
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)
|
||||
===============================================================================
|
||||
|
||||
- Added `Predis\Session\SessionHandler` to make it easy to store PHP sessions
|
||||
on Redis using Predis. Please note that this class needs either PHP >= 5.4.0
|
||||
or a polyfill for PHP's `SessionHandlerInterface`.
|
||||
|
||||
- Added the ability to get the default value of a client option directly from
|
||||
`Predis\Option\ClientOption` using the `getDefault()` method by passing the
|
||||
option name or its instance.
|
||||
|
||||
- __FIX__: the standard pipeline executor was not using the response parser
|
||||
methods associated to commands to process raw responses (ISSUE #101).
|
||||
|
||||
|
||||
v0.8.1 (2013-01-19)
|
||||
===============================================================================
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ $client->hmset('my:hash', array('field1'=>'value1', 'field2'=>'value2'); // valu
|
||||
```
|
||||
|
||||
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/master/tests/Predis/Command/KeySortTest.php#L56-77).
|
||||
[passed using a named array](tests/Predis/Command/KeySortTest.php#L56-77).
|
||||
|
||||
|
||||
|
||||
@@ -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',
|
||||
)
|
||||
));
|
||||
```
|
||||
|
||||
@@ -140,7 +146,7 @@ $client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
```
|
||||
|
||||
For a more in-depth insight on how to create new connection backends you can look at the actual
|
||||
implementation of the classes contained in `Predis\Connection` namespace.
|
||||
implementation of the classes contained in the `Predis\Connection` namespace.
|
||||
|
||||
|
||||
### Defining and registering new commands on the client at runtime ###
|
||||
@@ -214,7 +220,7 @@ Redis. If you do not have Redis up and running, integration tests can be disable
|
||||
suite is configured to execute integration tests using the server profile for Redis v2.4 (which is the
|
||||
current stable version of Redis). You can optionally run the suite against a Redis instance built from
|
||||
the `unstable` branch with the development profile by changing the `REDIS_SERVER_VERSION` to `dev` in
|
||||
the `phpunit.xml` file. More details about testing Predis are available in `tests/README.md`.
|
||||
the `phpunit.xml` file. More details on testing Predis can be found in [the tests README](tests/README.md).
|
||||
|
||||
Predis uses Travis CI for continuous integration. You can find the results of the test suite and the build
|
||||
history [on its project page](http://travis-ci.org/nrk/predis).
|
||||
@@ -252,4 +258,4 @@ history [on its project page](http://travis-ci.org/nrk/predis).
|
||||
|
||||
## License ##
|
||||
|
||||
The code for Predis is distributed under the terms of the MIT license (see LICENSE).
|
||||
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
|
||||
|
||||
@@ -116,7 +116,8 @@ class CommandTestCaseGenerator
|
||||
return $this->options['realm'];
|
||||
}
|
||||
|
||||
$class = array_pop(explode('\\', $this->options['fqn']));
|
||||
$fqnParts = explode('\\', $this->options['fqn']);
|
||||
$class = array_pop($fqnParts);
|
||||
list($realm,) = preg_split('/([[:upper:]][[:lower:]]+)/', $class, 2, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
return strtolower($realm);
|
||||
@@ -152,7 +153,8 @@ class CommandTestCaseGenerator
|
||||
{
|
||||
$id = $instance->getId();
|
||||
$fqn = get_class($instance);
|
||||
$class = array_pop(explode('\\', $fqn)) . "Test";
|
||||
$fqnParts = explode('\\', $fqn);
|
||||
$class = array_pop($fqnParts) . "Test";
|
||||
$realm = $this->getTestRealm();
|
||||
|
||||
$buffer =<<<PHP
|
||||
@@ -245,6 +247,17 @@ PHP;
|
||||
\$this->assertSame(\$expected, \$command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
\$command = \$this->getCommand();
|
||||
\$command->prefixKeys('prefix:');
|
||||
|
||||
\$this->assertSame(array(), \$command->getArguments());
|
||||
}
|
||||
|
||||
PHP;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@ $parameters = array(
|
||||
);
|
||||
|
||||
$options = array(
|
||||
'profile' => function ($options) {
|
||||
$profile = ServerProfile::get('2.6');
|
||||
'profile' => function ($options, $option) {
|
||||
$profile = $options->getDefault($option);
|
||||
$profile->defineCommand('hmgetall', 'HashMultipleGetAll');
|
||||
|
||||
return $profile;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
|
||||
// This example demonstrates how to leverage Predis to save PHP sessions on Redis.
|
||||
//
|
||||
// The value of `session.gc_maxlifetime` in `php.ini` will be used by default as the
|
||||
// the TTL for keys holding session data on Redis, but this value can be overridden
|
||||
// when creating the session handler instance with the `gc_maxlifetime` option.
|
||||
//
|
||||
// Note that this class needs PHP >= 5.4 but can be used on PHP 5.3 if a polyfill for
|
||||
// SessionHandlerInterface (see http://www.php.net/class.sessionhandlerinterface.php)
|
||||
// is provided either by you or an external package like `symfony/http-foundation`.
|
||||
|
||||
if (!interface_exists('SessionHandlerInterface')) {
|
||||
die("ATTENTION: the session handler implemented by Predis needs PHP >= 5.4.0 or a polyfill ".
|
||||
"for \SessionHandlerInterface either provided by you or an external package.\n");
|
||||
}
|
||||
|
||||
// Instantiate a new client just like you would normally do. We'll prefix our session keys here.
|
||||
$client = new Predis\Client($single_server, array('prefix' => 'sessions:'));
|
||||
|
||||
// Set `gc_maxlifetime` so that a session will be expired after 5 seconds since last access.
|
||||
$handler = new Predis\Session\SessionHandler($client, array('gc_maxlifetime' => 5));
|
||||
|
||||
// Register our session handler (it uses `session_set_save_handler()` internally).
|
||||
$handler->register();
|
||||
|
||||
// Set a fixed session ID just for the sake of our example.
|
||||
session_id('example_session_id');
|
||||
|
||||
session_start();
|
||||
|
||||
if (isset($_SESSION['foo'])) {
|
||||
echo "Session has `foo` set to {$_SESSION['foo']}\n";
|
||||
} else {
|
||||
$_SESSION['foo'] = $value = mt_rand();
|
||||
echo "Empty session, `foo` has been set with $value\n";
|
||||
}
|
||||
+24
-15
@@ -15,14 +15,12 @@ use Predis\Command\CommandInterface;
|
||||
use Predis\Command\ScriptedCommand;
|
||||
use Predis\Connection\AggregatedConnectionInterface;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Connection\ConnectionFactory;
|
||||
use Predis\Connection\ConnectionFactoryInterface;
|
||||
use Predis\Monitor\MonitorContext;
|
||||
use Predis\Option\ClientOptions;
|
||||
use Predis\Option\ClientOptionsInterface;
|
||||
use Predis\Pipeline\PipelineContext;
|
||||
use Predis\Profile\ServerProfile;
|
||||
use Predis\Profile\ServerProfileInterface;
|
||||
use Predis\PubSub\PubSubContext;
|
||||
use Predis\Transaction\MultiExecContext;
|
||||
|
||||
@@ -33,12 +31,11 @@ use Predis\Transaction\MultiExecContext;
|
||||
*/
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
const VERSION = '0.8.1';
|
||||
const VERSION = '0.8.4';
|
||||
|
||||
private $options;
|
||||
private $profile;
|
||||
private $connection;
|
||||
private $connections;
|
||||
|
||||
/**
|
||||
* Initializes a new client with optional connection parameters and client options.
|
||||
@@ -50,7 +47,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 +60,7 @@ class Client implements ClientInterface
|
||||
*/
|
||||
protected function filterOptions($options)
|
||||
{
|
||||
if ($options === null) {
|
||||
if (!isset($options)) {
|
||||
return new ClientOptions();
|
||||
}
|
||||
|
||||
@@ -94,13 +90,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 +135,7 @@ class Client implements ClientInterface
|
||||
*/
|
||||
public function getConnectionFactory()
|
||||
{
|
||||
return $this->connections;
|
||||
return $this->options->connections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +147,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'");
|
||||
}
|
||||
|
||||
@@ -194,7 +203,7 @@ class Client implements ClientInterface
|
||||
* Retrieves a single connection out of an aggregated connections instance.
|
||||
*
|
||||
* @param string $connectionId Index or alias of the connection.
|
||||
* @return SingleConnectionInterface
|
||||
* @return Connection\SingleConnectionInterface
|
||||
*/
|
||||
public function getConnectionById($connectionId)
|
||||
{
|
||||
@@ -269,14 +278,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());
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ interface ClientInterface extends BasicClientInterface
|
||||
*
|
||||
* @param string $method The name of a Redis command.
|
||||
* @param array $arguments The arguments for the command.
|
||||
* @return CommandInterface
|
||||
* @return Command\CommandInterface
|
||||
*/
|
||||
public function createCommand($method, $arguments = array());
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Predis\Cluster\Distribution;
|
||||
|
||||
use Predis\Cluster\Hash\HashGeneratorInterface;
|
||||
|
||||
/**
|
||||
* A distributor implements the logic to automatically distribute
|
||||
* keys among several nodes for client-side sharding.
|
||||
@@ -44,7 +46,7 @@ interface DistributionStrategyInterface
|
||||
/**
|
||||
* Returns the underlying hash generator instance.
|
||||
*
|
||||
* @return Predis\Cluster\Hash\HashGeneratorInterface
|
||||
* @return HashGeneratorInterface
|
||||
*/
|
||||
public function getHashGenerator();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -58,6 +58,8 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
'TTL' => $keyIsFirstArgument,
|
||||
'PTTL' => $keyIsFirstArgument,
|
||||
'SORT' => $keyIsFirstArgument, // TODO
|
||||
'DUMP' => $keyIsFirstArgument,
|
||||
'RESTORE' => $keyIsFirstArgument,
|
||||
|
||||
/* commands operating on string values */
|
||||
'APPEND' => $keyIsFirstArgument,
|
||||
@@ -140,6 +142,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
'HGET' => $keyIsFirstArgument,
|
||||
'HGETALL' => $keyIsFirstArgument,
|
||||
'HMGET' => $keyIsFirstArgument,
|
||||
'HMSET' => $keyIsFirstArgument,
|
||||
'HINCRBY' => $keyIsFirstArgument,
|
||||
'HINCRBYFLOAT' => $keyIsFirstArgument,
|
||||
'HKEYS' => $keyIsFirstArgument,
|
||||
@@ -294,9 +297,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 +346,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function checkSameHashForKeys(Array $keys)
|
||||
{
|
||||
if (($count = count($keys)) === 0) {
|
||||
if (!$count = count($keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Predis\Cluster;
|
||||
|
||||
use Predis\Cluster\Hash\CRC16HashGenerator;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\ScriptedCommand;
|
||||
|
||||
/**
|
||||
* Default class used by Predis to calculate hashes out of keys of
|
||||
@@ -127,6 +128,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
'HGET' => $keyIsFirstArgument,
|
||||
'HGETALL' => $keyIsFirstArgument,
|
||||
'HMGET' => $keyIsFirstArgument,
|
||||
'HMSET' => $keyIsFirstArgument,
|
||||
'HINCRBY' => $keyIsFirstArgument,
|
||||
'HINCRBYFLOAT' => $keyIsFirstArgument,
|
||||
'HKEYS' => $keyIsFirstArgument,
|
||||
@@ -246,9 +248,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/dump
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class KeyDump extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'DUMP';
|
||||
}
|
||||
}
|
||||
@@ -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\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/restore
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class KeyRestore extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'RESTORE';
|
||||
}
|
||||
}
|
||||
@@ -86,31 +86,32 @@ class KeySort extends AbstractCommand implements PrefixableCommandInterface
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
$arguments[0] = "$prefix{$arguments[0]}";
|
||||
if ($arguments = $this->getArguments()) {
|
||||
$arguments[0] = "$prefix{$arguments[0]}";
|
||||
|
||||
if (($count = count($arguments)) > 1) {
|
||||
for ($i = 1; $i < $count; $i++) {
|
||||
switch ($arguments[$i]) {
|
||||
case 'BY':
|
||||
case 'STORE':
|
||||
$arguments[$i] = "$prefix{$arguments[++$i]}";
|
||||
break;
|
||||
if (($count = count($arguments)) > 1) {
|
||||
for ($i = 1; $i < $count; $i++) {
|
||||
switch ($arguments[$i]) {
|
||||
case 'BY':
|
||||
case 'STORE':
|
||||
$arguments[$i] = "$prefix{$arguments[++$i]}";
|
||||
break;
|
||||
|
||||
case 'GET':
|
||||
$value = $arguments[++$i];
|
||||
if ($value !== '#') {
|
||||
$arguments[$i] = "$prefix$value";
|
||||
}
|
||||
break;
|
||||
case 'GET':
|
||||
$value = $arguments[++$i];
|
||||
if ($value !== '#') {
|
||||
$arguments[$i] = "$prefix$value";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'LIMIT';
|
||||
$i += 2;
|
||||
break;
|
||||
case 'LIMIT';
|
||||
$i += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->setRawArguments($arguments);
|
||||
$this->setRawArguments($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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,13 +40,13 @@ class PrefixHelpers
|
||||
*/
|
||||
public static function all(CommandInterface $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
if ($arguments = $command->getArguments()) {
|
||||
foreach ($arguments as &$key) {
|
||||
$key = "$prefix$key";
|
||||
}
|
||||
|
||||
foreach ($arguments as &$key) {
|
||||
$key = "$prefix$key";
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,14 +57,15 @@ class PrefixHelpers
|
||||
*/
|
||||
public static function interleaved(CommandInterface $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$length = count($arguments);
|
||||
if ($arguments = $command->getArguments()) {
|
||||
$length = count($arguments);
|
||||
|
||||
for ($i = 0; $i < $length; $i += 2) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
for ($i = 0; $i < $length; $i += 2) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,14 +76,15 @@ class PrefixHelpers
|
||||
*/
|
||||
public static function skipFirst(CommandInterface $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$length = count($arguments);
|
||||
if ($arguments = $command->getArguments()) {
|
||||
$length = count($arguments);
|
||||
|
||||
for ($i = 1; $i < $length; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
for ($i = 1; $i < $length; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,13 +95,14 @@ class PrefixHelpers
|
||||
*/
|
||||
public static function skipLast(CommandInterface $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$length = count($arguments);
|
||||
if ($arguments = $command->getArguments()) {
|
||||
$length = count($arguments);
|
||||
|
||||
for ($i = 0; $i < $length - 1; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
for ($i = 0; $i < $length - 1; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class KeyPrefixProcessor implements CommandProcessorInterface
|
||||
*/
|
||||
public function process(CommandInterface $command)
|
||||
{
|
||||
if ($command instanceof PrefixableCommandInterface) {
|
||||
if ($command instanceof PrefixableCommandInterface && $command->getArguments()) {
|
||||
$command->prefixKeys($this->prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -30,13 +30,13 @@ class ServerEval extends AbstractCommand implements PrefixableCommandInterface
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
if ($arguments = $this->getArguments()) {
|
||||
for ($i = 2; $i < $arguments[1] + 2; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
for ($i = 2; $i < $arguments[1] + 2; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
$this->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
$this->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -33,7 +33,7 @@ class ZSetRange extends PrefixableCommand
|
||||
if (count($arguments) === 4) {
|
||||
$lastType = gettype($arguments[3]);
|
||||
|
||||
if ($lastType === 'string' && strtolower($arguments[3]) === 'withscores') {
|
||||
if ($lastType === 'string' && strtoupper($arguments[3]) === 'WITHSCORES') {
|
||||
// Used for compatibility with older versions
|
||||
$arguments[3] = array('WITHSCORES' => true);
|
||||
$lastType = 'array';
|
||||
@@ -59,7 +59,7 @@ class ZSetRange extends PrefixableCommand
|
||||
$opts = array_change_key_case($options, CASE_UPPER);
|
||||
$finalizedOpts = array();
|
||||
|
||||
if (isset($opts['WITHSCORES'])) {
|
||||
if (!empty($opts['WITHSCORES'])) {
|
||||
$finalizedOpts[] = 'WITHSCORES';
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,15 +79,15 @@ class ZSetUnionStore extends PrefixableCommand
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
if ($arguments = $this->getArguments()) {
|
||||
$arguments[0] = "$prefix{$arguments[0]}";
|
||||
$length = ((int) $arguments[1]) + 2;
|
||||
|
||||
$arguments[0] = "$prefix{$arguments[0]}";
|
||||
$length = ((int) $arguments[1]) + 2;
|
||||
for ($i = 2; $i < $length; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
for ($i = 2; $i < $length; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
$this->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
$this->setRawArguments($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 [{$this->parameters->scheme}://{$this->getIdentifier()}]", $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 [{$this->parameters->scheme}://{$this->getIdentifier()}]"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
* Defines a cluster of Redis servers formed by aggregating multiple
|
||||
* connection objects.
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\Profile\ServerProfileInterface;
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by classes that provide their own mechanism
|
||||
* to create and initialize new instances of Predis\Connection\SingleConnectionInterface.
|
||||
@@ -40,16 +38,16 @@ interface ConnectionFactoryInterface
|
||||
* Creates a new connection object.
|
||||
*
|
||||
* @param mixed $parameters Parameters for the connection.
|
||||
* @return Predis\Connection\SingleConnectionInterface
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
public function create($parameters);
|
||||
|
||||
/**
|
||||
* Prepares an aggregation of connection objects.
|
||||
*
|
||||
* @param AggregatedConnectionInterface Instance of an aggregated connection class.
|
||||
* @param AggregatedConnectionInterface $cluster Instance of an aggregated connection class.
|
||||
* @param array $parameters List of parameters for each connection object.
|
||||
* @return Predis\Connection\AggregatedConnectionInterface
|
||||
* @return AggregatedConnectionInterface
|
||||
*/
|
||||
public function createAggregated(AggregatedConnectionInterface $cluster, Array $parameters);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\Option\OptionInterface;
|
||||
|
||||
/**
|
||||
* Handles parsing and validation of connection parameters.
|
||||
@@ -28,7 +27,6 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'timeout' => 5.0,
|
||||
'iterable_multibulk' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -37,7 +35,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 +107,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 +138,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) {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Replication\ReplicationStrategy;
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\ResponseError;
|
||||
use Predis\ResponseQueued;
|
||||
@@ -41,7 +40,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 +89,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);
|
||||
}
|
||||
|
||||
@@ -236,10 +235,10 @@ class PhpiredisConnection extends AbstractConnection
|
||||
$host = $parameters->host;
|
||||
|
||||
if (ip2long($host) === false) {
|
||||
if (($address = gethostbyname($host)) === $host) {
|
||||
if (($addresses = gethostbynamel($host)) === false) {
|
||||
$this->onConnectionError("Cannot resolve the address of $host");
|
||||
}
|
||||
return $address;
|
||||
return $addresses[array_rand($addresses)];
|
||||
}
|
||||
|
||||
return $host;
|
||||
@@ -296,7 +295,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();
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\Cluster\CommandHashStrategyInterface;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\Cluster\PredisClusterHashStrategy;
|
||||
use Predis\Cluster\Distribution\DistributionStrategyInterface;
|
||||
@@ -166,7 +166,7 @@ class PredisCluster implements ClusterConnectionInterface, \IteratorAggregate, \
|
||||
* Returns the underlying command hash strategy used to hash
|
||||
* commands by their keys.
|
||||
*
|
||||
* @return Predis\Cluster\CommandHashStrategyInterface
|
||||
* @return CommandHashStrategyInterface
|
||||
*/
|
||||
public function getCommandHashStrategy()
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\Cluster\CommandHashStrategyInterface;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\ResponseErrorInterface;
|
||||
use Predis\Cluster\RedisClusterHashStrategy;
|
||||
@@ -135,7 +136,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 +178,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 +196,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 +215,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]");
|
||||
}
|
||||
|
||||
@@ -306,7 +307,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
* Returns the underlying command hash strategy used to hash
|
||||
* commands by their keys.
|
||||
*
|
||||
* @return Predis\Cluster\CommandHashStrategyInterface
|
||||
* @return CommandHashStrategyInterface
|
||||
*/
|
||||
public function getCommandHashStrategy()
|
||||
{
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
* Defines a group of Redis servers in a master/slave replication configuration.
|
||||
*
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\ResponseError;
|
||||
use Predis\ResponseQueued;
|
||||
use Predis\Command\CommandInterface;
|
||||
@@ -27,6 +26,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 +53,7 @@ class StreamConnection extends AbstractConnection
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (!$this->parameters->persistent) {
|
||||
if (isset($this->parameters) && !$this->parameters->persistent) {
|
||||
$this->disconnect();
|
||||
}
|
||||
}
|
||||
@@ -80,10 +80,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 +101,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 +120,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 +140,7 @@ class StreamConnection extends AbstractConnection
|
||||
{
|
||||
parent::connect();
|
||||
|
||||
if (count($this->initCmds) > 0){
|
||||
if ($this->initCmds) {
|
||||
$this->sendInitializationCommands();
|
||||
}
|
||||
}
|
||||
@@ -244,7 +249,7 @@ class StreamConnection extends AbstractConnection
|
||||
if ($count === -1) {
|
||||
return null;
|
||||
}
|
||||
if ($this->mbiterable === true) {
|
||||
if ($this->mbiterable) {
|
||||
return new MultiBulkResponseSimple($this, $count);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,11 @@
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Connection\AggregatedConnectionInterface;
|
||||
use Predis\Connection\ClusterConnectionInterface;
|
||||
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 +23,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 +42,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 +58,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
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ class MonitorContext implements \Iterator
|
||||
private $position;
|
||||
|
||||
/**
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
*/
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ class MonitorContext implements \Iterator
|
||||
* Checks if the passed client instance satisfies the required conditions
|
||||
* needed to initialize a monitor context.
|
||||
*
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
*/
|
||||
private function checkCapabilities(ClientInterface $client)
|
||||
{
|
||||
|
||||
@@ -103,4 +103,23 @@ class ClientOptions implements ClientOptionsInterface
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value for the specified option.
|
||||
*
|
||||
* @param string|OptionInterface $option Name or instance of the option.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault($option)
|
||||
{
|
||||
if ($option instanceof OptionInterface) {
|
||||
return $option->getDefault($this);
|
||||
}
|
||||
|
||||
$options = $this->getDefaultOptions();
|
||||
|
||||
if (isset($options[$option])) {
|
||||
return $options[$option]->getDefault($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class FireAndForgetExecutor implements PipelineExecutorInterface
|
||||
* connection before starting to execute the commands stored
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param ConnectionInterface Connection instance.
|
||||
* @param ConnectionInterface $connection Connection instance.
|
||||
*/
|
||||
protected function checkConnection(ConnectionInterface $connection)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@ use SplQueue;
|
||||
use Predis\ClientException;
|
||||
use Predis\ResponseErrorInterface;
|
||||
use Predis\ResponseObjectInterface;
|
||||
use Predis\ResponseQueued;
|
||||
use Predis\ServerException;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Connection\SingleConnectionInterface;
|
||||
@@ -47,7 +46,7 @@ class MultiExecExecutor implements PipelineExecutorInterface
|
||||
* connection before starting to execute the commands stored
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param ConnectionInterface Connection instance.
|
||||
* @param ConnectionInterface $connection Connection instance.
|
||||
*/
|
||||
protected function checkConnection(ConnectionInterface $connection)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@ use Predis\BasicClientInterface;
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\ExecutableContextInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
@@ -49,7 +48,7 @@ class PipelineContext implements BasicClientInterface, ExecutableContextInterfac
|
||||
* Returns a pipeline executor depending on the kind of the underlying
|
||||
* connection and the passed options.
|
||||
*
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @return PipelineExecutorInterface
|
||||
*/
|
||||
protected function createExecutor(ClientInterface $client)
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace Predis\Pipeline;
|
||||
|
||||
use SplQueue;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\ServerException;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,9 +11,12 @@
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Iterator;
|
||||
use SplQueue;
|
||||
use Predis\ResponseErrorInterface;
|
||||
use Predis\ResponseObjectInterface;
|
||||
use Predis\ServerException;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Connection\ReplicationConnectionInterface;
|
||||
|
||||
@@ -41,7 +44,7 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
* connection before starting to execute the commands stored
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param ConnectionInterface Connection instance.
|
||||
* @param ConnectionInterface $connection Connection instance.
|
||||
*/
|
||||
protected function checkConnection(ConnectionInterface $connection)
|
||||
{
|
||||
@@ -50,6 +53,27 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a response object.
|
||||
*
|
||||
* @param ConnectionInterface $connection
|
||||
* @param CommandInterface $command
|
||||
* @param ResponseObjectInterface $response
|
||||
* @return mixed
|
||||
*/
|
||||
protected function onResponseObject(ConnectionInterface $connection, CommandInterface $command, ResponseObjectInterface $response)
|
||||
{
|
||||
if ($response instanceof ResponseErrorInterface) {
|
||||
return $this->onResponseError($connection, $response);
|
||||
}
|
||||
|
||||
if ($response instanceof Iterator) {
|
||||
return $command->parseResponse(iterator_to_array($response));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles -ERR responses returned by Redis.
|
||||
*
|
||||
@@ -58,6 +82,10 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
*/
|
||||
protected function onResponseError(ConnectionInterface $connection, ResponseErrorInterface $response)
|
||||
{
|
||||
if (!$this->exceptions) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Force disconnection to prevent protocol desynchronization.
|
||||
$connection->disconnect();
|
||||
$message = $response->getMessage();
|
||||
@@ -70,24 +98,23 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
*/
|
||||
public function execute(ConnectionInterface $connection, SplQueue $commands)
|
||||
{
|
||||
$size = count($commands);
|
||||
$values = array();
|
||||
$exceptions = $this->exceptions;
|
||||
|
||||
$this->checkConnection($connection);
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$response = $connection->readResponse($commands->dequeue());
|
||||
$values = array();
|
||||
|
||||
if ($response instanceof ResponseErrorInterface && $exceptions === true) {
|
||||
$this->onResponseError($connection, $response);
|
||||
while (!$commands->isEmpty()) {
|
||||
$command = $commands->dequeue();
|
||||
$response = $connection->readResponse($command);
|
||||
|
||||
if ($response instanceof ResponseObjectInterface) {
|
||||
$values[] = $this->onResponseObject($connection, $command, $response);
|
||||
} else {
|
||||
$values[] = $command->parseResponse($response);
|
||||
}
|
||||
|
||||
$values[$i] = $response instanceof \Iterator ? iterator_to_array($response) : $response;
|
||||
}
|
||||
|
||||
return $values;
|
||||
|
||||
@@ -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,6 +11,7 @@
|
||||
|
||||
namespace Predis\Profile;
|
||||
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
* A server profile defines features and commands supported by certain
|
||||
@@ -49,7 +50,7 @@ interface ServerProfileInterface
|
||||
*
|
||||
* @param string $method Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @return Predis\Command\CommandInterface
|
||||
* @return CommandInterface
|
||||
*/
|
||||
public function createCommand($method, $arguments = array());
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ class ServerVersion26 extends ServerProfile
|
||||
'ttl' => 'Predis\Command\KeyTimeToLive',
|
||||
'move' => 'Predis\Command\KeyMove',
|
||||
'sort' => 'Predis\Command\KeySort',
|
||||
'dump' => 'Predis\Command\KeyDump',
|
||||
'restore' => 'Predis\Command\KeyRestore',
|
||||
|
||||
/* commands operating on string values */
|
||||
'set' => 'Predis\Command\StringSet',
|
||||
|
||||
@@ -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,10 +11,9 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\ResponseError;
|
||||
use Predis\ResponseQueued;
|
||||
use Predis\ServerException;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Iterator\MultiBulkResponseSimple;
|
||||
@@ -98,7 +97,7 @@ class TextProtocol implements ProtocolInterface
|
||||
if ($count === -1) {
|
||||
return null;
|
||||
}
|
||||
if ($this->mbiterable == true) {
|
||||
if ($this->mbiterable) {
|
||||
return new MultiBulkResponseSimple($connection, $count);
|
||||
}
|
||||
|
||||
@@ -117,7 +116,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
namespace Predis\PubSub;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\NotSupportedException;
|
||||
|
||||
/**
|
||||
* Client-side abstraction of a Publish / Subscribe context.
|
||||
*
|
||||
|
||||
@@ -21,26 +21,25 @@ use Predis\ClientInterface;
|
||||
*/
|
||||
class DispatcherLoop
|
||||
{
|
||||
private $client;
|
||||
private $pubSubContext;
|
||||
private $callbacks;
|
||||
private $defaultCallback;
|
||||
private $subscriptionCallback;
|
||||
|
||||
protected $callbacks;
|
||||
protected $defaultCallback;
|
||||
protected $subscriptionCallback;
|
||||
|
||||
/**
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
*/
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->callbacks = array();
|
||||
$this->client = $client;
|
||||
$this->pubSubContext = $client->pubSub();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the passed argument is a valid callback.
|
||||
*
|
||||
* @param mixed A callback.
|
||||
* @param mixed $callable A callback.
|
||||
*/
|
||||
protected function validateCallback($callable)
|
||||
{
|
||||
@@ -96,8 +95,10 @@ class DispatcherLoop
|
||||
*/
|
||||
public function attachCallback($channel, $callback)
|
||||
{
|
||||
$callbackName = $this->getPrefixKeys() . $channel;
|
||||
|
||||
$this->validateCallback($callback);
|
||||
$this->callbacks[$channel] = $callback;
|
||||
$this->callbacks[$callbackName] = $callback;
|
||||
$this->pubSubContext->subscribe($channel);
|
||||
}
|
||||
|
||||
@@ -108,8 +109,10 @@ class DispatcherLoop
|
||||
*/
|
||||
public function detachCallback($channel)
|
||||
{
|
||||
if (isset($this->callbacks[$channel])) {
|
||||
unset($this->callbacks[$channel]);
|
||||
$callbackName = $this->getPrefixKeys() . $channel;
|
||||
|
||||
if (isset($this->callbacks[$callbackName])) {
|
||||
unset($this->callbacks[$callbackName]);
|
||||
$this->pubSubContext->unsubscribe($channel);
|
||||
}
|
||||
}
|
||||
@@ -148,4 +151,20 @@ class DispatcherLoop
|
||||
{
|
||||
$this->pubSubContext->closeContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prefix of the keys
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getPrefixKeys()
|
||||
{
|
||||
$options = $this->pubSubContext->getClient()->getOptions();
|
||||
|
||||
if (isset($options->prefix)) {
|
||||
return $options->prefix->getPrefix();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -28,8 +28,8 @@ class PubSubContext extends AbstractPubSubContext
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param array Options for the context initialization.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @param array $options Options for the context initialization.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, Array $options = null)
|
||||
{
|
||||
@@ -41,11 +41,21 @@ class PubSubContext extends AbstractPubSubContext
|
||||
$this->genericSubscribeInit('psubscribe');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying client instance used by the pub/sub iterator.
|
||||
*
|
||||
* @return ClientInterface
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the passed client instance satisfies the required conditions
|
||||
* needed to initialize a Publish / Subscribe context.
|
||||
*
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
*/
|
||||
private function checkCapabilities(ClientInterface $client)
|
||||
{
|
||||
@@ -77,7 +87,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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
<?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\Session;
|
||||
|
||||
use SessionHandlerInterface;
|
||||
use Predis\ClientInterface;
|
||||
|
||||
/**
|
||||
* Session handler class that relies on Predis\Client to store PHP's sessions
|
||||
* data into one or multiple Redis servers.
|
||||
*
|
||||
* This class is mostly intended for PHP 5.4 but it can be used under PHP 5.3 provided
|
||||
* that a polyfill for `SessionHandlerInterface` is defined by either you or an external
|
||||
* package such as `symfony/http-foundation`.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class SessionHandler implements SessionHandlerInterface
|
||||
{
|
||||
protected $client;
|
||||
protected $ttl;
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client Fully initialized client instance.
|
||||
* @param array $options Session handler options.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, Array $options = array())
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->ttl = (int) (isset($options['gc_maxlifetime']) ? $options['gc_maxlifetime'] : ini_get('session.gc_maxlifetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the handler instance as the current session handler.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
session_set_save_handler($this, true);
|
||||
} else {
|
||||
session_set_save_handler(
|
||||
array($this, 'open'),
|
||||
array($this, 'close'),
|
||||
array($this, 'read'),
|
||||
array($this, 'write'),
|
||||
array($this, 'destroy'),
|
||||
array($this, 'gc')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function open($save_path, $session_id)
|
||||
{
|
||||
// NOOP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
// NOOP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
// NOOP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($session_id)
|
||||
{
|
||||
if ($data = $this->client->get($session_id)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write($session_id, $session_data)
|
||||
{
|
||||
$this->client->setex($session_id, $this->ttl, $session_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function destroy($session_id)
|
||||
{
|
||||
$this->client->del($session_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying client instance.
|
||||
*
|
||||
* @return ClientInterface
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session max lifetime value.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxLifeTime()
|
||||
{
|
||||
return $this->ttl;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -48,8 +47,8 @@ class MultiExecContext implements BasicClientInterface, ExecutableContextInterfa
|
||||
protected $commands;
|
||||
|
||||
/**
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param array Options for the context initialization.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @param array $options Options for the context initialization.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, Array $options = null)
|
||||
{
|
||||
@@ -114,7 +113,7 @@ class MultiExecContext implements BasicClientInterface, ExecutableContextInterfa
|
||||
* Checks if the passed client instance satisfies the required conditions
|
||||
* needed to initialize a transaction context.
|
||||
*
|
||||
* @param ClientInterface Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
*/
|
||||
private function checkCapabilities(ClientInterface $client)
|
||||
{
|
||||
@@ -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
|
||||
));
|
||||
}
|
||||
|
||||
+3
-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.1"
|
||||
version = "0.8.4"
|
||||
stability = "stable"
|
||||
channel = "pear.nrk.io"
|
||||
|
||||
@@ -21,7 +21,9 @@ php = ">= 5.3.2"
|
||||
pearinstaller = "1.4.1"
|
||||
|
||||
[roles]
|
||||
*.xml.dist = test
|
||||
*.md = doc
|
||||
LICENSE = doc
|
||||
lib = php
|
||||
|
||||
[optional phpiredis]
|
||||
|
||||
@@ -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}'));
|
||||
@@ -261,6 +263,8 @@ class PredisClusterHashStrategyTest extends StandardTestCase
|
||||
'TTL' => 'keys-first',
|
||||
'PTTL' => 'keys-first',
|
||||
'SORT' => 'keys-first', // TODO
|
||||
'DUMP' => 'keys-first',
|
||||
'RESTORE' => 'keys-first',
|
||||
|
||||
/* commands operating on string values */
|
||||
'APPEND' => 'keys-first',
|
||||
@@ -343,6 +347,7 @@ class PredisClusterHashStrategyTest extends StandardTestCase
|
||||
'HGET' => 'keys-first',
|
||||
'HGETALL' => 'keys-first',
|
||||
'HMGET' => 'keys-first',
|
||||
'HMSET' => 'keys-first',
|
||||
'HINCRBY' => 'keys-first',
|
||||
'HINCRBYFLOAT' => 'keys-first',
|
||||
'HKEYS' => 'keys-first',
|
||||
|
||||
@@ -186,7 +186,7 @@ class RedisClusterHashStrategyTest extends StandardTestCase
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue('return true'));
|
||||
$command->expects($this->exactly(1))
|
||||
$command->expects($this->exactly(2))
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(1));
|
||||
$command->setArguments($arguments);
|
||||
@@ -340,6 +340,7 @@ class RedisClusterHashStrategyTest extends StandardTestCase
|
||||
'HGET' => 'keys-first',
|
||||
'HGETALL' => 'keys-first',
|
||||
'HMGET' => 'keys-first',
|
||||
'HMSET' => 'keys-first',
|
||||
'HINCRBY' => 'keys-first',
|
||||
'HINCRBYFLOAT' => 'keys-first',
|
||||
'HKEYS' => 'keys-first',
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,17 @@ class HashDeleteTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,17 @@ class HashExistsTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -76,6 +76,17 @@ class HashGetAllTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -90,6 +90,17 @@ class HashGetMultipleTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,17 @@ class HashGetTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,17 @@ class HashIncrementByFloatTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,17 @@ class HashIncrementByTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -76,6 +76,17 @@ class HashKeysTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,17 @@ class HashLengthTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -85,6 +85,17 @@ class HashSetMultipleTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,17 @@ class HashSetPreserveTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,17 @@ class HashSetTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -76,6 +76,17 @@ class HashValuesTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -86,6 +86,17 @@ class KeyDeleteTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?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\Command;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-key
|
||||
*/
|
||||
class KeyDumpTest extends CommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand()
|
||||
{
|
||||
return 'Predis\Command\KeyDump';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId()
|
||||
{
|
||||
return 'DUMP';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments()
|
||||
{
|
||||
$arguments = array('key');
|
||||
$expected = array('key');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse()
|
||||
{
|
||||
$raw = "\x00\xC0\n\x06\x00\xF8r?\xC5\xFB\xFB_(";
|
||||
$expected = "\x00\xC0\n\x06\x00\xF8r?\xC5\xFB\xFB_(";
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeys()
|
||||
{
|
||||
$arguments = array('key');
|
||||
$expected = array('prefix:key');
|
||||
|
||||
$command = $this->getCommandWithArgumentsArray($arguments);
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,17 @@ class KeyExistsTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,17 @@ class KeyExpireAtTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
@@ -85,6 +96,7 @@ class KeyExpireAtTest extends CommandTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
* @group connected
|
||||
* @group slow
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,17 @@ class KeyExpireTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
@@ -85,6 +96,7 @@ class KeyExpireTest extends CommandTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
* @group connected
|
||||
* @group slow
|
||||
*/
|
||||
@@ -103,6 +115,7 @@ class KeyExpireTest extends CommandTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
* @group connected
|
||||
* @group slow
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,17 @@ class KeyKeysTest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame(array(), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user