Compare commits

..

31 Commits

Author SHA1 Message Date
Daniele Alessandri 5a1430e99c Implement abstraction for WAIT.
This abstraction makes it possible to issue a WAIT command using a
client instance connected to a single Redis node or configured with
either a replication or cluster backend:

  $client = new Predis\Client($parameters, $options);
  $ack = new Predis\Replication\WaitContext($client);

  $ack->set('key:1', 'value:1');
  $ack->set('key:2', 'value:2');

  if ($ack->wait(2, 500)) {
    // Writes acknowledged by at least 2 slaves.
  } else {
    // Writes were not acknowledged by at least 2 slaves in 500ms.
  }

When the client is operating in replication mode, WAIT is executed
against the connection currently in use by the underlying backend. On
the other hand when it is operating in cluster mode WAIT is executed
against only one connection as cross-slot operations are not allowed.

This is just a first draft in response to #298 that serves as a base
for further improvements and changes. Tests are still missing.
2016-06-15 18:23:24 +02:00
Daniele Alessandri a70971549e Fix GC issues with closures for phpiredis reader handlers.
The following code, despite not being something you would do in real
world scenarios, eventually ended up generating an exception for "Too
many open files".

  for ($i = 0; $i < 10000; $i++) {
    $client = new Predis\Client();
    $client->connect();
  }

The reason was that the destructor for the connection was not invoked
by PHP as expected when the client instance went out of scope, so the
underlying stream resource were not being properly released.
Even without an actual "connect()" operation, the memory usage of PHP
kept growing until exhausting the configured value of max memory.

The source of the issue is related to the use of closures as handlers
for the phpiredis reader resource, to be more precise it seems to be
some kind of circular reference memory leak. Apparently PHP does not
like the fact that a closure, automatically bound to "$this" starting
with PHP 5.4, is stored in the reader resource which in turn is kept
referenced by "$this". This ends up the refcount not going down thus
the GC does not collect those connection objects going out of scope.
This is confirmed by the fact that this issue is not triggered when
using PHP 5.3 where the ZE does not automatically bind closures to
"$this", unless you capture "$this" with the "use()" directive (and
the usual "$that = $this" trick).

Using a static assignement instead of simply returning new closures
in "getStatusHandler()" and "getErrorHandler()" is kind of an hack
that seems to be working fine, the added value of this solution is
that we do not have to break the internal API of the three connection
backends based on ext-phpiredis.

This commit fixes #345.
2016-06-14 21:27:42 +02:00
Daniele Alessandri e88ffc767d Merge remote-tracking branch 'github/pr/346' 2016-06-14 17:19:32 +02:00
Pascal Hofmann ce8b3fb683 Don't send AUTH and/or SELECT command after connecting to sentinels 2016-06-14 16:38:59 +02:00
Daniele Alessandri e0b4b2c20a [tests] Add test for Predis\Cluster\Hash\CRC16. 2016-06-13 18:58:02 +02:00
Daniele Alessandri 2640062803 Use master for connect() when sentinel reports no slaves.
Fixes #342.
2016-06-13 16:32:45 +02:00
orvice 1811288009 fix typos
possibile -> possible
indentify -> identify
publis ->  publish
2016-06-13 15:22:31 +02:00
Daniele Alessandri fa643ac20c Apply CS fixes. 2016-06-10 11:12:26 +02:00
Daniele Alessandri eb1e686ff9 [tests] Change indentation of mock method expectations. 2016-06-10 11:08:26 +02:00
Daniele Alessandri f02f3b6d37 [tests] Improve code coverage.
There is still some work to improve coverage in other classes though.
2016-06-09 16:41:19 +02:00
Daniele Alessandri d72a1b5550 Do not extend EVALSHA for ScriptCommand class. 2016-06-09 14:02:22 +02:00
Daniele Alessandri 8b466d05df Get string of basic connection parameters from parameters class. 2016-06-08 18:36:35 +02:00
Daniele Alessandri b553c6b9d0 Pass dispatcher loop instance to callback.
This should not break existing code but allows users to retrieve more
easily the current dispatcher loop instance without resorting to some
tricks (like relying on the "use()" directive with closures).
2016-06-08 12:12:31 +02:00
Daniele Alessandri c10479e238 Remove executeCommandOnNodes() from predis cluster backend.
It is still possible to achieve the same simply by iterating over the
connection or, even better, over the client instance.
2016-06-08 12:01:54 +02:00
Daniele Alessandri 228ccaebe3 Use static instead of self. 2016-06-07 21:01:59 +02:00
Daniele Alessandri 82c256422a Fix failure on PHP 5.3.
Also use get_called_class() where possible.
2016-06-07 20:42:08 +02:00
Daniele Alessandri ee7104d2e5 Replace "getClientFor()" with "on()" in Client.
This new method acts exactly like "getClientFor()" by returning a new
client instance for the specified node unless a callback is passed as
the second argument, in this case the callback is invoked and the new
client instance is passed to it. The value returned by the callback
is used as the return value of the "on()" method.
2016-06-07 20:00:11 +02:00
Daniele Alessandri 7c4c4ae58a Change methods of replication connection interface.
Promoted the "switchToMaster()" and "switchToSlave()" methods to be
part of the replication connection interface and demoted the method
"switchTo($connection)".
2016-06-07 18:50:11 +02:00
Daniele Alessandri 185e31e080 Make some fields of Predis\Client private. 2016-06-07 18:22:57 +02:00
Daniele Alessandri 64b3a4805c Apply CS fixes. 2016-06-07 15:23:32 +02:00
Daniele Alessandri 5b4e942112 Add notice about dangers of using master branch. 2016-06-07 15:23:32 +02:00
Daniele Alessandri b2547fc7f4 [tests] Ignore code coverage for Predis\Autoloader. 2016-06-07 15:23:32 +02:00
Daniele Alessandri d34bdd38c3 Reorganize and improve client options.
All option classes have been moved in the Predis\Configuration\Option
namespace and some have been optimized to have less impact on client
initialization timings.

Furthermore the accepted values for some options have been changed,
this is the complete list of accepted values:

- _aggregate_: callable returning an aggregate connection.
- cluster: string value ("predis", "redis"), callable returning an
  aggregate connection.
- replication: string value ("predis", "sentinel"), callable returning
  an aggregate connection.
- commands: command factory, named array mapping command IDs to PHP
  classes, callable returning a command factory or a named array.
- connections: connection factory, callable returning a connection
  factory, named array mapping connection schemes to PHP classes.
- _prefix_: string value, command processor, callable.
- _exceptions_: boolean value.

Note that the cluster and replication options now return a closure
acting as initializer instead of an aggregate connection.
2016-06-07 15:23:32 +02:00
Daniele Alessandri 1028599ac5 Split Predis\Connection\Aggregate namespace.
Now we have two namespaces for cluster and replication backends:

  - Predis\Connection\Cluster
  - Predis\Connection\Replication
2016-06-07 15:23:32 +02:00
Daniele Alessandri 822f02b8eb Implement new logic to load command classes.
By default Predis now uses a convention-over-configuration approach
by looking for a command class in the Predis\Command\Redis namespace
if it is not already defined in the commands class map.

This change allow us to decrease the time needed to load Predis on
each request since we removed 99% of the mappings in the commands
class map. Classes defined in the internal class map still take the
precedence over this mechanism, so users can still define their own
command classes to handle each command.
2016-06-07 15:23:28 +02:00
Daniele Alessandri 4b47639f9e Rename command classes using command ID as name.
Some notable exceptions are EVAL and ECHO because having these names
as class names would raise a syntax error.
2016-06-04 20:54:41 +02:00
Daniele Alessandri e4872af747 Modify ctor signature of Predis\Command\RawCommand. 2016-06-04 20:54:36 +02:00
Daniele Alessandri c1d34f022f Drop useless method from base command class. 2016-06-04 15:57:12 +02:00
Daniele Alessandri 62b421f20e Switch from server profiles to commands factory.
This change reduces some unnecessary complexity in the library, Redis
commands do not change much after all. Developers can still implement
their own commands factory, inject new commands or override existing
ones. The "profile" client options has been renamed to "commands" and
it accepts instances of Predis\Command\FactoryInterface.

