mirror of
https://github.com/predis/predis.git
synced 2026-08-20 14:21:51 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8be2418f01 | |||
| b9ebe8a376 | |||
| e2d26926d2 | |||
| 309248042f | |||
| 87452e62d0 | |||
| 31baa9b241 | |||
| 6f942400a1 | |||
| 5e220a0b57 | |||
| 0eb2633348 | |||
| cbbd6bba88 | |||
| 3702f24efc | |||
| 82fefe057b | |||
| 42336537dc | |||
| 802abac55e | |||
| 61e75816ce | |||
| 17f0c08cb6 | |||
| 2b8af1eef2 | |||
| c5f2b441b4 | |||
| 2440a61cba | |||
| 7100884201 | |||
| 2a932d7292 | |||
| 0a6306b73e | |||
| 4363345f7c | |||
| 39ff616e86 | |||
| 738ec0c50f | |||
| 1828222e27 |
+2
-1
@@ -3,10 +3,11 @@
|
||||
/tests/PHPUnit export-ignore
|
||||
/tests/Predis export-ignore
|
||||
/tests/bootstrap.php export-ignore
|
||||
/.github export-ignore
|
||||
/.editorconfig export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.php_cs export-ignore
|
||||
/.php_cs.dist export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/phpunit.xml.travisci export-ignore
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*.phar
|
||||
.php-version
|
||||
.php_cs.cache
|
||||
.phpunit.result.cache
|
||||
phpunit.xml
|
||||
package.xml
|
||||
composer.lock
|
||||
|
||||
@@ -1,3 +1,37 @@
|
||||
v1.1.4 (2020-08-31)
|
||||
================================================================================
|
||||
|
||||
- Improved @method annotations for methods responding to Redis commands defined
|
||||
by `Predis\ClientInterface` and `Predis\ClientContextInterface`. (PR #456 and
|
||||
PR #497, other fixes applied after further analysys).
|
||||
|
||||
- __FIX__: the client can now handle ACL authentication when connecting to Redis
|
||||
6.x simply by passing both `username` and `password` to connection parameters.
|
||||
See [the Redis docs](https://redis.io/topics/acl) for details on this topic.
|
||||
|
||||
- __FIX__: NULL or zero-length string values passed to `password` and `database`
|
||||
in the connection parameters list do not trigger spurious `AUTH` and `SELECT`
|
||||
commands anymore when connecting to Redis (ISSUE #436).
|
||||
|
||||
- __FIX__: initializing an iteration over a client instance when it is connected
|
||||
to a standalone Redis server will not throw an exception anymore, instead it
|
||||
will return an iterator that will run for just one loop returning a new client
|
||||
instance using the underlying single-node connection (ISSUE #552, PR #556).
|
||||
|
||||
- __FIX__: `Predis\Cluster\Distributor\HashRingaddNodeToRing()` was calculating
|
||||
the hash required for distribution by using `crc32()` directly instead of the
|
||||
method `Predis\Cluster\Hash\HashGeneratorInterface::hash()` implemented by the
|
||||
class itself. This bug fix does not have any impact on existing clusters that
|
||||
use client-side sharding based on this distributor simply because it does not
|
||||
take any external hash generators so distribution is not going to be affected.
|
||||
|
||||
- __FIX__: `SORT` now always trigger a switch to the master node in replication
|
||||
configurations instead of just when the `STORE` modifier is specified, this is
|
||||
because `SORT` is always considered to be a write operation and actually fails
|
||||
with a `-READONLY` error response when executed against a replica node. (ISSUE
|
||||
#554).
|
||||
|
||||
|
||||
v1.1.3 (2020-08-18)
|
||||
================================================================================
|
||||
|
||||
|
||||
@@ -87,6 +87,9 @@ $client = new Predis\Client([
|
||||
$client = new Predis\Client('tcp://10.0.0.1:6379');
|
||||
```
|
||||
|
||||
Password protected servers can be accessed by adding `password` to the parameters set. When ACLs are
|
||||
enabled on Redis >= 6.0, both `username` and `password` are required for user authentication.
|
||||
|
||||
It is also possible to connect to local instances of Redis using UNIX domain sockets, in this case
|
||||
the parameters must use the `unix` scheme and specify a path for the socket file:
|
||||
|
||||
|
||||
+2
-2
@@ -115,7 +115,7 @@ function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
|
||||
function generatePackageXml($packageINI)
|
||||
{
|
||||
$XML = <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package packagerversion="1.4.10" version="2.0"
|
||||
xmlns="http://pear.php.net/dtd/package-2.0"
|
||||
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
||||
@@ -197,7 +197,7 @@ function rewritePackageInstallAs($pkg)
|
||||
|
||||
function savePackageXml($xml)
|
||||
{
|
||||
$dom = new DOMDocument("1.0");
|
||||
$dom = new DOMDocument("1.0", "UTF-8");
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
$dom->loadXML($xml->asXML());
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ name = "Predis"
|
||||
desc = "Flexible and feature-complete Redis client for PHP and HHVM"
|
||||
homepage = "http://github.com/nrk/predis"
|
||||
license = "MIT"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
stability = "stable"
|
||||
channel = "pear.nrk.io"
|
||||
|
||||
|
||||
+4
-2
@@ -40,7 +40,7 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
|
||||
*/
|
||||
class Client implements ClientInterface, \IteratorAggregate
|
||||
{
|
||||
const VERSION = '1.1.3';
|
||||
const VERSION = '1.1.4';
|
||||
|
||||
protected $connection;
|
||||
protected $options;
|
||||
@@ -535,7 +535,9 @@ class Client implements ClientInterface, \IteratorAggregate
|
||||
$connection = $this->getConnection();
|
||||
|
||||
if (!$connection instanceof \Traversable) {
|
||||
throw new ClientException('The underlying connection is not traversable');
|
||||
return new \ArrayIterator(array(
|
||||
(string) $connection => new static($connection, $this->getOptions())
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($connection as $node) {
|
||||
|
||||
@@ -39,6 +39,7 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this bitcount($key, $start = null, $end = null)
|
||||
* @method $this bitop($operation, $destkey, $key)
|
||||
* @method $this bitfield($key, $subcommand, ...$subcommandArg)
|
||||
* @method $this bitpos($key, $bit, $start = null, $end = null)
|
||||
* @method $this decr($key)
|
||||
* @method $this decrby($key, $decrement)
|
||||
* @method $this get($key)
|
||||
@@ -81,7 +82,7 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this llen($key)
|
||||
* @method $this lpop($key)
|
||||
* @method $this lpush($key, array $values)
|
||||
* @method $this lpushx($key, $value)
|
||||
* @method $this lpushx($key, array $values)
|
||||
* @method $this lrange($key, $start, $stop)
|
||||
* @method $this lrem($key, $count, $value)
|
||||
* @method $this lset($key, $index, $value)
|
||||
@@ -89,7 +90,7 @@ use Predis\Command\CommandInterface;
|
||||
* @method $this rpop($key)
|
||||
* @method $this rpoplpush($source, $destination)
|
||||
* @method $this rpush($key, array $values)
|
||||
* @method $this rpushx($key, $value)
|
||||
* @method $this rpushx($key, array $values)
|
||||
* @method $this sadd($key, array $members)
|
||||
* @method $this scard($key)
|
||||
* @method $this sdiff(array|string $keys)
|
||||
|
||||
+148
-147
@@ -24,153 +24,154 @@ use Predis\Profile\ProfileInterface;
|
||||
* and more friendly interface to ease programming which is described in the
|
||||
* following list of methods:
|
||||
*
|
||||
* @method int del(array|string $keys)
|
||||
* @method string dump($key)
|
||||
* @method int exists($key)
|
||||
* @method int expire($key, $seconds)
|
||||
* @method int expireat($key, $timestamp)
|
||||
* @method array keys($pattern)
|
||||
* @method int move($key, $db)
|
||||
* @method mixed object($subcommand, $key)
|
||||
* @method int persist($key)
|
||||
* @method int pexpire($key, $milliseconds)
|
||||
* @method int pexpireat($key, $timestamp)
|
||||
* @method int pttl($key)
|
||||
* @method string randomkey()
|
||||
* @method mixed rename($key, $target)
|
||||
* @method int renamenx($key, $target)
|
||||
* @method array scan($cursor, array $options = null)
|
||||
* @method array sort($key, array $options = null)
|
||||
* @method int ttl($key)
|
||||
* @method mixed type($key)
|
||||
* @method int append($key, $value)
|
||||
* @method int bitcount($key, $start = null, $end = null)
|
||||
* @method int bitop($operation, $destkey, $key)
|
||||
* @method array bitfield($key, $subcommand, ...$subcommandArg)
|
||||
* @method int decr($key)
|
||||
* @method int decrby($key, $decrement)
|
||||
* @method string get($key)
|
||||
* @method int getbit($key, $offset)
|
||||
* @method string getrange($key, $start, $end)
|
||||
* @method string getset($key, $value)
|
||||
* @method int incr($key)
|
||||
* @method int incrby($key, $increment)
|
||||
* @method string incrbyfloat($key, $increment)
|
||||
* @method array mget(array $keys)
|
||||
* @method mixed mset(array $dictionary)
|
||||
* @method int msetnx(array $dictionary)
|
||||
* @method mixed psetex($key, $milliseconds, $value)
|
||||
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
|
||||
* @method int setbit($key, $offset, $value)
|
||||
* @method int setex($key, $seconds, $value)
|
||||
* @method int setnx($key, $value)
|
||||
* @method int setrange($key, $offset, $value)
|
||||
* @method int strlen($key)
|
||||
* @method int hdel($key, array $fields)
|
||||
* @method int hexists($key, $field)
|
||||
* @method string hget($key, $field)
|
||||
* @method array hgetall($key)
|
||||
* @method int hincrby($key, $field, $increment)
|
||||
* @method string hincrbyfloat($key, $field, $increment)
|
||||
* @method array hkeys($key)
|
||||
* @method int hlen($key)
|
||||
* @method array hmget($key, array $fields)
|
||||
* @method mixed hmset($key, array $dictionary)
|
||||
* @method array hscan($key, $cursor, array $options = null)
|
||||
* @method int hset($key, $field, $value)
|
||||
* @method int hsetnx($key, $field, $value)
|
||||
* @method array hvals($key)
|
||||
* @method int hstrlen($key, $field)
|
||||
* @method array blpop(array|string $keys, $timeout)
|
||||
* @method array brpop(array|string $keys, $timeout)
|
||||
* @method array brpoplpush($source, $destination, $timeout)
|
||||
* @method string lindex($key, $index)
|
||||
* @method int linsert($key, $whence, $pivot, $value)
|
||||
* @method int llen($key)
|
||||
* @method string lpop($key)
|
||||
* @method int lpush($key, array $values)
|
||||
* @method int lpushx($key, $value)
|
||||
* @method array lrange($key, $start, $stop)
|
||||
* @method int lrem($key, $count, $value)
|
||||
* @method mixed lset($key, $index, $value)
|
||||
* @method mixed ltrim($key, $start, $stop)
|
||||
* @method string rpop($key)
|
||||
* @method string rpoplpush($source, $destination)
|
||||
* @method int rpush($key, array $values)
|
||||
* @method int rpushx($key, $value)
|
||||
* @method int sadd($key, array $members)
|
||||
* @method int scard($key)
|
||||
* @method array sdiff(array|string $keys)
|
||||
* @method int sdiffstore($destination, array|string $keys)
|
||||
* @method array sinter(array|string $keys)
|
||||
* @method int sinterstore($destination, array|string $keys)
|
||||
* @method int sismember($key, $member)
|
||||
* @method array smembers($key)
|
||||
* @method int smove($source, $destination, $member)
|
||||
* @method array spop($key, $count = null)
|
||||
* @method string srandmember($key, $count = null)
|
||||
* @method int srem($key, $member)
|
||||
* @method array sscan($key, $cursor, array $options = null)
|
||||
* @method array sunion(array|string $keys)
|
||||
* @method int sunionstore($destination, array|string $keys)
|
||||
* @method int zadd($key, array $membersAndScoresDictionary)
|
||||
* @method int zcard($key)
|
||||
* @method string zcount($key, $min, $max)
|
||||
* @method string zincrby($key, $increment, $member)
|
||||
* @method int zinterstore($destination, array|string $keys, array $options = null)
|
||||
* @method array zrange($key, $start, $stop, array $options = null)
|
||||
* @method array zrangebyscore($key, $min, $max, array $options = null)
|
||||
* @method int zrank($key, $member)
|
||||
* @method int zrem($key, $member)
|
||||
* @method int zremrangebyrank($key, $start, $stop)
|
||||
* @method int zremrangebyscore($key, $min, $max)
|
||||
* @method array zrevrange($key, $start, $stop, array $options = null)
|
||||
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
|
||||
* @method int zrevrank($key, $member)
|
||||
* @method int zunionstore($destination, array|string $keys, array $options = null)
|
||||
* @method string zscore($key, $member)
|
||||
* @method array zscan($key, $cursor, array $options = null)
|
||||
* @method array zrangebylex($key, $start, $stop, array $options = null)
|
||||
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
|
||||
* @method int zremrangebylex($key, $min, $max)
|
||||
* @method int zlexcount($key, $min, $max)
|
||||
* @method int pfadd($key, array $elements)
|
||||
* @method mixed pfmerge($destinationKey, array|string $sourceKeys)
|
||||
* @method int pfcount(array|string $keys)
|
||||
* @method mixed pubsub($subcommand, $argument)
|
||||
* @method int publish($channel, $message)
|
||||
* @method mixed discard()
|
||||
* @method array exec()
|
||||
* @method mixed multi()
|
||||
* @method mixed unwatch()
|
||||
* @method mixed watch($key)
|
||||
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
|
||||
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
|
||||
* @method mixed script($subcommand, $argument = null)
|
||||
* @method mixed auth($password)
|
||||
* @method string echo($message)
|
||||
* @method mixed ping($message = null)
|
||||
* @method mixed select($database)
|
||||
* @method mixed bgrewriteaof()
|
||||
* @method mixed bgsave()
|
||||
* @method mixed client($subcommand, $argument = null)
|
||||
* @method mixed config($subcommand, $argument = null)
|
||||
* @method int dbsize()
|
||||
* @method mixed flushall()
|
||||
* @method mixed flushdb()
|
||||
* @method array info($section = null)
|
||||
* @method int lastsave()
|
||||
* @method mixed save()
|
||||
* @method mixed slaveof($host, $port)
|
||||
* @method mixed slowlog($subcommand, $argument = null)
|
||||
* @method array time()
|
||||
* @method array command()
|
||||
* @method int geoadd($key, $longitude, $latitude, $member)
|
||||
* @method array geohash($key, array $members)
|
||||
* @method array geopos($key, array $members)
|
||||
* @method string geodist($key, $member1, $member2, $unit = null)
|
||||
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
|
||||
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
|
||||
* @method int del(array|string $keys)
|
||||
* @method string|null dump($key)
|
||||
* @method int exists($key)
|
||||
* @method int expire($key, $seconds)
|
||||
* @method int expireat($key, $timestamp)
|
||||
* @method array keys($pattern)
|
||||
* @method int move($key, $db)
|
||||
* @method mixed object($subcommand, $key)
|
||||
* @method int persist($key)
|
||||
* @method int pexpire($key, $milliseconds)
|
||||
* @method int pexpireat($key, $timestamp)
|
||||
* @method int pttl($key)
|
||||
* @method string|null randomkey()
|
||||
* @method mixed rename($key, $target)
|
||||
* @method int renamenx($key, $target)
|
||||
* @method array scan($cursor, array $options = null)
|
||||
* @method array sort($key, array $options = null)
|
||||
* @method int ttl($key)
|
||||
* @method mixed type($key)
|
||||
* @method int append($key, $value)
|
||||
* @method int bitcount($key, $start = null, $end = null)
|
||||
* @method int bitop($operation, $destkey, $key)
|
||||
* @method array|null bitfield($key, $subcommand, ...$subcommandArg)
|
||||
* @method int bitpos($key, $bit, $start = null, $end = null)
|
||||
* @method int decr($key)
|
||||
* @method int decrby($key, $decrement)
|
||||
* @method string|null get($key)
|
||||
* @method int getbit($key, $offset)
|
||||
* @method string getrange($key, $start, $end)
|
||||
* @method string|null getset($key, $value)
|
||||
* @method int incr($key)
|
||||
* @method int incrby($key, $increment)
|
||||
* @method string incrbyfloat($key, $increment)
|
||||
* @method array mget(array $keys)
|
||||
* @method mixed mset(array $dictionary)
|
||||
* @method int msetnx(array $dictionary)
|
||||
* @method mixed psetex($key, $milliseconds, $value)
|
||||
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
|
||||
* @method int setbit($key, $offset, $value)
|
||||
* @method int setex($key, $seconds, $value)
|
||||
* @method int setnx($key, $value)
|
||||
* @method int setrange($key, $offset, $value)
|
||||
* @method int strlen($key)
|
||||
* @method int hdel($key, array $fields)
|
||||
* @method int hexists($key, $field)
|
||||
* @method string|null hget($key, $field)
|
||||
* @method array hgetall($key)
|
||||
* @method int hincrby($key, $field, $increment)
|
||||
* @method string hincrbyfloat($key, $field, $increment)
|
||||
* @method array hkeys($key)
|
||||
* @method int hlen($key)
|
||||
* @method array hmget($key, array $fields)
|
||||
* @method mixed hmset($key, array $dictionary)
|
||||
* @method array hscan($key, $cursor, array $options = null)
|
||||
* @method int hset($key, $field, $value)
|
||||
* @method int hsetnx($key, $field, $value)
|
||||
* @method array hvals($key)
|
||||
* @method int hstrlen($key, $field)
|
||||
* @method array|null blpop(array|string $keys, $timeout)
|
||||
* @method array|null brpop(array|string $keys, $timeout)
|
||||
* @method string|null brpoplpush($source, $destination, $timeout)
|
||||
* @method string|null lindex($key, $index)
|
||||
* @method int linsert($key, $whence, $pivot, $value)
|
||||
* @method int llen($key)
|
||||
* @method string|null lpop($key)
|
||||
* @method int lpush($key, array $values)
|
||||
* @method int lpushx($key, array $values)
|
||||
* @method array lrange($key, $start, $stop)
|
||||
* @method int lrem($key, $count, $value)
|
||||
* @method mixed lset($key, $index, $value)
|
||||
* @method mixed ltrim($key, $start, $stop)
|
||||
* @method string|null rpop($key)
|
||||
* @method string|null rpoplpush($source, $destination)
|
||||
* @method int rpush($key, array $values)
|
||||
* @method int rpushx($key, array $values)
|
||||
* @method int sadd($key, array $members)
|
||||
* @method int scard($key)
|
||||
* @method array sdiff(array|string $keys)
|
||||
* @method int sdiffstore($destination, array|string $keys)
|
||||
* @method array sinter(array|string $keys)
|
||||
* @method int sinterstore($destination, array|string $keys)
|
||||
* @method int sismember($key, $member)
|
||||
* @method array smembers($key)
|
||||
* @method int smove($source, $destination, $member)
|
||||
* @method string|null spop($key, $count = null)
|
||||
* @method string|null srandmember($key, $count = null)
|
||||
* @method int srem($key, $member)
|
||||
* @method array sscan($key, $cursor, array $options = null)
|
||||
* @method array sunion(array|string $keys)
|
||||
* @method int sunionstore($destination, array|string $keys)
|
||||
* @method int zadd($key, array $membersAndScoresDictionary)
|
||||
* @method int zcard($key)
|
||||
* @method string zcount($key, $min, $max)
|
||||
* @method string zincrby($key, $increment, $member)
|
||||
* @method int zinterstore($destination, array|string $keys, array $options = null)
|
||||
* @method array zrange($key, $start, $stop, array $options = null)
|
||||
* @method array zrangebyscore($key, $min, $max, array $options = null)
|
||||
* @method int|null zrank($key, $member)
|
||||
* @method int zrem($key, $member)
|
||||
* @method int zremrangebyrank($key, $start, $stop)
|
||||
* @method int zremrangebyscore($key, $min, $max)
|
||||
* @method array zrevrange($key, $start, $stop, array $options = null)
|
||||
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
|
||||
* @method int|null zrevrank($key, $member)
|
||||
* @method int zunionstore($destination, array|string $keys, array $options = null)
|
||||
* @method string|null zscore($key, $member)
|
||||
* @method array zscan($key, $cursor, array $options = null)
|
||||
* @method array zrangebylex($key, $start, $stop, array $options = null)
|
||||
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
|
||||
* @method int zremrangebylex($key, $min, $max)
|
||||
* @method int zlexcount($key, $min, $max)
|
||||
* @method int pfadd($key, array $elements)
|
||||
* @method mixed pfmerge($destinationKey, array|string $sourceKeys)
|
||||
* @method int pfcount(array|string $keys)
|
||||
* @method mixed pubsub($subcommand, $argument)
|
||||
* @method int publish($channel, $message)
|
||||
* @method mixed discard()
|
||||
* @method array|null exec()
|
||||
* @method mixed multi()
|
||||
* @method mixed unwatch()
|
||||
* @method mixed watch($key)
|
||||
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
|
||||
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
|
||||
* @method mixed script($subcommand, $argument = null)
|
||||
* @method mixed auth($password)
|
||||
* @method string echo($message)
|
||||
* @method mixed ping($message = null)
|
||||
* @method mixed select($database)
|
||||
* @method mixed bgrewriteaof()
|
||||
* @method mixed bgsave()
|
||||
* @method mixed client($subcommand, $argument = null)
|
||||
* @method mixed config($subcommand, $argument = null)
|
||||
* @method int dbsize()
|
||||
* @method mixed flushall()
|
||||
* @method mixed flushdb()
|
||||
* @method array info($section = null)
|
||||
* @method int lastsave()
|
||||
* @method mixed save()
|
||||
* @method mixed slaveof($host, $port)
|
||||
* @method mixed slowlog($subcommand, $argument = null)
|
||||
* @method array time()
|
||||
* @method array command()
|
||||
* @method int geoadd($key, $longitude, $latitude, $member)
|
||||
* @method array geohash($key, array $members)
|
||||
* @method array geopos($key, array $members)
|
||||
* @method string|null geodist($key, $member1, $member2, $unit = null)
|
||||
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
|
||||
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
|
||||
@@ -161,7 +161,7 @@ class HashRing implements DistributorInterface, HashGeneratorInterface
|
||||
$replicas = (int) round($weightRatio * $totalNodes * $replicas);
|
||||
|
||||
for ($i = 0; $i < $replicas; ++$i) {
|
||||
$key = crc32("$nodeHash:$i");
|
||||
$key = $this->hash("$nodeHash:$i");
|
||||
$ring[$key] = $nodeObject;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,13 +173,17 @@ class Factory implements FactoryInterface
|
||||
{
|
||||
$parameters = $connection->getParameters();
|
||||
|
||||
if (isset($parameters->password)) {
|
||||
if (isset($parameters->password) && strlen($parameters->password)) {
|
||||
$cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
|
||||
? array('AUTH', $parameters->username, $parameters->password)
|
||||
: array('AUTH', $parameters->password);
|
||||
|
||||
$connection->addConnectCommand(
|
||||
new RawCommand(array('AUTH', $parameters->password))
|
||||
new RawCommand($cmdAuthArgs)
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($parameters->database)) {
|
||||
if (isset($parameters->database) && strlen($parameters->database)) {
|
||||
$connection->addConnectCommand(
|
||||
new RawCommand(array('SELECT', $parameters->database))
|
||||
);
|
||||
|
||||
@@ -89,31 +89,6 @@ class ReplicationStrategy
|
||||
return isset($this->disallowed[$command->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a SORT command is a readable operation by parsing the arguments
|
||||
* array of the specified commad instance.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isSortReadOnly(CommandInterface $command)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$argc = count($arguments);
|
||||
|
||||
if ($argc > 1) {
|
||||
for ($i = 1; $i < $argc; ++$i) {
|
||||
$argument = strtoupper($arguments[$i]);
|
||||
if ($argument === 'STORE') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if BITFIELD performs a read-only operation by looking for certain
|
||||
* SET and INCRYBY modifiers in the arguments array of the command.
|
||||
@@ -292,7 +267,6 @@ class ReplicationStrategy
|
||||
'BITPOS' => true,
|
||||
'TIME' => true,
|
||||
'PFCOUNT' => true,
|
||||
'SORT' => array($this, 'isSortReadOnly'),
|
||||
'BITFIELD' => array($this, 'isBitfieldReadOnly'),
|
||||
'GEOHASH' => true,
|
||||
'GEOPOS' => true,
|
||||
|
||||
@@ -853,15 +853,17 @@ class ClientTest extends PredisTestCase
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException \Predis\ClientException
|
||||
* @expectedExceptionMessage The underlying connection is not traversable
|
||||
*/
|
||||
public function testGetIteratorWithNonTraversableConnectionThrowsException()
|
||||
public function testGetIteratorWithNonTraversableConnectionNoException()
|
||||
{
|
||||
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
|
||||
$connection = $this->getMockConnection('tcp://127.0.0.1:6381');
|
||||
$client = new Client($connection);
|
||||
|
||||
$client->getIterator();
|
||||
$iterator = $client->getIterator();
|
||||
|
||||
$this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
|
||||
$this->assertSame($connection, $nodeClient->getConnection());
|
||||
$this->assertSame('127.0.0.1:6381', $iterator->key());
|
||||
}
|
||||
|
||||
// ******************************************************************** //
|
||||
|
||||
@@ -102,13 +102,24 @@ class ServerCommandTest extends PredisCommandTestCase
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
|
||||
|
||||
// NOTE: starting with Redis 6.0 and the introduction of Access Control
|
||||
// Lists, COMMAND INFO returns an additional array for each specified
|
||||
// command in yhe request with a list of the ACL categories associated
|
||||
// to a command. We simply append this additional array in the expected
|
||||
// response if the test suite is executed against Redis >= 6.0.
|
||||
if ($this->isRedisServerVersion('>=', '6.0')) {
|
||||
$expected[0][] = array('@read', '@string', '@fast');
|
||||
}
|
||||
|
||||
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
|
||||
|
||||
// NOTE: we use assertEquals instead of assertSame because Redis returns
|
||||
// flags as +STATUS responses, represented by Predis with instances of
|
||||
// Predis\Response\Status instead of plain strings. This class responds
|
||||
// to __toString() so the string conversion is implicit, but assertSame
|
||||
// checks for strict equality while assertEquals is loose.
|
||||
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
|
||||
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
|
||||
$this->assertEquals($expected, $response);
|
||||
}
|
||||
|
||||
|
||||
@@ -541,29 +541,6 @@ class MasterSlaveReplicationTest extends PredisTestCase
|
||||
$replication->executeCommand($cmdEval);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testSortTriggersSwitchToMasterConnectionOnStoreModifier()
|
||||
{
|
||||
$profile = Profile\Factory::get('dev');
|
||||
$cmdSortNormal = $profile->createCommand('sort', array('key'));
|
||||
$cmdSortStore = $profile->createCommand('sort', array('key', array('store' => 'key:store')));
|
||||
|
||||
$master = $this->getMockConnection('tcp://host1?alias=master');
|
||||
$master->expects($this->once())->method('executeCommand')->with($cmdSortStore);
|
||||
|
||||
$slave1 = $this->getMockConnection('tcp://host2?alias=slave1');
|
||||
$slave1->expects($this->once())->method('executeCommand')->with($cmdSortNormal);
|
||||
|
||||
$replication = new MasterSlaveReplication();
|
||||
$replication->add($master);
|
||||
$replication->add($slave1);
|
||||
|
||||
$replication->executeCommand($cmdSortNormal);
|
||||
$replication->executeCommand($cmdSortStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -280,8 +280,6 @@ class FactoryTest extends PredisTestCase
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*
|
||||
* @todo This test smells but there's no other way around it right now.
|
||||
*/
|
||||
public function testCreateConnectionWithInitializationCommands()
|
||||
{
|
||||
@@ -303,6 +301,111 @@ class FactoryTest extends PredisTestCase
|
||||
|
||||
$factory = new Factory();
|
||||
|
||||
// TODO: using reflection to make a protected method accessible :facepalm:
|
||||
$reflection = new \ReflectionObject($factory);
|
||||
$prepareConnection = $reflection->getMethod('prepareConnection');
|
||||
$prepareConnection->setAccessible(true);
|
||||
$prepareConnection->invoke($factory, $connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testCreateConnectionWithPasswordAndNoUsernameAddsInitializationCommandAuthWithOneArgument()
|
||||
{
|
||||
$parameters = new Parameters(array(
|
||||
'password' => 'foobar',
|
||||
));
|
||||
|
||||
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
|
||||
$connection->expects($this->once())
|
||||
->method('getParameters')
|
||||
->will($this->returnValue($parameters));
|
||||
$connection->expects($this->once(1))
|
||||
->method('addConnectCommand')
|
||||
->with($this->isRedisCommand('AUTH', array('foobar')));
|
||||
|
||||
$factory = new Factory();
|
||||
|
||||
// TODO: using reflection to make a protected method accessible :facepalm:
|
||||
$reflection = new \ReflectionObject($factory);
|
||||
$prepareConnection = $reflection->getMethod('prepareConnection');
|
||||
$prepareConnection->setAccessible(true);
|
||||
$prepareConnection->invoke($factory, $connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testCreateConnectionWithPasswordAndUsernameAddsInitializationCommandAuthWithTwoArguments()
|
||||
{
|
||||
$parameters = new Parameters(array(
|
||||
'username' => 'myusername',
|
||||
'password' => 'foobar',
|
||||
));
|
||||
|
||||
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
|
||||
$connection->expects($this->once())
|
||||
->method('getParameters')
|
||||
->will($this->returnValue($parameters));
|
||||
$connection->expects($this->once(1))
|
||||
->method('addConnectCommand')
|
||||
->with($this->isRedisCommand('AUTH', array('myusername', 'foobar')));
|
||||
|
||||
$factory = new Factory();
|
||||
|
||||
// TODO: using reflection to make a protected method accessible :facepalm:
|
||||
$reflection = new \ReflectionObject($factory);
|
||||
$prepareConnection = $reflection->getMethod('prepareConnection');
|
||||
$prepareConnection->setAccessible(true);
|
||||
$prepareConnection->invoke($factory, $connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testCreateConnectionWithUsernameAndNoPasswordDoesNotAddInitializationCommands()
|
||||
{
|
||||
$parameters = new Parameters(array(
|
||||
'username' => 'myusername',
|
||||
));
|
||||
|
||||
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
|
||||
$connection->expects($this->once())
|
||||
->method('getParameters')
|
||||
->will($this->returnValue($parameters));
|
||||
$connection->expects($this->never())
|
||||
->method('addConnectCommand');
|
||||
|
||||
$factory = new Factory();
|
||||
|
||||
// TODO: using reflection to make a protected method accessible :facepalm:
|
||||
$reflection = new \ReflectionObject($factory);
|
||||
$prepareConnection = $reflection->getMethod('prepareConnection');
|
||||
$prepareConnection->setAccessible(true);
|
||||
$prepareConnection->invoke($factory, $connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider provideEmptyParametersForInitializationCommands
|
||||
*/
|
||||
public function testCreateConnectionWithEmptyParametersDoesNotAddInitializationCommands($parameter, $value)
|
||||
{
|
||||
$parameters = new Parameters(array(
|
||||
$parameter => $value,
|
||||
));
|
||||
|
||||
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
|
||||
$connection->expects($this->once())
|
||||
->method('getParameters')
|
||||
->will($this->returnValue($parameters));
|
||||
$connection->expects($this->never())
|
||||
->method('addConnectCommand');
|
||||
|
||||
$factory = new Factory();
|
||||
|
||||
// TODO: using reflection to make a protected method accessible :facepalm:
|
||||
$reflection = new \ReflectionObject($factory);
|
||||
$prepareConnection = $reflection->getMethod('prepareConnection');
|
||||
$prepareConnection->setAccessible(true);
|
||||
@@ -487,4 +590,28 @@ class FactoryTest extends PredisTestCase
|
||||
|
||||
return array($connection, get_class($connection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides empty values for specific parameters.
|
||||
*
|
||||
* These parameters usually trigger the addition of initializatin commands
|
||||
* to connection instances like `password` => AUTH and `database` => SELECT,
|
||||
* but they should not be added when their values are NULL or empty strings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function provideEmptyParametersForInitializationCommands()
|
||||
{
|
||||
return array(
|
||||
// AUTH
|
||||
array('username', ''),
|
||||
array('username', null),
|
||||
array('password', ''),
|
||||
array('password', null),
|
||||
|
||||
// SELECT
|
||||
array('database', ''),
|
||||
array('database', null),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,11 +297,27 @@ class ConsumerTest extends PredisTestCase
|
||||
// ---- INTEGRATION TESTS --------------------------------------------- //
|
||||
// ******************************************************************** //
|
||||
|
||||
// NOTE: the following 2 tests fail at random without any apparent reason
|
||||
// when executed on our CI environments and these failures are not tied
|
||||
// to a particular version of PHP or Redis. It is most likely some weird
|
||||
// timing issue on busy systems as it is really rare to get it triggered
|
||||
// locally. The chances it is a bug in the library are pretty low so for
|
||||
// now we just mark this test skipped on our CI environments (but still
|
||||
// enabled for local test runs) and "debug" this issue using a separate
|
||||
// branch to avoid having spurious failures on main development branches
|
||||
// which is utterly annoying.
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testPubSubAgainstRedisServer()
|
||||
{
|
||||
if (getenv('GITHUB_ACTIONS') || getenv('TRAVIS')) {
|
||||
$this->markTestSkipped(
|
||||
'Test temporarily skipped on CI environments, see note in the body of the test'
|
||||
);
|
||||
}
|
||||
|
||||
$parameters = array(
|
||||
'host' => REDIS_SERVER_HOST,
|
||||
'port' => REDIS_SERVER_PORT,
|
||||
@@ -347,6 +363,12 @@ class ConsumerTest extends PredisTestCase
|
||||
*/
|
||||
public function testPubSubAgainstRedisServerBlocking()
|
||||
{
|
||||
if (getenv('GITHUB_ACTIONS') || getenv('TRAVIS')) {
|
||||
$this->markTestSkipped(
|
||||
'Test temporarily skipped on CI environments, see note in the body of the test'
|
||||
);
|
||||
}
|
||||
|
||||
$parameters = array(
|
||||
'host' => REDIS_SERVER_HOST,
|
||||
'port' => REDIS_SERVER_PORT,
|
||||
|
||||
@@ -81,15 +81,15 @@ class ReplicationStrategyTest extends PredisTestCase
|
||||
$profile = Profile\Factory::getDevelopment();
|
||||
$strategy = new ReplicationStrategy();
|
||||
|
||||
$cmdReadSort = $profile->createCommand('SORT', array('key:list'));
|
||||
$this->assertTrue(
|
||||
$strategy->isReadOperation($cmdReadSort),
|
||||
'SORT is expected to be a read operation.'
|
||||
$cmdReturnSort = $profile->createCommand('SORT', array('key:list'));
|
||||
$this->assertFalse(
|
||||
$strategy->isReadOperation($cmdReturnSort),
|
||||
'SORT is expected to be a write operation.'
|
||||
);
|
||||
|
||||
$cmdWriteSort = $profile->createCommand('SORT', array('key:list', array('store' => 'key:stored')));
|
||||
$cmdStoreSort = $profile->createCommand('SORT', array('key:list', array('store' => 'key:stored')));
|
||||
$this->assertFalse(
|
||||
$strategy->isReadOperation($cmdWriteSort),
|
||||
$strategy->isReadOperation($cmdStoreSort),
|
||||
'SORT with STORE is expected to be a write operation.'
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user