The test suite checks at runtime the version of the running instance
of Redis for integration tests to adapt itself automatically.
2016-06-04 15:36:21 +02:00
Daniele Alessandri 6e3f301588 Move commands classes in Predis\Command\Redis. 2016-06-04 15:36:16 +02:00
Daniele Alessandri 3dccd6bf87 Back to development.
The master branch now hosts the development of Predis v2.0.0-dev.
2016-06-02 09:10:25 +02:00
493 changed files with 8382 additions and 9695 deletions
+2 -5
View File
@@ -1,13 +1,10 @@
* text=auto
/tests/PHPUnit export-ignore
/tests/Predis export-ignore
/tests/bootstrap.php export-ignore
/.github export-ignore
/tests export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.php_cs.dist export-ignore
/.php_cs export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/phpunit.xml.travisci export-ignore
-2
View File
@@ -1,2 +0,0 @@
github: tillkruss
custom: "https://www.paypal.me/tillkruss"
-31
View File
@@ -1,31 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Run command '...'
2. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Versions (please complete the following information):**
- Predis: [e.g. 1.1.2]
- PHP [e.g. 8.0.0]
- Redis Server [e.g. 6.0.0]
- OS [e.g. Ubuntu 20.10]
**Code sample**
If applicable, a small snippet of code that reproduces the issue.
**Additional context**
Add any other context about the problem here.
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
-1
View File
@@ -2,7 +2,6 @@
*.phar
.php-version
.php_cs.cache
.phpunit.result.cache
phpunit.xml
package.xml
composer.lock
+34
View File
@@ -0,0 +1,34 @@
<?php
$PREDIS_HEADER = <<<EOS
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.
EOS;
Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($PREDIS_HEADER);
return Symfony\CS\Config\Config::create()
->setUsingCache(true)
->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL)
->fixers(array(
// Symfony
'-unalign_equals',
'-unalign_double_arrow',
// Contribs
'header_comment',
'ordered_use',
'phpdoc_order',
'long_array_syntax',
))
->finder(
Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__.'/bin')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->in(__DIR__.'/examples')
);
-33
View File
@@ -1,33 +0,0 @@
<?php
$PREDIS_HEADER = <<<EOS
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.
EOS;
return PhpCsFixer\Config::create()
->setUsingCache(true)
->setRules(array(
'@Symfony' => true,
'header_comment' => array(
'header' => $PREDIS_HEADER,
),
'ordered_imports' => true,
'phpdoc_order' => true,
'binary_operator_spaces' => array(
'align_double_arrow' => false,
'align_equals' => false,
),
'array_syntax' => array('syntax' => 'long'),
))
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__.'/bin')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->in(__DIR__.'/examples')
);
+9 -21
View File
@@ -1,35 +1,23 @@
language: php
sudo: false
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
branches:
except:
- v0.5
- v0.6
- v0.6-PHP_5.2
- documentation
before_install:
- docker run -d --rm -p 127.0.0.1:6379:6379 redis:3
services: redis-server
before_script:
- composer self-update
- composer install --no-interaction --prefer-source --dev
script:
- travis_retry vendor/bin/phpunit -c phpunit.xml.travisci
- vendor/bin/phpunit -c phpunit.xml.travisci
matrix:
fast_finish: true
include:
- php: 5.3
dist: precise
services: redis-server
before_install: skip
- php: 5.4
dist: trusty
- php: 5.5
dist: trusty
- php: 5.6
- php: 7.0
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
- php: nightly # PHP 8.0.0-dev
allow_failures:
- php: nightly
+46 -61
View File
@@ -1,76 +1,61 @@
v1.1.4 (2020-08-31)
v2.0.0 (201x-xx-xx)
================================================================================
- 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).
- Accepted values for some client options have changed, this is the new list of
accepted values:
- __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.
- `aggregate`: callable returning an aggregate connection.
- `cluster`: string value (`predis`, `redis`), callable returning an aggregate
connection.
- `replication`: string value (`predis`, `sentinel`), callable returning an
aggregate connection.
- `commands`: command factory, named array mapping command IDs to PHP classes,
callable returning a command factory or a named array.
- `connections`: connection factory, callable returning a connection factory,
named array mapping connection schemes to PHP classes.
- `prefix`: string value, command processor, callable.
- `exceptions`: boolean.
- __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).
Note that both the `cluster` and `replication` options now return a closure
acting as initializer instead of an aggregate connection instance.
- __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).
- Client option classes now live in the `Predis\Configuration\Option` namespace.
- __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.
- Classes for Redis commands have been moved into the new `Predis\Command\Redis`
namespace and each class name mirrors the respective Redis command ID.
- __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).
- The concept of server profiles is gone, the library now uses a single command
factory to create instances of commands classes. The `profile` option has been
replaced by the `commands` option accepting `Predis\Command\FactoryInterface`
to customize the underlying command factory. The default command factory class
used by Predis is `Predis\Command\RedisFactory` and it still allows developers
to define or override commands with their own implementations. In addition to
that, `Predis\Command\RedisFactory` relies on a convention-over-configuration
approach by looking for a suitable class with the same name as the command ID
in the `Predis\Command\Redis` when the internal class map does not contain a
class associated.
- The method `Predis\Client::getClientFor($connectionID)` has been replaced by
`Predis\Client::on($connectionID, $callable = null)`. This new method returns
a new client instance for the specified node just like before when the second
argument is omitted, otherwise the callback is invoked and the new client is
passed to it. The value returned by the callback is used as the return value
of the "on()" method.
v1.1.3 (2020-08-18)
================================================================================
- Changed the signature for the constructor of `Predis\Command\RawCommand`.
- Ensure compatibility with PHP 8.
- The `Predis\Connection\Aggregate` namespace has been split into two separate
namespaces for cluster backends (`Predis\Connection\Cluster`) and replication
backends (`Predis\Connection\Replication`).
- Moved repository from `github.com/nrk/predis` to `github.com/predis/predis`.
- The methods `switchToMaster()` and `switchToSlave()` have been promoted to be
part of `Predis\Connection\Replication\ReplicationInterface` while the method
`switchTo($connection)` has been removed from it.
- __FIX__: Moved `cweagans/composer-patches` dependency to `require-dev`.
- __FIX__: Include PHPUnit `.patch` files in exports.
v1.1.2 (2020-08-11)
================================================================================
- __FIX__: pure CRC16 implementation failed to calculate the correct hash when
the input value passed to the `hash()` method is an integer (PR #450).
- __FIX__: make PHP iterator abstractions for `ZSCAN` and `HSCAN` working with
PHP 7.2 due to a breaking change, namely the removal of `each()` (PR #448).
v1.1.1 (2016-06-16)
================================================================================
- __FIX__: `password` and `database` from the global `parameters` client option
were still being applied to sentinels connections making them fail (sentinels
do not understand the `AUTH` and `SELECT` commands) (PR #346).
- __FIX__: when a sentinel instance reports no sentinel for a service, invoking
`connect()` on the redis-sentinel connection backend should fall back to the
master connection instead of failing (ISSUE #342).
- __FIX__: the two connection backends based on ext-phpiredis has some kind of
issues with the GC and the internal use of closures as reader callbacks that
prevented connections going out of scope from being properly collected and the
underlying stream or socket resources from being closed and freed. This should
not have had any actual effect in real-world scenarios due to the lifecycle of
PHP scripts, but we fixed it anyway (ISSUE #345).
- The method `Predis\Connection\Cluster\PredisCluster::executeCommandOnNodes()`
has been removed as it is possible to achieve the same by iterating over the
connection or, even better, over the client instance in order to execute the
same command against all of the registered connections.
v1.1.0 (2016-06-02)
+1 -1
View File
@@ -1,6 +1,6 @@
## Filing bug reports ##
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/predis/predis/issues)
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/nrk/predis/issues)
section of the project.
When reporting bugs, in addition to the obvious description of your issue you __must__ always provide
+1 -1
View File
@@ -33,7 +33,7 @@ usually something that developers prefer to customize depending on their needs a
generalized when using Redis because of the many possible access patterns for your data. This does
not mean that it is impossible to have such a feature since you can leverage the extensibility of
this library to define your own serialization-aware commands. You can find more details about how to
do that [on this issue](http://github.com/predis/predis/issues/29#issuecomment-1202624).
do that [on this issue](http://github.com/nrk/predis/issues/29#issuecomment-1202624).
### How can I force Predis to connect to Redis before sending any command? ###
+49 -39
View File
@@ -5,19 +5,27 @@
[![Latest development][ico-version-dev]][link-packagist]
[![Monthly installs][ico-downloads-monthly]][link-downloads]
[![Build status][ico-travis]][link-travis]
[![HHVM support][ico-hhvm]][link-hhvm]
[![Gitter room][ico-gitter]][link-gitter]
Flexible and feature-complete [Redis](http://redis.io) client for PHP >= 5.3 and HHVM >= 2.3.0.
__ATTENTION:__ you are on the README file of an unstable branch of Predis specifically meant for the
development of future releases. This means that the code on this branch is potentially unstable, and
breaking change may happen without any prior notice. Do not use it in production environments or use
it at your own risk!
Predis does not require any additional C extension by default, but it can be optionally paired with
[phpiredis](https://github.com/nrk/phpiredis) to lower the overhead of the serialization and parsing
of the [Redis RESP Protocol](http://redis.io/topics/protocol).
of the [Redis RESP Protocol](http://redis.io/topics/protocol). For an __experimental__ asynchronous
implementation of the client you can refer to [Predis\Async](https://github.com/nrk/predis-async).
More details about this project can be found on the [frequently asked questions](FAQ.md).
## Main features ##
- Support for different versions of Redis (from __2.0__ to __3.2__) using profiles.
- Support for Redis from __2.0__ to __3.2__.
- Support for clustering using client-side sharding and pluggable keyspace distributors.
- Support for [redis-cluster](http://redis.io/topics/cluster-tutorial) (Redis >= 3.0).
- Support for master-slave replication setups and [redis-sentinel](http://redis.io/topics/sentinel).
@@ -30,7 +38,7 @@ More details about this project can be found on the [frequently asked questions]
- Connections can be established via TCP/IP (also TLS/SSL-encrypted) or UNIX domain sockets.
- Support for [Webdis](http://webd.is) (requires both `ext-curl` and `ext-phpiredis`).
- Support for custom connection classes for providing different network or protocol backends.
- Flexible system for defining custom commands and profiles and override the default ones.
- Flexible system for defining custom commands and override the default ones.
## How to _install_ and use Predis ##
@@ -38,7 +46,7 @@ More details about this project can be found on the [frequently asked questions]
This library can be found on [Packagist](http://packagist.org/packages/predis/predis) for an easier
management of projects dependencies using [Composer](http://packagist.org/about-composer) or on our
[own PEAR channel](http://pear.nrk.io) for a more traditional installation using PEAR. Ultimately,
compressed archives of each release are [available on GitHub](https://github.com/predis/predis/releases).
compressed archives of each release are [available on GitHub](https://github.com/nrk/predis/tags).
### Loading the library ###
@@ -87,9 +95,6 @@ $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:
@@ -108,7 +113,7 @@ of suitable [options](http://php.net/manual/context.ssl.php) passed via the `ssl
$client = new Predis\Client([
'scheme' => 'tls',
'ssl' => ['cafile' => 'private.pem', 'verify_peer' => true],
]);
]
// Same set of parameters, but using an URI string:
$client = new Predis\Client('tls://127.0.0.1?ssl[cafile]=private.pem&ssl[verify_peer]=1');
@@ -148,20 +153,20 @@ Many aspects and behaviors of the client can be configured by passing specific c
second argument of `Predis\Client::__construct()`:
```php
$client = new Predis\Client($parameters, ['profile' => '2.8', 'prefix' => 'sample:']);
$client = new Predis\Client($parameters, ['prefix' => 'sample:']);
```
Options are managed using a mini DI-alike container and their values can be lazily initialized only
when needed. The client options supported by default in Predis are:
- `profile`: specifies the profile to use to match a specific version of Redis.
- `prefix`: prefix string automatically applied to keys found in commands.
- `prefix`: prefix string applied to every key found in commands.
- `exceptions`: whether the client should throw or return responses upon Redis errors.
- `connections`: list of connection backends or a connection factory instance.
- `cluster`: specifies a cluster backend (`predis`, `redis` or callable object).
- `replication`: specifies a replication backend (`TRUE`, `sentinel` or callable object).
- `aggregate`: overrides `cluster` and `replication` to provide a custom connections aggregator.
- `cluster`: specifies a cluster backend (`predis`, `redis` or callable).
- `replication`: specifies a replication backend (`predis`, `sentinel` or callable).
- `aggregate`: configures the client with a custom aggregate connection (callable).
- `parameters`: list of default connection parameters for aggregate connections.
- `commands`: specifies a command factory instance to use through the library.
Users can also provide custom options with values or callable objects (for lazy initialization) that
are stored in the options container for later use through the library.
@@ -265,7 +270,7 @@ $options = ['replication' => function () {
$strategy = new Predis\Replication\ReplicationStrategy();
$strategy->setScriptReadOnly($LUA_SCRIPT);
return new Predis\Connection\Aggregate\MasterSlaveReplication($strategy);
return new Predis\Connection\Replication\MasterSlaveReplication($strategy);
}];
$client = new Predis\Client($parameters, $options);
@@ -324,7 +329,7 @@ of a transaction using CAS you can see [the following example](examples/transact
While we try to update Predis to stay up to date with all the commands available in Redis, you might
prefer to stick with an old version of the library or provide a different way to filter arguments or
parse responses for specific commands. To achieve that, Predis provides the ability to implement new
command classes to define or override commands in the default server profiles used by the client:
command classes to define or override commands in the default command factory used by the client:
```php
// Define a new command by extending Predis\Command\Command:
@@ -336,9 +341,12 @@ class BrandNewRedisCommand extends Predis\Command\Command
}
}
// Inject your command in the current profile:
$client = new Predis\Client();
$client->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
// Inject your command in the current command factory:
$client = new Predis\Client($parameters, [
'commands' => [
'newcmd' => 'BrandNewRedisCommand',
],
]);
$response = $client->newcmd();
```
@@ -357,7 +365,7 @@ $response = $client->executeRaw(['SET', 'foo', 'bar']);
While it is possible to leverage [Lua scripting](http://redis.io/commands/eval) on Redis 2.6+ using
directly [`EVAL`](http://redis.io/commands/eval) and [`EVALSHA`](http://redis.io/commands/evalsha),
Predis offers script commands as an higher level abstraction built upon them to make things simple.
Script commands can be registered in the server profile used by the client and are accessible as if
Script commands can be registered in the command factory used by the client and are accessible as if
they were plain Redis commands, but they define Lua scripts that get transmitted to the server for
remote execution. Internally they use [`EVALSHA`](http://redis.io/commands/evalsha) by default and
identify a script by its SHA1 hash to save bandwidth, but [`EVAL`](http://redis.io/commands/eval)
@@ -383,9 +391,12 @@ LUA;
}
}
// Inject the script command in the current profile:
$client = new Predis\Client();
$client->getProfile()->defineCommand('lpushrand', 'ListPushRandomValue');
// Inject the script command in the current command factory:
$client = new Predis\Client($parameters, [
'commands' => [
'lpushrand' => 'ListPushRandomValue',
],
]);
$response = $client->lpushrand('random_values', $seed = mt_rand());
```
@@ -443,18 +454,14 @@ stay consistent while working on the project.
__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running
in production environments or containing data you are interested in!
Predis has a comprehensive test suite covering every aspect of the library. This test suite performs
integration tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct
behavior of the implementation of each command and automatically skips commands not defined in the
specified Redis profile. If you do not have Redis up and running, integration tests can be disabled.
By default the test suite is configured to execute integration tests using the profile for Redis 3.2
(which is the current stable version of Redis) but can optionally target a Redis instance built from
the `unstable` branch by modifying `phpunit.xml` and setting `REDIS_SERVER_VERSION` to `dev` so that
the development server profile will be used. You can refer to [the tests README](tests/README.md)
for more detailed information about testing Predis.
Predis has a comprehensive test suite covering every aspect of the library and that can optionally
perform integration tests against a running instance of Redis (required >= 2.4.0 in order to verify
the correct behavior of the implementation of each command. Integration tests for unsupported Redis
commands are automatically skipped. If you do not have Redis up and running, integration tests can
be disabled. See [the tests README](tests/README.md) for more details about testing this library.
Predis uses Travis CI for continuous integration and the history for past and current builds can be
found [on its project page](http://travis-ci.org/predis/predis).
found [on its project page](http://travis-ci.org/nrk/predis).
## Other ##
@@ -462,9 +469,9 @@ found [on its project page](http://travis-ci.org/predis/predis).
### Project related links ###
- [Source code](https://github.com/predis/predis)
- [Wiki](https://github.com/predis/predis/wiki)
- [Issue tracker](https://github.com/predis/predis/issues)
- [Source code](https://github.com/nrk/predis)
- [Wiki](https://wiki.github.com/nrk/predis)
- [Issue tracker](https://github.com/nrk/predis/issues)
- [PEAR channel](http://pear.nrk.io)
@@ -477,13 +484,16 @@ found [on its project page](http://travis-ci.org/predis/predis).
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
[ico-license]: https://img.shields.io/github/license/predis/predis.svg?style=flat-square
[ico-license]: https://img.shields.io/github/license/nrk/predis.svg?style=flat-square
[ico-version-stable]: https://img.shields.io/packagist/v/predis/predis.svg?style=flat-square
[ico-version-dev]: https://img.shields.io/packagist/vpre/predis/predis.svg?style=flat-square
[ico-downloads-monthly]: https://img.shields.io/packagist/dm/predis/predis.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/predis/predis.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/nrk/predis.svg?style=flat-square
[ico-hhvm]: https://img.shields.io/hhvm/predis/predis.svg?style=flat-square
[ico-gitter]: https://img.shields.io/gitter/room/nrk/predis.svg?style=flat-square
[link-packagist]: https://packagist.org/packages/predis/predis
[link-travis]: https://travis-ci.org/predis/predis
[link-travis]: https://travis-ci.org/nrk/predis
[link-downloads]: https://packagist.org/packages/predis/predis/stats
[link-hhvm]: http://hhvm.h4cc.de/package/predis/predis
[link-gitter]: https://gitter.im/nrk/predis
+1 -1
View File
@@ -1 +1 @@
1.1.4
2.0.0-dev
+18 -15
View File
@@ -15,7 +15,7 @@
// of a test case to test a Redis command by specifying the name of the class
// in the Predis\Command namespace (only classes in this namespace are valid).
// For example, to generate a test case for SET (which is represented by the
// Predis\Command\StringSet class):
// Predis\Command\Redis\StringSet class):
//
// $ ./bin/generate-command-test --class=StringSet
//
@@ -45,6 +45,11 @@ class CommandTestCaseGenerator
if (!isset($options['class'])) {
throw new RuntimeException("Missing 'class' option.");
}
if (!isset($options['realm'])) {
throw new RuntimeException("Missing 'realm' option.");
}
$this->options = $options;
}
@@ -92,8 +97,12 @@ class CommandTestCaseGenerator
throw new RuntimeException("Missing 'class' option.");
}
$options['fqn'] = "Predis\\Command\\{$options['class']}";
$options['path'] = "Command/{$options['class']}.php";
if (!isset($options['realm'])) {
throw new RuntimeException("Missing 'realm' option.");
}
$options['fqn'] = "Predis\\Command\\Redis\\{$options['class']}";
$options['path'] = "Command/Redis/{$options['class']}.php";
$source = __DIR__.'/../src/'.$options['path'];
if (!file_exists($source)) {
@@ -101,7 +110,7 @@ class CommandTestCaseGenerator
}
if (!isset($options['output'])) {
$options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', 'Test.php', $options['path']));
$options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', '_Test.php', $options['path']));
}
return new self($options);
@@ -109,18 +118,11 @@ class CommandTestCaseGenerator
protected function getTestRealm()
{
if (isset($this->options['realm'])) {
if (!$this->options['realm']) {
throw new RuntimeException('Invalid value for realm has been sepcified (empty).');
}
return $this->options['realm'];
if (empty($this->options['realm'])) {
throw new RuntimeException('Invalid value for realm has been sepcified (empty).');
}
$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);
return $this->options['realm'];
}
public function generate()
@@ -130,6 +132,7 @@ class CommandTestCaseGenerator
if (!$reflection->isInstantiable()) {
throw new RuntimeException("Class $class must be instantiable, abstract classes or interfaces are not allowed.");
}
if (!$reflection->implementsInterface('Predis\Command\CommandInterface')) {
throw new RuntimeException("Class $class must implement Predis\Command\CommandInterface.");
}
@@ -173,7 +176,7 @@ class CommandTestCaseGenerator
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
/**
* @group commands
+2 -2
View File
@@ -115,7 +115,7 @@ function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
function generatePackageXml($packageINI)
{
$XML = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0"?>
<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", "UTF-8");
$dom = new DOMDocument("1.0");
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
+1 -1
View File
@@ -59,7 +59,7 @@ spl_autoload_register(function (\$class) {
}
}
});
__halt_compiler();
__HALT_COMPILER();
EOSTUB;
}
+9 -31
View File
@@ -3,56 +3,34 @@
"type": "library",
"description": "Flexible and feature-complete Redis client for PHP and HHVM",
"keywords": ["nosql", "redis", "predis"],
"homepage": "http://github.com/predis/predis",
"homepage": "http://github.com/nrk/predis",
"license": "MIT",
"support": {
"issues": "https://github.com/predis/predis/issues"
"issues": "https://github.com/nrk/predis/issues"
},
"authors": [
{
"name": "Daniele Alessandri",
"email": "suppakilla@gmail.com",
"homepage": "http://clorophilla.net",
"role": "Creator & Maintainer"
},
{
"name": "Till Krüss",
"homepage": "https://till.im",
"role": "Maintainer"
}
],
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/tillkruss"
"homepage": "http://clorophilla.net"
}
],
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"phpunit/phpunit": "~4.8",
"cweagans/composer-patches": "^1.6"
"phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol",
"ext-curl": "Allows access to Webdis when paired with phpiredis"
},
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
"psr-4": {"Predis\\": "src/"}
},
"extra": {
"composer-exit-on-patch-failure": true,
"patches": {
"phpunit/phpunit-mock-objects": {
"Fix PHP 7 and 8 compatibility": "./tests/phpunit_mock_objects.patch"
},
"phpunit/phpunit": {
"Fix PHP 7 compatibility": "./tests/phpunit_php7.patch",
"Fix PHP 8 compatibility": "./tests/phpunit_php8.patch"
}
}
}
"branch-alias": {
"dev-master": "2.0-dev"
}
}
}
+3 -3
View File
@@ -18,7 +18,7 @@ require __DIR__.'/shared.php';
use Predis\Cluster\Distributor\DistributorInterface;
use Predis\Cluster\Hash\HashGeneratorInterface;
use Predis\Cluster\PredisStrategy;
use Predis\Connection\Aggregate\PredisCluster;
use Predis\Connection\Cluster\PredisCluster;
class NaiveDistributor implements DistributorInterface, HashGeneratorInterface
{
@@ -104,8 +104,8 @@ for ($i = 0; $i < 100; ++$i) {
$client->get("key:$i");
}
$server1 = $client->getClientFor('first')->info();
$server2 = $client->getClientFor('second')->info();
$server1 = $client->on('first')->info();
$server2 = $client->on('second')->info();
if (isset($server1['Keyspace'], $server2['Keyspace'])) {
$server1 = $server1['Keyspace'];
+2 -2
View File
@@ -51,7 +51,7 @@ class EventsListener implements Countable
return $this->events;
}
public function __invoke($payload)
public function __invoke($payload, $dispatcher)
{
$this->events[] = $payload;
}
@@ -61,7 +61,7 @@ class EventsListener implements Countable
$dispatcher->attachCallback('events', ($events = new EventsListener()));
// Attach a function to control the dispatcher loop termination with a message.
$dispatcher->attachCallback('control', function ($payload) use ($dispatcher) {
$dispatcher->attachCallback('control', function ($payload, $dispatcher) {
if ($payload === 'terminate_dispatcher') {
$dispatcher->stop();
}
+7 -11
View File
@@ -13,11 +13,10 @@ require __DIR__.'/shared.php';
// This example will not work with versions of Redis < 2.6.
//
// Additionally to the EVAL command defined in the current development profile,
// the Predis\Command\ScriptCommand class can be used to build an higher level
// abstraction for "scriptable" commands so that they will appear just like any
// other command on the client-side. This is a quick example used to implement
// INCREX.
// Additionally to the EVAL command, the Predis\Command\ScriptCommand class can
// be used to leverage an higher level abstraction for Lua scripting that makes
// scripts appear just like any other command on the client-side. This is basic
// example on how a script-based INCREX command can be defined:
use Predis\Command\ScriptCommand;
@@ -50,12 +49,9 @@ LUA;
}
$client = new Predis\Client($single_server, array(
'profile' => function ($options) {
$profile = $options->getDefault('profile');
$profile->defineCommand('increxby', 'IncrementExistingKeysBy');
return $profile;
},
'commands' => array(
'increxby' => 'IncrementExistingKeysBy',
),
));
$client->mset('foo', 10, 'foobar', 100);
+2 -3
View File
@@ -13,7 +13,7 @@ require __DIR__.'/shared.php';
use Predis\Collection\Iterator;
// Starting from Redis 2.8, clients can iterate incrementally over collections
// Starting with Redis 2.8, clients can iterate incrementally over collections
// without blocking the server like it happens when a command such as KEYS is
// executed on a Redis instance storing millions of keys. These commands are:
//
@@ -29,8 +29,7 @@ use Predis\Collection\Iterator;
// See http://redis.io/commands/scan for more details.
//
// Create a client using `2.8` as a server profile (needs Redis 2.8!)
$client = new Predis\Client($single_server, array('profile' => '2.8'));
$client = new Predis\Client($single_server);
// Prepare some keys for our example
$client->del('predis:set', 'predis:zset', 'predis:hash');
+7 -10
View File
@@ -14,12 +14,12 @@ require __DIR__.'/shared.php';
// Predis allows to set Lua scripts as read-only operations for replication.
// This works for both EVAL and EVALSHA and also for the client-side abstraction
// built upon them (Predis\Command\ScriptCommand). This example shows a slightly
// more complex configuration that injects a new script command in the server
// profile used by the new client instance and marks it marks it as a read-only
// operation for replication so that it will be executed on slaves.
// more complex configuration that injects a new script command in the command
// factory used by the client and marks it as a read-only operation so that it
// will be executed on slaves.
use Predis\Command\ScriptCommand;
use Predis\Connection\Aggregate\MasterSlaveReplication;
use Predis\Connection\Replication\MasterSlaveReplication;
use Predis\Replication\ReplicationStrategy;
// ------------------------------------------------------------------------- //
@@ -52,12 +52,9 @@ $parameters = array(
);
$options = array(
'profile' => function ($options, $option) {
$profile = $options->getDefault($option);
$profile->defineCommand('hmgetall', 'HashMultipleGetAll');
return $profile;
},
'commands' => array(
'hmgetall' => 'HashMultipleGetAll',
),
'replication' => function () {
$strategy = new ReplicationStrategy();
$strategy->setScriptReadOnly(HashMultipleGetAll::BODY);
+1 -1
View File
@@ -26,7 +26,7 @@ $parameters = array(
'tcp://127.0.0.1:6380?database=15&alias=slave',
);
$options = array('replication' => true);
$options = array('replication' => 'predis');
$client = new Predis\Client($parameters, $options);
-4
View File
@@ -9,10 +9,6 @@
* file that was distributed with this source code.
*/
if (PHP_SAPI !== 'cli') {
die("Example scripts are meant to be executed locally via CLI.");
}
require __DIR__.'/../autoload.php';
function redis_version($info)
+2 -2
View File
@@ -10,8 +10,8 @@ name = "Predis"
desc = "Flexible and feature-complete Redis client for PHP and HHVM"
homepage = "http://github.com/nrk/predis"
license = "MIT"
version = "1.1.4"
stability = "stable"
version = "2.0.0"
stability = "devel"
channel = "pear.nrk.io"
author = "Daniele Alessandri \"nrk\" <suppakilla@gmail.com>"
-1
View File
@@ -38,7 +38,6 @@
<php>
<!-- Redis -->
<const name="REDIS_SERVER_VERSION" value="3.2" />
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_SERVER_DBNUM" value="15" />
-1
View File
@@ -42,7 +42,6 @@
<php>
<!-- Redis -->
<const name="REDIS_SERVER_VERSION" value="3.2" />
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_SERVER_DBNUM" value="15" />
+1
View File
@@ -16,6 +16,7 @@ namespace Predis;
*
* @author Eric Naeseth <eric@thumbtack.com>
* @author Daniele Alessandri <suppakilla@gmail.com>
* @codeCoverageIgnore
*/
class Autoloader
{
+78 -62
View File
@@ -19,6 +19,7 @@ use Predis\Configuration\OptionsInterface;
use Predis\Connection\AggregateConnectionInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\ParametersInterface;
use Predis\Connection\Replication\SentinelReplication;
use Predis\Monitor\Consumer as MonitorConsumer;
use Predis\Pipeline\Pipeline;
use Predis\PubSub\Consumer as PubSubConsumer;
@@ -40,11 +41,22 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
*/
class Client implements ClientInterface, \IteratorAggregate
{
const VERSION = '1.1.4';
const VERSION = '2.0.0-dev';
protected $connection;
protected $options;
private $profile;
/**
* @var Predis\Configuration\OptionsInterface
*/
private $options;
/**
* @var Predis\Connection\ConnectionInterface
*/
private $connection;
/**
* @var Predis\Command\FactoryInterface
*/
private $commands;
/**
* @param mixed $parameters Connection parameters for one or more servers.
@@ -54,7 +66,7 @@ class Client implements ClientInterface, \IteratorAggregate
{
$this->options = $this->createOptions($options ?: array());
$this->connection = $this->createConnection($parameters ?: array());
$this->profile = $this->options->profile;
$this->commands = $this->options->commands;
}
/**
@@ -78,7 +90,7 @@ class Client implements ClientInterface, \IteratorAggregate
return $options;
}
throw new \InvalidArgumentException('Invalid type for client options.');
throw new \InvalidArgumentException('Invalid type for client options');
}
/**
@@ -102,81 +114,76 @@ class Client implements ClientInterface, \IteratorAggregate
*/
protected function createConnection($parameters)
{
$options = $this->getOptions();
if ($parameters instanceof ConnectionInterface) {
return $parameters;
}
if ($parameters instanceof ParametersInterface || is_string($parameters)) {
return $this->options->connections->create($parameters);
return $options->connections->create($parameters);
}
if (is_array($parameters)) {
if (!isset($parameters[0])) {
return $this->options->connections->create($parameters);
return $options->connections->create($parameters);
}
$options = $this->options;
if ($options->defined('aggregate')) {
$initializer = $this->getConnectionInitializerWrapper($options->aggregate);
$connection = $initializer($parameters, $options);
if ($options->defined('cluster')) {
return $this->createAggregateConnection($parameters, 'cluster');
} elseif ($options->defined('replication')) {
$replication = $options->replication;
if ($replication instanceof AggregateConnectionInterface) {
$connection = $replication;
$options->connections->aggregate($connection, $parameters);
} else {
$initializer = $this->getConnectionInitializerWrapper($replication);
$connection = $initializer($parameters, $options);
}
return $this->createAggregateConnection($parameters, 'replication');
} elseif ($options->defined('aggregate')) {
return $this->createAggregateConnection($parameters, 'aggregate');
} else {
$connection = $options->cluster;
$options->connections->aggregate($connection, $parameters);
throw new \InvalidArgumentException(
'Array of connection parameters requires `cluster`, `replication` or `aggregate` client option'
);
}
return $connection;
}
if (is_callable($parameters)) {
$initializer = $this->getConnectionInitializerWrapper($parameters);
$connection = $initializer($this->options);
$connection = call_user_func($parameters, $options);
if (!$connection instanceof ConnectionInterface) {
throw new \InvalidArgumentException('Callable parameters must return a valid connection');
}
return $connection;
}
throw new \InvalidArgumentException('Invalid type for connection parameters.');
throw new \InvalidArgumentException('Invalid type for connection parameters');
}
/**
* Wraps a callable to make sure that its returned value represents a valid
* connection type.
* Creates an aggregate connection.
*
* @param mixed $callable
* @param mixed $parameters Connection parameters.
* @param string $option Option for aggregate connections (`aggregate`, `cluster`, `replication`).
*
* @return \Closure
*/
protected function getConnectionInitializerWrapper($callable)
protected function createAggregateConnection($parameters, $option)
{
return function () use ($callable) {
$connection = call_user_func_array($callable, func_get_args());
$options = $this->getOptions();
if (!$connection instanceof ConnectionInterface) {
throw new \UnexpectedValueException(
'The callable connection initializer returned an invalid type.'
);
}
$initializer = $options->$option;
$connection = $initializer($parameters);
return $connection;
};
// TODO: this is dirty but we must skip the redis-sentinel backend for now.
if ($option !== 'aggregate' && !$connection instanceof SentinelReplication) {
$options->connections->aggregate($connection, $parameters);
}
return $connection;
}
/**
* {@inheritdoc}
*/
public function getProfile()
public function getCommandFactory()
{
return $this->profile;
return $this->commands;
}
/**
@@ -188,23 +195,34 @@ class Client implements ClientInterface, \IteratorAggregate
}
/**
* Creates a new client instance for the specified connection ID or alias,
* only when working with an aggregate connection (cluster, replication).
* The new client instances uses the same options of the original one.
* Creates a new client from the specified connection ID / alias.
*
* @param string $connectionID Identifier of a connection.
* The new client instances inherites the same options of the original one.
* When no callable object is supplied, this method returns the new client.
* When a callable object is supplied, the new client is passed as its sole
* argument and its return value is returned by this method to the caller.
*
* @throws \InvalidArgumentException
* NOTE: This method works only when the client is configured to work with
* aggregate connections (cluster, replication).
*
* @return Client
* @param string $connectionID Identifier of a connection.
* @param callable|null $callable Optional callable object.
*
* @return ClientInterface|mixed
*/
public function getClientFor($connectionID)
public function on($connectionID, $callable = null)
{
if (!$connection = $this->getConnectionById($connectionID)) {
throw new \InvalidArgumentException("Invalid connection ID: $connectionID.");
throw new \InvalidArgumentException("Invalid connection ID: `$connectionID`");
}
return new static($connection, $this->options);
$client = new static($connection, $this->getOptions());
if ($callable) {
return call_user_func($callable, $client);
} else {
return $client;
}
}
/**
@@ -289,9 +307,10 @@ class Client implements ClientInterface, \IteratorAggregate
public function executeRaw(array $arguments, &$error = null)
{
$error = false;
$commandID = array_shift($arguments);
$response = $this->connection->executeCommand(
new RawCommand($arguments)
new RawCommand($commandID, $arguments)
);
if ($response instanceof ResponseInterface) {
@@ -320,7 +339,7 @@ class Client implements ClientInterface, \IteratorAggregate
*/
public function createCommand($commandID, $arguments = array())
{
return $this->profile->createCommand($commandID, $arguments);
return $this->commands->createCommand($commandID, $arguments);
}
/**
@@ -354,10 +373,7 @@ class Client implements ClientInterface, \IteratorAggregate
protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $response)
{
if ($command instanceof ScriptCommand && $response->getErrorType() === 'NOSCRIPT') {
$eval = $this->createCommand('EVAL');
$eval->setRawArguments($command->getEvalArguments());
$response = $this->executeCommand($eval);
$response = $this->executeCommand($command->getEvalCommand());
if (!$response instanceof ResponseInterface) {
$response = $command->parseResponse($response);
@@ -400,9 +416,11 @@ class Client implements ClientInterface, \IteratorAggregate
return $this->$initializer($arg0, $arg1);
// @codeCoverageIgnoreStart
default:
return $this->$initializer($this, $argv);
}
// @codeCoverageIgnoreEnd
}
/**
@@ -535,9 +553,7 @@ class Client implements ClientInterface, \IteratorAggregate
$connection = $this->getConnection();
if (!$connection instanceof \Traversable) {
return new \ArrayIterator(array(
(string) $connection => new static($connection, $this->getOptions())
));
throw new ClientException('The underlying connection is not traversable');
}
foreach ($connection as $node) {
+16 -17
View File
@@ -16,7 +16,7 @@ use Predis\Command\CommandInterface;
/**
* Interface defining a client-side context such as a pipeline or transaction.
*
* @method $this del(array|string $keys)
* @method $this del(array $keys)
* @method $this dump($key)
* @method $this exists($key)
* @method $this expire($key, $seconds)
@@ -38,8 +38,7 @@ use Predis\Command\CommandInterface;
* @method $this append($key, $value)
* @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 bitfield($key, ...)
* @method $this decr($key)
* @method $this decrby($key, $decrement)
* @method $this get($key)
@@ -74,15 +73,15 @@ use Predis\Command\CommandInterface;
* @method $this hsetnx($key, $field, $value)
* @method $this hvals($key)
* @method $this hstrlen($key, $field)
* @method $this blpop(array|string $keys, $timeout)
* @method $this brpop(array|string $keys, $timeout)
* @method $this blpop(array $keys, $timeout)
* @method $this brpop(array $keys, $timeout)
* @method $this brpoplpush($source, $destination, $timeout)
* @method $this lindex($key, $index)
* @method $this linsert($key, $whence, $pivot, $value)
* @method $this llen($key)
* @method $this lpop($key)
* @method $this lpush($key, array $values)
* @method $this lpushx($key, array $values)
* @method $this lpushx($key, $value)
* @method $this lrange($key, $start, $stop)
* @method $this lrem($key, $count, $value)
* @method $this lset($key, $index, $value)
@@ -90,13 +89,13 @@ use Predis\Command\CommandInterface;
* @method $this rpop($key)
* @method $this rpoplpush($source, $destination)
* @method $this rpush($key, array $values)
* @method $this rpushx($key, array $values)
* @method $this rpushx($key, $value)
* @method $this sadd($key, array $members)
* @method $this scard($key)
* @method $this sdiff(array|string $keys)
* @method $this sdiffstore($destination, array|string $keys)
* @method $this sinter(array|string $keys)
* @method $this sinterstore($destination, array|string $keys)
* @method $this sdiff(array $keys)
* @method $this sdiffstore($destination, array $keys)
* @method $this sinter(array $keys)
* @method $this sinterstore($destination, array $keys)
* @method $this sismember($key, $member)
* @method $this smembers($key)
* @method $this smove($source, $destination, $member)
@@ -104,13 +103,13 @@ use Predis\Command\CommandInterface;
* @method $this srandmember($key, $count = null)
* @method $this srem($key, $member)
* @method $this sscan($key, $cursor, array $options = null)
* @method $this sunion(array|string $keys)
* @method $this sunionstore($destination, array|string $keys)
* @method $this sunion(array $keys)
* @method $this sunionstore($destination, array $keys)
* @method $this zadd($key, array $membersAndScoresDictionary)
* @method $this zcard($key)
* @method $this zcount($key, $min, $max)
* @method $this zincrby($key, $increment, $member)
* @method $this zinterstore($destination, array|string $keys, array $options = null)
* @method $this zinterstore($destination, array $keys, array $options = null)
* @method $this zrange($key, $start, $stop, array $options = null)
* @method $this zrangebyscore($key, $min, $max, array $options = null)
* @method $this zrank($key, $member)
@@ -120,7 +119,7 @@ use Predis\Command\CommandInterface;
* @method $this zrevrange($key, $start, $stop, array $options = null)
* @method $this zrevrangebyscore($key, $min, $max, array $options = null)
* @method $this zrevrank($key, $member)
* @method $this zunionstore($destination, array|string $keys, array $options = null)
* @method $this zunionstore($destination, array $keys, array $options = null)
* @method $this zscore($key, $member)
* @method $this zscan($key, $cursor, array $options = null)
* @method $this zrangebylex($key, $start, $stop, array $options = null)
@@ -128,8 +127,8 @@ use Predis\Command\CommandInterface;
* @method $this zremrangebylex($key, $min, $max)
* @method $this zlexcount($key, $min, $max)
* @method $this pfadd($key, array $elements)
* @method $this pfmerge($destinationKey, array|string $sourceKeys)
* @method $this pfcount(array|string $keys)
* @method $this pfmerge($destinationKey, array $sourceKeys)
* @method $this pfcount(array $keys)
* @method $this pubsub($subcommand, $argument)
* @method $this publish($channel, $message)
* @method $this discard()
+151 -152
View File
@@ -12,9 +12,9 @@
namespace Predis;
use Predis\Command\CommandInterface;
use Predis\Command\FactoryInterface;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Profile\ProfileInterface;
/**
* Interface defining a client able to execute commands against Redis.
@@ -24,165 +24,164 @@ 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|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)
* @method int del(array $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, ...)
* @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 $keys, $timeout)
* @method array brpop(array $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 $keys)
* @method int sdiffstore($destination, array $keys)
* @method array sinter(array $keys)
* @method int sinterstore($destination, array $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method string 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 $keys)
* @method int sunionstore($destination, array $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 $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 $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 $sourceKeys)
* @method int pfcount(array $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)
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
interface ClientInterface
{
/**
* Returns the server profile used by the client.
* Returns the command factory used by the client.
*
* @return ProfileInterface
* @return FactoryInterface
*/
public function getProfile();
public function getCommandFactory();
/**
* Returns the client options specified upon initialization.
+1 -1
View File
@@ -161,7 +161,7 @@ class HashRing implements DistributorInterface, HashGeneratorInterface
$replicas = (int) round($weightRatio * $totalNodes * $replicas);
for ($i = 0; $i < $replicas; ++$i) {
$key = $this->hash("$nodeHash:$i");
$key = crc32("$nodeHash:$i");
$ring[$key] = $nodeObject;
}
}
-2
View File
@@ -61,8 +61,6 @@ class CRC16 implements HashGeneratorInterface
// CRC-CCITT-16 algorithm
$crc = 0;
$CCITT_16 = self::$CCITT_16;
$value = (string) $value;
$strlen = strlen($value);
for ($i = 0; $i < $strlen; ++$i) {
@@ -65,8 +65,8 @@ abstract class CursorBasedIterator implements \Iterator
*/
protected function requiredCommand(ClientInterface $client, $commandID)
{
if (!$client->getProfile()->supportsCommand($commandID)) {
throw new NotSupportedException("The current profile does not support '$commandID'.");
if (!$client->getCommandFactory()->supportsCommand($commandID)) {
throw new NotSupportedException("'$commandID' is not supported by the current command factory.");
}
}
+5 -3
View File
@@ -50,9 +50,11 @@ class HashKey extends CursorBasedIterator
*/
protected function extractNext()
{
$this->position = key($this->elements);
$this->current = current($this->elements);
if ($kv = each($this->elements)) {
$this->position = $kv[0];
$this->current = $kv[1];
unset($this->elements[$this->position]);
unset($this->elements[$this->position]);
}
}
}
+2 -2
View File
@@ -73,8 +73,8 @@ class ListKey implements \Iterator
*/
protected function requiredCommand(ClientInterface $client, $commandID)
{
if (!$client->getProfile()->supportsCommand($commandID)) {
throw new NotSupportedException("The current profile does not support '$commandID'.");
if (!$client->getCommandFactory()->supportsCommand($commandID)) {
throw new NotSupportedException("'$commandID' is not supported by the current command factory.");
}
}
+5 -3
View File
@@ -50,9 +50,11 @@ class SortedSetKey extends CursorBasedIterator
*/
protected function extractNext()
{
$this->position = key($this->elements);
$this->current = current($this->elements);
if ($kv = each($this->elements)) {
$this->position = $kv[0];
$this->current = $kv[1];
unset($this->elements[$this->position]);
unset($this->elements[$this->position]);
}
}
}
+1 -13
View File
@@ -21,24 +21,12 @@ abstract class Command implements CommandInterface
private $slot;
private $arguments = array();
/**
* Returns a filtered array of the arguments.
*
* @param array $arguments List of arguments.
*
* @return array
*/
protected function filterArguments(array $arguments)
{
return $arguments;
}
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
{
$this->arguments = $this->filterArguments($arguments);
$this->arguments = $arguments;
unset($this->slot);
}
@@ -9,43 +9,30 @@
* file that was distributed with this source code.
*/
namespace Predis\Profile;
namespace Predis\Command;
use Predis\ClientException;
use Predis\Command\Processor\ProcessorInterface;
/**
* Base class implementing common functionalities for Redis server profiles.
* Base command factory.
*
* This class provides all of the common functionalities needed for the creation
* of new instances of Redis commands.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
abstract class RedisProfile implements ProfileInterface
abstract class Factory implements FactoryInterface
{
private $commands;
private $processor;
/**
*
*/
public function __construct()
{
$this->commands = $this->getSupportedCommands();
}
/**
* Returns a map of all the commands supported by the profile and their
* actual PHP classes.
*
* @return array
*/
abstract protected function getSupportedCommands();
protected $commands = array();
protected $processor;
/**
* {@inheritdoc}
*/
public function supportsCommand($commandID)
{
return isset($this->commands[strtoupper($commandID)]);
return $this->getCommandClass($commandID) !== null;
}
/**
@@ -63,8 +50,9 @@ abstract class RedisProfile implements ProfileInterface
}
/**
* Returns the fully-qualified name of a class representing the specified
* command ID registered in the current server profile.
* Returns the FQN of a class that represents the specified command ID.
*
* @codeCoverageIgnore
*
* @param string $commandID Command ID.
*
@@ -82,13 +70,12 @@ abstract class RedisProfile implements ProfileInterface
*/
public function createCommand($commandID, array $arguments = array())
{
$commandID = strtoupper($commandID);
if (!$commandClass = $this->getCommandClass($commandID)) {
$commandID = strtoupper($commandID);
if (!isset($this->commands[$commandID])) {
throw new ClientException("Command '$commandID' is not a registered Redis command.");
}
$commandClass = $this->commands[$commandID];
$command = new $commandClass();
$command->setArguments($arguments);
@@ -100,7 +87,7 @@ abstract class RedisProfile implements ProfileInterface
}
/**
* Defines a new command in the server profile.
* Defines a new command in the factory.
*
* @param string $commandID Command ID.
* @param string $class Fully-qualified name of a Predis\Command\CommandInterface.
@@ -109,10 +96,12 @@ abstract class RedisProfile implements ProfileInterface
*/
public function defineCommand($commandID, $class)
{
$reflection = new \ReflectionClass($class);
if ($class !== null) {
$reflection = new \ReflectionClass($class);
if (!$reflection->isSubclassOf('Predis\Command\CommandInterface')) {
throw new \InvalidArgumentException("The class '$class' is not a valid command class.");
if (!$reflection->isSubclassOf('Predis\Command\CommandInterface')) {
throw new \InvalidArgumentException("The class '$class' is not a valid command class.");
}
}
$this->commands[strtoupper($commandID)] = $class;
@@ -133,14 +122,4 @@ abstract class RedisProfile implements ProfileInterface
{
return $this->processor;
}
/**
* Returns the version of server profile as its string representation.
*
* @return string
*/
public function __toString()
{
return $this->getVersion();
}
}
@@ -9,28 +9,20 @@
* file that was distributed with this source code.
*/
namespace Predis\Profile;
use Predis\Command\CommandInterface;
namespace Predis\Command;
/**
* A profile defines all the features and commands supported by certain versions
* of Redis. Instances of Predis\Client should use a server profile matching the
* version of Redis being used.
* Command factory interface.
*
* Each Redis command should have a class counterpart and commands factories are
* used to create new instances of these classes through the library.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
interface ProfileInterface
interface FactoryInterface
{
/**
* Returns the profile version corresponding to the Redis version.
*
* @return string
*/
public function getVersion();
/**
* Checks if the profile supports the specified command.
* Checks if the command factory supports the specified command.
*
* @param string $commandID Command ID.
*
@@ -39,7 +31,7 @@ interface ProfileInterface
public function supportsCommand($commandID);
/**
* Checks if the profile supports the specified list of commands.
* Checks if the command factory supports the specified list of commands.
*
* @param array $commandIDs List of command IDs.
*
+1 -2
View File
@@ -111,8 +111,7 @@ class ProcessorChain implements \ArrayAccess, ProcessorInterface
{
if (!$processor instanceof ProcessorInterface) {
throw new \InvalidArgumentException(
'A processor chain accepts only instances of '.
"'Predis\Command\Processor\ProcessorInterface'."
'Processor chain accepts only instances of `Predis\Command\Processor\ProcessorInterface`'
);
}
+6 -13
View File
@@ -28,20 +28,13 @@ class RawCommand implements CommandInterface
private $arguments;
/**
* @param array $arguments Command ID and its arguments.
*
* @throws \InvalidArgumentException
* @param string $commandID Command ID.
* @param array $arguments Command arguments.
*/
public function __construct(array $arguments)
public function __construct($commandID, array $arguments = array())
{
if (!$arguments) {
throw new \InvalidArgumentException(
'The arguments array must contain at least the command ID.'
);
}
$this->commandID = strtoupper(array_shift($arguments));
$this->arguments = $arguments;
$this->commandID = strtoupper($commandID);
$this->setArguments($arguments);
}
/**
@@ -55,7 +48,7 @@ class RawCommand implements CommandInterface
public static function create($commandID /* [ $arg, ... */)
{
$arguments = func_get_args();
$command = new self($arguments);
$command = new static(array_shift($arguments), $arguments);
return $command;
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/append
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringAppend extends Command
class APPEND extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/auth
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ConnectionAuth extends Command
class AUTH extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/bgrewriteaof
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerBackgroundRewriteAOF extends Command
class BGREWRITEAOF extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/bgsave
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerBackgroundSave extends Command
class BGSAVE extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/bitcount
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringBitCount extends Command
class BITCOUNT extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/bitfield
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringBitField extends Command
class BITFIELD extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/bitop
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringBitOp extends Command
class BITOP extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,7 +31,7 @@ class StringBitOp extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if (count($arguments) === 3 && is_array($arguments[2])) {
list($operation, $destination) = $arguments;
@@ -37,6 +39,6 @@ class StringBitOp extends Command
array_unshift($arguments, $operation, $destination);
}
return $arguments;
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/bitpos
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringBitPos extends Command
class BITPOS extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/blpop
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ListPopFirstBlocking extends Command
class BLPOP extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,13 +31,13 @@ class ListPopFirstBlocking extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[0])) {
list($arguments, $timeout) = $arguments;
array_push($arguments, $timeout);
}
return $arguments;
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/brpop
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ListPopLastBlocking extends ListPopFirstBlocking
class BRPOP extends RedisCommand
{
/**
* {@inheritdoc}
@@ -25,4 +27,17 @@ class ListPopLastBlocking extends ListPopFirstBlocking
{
return 'BRPOP';
}
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[0])) {
list($arguments, $timeout) = $arguments;
array_push($arguments, $timeout);
}
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/brpoplpush
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ListPopLastPushHeadBlocking extends Command
class BRPOPLPUSH extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,7 +9,9 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/client-list
@@ -19,7 +21,7 @@ namespace Predis\Command;
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerClient extends Command
class CLIENT extends RedisCommand
{
/**
* {@inheritdoc}
@@ -44,7 +46,7 @@ class ServerClient extends Command
case 'SETNAME':
default:
return $data;
}
} // @codeCoverageIgnore
}
/**
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as BaseCommand;
/**
* @link http://redis.io/commands/command
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerCommand extends Command
class COMMAND extends BaseCommand
{
/**
* {@inheritdoc}
@@ -9,7 +9,9 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/config-set
@@ -19,7 +21,7 @@ namespace Predis\Command;
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerConfig extends Command
class CONFIG extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/dbsize
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerDatabaseSize extends Command
class DBSIZE extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/decr
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringDecrement extends Command
class DECR extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/decrby
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringDecrementBy extends Command
class DECRBY extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/del
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class KeyDelete extends Command
class DEL extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,8 +31,10 @@ class KeyDelete extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
return self::normalizeArguments($arguments);
$arguments = self::normalizeArguments($arguments);
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/discard
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class TransactionDiscard extends Command
class DISCARD extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/dump
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class KeyDump extends Command
class DUMP extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/echo
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ConnectionEcho extends Command
class ECHO_ extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
/**
* @link http://redis.io/commands/evalsha
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerEvalSHA extends ServerEval
class EVALSHA extends EVAL_
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/eval
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerEval extends Command
class EVAL_ extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/exec
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class TransactionExec extends Command
class EXEC extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/exists
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class KeyExists extends Command
class EXISTS extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/expire
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class KeyExpire extends Command
class EXPIRE extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/expireat
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class KeyExpireAt extends Command
class EXPIREAT extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/flushall
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerFlushAll extends Command
class FLUSHALL extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/flushdb
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerFlushDatabase extends Command
class FLUSHDB extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/geoadd
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GeospatialGeoAdd extends Command
class GEOADD extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,7 +31,7 @@ class GeospatialGeoAdd extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
foreach (array_pop($arguments) as $item) {
@@ -37,6 +39,6 @@ class GeospatialGeoAdd extends Command
}
}
return $arguments;
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/geodist
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GeospatialGeoDist extends Command
class GEODIST extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/geohash
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GeospatialGeoHash extends Command
class GEOHASH extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,13 +31,13 @@ class GeospatialGeoHash extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$members = array_pop($arguments);
$arguments = array_merge($arguments, $members);
}
return $arguments;
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/geopos
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GeospatialGeoPos extends Command
class GEOPOS extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,13 +31,13 @@ class GeospatialGeoPos extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$members = array_pop($arguments);
$arguments = array_merge($arguments, $members);
}
return $arguments;
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/georadius
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GeospatialGeoRadius extends Command
class GEORADIUS extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,7 +31,7 @@ class GeospatialGeoRadius extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if ($arguments && is_array(end($arguments))) {
$options = array_change_key_case(array_pop($arguments), CASE_UPPER);
@@ -66,6 +68,6 @@ class GeospatialGeoRadius extends Command
}
}
return $arguments;
parent::setArguments($arguments);
}
}
@@ -9,14 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
/**
* @link http://redis.io/commands/georadiusbymember
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GeospatialGeoRadiusByMember extends GeospatialGeoRadius
class GEORADIUSBYMEMBER extends GEORADIUS
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/get
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringGet extends Command
class GET extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/getbit
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringGetBit extends Command
class GETBIT extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/getrange
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringGetRange extends Command
class GETRANGE extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/getset
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringGetSet extends Command
class GETSET extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hdel
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashDelete extends Command
class HDEL extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,8 +31,10 @@ class HashDelete extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
$arguments = self::normalizeVariadic($arguments);
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hexists
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashExists extends Command
class HEXISTS extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hget
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashGet extends Command
class HGET extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hgetall
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashGetAll extends Command
class HGETALL extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hincrby
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashIncrementBy extends Command
class HINCRBY extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hincrbyfloat
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashIncrementByFloat extends Command
class HINCRBYFLOAT extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hkeys
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashKeys extends Command
class HKEYS extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hlen
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashLength extends Command
class HLEN extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hmget
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashGetMultiple extends Command
class HMGET extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,8 +31,10 @@ class HashGetMultiple extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
return self::normalizeVariadic($arguments);
$arguments = self::normalizeVariadic($arguments);
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hmset
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashSetMultiple extends Command
class HMSET extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,7 +31,7 @@ class HashSetMultiple extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$flattenedKVs = array($arguments[0]);
@@ -40,9 +42,9 @@ class HashSetMultiple extends Command
$flattenedKVs[] = $v;
}
return $flattenedKVs;
$arguments = $flattenedKVs;
}
return $arguments;
parent::setArguments($arguments);
}
}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hscan
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashScan extends Command
class HSCAN extends RedisCommand
{
/**
* {@inheritdoc}
@@ -29,14 +31,14 @@ class HashScan extends Command
/**
* {@inheritdoc}
*/
protected function filterArguments(array $arguments)
public function setArguments(array $arguments)
{
if (count($arguments) === 3 && is_array($arguments[2])) {
$options = $this->prepareOptions(array_pop($arguments));
$arguments = array_merge($arguments, $options);
}
return $arguments;
parent::setArguments($arguments);
}
/**
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hset
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashSet extends Command
class HSET extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hsetnx
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashSetPreserve extends Command
class HSETNX extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hstrlen
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashStringLength extends Command
class HSTRLEN extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/hvals
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HashValues extends Command
class HVALS extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/incr
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringIncrement extends Command
class INCR extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/incrby
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringIncrementBy extends Command
class INCRBY extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/incrbyfloat
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class StringIncrementByFloat extends Command
class INCRBYFLOAT extends RedisCommand
{
/**
* {@inheritdoc}
@@ -9,14 +9,16 @@
* file that was distributed with this source code.
*/
namespace Predis\Command;
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
/**
* @link http://redis.io/commands/info
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ServerInfo extends Command
class INFO extends RedisCommand
{
/**
* {@inheritdoc}
@@ -31,10 +33,51 @@ class ServerInfo extends Command
*/
public function parseResponse($data)
{
$info = array();
$infoLines = preg_split('/\r?\n/', $data);
if (empty($data) || !$lines = preg_split('/\r?\n/', $data)) {
return array();
}
foreach ($infoLines as $row) {
if (strpos($lines[0], '#') === 0) {
return $this->parseNewResponseFormat($lines);
} else {
return $this->parseOldResponseFormat($lines);
}
}
/**
* {@inheritdoc}
*/
public function parseNewResponseFormat($lines)
{
$info = array();
$current = null;
foreach ($lines as $row) {
if ($row === '') {
continue;
}
if (preg_match('/^# (\w+)$/', $row, $matches)) {
$info[$matches[1]] = array();
$current = &$info[$matches[1]];
continue;
}
list($k, $v) = $this->parseRow($row);
$current[$k] = $v;
}
return $info;
}
/**
* {@inheritdoc}
*/
public function parseOldResponseFormat($lines)
{
$info = array();
foreach ($lines as $row) {
if (strpos($row, ':') === false) {
continue;
}
@@ -82,30 +125,4 @@ class ServerInfo extends Command
return $db;
}
/**
* Parses the response and extracts the allocation statistics.
*
* @param string $str Response buffer.
*
* @return array
*/
protected function parseAllocationStats($str)
{
$stats = array();
foreach (explode(',', $str) as $kv) {
@list($size, $objects, $extra) = explode('=', $kv);
// hack to prevent incorrect values when parsing the >=256 key
if (isset($extra)) {
$size = ">=$objects";
$objects = $extra;
}
$stats[$size] = $objects;
}
return $stats;
}
}

Some files were not shown because too many files have changed in this diff Show More