mirror of
https://github.com/predis/predis.git
synced 2026-08-20 14:01:51 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c0498a893 | |||
| aba24d0f6f | |||
| a1df4f20da | |||
| 116eaba75e | |||
| de4bae3f9b | |||
| b50a5975ac | |||
| 1c1b4096f6 | |||
| f8e4ba152f | |||
| 6b6b73f5f4 | |||
| 729e40d6c0 | |||
| fbcfdc343e | |||
| 8cbcb09c4c | |||
| 2781bd780f | |||
| 9675626aac | |||
| f8829985f7 | |||
| e2e809c9d4 | |||
| ef0067e1a4 | |||
| da343046e5 | |||
| 76d6681f68 | |||
| 8d01be388d | |||
| c38376dcc4 | |||
| c354d02105 | |||
| d6685a424a | |||
| 05ef62ff97 | |||
| b76e876b73 | |||
| ebd895a67d | |||
| 923e7ed5fd | |||
| 9e0fe7bdc7 | |||
| 5d774dc581 | |||
| dffbb8b042 | |||
| 06d5475129 | |||
| 1536455fea | |||
| aa1b070f9b | |||
| 3e125c964c | |||
| e9fdc47d3f | |||
| d3930ea298 | |||
| 0efcbb7992 | |||
| f2af247c63 | |||
| a5cf6d72cd | |||
| 7173f0c80c | |||
| 495e3c6f8a | |||
| 3465bc7c1f | |||
| 8bf896f81f | |||
| 0085bc08ae | |||
| f7232b9ddc | |||
| 95cc528904 | |||
| 4a16cb9417 | |||
| 94758d5f58 | |||
| acc0f04bdb | |||
| 09de7be7cb | |||
| 70b279bbdc | |||
| f8cbbc5b8f | |||
| 83720075f3 | |||
| 9901233fa1 | |||
| dcb4093046 | |||
| 1e8af648cb | |||
| ff5e3515c3 | |||
| 59813cd74e | |||
| bfd96b15dc | |||
| 51b466267d | |||
| 78f3596566 | |||
| ac01c1a17f | |||
| 46920c9c77 | |||
| b26d6103a6 | |||
| a4760d65cd | |||
| 49aa6f0aca | |||
| 292f9939b2 | |||
| daa36a980d | |||
| 0b09d2c359 |
@@ -2,4 +2,6 @@
|
||||
*.phar
|
||||
phpunit.xml
|
||||
package.xml
|
||||
composer.lock
|
||||
experiments/
|
||||
vendor/
|
||||
|
||||
+6
-4
@@ -2,10 +2,12 @@ language: php
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- v0.7
|
||||
- v0.8
|
||||
except:
|
||||
- v0.5
|
||||
- v0.6
|
||||
- php5.2_backport
|
||||
- documentation
|
||||
services: redis-server
|
||||
script: phpunit -c phpunit.xml.travisci
|
||||
|
||||
+78
-2
@@ -1,3 +1,79 @@
|
||||
v0.8.3 (2013-02-18)
|
||||
===============================================================================
|
||||
|
||||
- Added `CLIENT SETNAME` and `CLIENT GETNAME` (ISSUE #102).
|
||||
|
||||
- Implemented the `Predis\Connection\PhpiredisStreamConnection` class using the
|
||||
`phpiredis` extension like `Predis\Connection\PhpiredisStreamConnection`, but
|
||||
without requiring the `socket` extension since it relies on PHP's streams.
|
||||
|
||||
- Added support for the TCP_NODELAY flag via the `tcp_nodelay` parameter for
|
||||
stream-based connections, namely `Predis\Connection\StreamConnection` and
|
||||
`Predis\Connection\PhpiredisStreamConnection` (requires PHP >= 5.4.0).
|
||||
|
||||
- Updated the aggregated connection class for redis-cluster to work with 16384
|
||||
hash slots instead of 4096 to reflect the recent change from redis unstable
|
||||
([see this commit](https://github.com/antirez/redis/commit/ebd666d)).
|
||||
|
||||
- The constructor of `Predis\Client` now accepts a callable as first argument
|
||||
returning `Predis\Connection\ConnectionInterface`. Users can create their
|
||||
own self-contained strategies to create and set up the underlying connection.
|
||||
|
||||
- Users should return `0` from `Predis\Command\ScriptedCommand::getKeysCount()`
|
||||
instead of `FALSE` to indicate that all of the arguments of a Lua script must
|
||||
be used to populate `ARGV[]`. This does not represent a breaking change.
|
||||
|
||||
- The `Predis\Helpers` class has been deprecated and it will be removed in
|
||||
future releases.
|
||||
|
||||
|
||||
v0.8.2 (2013-02-03)
|
||||
===============================================================================
|
||||
|
||||
- Added `Predis\Session\SessionHandler` to make it easy to store PHP sessions
|
||||
on Redis using Predis. Please note that this class needs either PHP >= 5.4.0
|
||||
or a polyfill for PHP's `SessionHandlerInterface`.
|
||||
|
||||
- Added the ability to get the default value of a client option directly from
|
||||
`Predis\Option\ClientOption` using the `getDefault()` method by passing the
|
||||
option name or its instance.
|
||||
|
||||
- __FIX__: the standard pipeline executor was not using the response parser
|
||||
methods associated to commands to process raw responses (ISSUE #101).
|
||||
|
||||
|
||||
v0.8.1 (2013-01-19)
|
||||
===============================================================================
|
||||
|
||||
- The `connections` client option can now accept a callable object returning
|
||||
an instance of `Predis\Connection\ConnectionFactoryInterface`.
|
||||
|
||||
- Client options accepting callable objects as factories now pass their actual
|
||||
instance to the callable as the second argument.
|
||||
|
||||
- `Predis\Command\Processor\KeyPrefixProcessor` can now be directly casted to
|
||||
string to obtain the current prefix, useful with string interpolation.
|
||||
|
||||
- Added an optional callable argument to `Predis\Cluster\Distribution\HashRing`
|
||||
and `Predis\Cluster\Distribution\KetamaPureRing` constructor that can be used
|
||||
to customize how the distributor should extract the connection hash when
|
||||
initializing the nodes distribution (ISSUE #36).
|
||||
|
||||
- Correctly handle `TTL` and `PTTL` returning -2 on non existing keys starting
|
||||
with Redis 2.8.
|
||||
|
||||
- __FIX__: a missing use directive in `Predis\Transaction\MultiExecContext`
|
||||
caused PHP errors when Redis did not return `+QUEUED` replies to commands
|
||||
when inside a MULTI / EXEC context.
|
||||
|
||||
- __FIX__: the `parseResponse()` method implemented for a scripted command was
|
||||
ignored when retrying to execute a Lua script by falling back to `EVAL` after
|
||||
a `-NOSCRIPT` error (ISSUE #94).
|
||||
|
||||
- __FIX__: when subclassing `Predis\Client` the `getClientFor()` method returns
|
||||
a new instance of the subclass instead of a new instance of `Predis\Client`.
|
||||
|
||||
|
||||
v0.8.0 (2012-10-23)
|
||||
===============================================================================
|
||||
|
||||
@@ -351,7 +427,7 @@ v0.6.0 (2010-05-24)
|
||||
to instances of Redis 1.2.x).
|
||||
|
||||
- Support for Redis 1.0 is now optional and it is provided by requiring
|
||||
'Predis_Compatibility.php' before creating an instance of Predis\Client.
|
||||
'Predis_Compatibility.php' before creating an instance of `Predis\Client`.
|
||||
|
||||
- New commands added to the Redis 2.0 profile since Predis 0.5.1:
|
||||
- Strings: `SETEX`, `APPEND`, `SUBSTR`
|
||||
@@ -364,7 +440,7 @@ v0.6.0 (2010-05-24)
|
||||
|
||||
- Introduced client-level options with the new `Predis\ClientOptions` class.
|
||||
Options can be passed to the constructor of `Predis\Client` in its second
|
||||
argument as an array or an instance of Predis\ClientOptions. For brevity's
|
||||
argument as an array or an instance of `Predis\ClientOptions`. For brevity's
|
||||
sake and compatibility with older versions, the constructor still accepts
|
||||
an instance of `Predis\RedisServerProfile` in its second argument. The
|
||||
currently supported client options are:
|
||||
|
||||
+5
-4
@@ -6,10 +6,11 @@ section of the project.
|
||||
When reporting bugs, in addition to the obvious description of your issue you __must__ always provide
|
||||
some essential information about your environment such as:
|
||||
|
||||
1. version of Predis.
|
||||
2. version of PHP.
|
||||
3. name and version of the operating system.
|
||||
4. when possible, a small snippet of code that reproduces the issue.
|
||||
1. version of Predis (check the `VERSION` file or the `Predis\Client::VERSION` constant).
|
||||
2. version of Redis (check the `redis_version` field returned by [`INFO`](http://redis.io/commands/info)).
|
||||
3. version of PHP.
|
||||
4. name and version of the operating system.
|
||||
5. when possible, a small snippet of code that reproduces the issue.
|
||||
|
||||
__Think about it__: we do not have a crystal ball and cannot predict things and peer into the unknown,
|
||||
so please provide as much details as possible to help us isolating issues and fix them.
|
||||
|
||||
@@ -37,7 +37,7 @@ connections to the server, but this behavior can be inconvenient in certain scen
|
||||
need to do an upfront check to detect if the server is up and running and eventually catch exceptions on
|
||||
failures. In this case developers can use `Predis\Client::connect()` to explicitly connect to the server:
|
||||
|
||||
```
|
||||
```php
|
||||
$client = new Predis\Client();
|
||||
|
||||
try {
|
||||
@@ -59,7 +59,7 @@ Redis works or if you need to look up how to use certain commands. Alternatively
|
||||
accept an array for keys or values (depending on the command) instead of a list of arguments. See for
|
||||
example how [RPUSH](http://redis.io/commands/rpush) or [HMSET](http://redis.io/commands/hmset) work:
|
||||
|
||||
```
|
||||
```php
|
||||
$client->rpush('my:list', 'value1', 'value2', 'value3'); // values as arguments
|
||||
$client->rpush('my:list', array('value1', 'value2', 'value3')); // values as single argument array
|
||||
|
||||
@@ -68,7 +68,7 @@ $client->hmset('my:hash', array('field1'=>'value1', 'field2'=>'value2'); // valu
|
||||
```
|
||||
|
||||
The only exception to this _rule_ is the [SORT](http://redis.io/commands/sort) command for which modifiers are
|
||||
[passed using a named array](https://github.com/nrk/predis/blob/master/tests/Predis/Command/KeySortTest.php#L56-77).
|
||||
[passed using a named array](tests/Predis/Command/KeySortTest.php#L56-77).
|
||||
|
||||
|
||||
|
||||
@@ -79,18 +79,18 @@ _________________________________________________
|
||||
### Predis is a pure-PHP implementation: it can not be fast enough! ###
|
||||
|
||||
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you
|
||||
a couple of easy numbers using a single Predis client with PHP 5.3.5 (custom build) and Redis 2.2
|
||||
(localhost) under Ubuntu 11.04 (running on a Intel Q6600):
|
||||
a couple of easy numbers using a single Predis client with PHP 5.4.7 (custom build) and Redis 2.2
|
||||
(localhost) under Ubuntu 12.04.1 (running on a Intel Q6600):
|
||||
|
||||
19600 SET/sec using 12 bytes for both key and value
|
||||
18900 GET/sec while retrieving the very same values
|
||||
0.200 seconds to fetch 30000 keys using _KEYS *_.
|
||||
21500 SET/sec using 12 bytes for both key and value
|
||||
21000 GET/sec while retrieving the very same values
|
||||
0.130 seconds to fetch 30000 keys using _KEYS *_.
|
||||
|
||||
How does it compare with a nice C-based extension such as [__phpredis__](http://github.com/nicolasff/phpredis)?
|
||||
|
||||
30500 SET/sec using 12 bytes for both key and value
|
||||
31000 GET/sec while retrieving the very same values
|
||||
0.030 seconds to fetch 30000 keys using "KEYS *"".
|
||||
30100 SET/sec using 12 bytes for both key and value
|
||||
29400 GET/sec while retrieving the very same values
|
||||
0.035 seconds to fetch 30000 keys using "KEYS *"".
|
||||
|
||||
Wow, __phpredis__ looks so much faster! Well we are comparing a C extension with a pure-PHP library so
|
||||
lower numbers are quite expected, but there is a fundamental flaw in them: is this really how you are
|
||||
@@ -104,14 +104,14 @@ Redis, but how these numbers change when we hit the network by connecting to ins
|
||||
reside on other servers?
|
||||
|
||||
Using Predis:
|
||||
3600 SET/sec using 12 bytes for both key and value
|
||||
3600 GET/sec while retrieving the very same values
|
||||
0.210 seconds to fetch 30000 keys using "KEYS *".
|
||||
3200 SET/sec using 12 bytes for both key and value
|
||||
3200 GET/sec while retrieving the very same values
|
||||
0.132 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
Using phpredis:
|
||||
4000 SET/sec using 12 bytes for both key and value
|
||||
4000 GET/sec while retrieving the very same values
|
||||
0.051 seconds to fetch 30000 keys using "KEYS *".
|
||||
3500 SET/sec using 12 bytes for both key and value
|
||||
3500 GET/sec while retrieving the very same values
|
||||
0.045 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
There you go, you get almost the same average numbers and the reason is quite simple: network latency
|
||||
is a real performance killer and you cannot do (almost) anything about that. As a disclaimer, please
|
||||
@@ -124,14 +124,21 @@ to how your application will use Redis.
|
||||
### I am convinced, but performances for multi-bulk replies (e.g. _KEYS *_) are still worse ###
|
||||
|
||||
Fair enough, but there is actually an option for you if you need even more speed and it consists on
|
||||
installing __[phpiredis](http://github.com/seppo0010/phpiredis)__ (note the additional _i_ in the
|
||||
name) and let Predis using it. __phpiredis__ is a C-based extension that wraps __hiredis__ (the
|
||||
official Redis C client library) with a thin layer that exposes its features to PHP. You will now
|
||||
get the benefits of a faster protocol parser just by adding a single line of code in your application:
|
||||
installing __[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name)
|
||||
and let Predis using it. __phpiredis__ is a C-based extension that wraps __hiredis__ (the official
|
||||
Redis C client library) with a thin layer that exposes its features to PHP. You can choose between
|
||||
two different connection backend classes: `Predis\Connection\PhpiredisConnection` (it depends on the
|
||||
`socket` extension) and `Predis\Connection\PhpiredisStreamConnection` (it uses PHP's native streams).
|
||||
You will now get the benefits of a faster protocol parser just by adding a couple of lines of code:
|
||||
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array('tcp' => 'Predis\Connection\PhpiredisConnection')
|
||||
));
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisConnection',
|
||||
),
|
||||
));
|
||||
```
|
||||
|
||||
As simple as it is, nothing will really change in the way you use the library in your application. So,
|
||||
how fast is it now? There are not much improvements for inline or short bulk replies (e.g. _SET_ or
|
||||
@@ -139,8 +146,8 @@ _GET_), but the speed for parsing multi-bulk replies is now on par with phpredis
|
||||
|
||||
Using Predis with a phpiredis-based connection to fetch 30000 keys using _KEYS *_:
|
||||
|
||||
0.031 seconds from a local Redis instance
|
||||
0.058 seconds from a remote Redis instance
|
||||
0.035 seconds from a local Redis instance
|
||||
0.047 seconds from a remote Redis instance
|
||||
|
||||
|
||||
### If I need to install a C extension to get better performances, why not using phpredis? ###
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2012 Daniele Alessandri
|
||||
Copyright (c) 2009-2013 Daniele Alessandri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
Predis is a flexible and feature-complete PHP (>= 5.3) client library for the Redis key-value store.
|
||||
|
||||
The library does not require any additional extension loaded in PHP but it can be optionally paired
|
||||
with the [phpiredis](https://github.com/seppo0010/phpiredis) C extension to lower the overhead of
|
||||
with the [phpiredis](https://github.com/nrk/phpiredis) C-based extension to lower the overhead of
|
||||
serializing and parsing the Redis protocol. Predis is also available in an asynchronous fashion
|
||||
through the experimental client provided by the [Predis\Async](http://github.com/nrk/predis-async)
|
||||
library.
|
||||
|
||||
For a list of frequently asked questions about Predis, see __FAQ.md__ in the root of the repository.
|
||||
For a list of frequently asked questions about Predis see our [FAQ](FAQ.md).
|
||||
More details are available on the [official wiki](http://wiki.github.com/nrk/predis) of the project.
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ compatible with most of the major frameworks and libraries. Autoloading in your
|
||||
automatically when managing the dependencies with Composer, but you can also leverage its own autoloader
|
||||
class if you are going to use it in a project or script without any PSR-0 compliant autoloading facility:
|
||||
|
||||
``` php
|
||||
```php
|
||||
<?php
|
||||
// prepend a base path if Predis is not present in your "include_path".
|
||||
require 'Predis/Autoloader.php';
|
||||
@@ -68,8 +68,7 @@ using functions such as `require` and `include`, but this practice is not encour
|
||||
By default Predis uses `127.0.0.1` and `6379` as the default host and port when creating a new client
|
||||
instance without specifying any connection parameter:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
```php
|
||||
$redis = new Predis\Client();
|
||||
$redis->set('foo', 'bar');
|
||||
$value = $redis->get('foo');
|
||||
@@ -77,8 +76,7 @@ $value = $redis->get('foo');
|
||||
|
||||
It is possible to specify the various connection parameters using URI strings or named arrays:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
```php
|
||||
$redis = new Predis\Client('tcp://10.0.0.1:6379');
|
||||
|
||||
// is equivalent to:
|
||||
@@ -98,8 +96,7 @@ Furthermore, pipelining works transparently even on aggregated connections. To a
|
||||
supports client-side sharding using consistent-hashing on keys while clustered connections are supported
|
||||
natively by the client class.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
```php
|
||||
$redis = new Predis\Client(array(
|
||||
array('host' => '10.0.0.1', 'port' => 6379),
|
||||
array('host' => '10.0.0.2', 'port' => 6379)
|
||||
@@ -116,14 +113,19 @@ $replies = $redis->pipeline(function ($pipe) {
|
||||
|
||||
### Multiple and customizable connection backends ###
|
||||
|
||||
Predis can optionally use different connection backends to connect to Redis. One of them leverages
|
||||
the [phpiredis](http://github.com/seppo0010/phpiredis) C extension resulting in a major speed bump
|
||||
especially when dealing with long multibulk replies (the `socket` extension is also required):
|
||||
Predis can optionally use different connection backends to connect to Redis. Two of them leverage
|
||||
the [phpiredis](http://github.com/nrk/phpiredis) C-based extension resulting in a major speed bump
|
||||
especially when dealing with long multibulk replies, namely `Predis\Connection\PhpiredisConnection`
|
||||
(the `socket` extension is also required) and `Predis\Connection\StreamPhpiredisConnection` (it
|
||||
does not require additional extensions since it relies on PHP's native streams). Both of them can
|
||||
connect to Redis using standard TCP/IP connections or UNIX domain sockets:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array('tcp' => 'Predis\Connection\PhpiredisConnection')
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisStreamConnection',
|
||||
)
|
||||
));
|
||||
```
|
||||
|
||||
@@ -131,8 +133,7 @@ Developers can also create their own connection backends to add support for new
|
||||
existing ones or provide different implementations. Connection backend classes must implement
|
||||
`Predis\Connection\SingleConnectionInterface` or extend `Predis\Connection\AbstractConnection`:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
```php
|
||||
class MyConnectionClass implements Predis\Connection\SingleConnectionInterface
|
||||
{
|
||||
// implementation goes here
|
||||
@@ -145,7 +146,7 @@ $client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
```
|
||||
|
||||
For a more in-depth insight on how to create new connection backends you can look at the actual
|
||||
implementation of the classes contained in `Predis\Connection` namespace.
|
||||
implementation of the classes contained in the `Predis\Connection` namespace.
|
||||
|
||||
|
||||
### Defining and registering new commands on the client at runtime ###
|
||||
@@ -156,8 +157,7 @@ code or waiting for it to find its way into a stable Predis release, then you ca
|
||||
a new class that matches the command type and its behaviour and then bind it to a client instance at
|
||||
runtime. Actually, it is easier done than said:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
```php
|
||||
class BrandNewRedisCommand extends Predis\Command\AbstractCommand
|
||||
{
|
||||
public function getId()
|
||||
@@ -181,8 +181,7 @@ in the server profile being used by the client instance. Internally, scripted co
|
||||
to save bandwidth, but they are capable of falling back to [EVAL](http://redis.io/commands/eval)
|
||||
when needed:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
```php
|
||||
class ListPushRandomValue extends Predis\Command\ScriptedCommand
|
||||
{
|
||||
public function getKeysCount()
|
||||
@@ -221,7 +220,7 @@ Redis. If you do not have Redis up and running, integration tests can be disable
|
||||
suite is configured to execute integration tests using the server profile for Redis v2.4 (which is the
|
||||
current stable version of Redis). You can optionally run the suite against a Redis instance built from
|
||||
the `unstable` branch with the development profile by changing the `REDIS_SERVER_VERSION` to `dev` in
|
||||
the `phpunit.xml` file. More details about testing Predis are available in `tests/README.md`.
|
||||
the `phpunit.xml` file. More details on testing Predis can be found in [the tests README](tests/README.md).
|
||||
|
||||
Predis uses Travis CI for continuous integration. You can find the results of the test suite and the build
|
||||
history [on its project page](http://travis-ci.org/nrk/predis).
|
||||
@@ -255,8 +254,8 @@ history [on its project page](http://travis-ci.org/nrk/predis).
|
||||
- [Lorenzo Castelli](http://github.com/lcastelli)
|
||||
- [Jordi Boggiano](http://github.com/Seldaek) ([twitter](http://twitter.com/seldaek))
|
||||
- [Sebastian Waisbrot](http://github.com/seppo0010) ([twitter](http://twitter.com/seppo0010))
|
||||
for his work on extending [phpiredis](http://github.com/seppo0010/phpiredis) for Predis
|
||||
for his past work on extending [phpiredis](http://github.com/nrk/phpiredis) for Predis.
|
||||
|
||||
## License ##
|
||||
|
||||
The code for Predis is distributed under the terms of the MIT license (see LICENSE).
|
||||
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
|
||||
|
||||
@@ -51,8 +51,8 @@ $parameters = array(
|
||||
);
|
||||
|
||||
$options = array(
|
||||
'profile' => function ($options) {
|
||||
$profile = ServerProfile::get('2.6');
|
||||
'profile' => function ($options, $option) {
|
||||
$profile = $options->getDefault($option);
|
||||
$profile->defineCommand('hmgetall', 'HashMultipleGetAll');
|
||||
|
||||
return $profile;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
|
||||
// This example demonstrates how to leverage Predis to save PHP sessions on Redis.
|
||||
//
|
||||
// The value of `session.gc_maxlifetime` in `php.ini` will be used by default as the
|
||||
// the TTL for keys holding session data on Redis, but this value can be overridden
|
||||
// when creating the session handler instance with the `gc_maxlifetime` option.
|
||||
//
|
||||
// Note that this class needs PHP >= 5.4 but can be used on PHP 5.3 if a polyfill for
|
||||
// SessionHandlerInterface (see http://www.php.net/class.sessionhandlerinterface.php)
|
||||
// is provided either by you or an external package like `symfony/http-foundation`.
|
||||
|
||||
if (!interface_exists('SessionHandlerInterface')) {
|
||||
die("ATTENTION: the session handler implemented by Predis needs PHP >= 5.4.0 or a polyfill ".
|
||||
"for \SessionHandlerInterface either provided by you or an external package.\n");
|
||||
}
|
||||
|
||||
// Instantiate a new client just like you would normally do. We'll prefix our session keys here.
|
||||
$client = new Predis\Client($single_server, array('prefix' => 'sessions:'));
|
||||
|
||||
// Set `gc_maxlifetime` so that a session will be expired after 5 seconds since last access.
|
||||
$handler = new Predis\Session\SessionHandler($client, array('gc_maxlifetime' => 5));
|
||||
|
||||
// Register our session handler (it uses `session_set_save_handler()` internally).
|
||||
$handler->register();
|
||||
|
||||
// Set a fixed session ID just for the sake of our example.
|
||||
session_id('example_session_id');
|
||||
|
||||
session_start();
|
||||
|
||||
if (isset($_SESSION['foo'])) {
|
||||
echo "Session has `foo` set to {$_SESSION['foo']}\n";
|
||||
} else {
|
||||
$_SESSION['foo'] = $value = mt_rand();
|
||||
echo "Empty session, `foo` has been set with $value\n";
|
||||
}
|
||||
+30
-13
@@ -33,12 +33,11 @@ use Predis\Transaction\MultiExecContext;
|
||||
*/
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
const VERSION = '0.8.0';
|
||||
const VERSION = '0.8.3';
|
||||
|
||||
private $options;
|
||||
private $profile;
|
||||
private $connection;
|
||||
private $connections;
|
||||
|
||||
/**
|
||||
* Initializes a new client with optional connection parameters and client options.
|
||||
@@ -50,7 +49,6 @@ class Client implements ClientInterface
|
||||
{
|
||||
$this->options = $this->filterOptions($options);
|
||||
$this->profile = $this->options->profile;
|
||||
$this->connections = $this->options->connections;
|
||||
$this->connection = $this->initializeConnection($parameters);
|
||||
}
|
||||
|
||||
@@ -64,7 +62,7 @@ class Client implements ClientInterface
|
||||
*/
|
||||
protected function filterOptions($options)
|
||||
{
|
||||
if ($options === null) {
|
||||
if (!isset($options)) {
|
||||
return new ClientOptions();
|
||||
}
|
||||
|
||||
@@ -94,13 +92,26 @@ class Client implements ClientInterface
|
||||
}
|
||||
|
||||
if (is_array($parameters) && isset($parameters[0])) {
|
||||
$replication = isset($this->options->replication) && $this->options->replication;
|
||||
$connection = $this->options->{$replication ? 'replication' : 'cluster'};
|
||||
$options = $this->options;
|
||||
$replication = isset($options->replication) && $options->replication;
|
||||
$connection = $options->{$replication ? 'replication' : 'cluster'};
|
||||
|
||||
return $this->connections->createAggregated($connection, $parameters);
|
||||
return $options->connections->createAggregated($connection, $parameters);
|
||||
}
|
||||
|
||||
return $this->connections->create($parameters);
|
||||
if (is_callable($parameters)) {
|
||||
$connection = call_user_func($parameters, $this->options);
|
||||
|
||||
if (!$connection instanceof ConnectionInterface) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Callable parameters must return instances of Predis\Connection\ConnectionInterface'
|
||||
);
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
return $this->options->connections->create($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +137,7 @@ class Client implements ClientInterface
|
||||
*/
|
||||
public function getConnectionFactory()
|
||||
{
|
||||
return $this->connections;
|
||||
return $this->options->connections;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,11 +149,11 @@ class Client implements ClientInterface
|
||||
*/
|
||||
public function getClientFor($connectionID)
|
||||
{
|
||||
if (($connection = $this->getConnectionById($connectionID)) === null) {
|
||||
if (!$connection = $this->getConnectionById($connectionID)) {
|
||||
throw new \InvalidArgumentException("Invalid connection ID: '$connectionID'");
|
||||
}
|
||||
|
||||
return new Client($connection, $this->options);
|
||||
return new static($connection, $this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,10 +278,16 @@ class Client implements ClientInterface
|
||||
$eval = $this->createCommand('eval');
|
||||
$eval->setRawArguments($command->getEvalArguments());
|
||||
|
||||
return $this->executeCommand($eval);
|
||||
$response = $this->executeCommand($eval);
|
||||
|
||||
if (!$response instanceof ResponseObjectInterface) {
|
||||
$response = $command->parseResponse($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ($this->options->exceptions === true) {
|
||||
if ($this->options->exceptions) {
|
||||
throw new ServerException($response->getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -26,19 +26,21 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
const DEFAULT_REPLICAS = 128;
|
||||
const DEFAULT_WEIGHT = 100;
|
||||
|
||||
private $nodes;
|
||||
private $ring;
|
||||
private $ringKeys;
|
||||
private $ringKeysCount;
|
||||
private $replicas;
|
||||
private $nodeHashCallback;
|
||||
private $nodes = array();
|
||||
|
||||
/**
|
||||
* @param int $replicas Number of replicas in the ring.
|
||||
* @param mixed $nodeHashCallback Callback returning the string used to calculate the hash of a node.
|
||||
*/
|
||||
public function __construct($replicas = self::DEFAULT_REPLICAS)
|
||||
public function __construct($replicas = self::DEFAULT_REPLICAS, $nodeHashCallback = null)
|
||||
{
|
||||
$this->replicas = $replicas;
|
||||
$this->nodes = array();
|
||||
$this->nodeHashCallback = $nodeHashCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +122,7 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
return;
|
||||
}
|
||||
|
||||
if (count($this->nodes) === 0) {
|
||||
if (!$this->nodes) {
|
||||
throw new EmptyRingException('Cannot initialize empty hashring');
|
||||
}
|
||||
|
||||
@@ -164,7 +166,11 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
*/
|
||||
protected function getNodeHash($nodeObject)
|
||||
{
|
||||
return (string) $nodeObject;
|
||||
if ($this->nodeHashCallback === null) {
|
||||
return (string) $nodeObject;
|
||||
}
|
||||
|
||||
return call_user_func($this->nodeHashCallback, $nodeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,11 +24,11 @@ class KetamaPureRing extends HashRing
|
||||
const DEFAULT_REPLICAS = 160;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed $nodeHashCallback Callback returning the string used to calculate the hash of a node.
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct($nodeHashCallback = null)
|
||||
{
|
||||
parent::__construct($this::DEFAULT_REPLICAS);
|
||||
parent::__construct($this::DEFAULT_REPLICAS, $nodeHashCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,7 +64,7 @@ class CRC16HashGenerator implements HashGeneratorInterface
|
||||
$strlen = strlen($value);
|
||||
|
||||
for ($i = 0; $i < $strlen; $i++) {
|
||||
$crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 65535; // 0xFFFF
|
||||
$crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 0xFFFF;
|
||||
}
|
||||
|
||||
return $crc;
|
||||
|
||||
@@ -294,9 +294,11 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function getKeyFromScriptingCommands(CommandInterface $command)
|
||||
{
|
||||
$keys = $command instanceof ScriptedCommand
|
||||
? $command->getKeys()
|
||||
: array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
if ($command instanceof ScriptedCommand) {
|
||||
$keys = $command->getKeys();
|
||||
} else {
|
||||
$keys = array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
}
|
||||
|
||||
if ($keys && $this->checkSameHashForKeys($keys)) {
|
||||
return $keys[0];
|
||||
@@ -341,7 +343,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function checkSameHashForKeys(Array $keys)
|
||||
{
|
||||
if (($count = count($keys)) === 0) {
|
||||
if (!$count = count($keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -246,9 +246,11 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function getKeyFromScriptingCommands(CommandInterface $command)
|
||||
{
|
||||
$keys = $command instanceof ScriptedCommand
|
||||
? $command->getKeys()
|
||||
: array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
if ($command instanceof ScriptedCommand) {
|
||||
$keys = $command->getKeys();
|
||||
} else {
|
||||
$keys = array_slice($args = $command->getArguments(), 2, $args[1]);
|
||||
}
|
||||
|
||||
if (count($keys) === 1) {
|
||||
return $keys[0];
|
||||
|
||||
@@ -65,9 +65,9 @@ abstract class AbstractCommand implements CommandInterface
|
||||
*
|
||||
* @param array $arguments Position of the argument.
|
||||
*/
|
||||
public function getArgument($index = 0)
|
||||
public function getArgument($index)
|
||||
{
|
||||
if (isset($this->arguments[$index]) === true) {
|
||||
if (isset($this->arguments[$index])) {
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
}
|
||||
@@ -129,4 +129,34 @@ abstract class AbstractCommand implements CommandInterface
|
||||
$this->getId()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the arguments array passed to a Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeArguments(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 1 && is_array($arguments[0])) {
|
||||
return $arguments[0];
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the arguments array passed to a variadic Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeVariadic(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 2 && is_array($arguments[1])) {
|
||||
return array_merge(array($arguments[0]), $arguments[1]);
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,13 @@ interface CommandInterface
|
||||
*/
|
||||
public function getArguments();
|
||||
|
||||
/**
|
||||
* Gets the argument of the command at the specified index.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArgument($index);
|
||||
|
||||
/**
|
||||
* Parses a reply buffer and returns a PHP object.
|
||||
*
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/hdel
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class HashDelete extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/hmget
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class HashGetMultiple extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/del
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class KeyDelete extends AbstractCommand implements PrefixableCommandInterface
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/rpush
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class ListPushTail extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,4 +61,12 @@ class KeyPrefixProcessor implements CommandProcessorInterface
|
||||
$command->prefixKeys($this->prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getPrefix();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/subscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class PubSubSubscribe extends AbstractCommand implements PrefixableCommandInterf
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/psubscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/unsubscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class PubSubUnsubscribe extends AbstractCommand implements PrefixableCommandInte
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,19 +30,15 @@ abstract class ScriptedCommand extends ServerEvalSHA
|
||||
/**
|
||||
* Specifies the number of arguments that should be considered as keys.
|
||||
*
|
||||
* The default behaviour for the base class is to return FALSE to indicate that
|
||||
* The default behaviour for the base class is to return 0 to indicate that
|
||||
* all the elements of the arguments array should be considered as keys, but
|
||||
* subclasses can enforce a static number of keys.
|
||||
*
|
||||
* @todo How about returning 1 by default to make scripted commands act like
|
||||
* variadic ones where the first argument is the key (KEYS[1]) and the
|
||||
* rest are values (ARGV)?
|
||||
*
|
||||
* @return int|Boolean
|
||||
* @return int
|
||||
*/
|
||||
protected function getKeysCount()
|
||||
{
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,13 +56,11 @@ abstract class ScriptedCommand extends ServerEvalSHA
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
if (false !== $numkeys = $this->getKeysCount()) {
|
||||
$numkeys = $numkeys >= 0 ? $numkeys : count($arguments) + $numkeys;
|
||||
} else {
|
||||
$numkeys = count($arguments);
|
||||
if (($numkeys = $this->getKeysCount()) && $numkeys < 0) {
|
||||
$numkeys = count($arguments) + $numkeys;
|
||||
}
|
||||
|
||||
return array_merge(array(sha1($this->getScript()), $numkeys), $arguments);
|
||||
return array_merge(array(sha1($this->getScript()), (int) $numkeys), $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,8 +35,9 @@ class ServerClient extends AbstractCommand
|
||||
switch (strtoupper($args[0])) {
|
||||
case 'LIST':
|
||||
return $this->parseClientList($data);
|
||||
|
||||
case 'KILL':
|
||||
case 'GETNAME':
|
||||
case 'SETNAME':
|
||||
default:
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/object
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/sadd
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class SetAdd extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/sinter
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class SetIntersection extends AbstractCommand implements PrefixableCommandInterf
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/srem
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class SetRemove extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/mget
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,7 +30,7 @@ class StringGetMultiple extends AbstractCommand implements PrefixableCommandInte
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zadd
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zrem
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -32,6 +30,6 @@ class ZSetRemove extends PrefixableCommand
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterVariadicValues($arguments);
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,23 @@ abstract class CommunicationException extends PredisException
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offers a generic and reusable method to handle exceptions generated by
|
||||
* a connection object.
|
||||
*
|
||||
* @param CommunicationException $exception Exception.
|
||||
*/
|
||||
public static function handle(CommunicationException $exception)
|
||||
{
|
||||
if ($exception->shouldResetConnection()) {
|
||||
$connection = $exception->getConnection();
|
||||
|
||||
if ($connection->isConnected()) {
|
||||
$connection->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
@@ -136,7 +136,7 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
*/
|
||||
protected function onConnectionError($message, $code = null)
|
||||
{
|
||||
Helpers::onCommunicationException(new ConnectionException($this, $message, $code));
|
||||
CommunicationException::handle(new ConnectionException($this, $message, $code));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +146,7 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
*/
|
||||
protected function onProtocolError($message)
|
||||
{
|
||||
Helpers::onCommunicationException(new ProtocolException($this, $message));
|
||||
CommunicationException::handle(new ProtocolException($this, $message));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,12 +31,8 @@ class ComposableStreamConnection extends StreamConnection implements ComposableC
|
||||
*/
|
||||
public function __construct(ConnectionParametersInterface $parameters, ProtocolInterface $protocol = null)
|
||||
{
|
||||
$protocol = $protocol ?: new TextProtocol();
|
||||
$protocol->setOption('iterable_multibulk', $parameters->iterable_multibulk);
|
||||
|
||||
$this->mbiterable = null;
|
||||
$this->protocol = $protocol;
|
||||
$this->parameters = $this->checkParameters($parameters);
|
||||
$this->protocol = $protocol ?: new TextProtocol();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,6 +130,6 @@ class ComposableStreamConnection extends StreamConnection implements ComposableC
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array_merge(parent::__sleep(), array('protocol'));
|
||||
return array_diff(array_merge(parent::__sleep(), array('protocol')), array('mbiterable'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'timeout' => 5.0,
|
||||
'iterable_multibulk' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -37,7 +36,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
public function __construct($parameters = array())
|
||||
{
|
||||
if (!is_array($parameters)) {
|
||||
$parameters = $this->parseURI($parameters);
|
||||
$parameters = self::parseURI($parameters);
|
||||
}
|
||||
|
||||
$this->parameters = $this->filter($parameters) + $this->getDefaults();
|
||||
@@ -109,14 +108,14 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
* @param string $uri Connection string.
|
||||
* @return array
|
||||
*/
|
||||
private function parseURI($uri)
|
||||
public static function parseURI($uri)
|
||||
{
|
||||
if (stripos($uri, 'unix') === 0) {
|
||||
// Hack to support URIs for UNIX sockets with minimal effort.
|
||||
$uri = str_ireplace('unix:///', 'unix://localhost/', $uri);
|
||||
}
|
||||
|
||||
if (($parsed = @parse_url($uri)) === false || !isset($parsed['host'])) {
|
||||
if (!($parsed = @parse_url($uri)) || !isset($parsed['host'])) {
|
||||
throw new ClientException("Invalid URI: $uri");
|
||||
}
|
||||
|
||||
@@ -140,7 +139,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
*/
|
||||
private function filter(Array $parameters)
|
||||
{
|
||||
if (count($parameters) > 0) {
|
||||
if ($parameters) {
|
||||
$casters = array_intersect_key($this->getValueCasters(), $parameters);
|
||||
|
||||
foreach ($casters as $parameter => $caster) {
|
||||
|
||||
@@ -41,7 +41,7 @@ use Predis\Command\CommandInterface;
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
*
|
||||
* @link http://github.com/seppo0010/phpiredis
|
||||
* @link http://github.com/nrk/phpiredis
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PhpiredisConnection extends AbstractConnection
|
||||
@@ -90,10 +90,10 @@ class PhpiredisConnection extends AbstractConnection
|
||||
*/
|
||||
protected function checkParameters(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
if ($parameters->iterable_multibulk === true) {
|
||||
if (isset($parameters->iterable_multibulk)) {
|
||||
$this->onInvalidOption('iterable_multibulk', $parameters);
|
||||
}
|
||||
if ($parameters->persistent === true) {
|
||||
if (isset($parameters->persistent)) {
|
||||
$this->onInvalidOption('persistent', $parameters);
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ class PhpiredisConnection extends AbstractConnection
|
||||
|
||||
$this->connectWithTimeout($this->parameters);
|
||||
|
||||
if (count($this->initCmds) > 0) {
|
||||
if ($this->initCmds) {
|
||||
$this->sendInitializationCommands();
|
||||
}
|
||||
}
|
||||
@@ -328,7 +328,7 @@ class PhpiredisConnection extends AbstractConnection
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function write($buffer)
|
||||
protected function write($buffer)
|
||||
{
|
||||
$socket = $this->getResource();
|
||||
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\ResponseError;
|
||||
use Predis\ResponseQueued;
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
* This class provides the implementation of a Predis connection that uses PHP's
|
||||
* streams for network communication and wraps the phpiredis C extension (PHP
|
||||
* bindings for hiredis) to parse and serialize the Redis protocol. Everything
|
||||
* is highly experimental (even the very same phpiredis since it is quite new),
|
||||
* so use it at your own risk.
|
||||
*
|
||||
* This class is mainly intended to provide an optional low-overhead alternative
|
||||
* for processing replies from Redis compared to the standard pure-PHP classes.
|
||||
* Differences in speed when dealing with short inline replies are practically
|
||||
* nonexistent, the actual speed boost is for long multibulk replies when this
|
||||
* protocol processor can parse and return replies very fast.
|
||||
*
|
||||
* For instructions on how to build and install the phpiredis extension, please
|
||||
* consult the repository of the project.
|
||||
*
|
||||
* The connection parameters supported by this class are:
|
||||
*
|
||||
* - scheme: it can be either 'tcp' or 'unix'.
|
||||
* - host: hostname or IP address of the server.
|
||||
* - port: TCP port of the server.
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
* - async_connect: performs the connection asynchronously.
|
||||
* - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
|
||||
* - persistent: the connection is left intact after a GC collection.
|
||||
*
|
||||
* @link https://github.com/nrk/phpiredis
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PhpiredisStreamConnection extends StreamConnection
|
||||
{
|
||||
private $reader;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
$this->checkExtensions();
|
||||
$this->initializeReader();
|
||||
|
||||
parent::__construct($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
phpiredis_reader_destroy($this->reader);
|
||||
|
||||
parent::__destruct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the phpiredis extension is loaded in PHP.
|
||||
*/
|
||||
protected function checkExtensions()
|
||||
{
|
||||
if (!function_exists('phpiredis_reader_create')) {
|
||||
throw new NotSupportedException(
|
||||
'The phpiredis extension must be loaded in order to be able to use this connection class'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkParameters(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
if (isset($parameters->iterable_multibulk)) {
|
||||
$this->onInvalidOption('iterable_multibulk', $parameters);
|
||||
}
|
||||
|
||||
return parent::checkParameters($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the protocol reader resource.
|
||||
*/
|
||||
protected function initializeReader()
|
||||
{
|
||||
$reader = phpiredis_reader_create();
|
||||
|
||||
phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
|
||||
phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());
|
||||
|
||||
$this->reader = $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the handler used by the protocol reader to handle status replies.
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getStatusHandler()
|
||||
{
|
||||
return function ($payload) {
|
||||
switch ($payload) {
|
||||
case 'OK':
|
||||
return true;
|
||||
|
||||
case 'QUEUED':
|
||||
return new ResponseQueued();
|
||||
|
||||
default:
|
||||
return $payload;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the handler used by the protocol reader to handle Redis errors.
|
||||
*
|
||||
* @param Boolean $throw_errors Specify if Redis errors throw exceptions.
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getErrorHandler()
|
||||
{
|
||||
return function ($errorMessage) {
|
||||
return new ResponseError($errorMessage);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read()
|
||||
{
|
||||
$socket = $this->getResource();
|
||||
$reader = $this->reader;
|
||||
|
||||
while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
|
||||
$buffer = fread($socket, 4096);
|
||||
|
||||
if ($buffer === false || $buffer === '') {
|
||||
$this->onConnectionError('Error while reading bytes from the server');
|
||||
return;
|
||||
}
|
||||
|
||||
phpiredis_reader_feed($reader, $buffer);
|
||||
}
|
||||
|
||||
if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
|
||||
return phpiredis_reader_get_reply($reader);
|
||||
} else {
|
||||
$this->onProtocolError(phpiredis_reader_get_error($reader));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function writeCommand(CommandInterface $command)
|
||||
{
|
||||
$cmdargs = $command->getArguments();
|
||||
array_unshift($cmdargs, $command->getId());
|
||||
$this->writeBytes(phpiredis_format_command($cmdargs));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array_diff(parent::__sleep(), array('mbiterable'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->checkExtensions();
|
||||
$this->initializeReader();
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
public function buildSlotsMap()
|
||||
{
|
||||
$this->slotsMap = array();
|
||||
$this->slotsPerNode = (int) (4096 / count($this->pool));
|
||||
$this->slotsPerNode = (int) (16384 / count($this->pool));
|
||||
|
||||
foreach ($this->pool as $connectionID => $connection) {
|
||||
$parameters = $connection->getParameters();
|
||||
@@ -177,7 +177,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
*/
|
||||
public function setSlots($first, $last, $connection)
|
||||
{
|
||||
if ($first < 0 || $first > 4095 || $last < 0 || $last > 4095 || $last < $first) {
|
||||
if ($first < 0x0000 || $first > 0x3FFF || $last < 0x0000 || $last > 0x3FFF || $last < $first) {
|
||||
throw new \OutOfBoundsException("Invalid slot values for $connection: [$first-$last]");
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
throw new NotSupportedException("Cannot use {$command->getId()} with redis-cluster");
|
||||
}
|
||||
|
||||
$slot = $hash & 4095; // 0x0FFF
|
||||
$slot = $hash & 0x3FFF;
|
||||
|
||||
if (isset($this->slots[$slot])) {
|
||||
return $this->slots[$slot];
|
||||
@@ -214,7 +214,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
*/
|
||||
public function getConnectionBySlot($slot)
|
||||
{
|
||||
if ($slot < 0 || $slot > 4095) {
|
||||
if ($slot < 0x0000 || $slot > 0x3FFF) {
|
||||
throw new \OutOfBoundsException("Invalid slot value [$slot]");
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ use Predis\Iterator\MultiBulkResponseSimple;
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
* - async_connect: performs the connection asynchronously.
|
||||
* - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
|
||||
* - persistent: the connection is left intact after a GC collection.
|
||||
* - iterable_multibulk: multibulk replies treated as iterable objects.
|
||||
*
|
||||
@@ -53,7 +54,7 @@ class StreamConnection extends AbstractConnection
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (!$this->parameters->persistent) {
|
||||
if (isset($this->parameters) && !$this->parameters->persistent) {
|
||||
$this->disconnect();
|
||||
}
|
||||
}
|
||||
@@ -80,10 +81,10 @@ class StreamConnection extends AbstractConnection
|
||||
$uri = "tcp://{$parameters->host}:{$parameters->port}/";
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
|
||||
if (isset($parameters->async_connect) && $parameters->async_connect === true) {
|
||||
if (isset($parameters->async_connect) && $parameters->async_connect) {
|
||||
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
|
||||
}
|
||||
if (isset($parameters->persistent) && $parameters->persistent === true) {
|
||||
if (isset($parameters->persistent) && $parameters->persistent) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
}
|
||||
|
||||
@@ -101,6 +102,11 @@ class StreamConnection extends AbstractConnection
|
||||
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
|
||||
}
|
||||
|
||||
if (isset($parameters->tcp_nodelay) && version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
$socket = socket_import_stream($resource);
|
||||
socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
@@ -115,7 +121,7 @@ class StreamConnection extends AbstractConnection
|
||||
$uri = "unix://{$parameters->path}";
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
|
||||
if ($parameters->persistent === true) {
|
||||
if ($parameters->persistent) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
}
|
||||
|
||||
@@ -135,7 +141,7 @@ class StreamConnection extends AbstractConnection
|
||||
{
|
||||
parent::connect();
|
||||
|
||||
if (count($this->initCmds) > 0){
|
||||
if ($this->initCmds) {
|
||||
$this->sendInitializationCommands();
|
||||
}
|
||||
}
|
||||
@@ -244,7 +250,7 @@ class StreamConnection extends AbstractConnection
|
||||
if ($count === -1) {
|
||||
return null;
|
||||
}
|
||||
if ($this->mbiterable === true) {
|
||||
if ($this->mbiterable) {
|
||||
return new MultiBulkResponseSimple($this, $count);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ use Predis\Connection\ConnectionInterface;
|
||||
* Defines a few helper methods.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
* @deprecated Deprecated since v0.8.3.
|
||||
*/
|
||||
class Helpers
|
||||
{
|
||||
@@ -26,6 +27,7 @@ class Helpers
|
||||
* Offers a generic and reusable method to handle exceptions generated by
|
||||
* a connection object.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\CommunicationException::handle()
|
||||
* @param CommunicationException $exception Exception.
|
||||
*/
|
||||
public static function onCommunicationException(CommunicationException $exception)
|
||||
@@ -44,6 +46,7 @@ class Helpers
|
||||
/**
|
||||
* Normalizes the arguments array passed to a Redis command.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeArguments()
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
@@ -59,6 +62,7 @@ class Helpers
|
||||
/**
|
||||
* Normalizes the arguments array passed to a variadic Redis command.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeVariadic()
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -43,7 +43,7 @@ class ClientCluster extends AbstractOption
|
||||
public function filter(ClientOptionsInterface $options, $value)
|
||||
{
|
||||
if (is_callable($value)) {
|
||||
return $this->checkInstance(call_user_func($value, $options));
|
||||
return $this->checkInstance(call_user_func($value, $options, $this));
|
||||
}
|
||||
|
||||
$initializer = $this->getInitializer($options, $value);
|
||||
|
||||
@@ -40,8 +40,20 @@ class ClientConnectionFactory extends AbstractOption
|
||||
return $factory;
|
||||
}
|
||||
|
||||
if (is_string($value) && class_exists($value)) {
|
||||
if (!($factory = new $value()) && !$factory instanceof ConnectionFactoryInterface) {
|
||||
if (is_callable($value)) {
|
||||
$factory = call_user_func($value, $options, $this);
|
||||
|
||||
if (!$factory instanceof ConnectionFactoryInterface) {
|
||||
throw new \InvalidArgumentException('Instance of Predis\Connection\ConnectionFactoryInterface expected');
|
||||
}
|
||||
|
||||
return $factory;
|
||||
}
|
||||
|
||||
if (@class_exists($value)) {
|
||||
$factory = new $value();
|
||||
|
||||
if (!$factory instanceof ConnectionFactoryInterface) {
|
||||
throw new \InvalidArgumentException("Class $value must be an instance of Predis\Connection\ConnectionFactoryInterface");
|
||||
}
|
||||
|
||||
|
||||
@@ -103,4 +103,23 @@ class ClientOptions implements ClientOptionsInterface
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value for the specified option.
|
||||
*
|
||||
* @param string|OptionInterface $option Name or instance of the option.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault($option)
|
||||
{
|
||||
if ($option instanceof OptionInterface) {
|
||||
return $option->getDefault($this);
|
||||
}
|
||||
|
||||
$options = $this->getDefaultOptions();
|
||||
|
||||
if (isset($options[$option])) {
|
||||
return $options[$option]->getDefault($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class ClientProfile extends AbstractOption
|
||||
}
|
||||
|
||||
if (is_callable($value)) {
|
||||
$value = call_user_func($value, $options);
|
||||
$value = call_user_func($value, $options, $this);
|
||||
}
|
||||
|
||||
if (!$value instanceof ServerProfileInterface) {
|
||||
|
||||
@@ -42,7 +42,7 @@ class ClientReplication extends AbstractOption
|
||||
public function filter(ClientOptionsInterface $options, $value)
|
||||
{
|
||||
if (is_callable($value)) {
|
||||
$connection = call_user_func($value, $options);
|
||||
$connection = call_user_func($value, $options, $this);
|
||||
|
||||
if (!$connection instanceof ReplicationConnectionInterface) {
|
||||
throw new \InvalidArgumentException('Instance of Predis\Connection\ReplicationConnectionInterface expected');
|
||||
|
||||
@@ -16,7 +16,6 @@ use Predis\BasicClientInterface;
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\ExecutableContextInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\Command\CommandInterface;
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,9 +11,12 @@
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Iterator;
|
||||
use SplQueue;
|
||||
use Predis\ResponseErrorInterface;
|
||||
use Predis\ResponseObjectInterface;
|
||||
use Predis\ServerException;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Connection\ReplicationConnectionInterface;
|
||||
|
||||
@@ -50,6 +53,27 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a response object.
|
||||
*
|
||||
* @param ConnectionInterface $connection
|
||||
* @param CommandInterface $command
|
||||
* @param ResponseObjectInterface $response
|
||||
* @return mixed
|
||||
*/
|
||||
protected function onResponseObject(ConnectionInterface $connection, CommandInterface $command, ResponseObjectInterface $response)
|
||||
{
|
||||
if ($response instanceof ResponseErrorInterface) {
|
||||
return $this->onResponseError($connection, $response);
|
||||
}
|
||||
|
||||
if ($response instanceof Iterator) {
|
||||
return $command->parseResponse(iterator_to_array($response));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles -ERR responses returned by Redis.
|
||||
*
|
||||
@@ -58,6 +82,10 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
*/
|
||||
protected function onResponseError(ConnectionInterface $connection, ResponseErrorInterface $response)
|
||||
{
|
||||
if (!$this->exceptions) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Force disconnection to prevent protocol desynchronization.
|
||||
$connection->disconnect();
|
||||
$message = $response->getMessage();
|
||||
@@ -70,24 +98,23 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
*/
|
||||
public function execute(ConnectionInterface $connection, SplQueue $commands)
|
||||
{
|
||||
$size = count($commands);
|
||||
$values = array();
|
||||
$exceptions = $this->exceptions;
|
||||
|
||||
$this->checkConnection($connection);
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$response = $connection->readResponse($commands->dequeue());
|
||||
$values = array();
|
||||
|
||||
if ($response instanceof ResponseErrorInterface && $exceptions === true) {
|
||||
$this->onResponseError($connection, $response);
|
||||
while (!$commands->isEmpty()) {
|
||||
$command = $commands->dequeue();
|
||||
$response = $connection->readResponse($command);
|
||||
|
||||
if ($response instanceof ResponseObjectInterface) {
|
||||
$values[] = $this->onResponseObject($connection, $command, $response);
|
||||
} else {
|
||||
$values[] = $command->parseResponse($response);
|
||||
}
|
||||
|
||||
$values[$i] = $response instanceof \Iterator ? iterator_to_array($response) : $response;
|
||||
}
|
||||
|
||||
return $values;
|
||||
|
||||
@@ -130,7 +130,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
public function supportsCommands(Array $commands)
|
||||
{
|
||||
foreach ($commands as $command) {
|
||||
if ($this->supportsCommand($command) === false) {
|
||||
if (!$this->supportsCommand($command)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -37,7 +37,7 @@ class ResponseBulkHandler implements ResponseHandlerInterface
|
||||
$length = (int) $lengthString;
|
||||
|
||||
if ("$length" !== $lengthString) {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$lengthString' as bulk length"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -39,7 +39,7 @@ class ResponseIntegerHandler implements ResponseHandlerInterface
|
||||
}
|
||||
|
||||
if ($number !== 'nil') {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$number' as numeric response"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -37,7 +37,7 @@ class ResponseMultiBulkHandler implements ResponseHandlerInterface
|
||||
$length = (int) $lengthString;
|
||||
|
||||
if ("$length" !== $lengthString) {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$lengthString' as multi-bulk length"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Iterator\MultiBulkResponseSimple;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
@@ -38,7 +38,7 @@ class ResponseMultiBulkStreamHandler implements ResponseHandlerInterface
|
||||
$length = (int) $lengthString;
|
||||
|
||||
if ("$length" != $lengthString) {
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Cannot parse '$lengthString' as multi-bulk length"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\ResponseError;
|
||||
use Predis\ResponseQueued;
|
||||
use Predis\ServerException;
|
||||
@@ -98,7 +98,7 @@ class TextProtocol implements ProtocolInterface
|
||||
if ($count === -1) {
|
||||
return null;
|
||||
}
|
||||
if ($this->mbiterable == true) {
|
||||
if ($this->mbiterable) {
|
||||
return new MultiBulkResponseSimple($connection, $count);
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ class TextProtocol implements ProtocolInterface
|
||||
return new ResponseError($payload);
|
||||
|
||||
default:
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$connection, "Unknown prefix: '$prefix'"
|
||||
));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\ComposableConnectionInterface;
|
||||
use Predis\Protocol\ProtocolException;
|
||||
use Predis\Protocol\ResponseHandlerInterface;
|
||||
@@ -108,6 +108,6 @@ class TextResponseReader implements ResponseReaderInterface
|
||||
*/
|
||||
private function protocolError(ComposableConnectionInterface $connection, $message)
|
||||
{
|
||||
Helpers::onCommunicationException(new ProtocolException($connection, $message));
|
||||
CommunicationException::handle(new ProtocolException($connection, $message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace Predis\PubSub;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\NotSupportedException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Predis\PubSub;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\ClientInterface;
|
||||
use Predis\Helpers;
|
||||
use Predis\Command\AbstractCommand as Command;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\Connection\AggregatedConnectionInterface;
|
||||
|
||||
@@ -77,7 +77,7 @@ class PubSubContext extends AbstractPubSubContext
|
||||
*/
|
||||
protected function writeCommand($method, $arguments)
|
||||
{
|
||||
$arguments = Helpers::filterArrayArguments($arguments);
|
||||
$arguments = Command::normalizeArguments($arguments);
|
||||
$command = $this->client->createCommand($method, $arguments);
|
||||
$this->client->getConnection()->writeCommand($command);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Session;
|
||||
|
||||
use SessionHandlerInterface;
|
||||
use Predis\ClientInterface;
|
||||
|
||||
/**
|
||||
* Session handler class that relies on Predis\Client to store PHP's sessions
|
||||
* data into one or multiple Redis servers.
|
||||
*
|
||||
* This class is mostly intended for PHP 5.4 but it can be used under PHP 5.3 provided
|
||||
* that a polyfill for `SessionHandlerInterface` is defined by either you or an external
|
||||
* package such as `symfony/http-foundation`.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class SessionHandler implements SessionHandlerInterface
|
||||
{
|
||||
protected $client;
|
||||
protected $ttl;
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client Fully initialized client instance.
|
||||
* @param array $options Session handler options.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, Array $options = array())
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->ttl = (int) (isset($options['gc_maxlifetime']) ? $options['gc_maxlifetime'] : ini_get('session.gc_maxlifetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the handler instance as the current session handler.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
session_set_save_handler($this, true);
|
||||
} else {
|
||||
session_set_save_handler(
|
||||
array($this, 'open'),
|
||||
array($this, 'close'),
|
||||
array($this, 'read'),
|
||||
array($this, 'write'),
|
||||
array($this, 'destroy'),
|
||||
array($this, 'gc')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function open($save_path, $session_id)
|
||||
{
|
||||
// NOOP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
// NOOP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
// NOOP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($session_id)
|
||||
{
|
||||
if ($data = $this->client->get($session_id)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write($session_id, $session_data)
|
||||
{
|
||||
$this->client->setex($session_id, $this->ttl, $session_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function destroy($session_id)
|
||||
{
|
||||
$this->client->del($session_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying client instance.
|
||||
*
|
||||
* @return ClientInterface
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session max lifetime value.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxLifeTime()
|
||||
{
|
||||
return $this->ttl;
|
||||
}
|
||||
}
|
||||
@@ -442,7 +442,7 @@ class MultiExecContext implements BasicClientInterface, ExecutableContextInterfa
|
||||
// Since a MULTI/EXEC block cannot be initialized when using aggregated
|
||||
// connections, we can safely assume that Predis\Client::getConnection()
|
||||
// will always return an instance of Predis\Connection\SingleConnectionInterface.
|
||||
Helpers::onCommunicationException(new ProtocolException(
|
||||
CommunicationException::handle(new ProtocolException(
|
||||
$this->client->getConnection(), $message
|
||||
));
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ name = "Predis"
|
||||
desc = "Flexible and feature-complete PHP client library for Redis"
|
||||
homepage = "http://github.com/nrk/predis"
|
||||
license = "MIT"
|
||||
version = "0.8.0"
|
||||
version = "0.8.3"
|
||||
stability = "stable"
|
||||
channel = "pear.nrk.io"
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<php>
|
||||
<!-- Redis -->
|
||||
<const name="REDIS_SERVER_VERSION" value="2.4" />
|
||||
<const name="REDIS_SERVER_VERSION" value="2.6" />
|
||||
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
|
||||
<const name="REDIS_SERVER_PORT" value="6379" />
|
||||
<const name="REDIS_SERVER_DBNUM" value="15" />
|
||||
|
||||
@@ -159,6 +159,32 @@ abstract class CommandTestCase extends StandardTestCase
|
||||
$this->assertEquals($this->getExpectedId(), $command->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $expectedVersion
|
||||
* @param string $message Optional message.
|
||||
* @throws \RuntimeException when unable to retrieve server info or redis version
|
||||
* @throws \PHPUnit_Framework_SkippedTestError when expected redis version is not met
|
||||
*/
|
||||
protected function markTestSkippedOnRedisVersionBelow($expectedVersion, $message = '')
|
||||
{
|
||||
$client = $this->getClient();
|
||||
$info = array_change_key_case($client->info());
|
||||
|
||||
if (isset($info['server']['redis_version'])) {
|
||||
// Redis >= 2.6
|
||||
$version = $info['server']['redis_version'];
|
||||
} else if (isset($info['redis_version'])) {
|
||||
// Redis < 2.6
|
||||
$version = $info['redis_version'];
|
||||
} else {
|
||||
throw new \RuntimeException('Unable to retrieve server info');
|
||||
}
|
||||
|
||||
if (version_compare($version, $expectedVersion) <= -1) {
|
||||
$this->markTestSkipped($message ?: "Test requires Redis $expectedVersion, current is $version.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -262,7 +262,7 @@ abstract class ConnectionTestCase extends StandardTestCase
|
||||
$connection->writeCommand($profile->createCommand('rpush', array('foo', 'baz')));
|
||||
|
||||
$this->assertInstanceOf('Predis\ResponseError', $error = $connection->read());
|
||||
$this->assertSame('ERR Operation against a key holding the wrong kind of value', $error->getMessage());
|
||||
$this->assertRegExp('/[ERR|WRONGTYPE] Operation against a key holding the wrong kind of value/', $error->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -197,6 +197,42 @@ class ClientTest extends StandardTestCase
|
||||
$this->assertSame($replication, $client->getConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testConstructorWithCallableArgument()
|
||||
{
|
||||
$connection = $this->getMock('Predis\Connection\ConnectionInterface');
|
||||
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
$callable->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($this->isInstanceOf('Predis\Option\ClientOptions'))
|
||||
->will($this->returnValue($connection));
|
||||
|
||||
$client = new Client($callable);
|
||||
|
||||
$this->assertSame($connection, $client->getConnection());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Callable parameters must return instances of Predis\Connection\ConnectionInterface
|
||||
*/
|
||||
public function testConstructorWithCallableArgumentButInvalidReturnType()
|
||||
{
|
||||
$wrongType = $this->getMock('stdClass');
|
||||
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
$callable->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($this->isInstanceOf('Predis\Option\ClientOptions'))
|
||||
->will($this->returnValue($wrongType));
|
||||
|
||||
$client = new Client($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -313,7 +349,7 @@ class ClientTest extends StandardTestCase
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testExecuteCommandThrowsExceptionOnRedisError()
|
||||
{
|
||||
@@ -376,7 +412,7 @@ class ClientTest extends StandardTestCase
|
||||
/**
|
||||
* @group disconnected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testCallingRedisCommandThrowsExceptionOnServerError()
|
||||
{
|
||||
@@ -462,10 +498,22 @@ class ClientTest extends StandardTestCase
|
||||
|
||||
$clientNode02 = $client->getClientFor('node02');
|
||||
|
||||
$this->assertInstanceOf('Predis\Client', $clientNode02);
|
||||
$this->assertSame($node02, $clientNode02->getConnection());
|
||||
$this->assertSame($client->getOptions(), $clientNode02->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetClientForReturnsInstanceOfSubclass()
|
||||
{
|
||||
$nodes = array('tcp://host1?alias=node01', 'tcp://host2?alias=node02');
|
||||
$client = $this->getMock('Predis\Client', array('dummy'), array($nodes), 'SubclassedClient');
|
||||
|
||||
$this->assertInstanceOf('SubclassedClient', $client->getClientFor('node02'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -656,10 +704,14 @@ class ClientTest extends StandardTestCase
|
||||
*/
|
||||
public function testClientResendScriptedCommandUsingEvalOnNoScriptErrors()
|
||||
{
|
||||
$command = $this->getMockForAbstractClass('Predis\Command\ScriptedCommand');
|
||||
$command = $this->getMockForAbstractClass('Predis\Command\ScriptedCommand', array(), '', true, true, true, array('parseResponse'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue('return redis.call(\'exists\', KEYS[1])'));
|
||||
$command->expects($this->once())
|
||||
->method('parseResponse')
|
||||
->with('OK')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$connection = $this->getMock('Predis\Connection\SingleConnectionInterface');
|
||||
$connection->expects($this->at(0))
|
||||
@@ -669,7 +721,7 @@ class ClientTest extends StandardTestCase
|
||||
$connection->expects($this->at(1))
|
||||
->method('executeCommand')
|
||||
->with($this->isInstanceOf('Predis\Command\ServerEval'))
|
||||
->will($this->returnValue(true));
|
||||
->will($this->returnValue('OK'));
|
||||
|
||||
$client = new Client($connection);
|
||||
|
||||
|
||||
@@ -129,4 +129,25 @@ class HashRingTest extends DistributionStrategyTestCase
|
||||
$this->assertSame($expected2, $actual2);
|
||||
$this->assertSame($expected3, $actual3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo This tests should be moved in Predis\Cluster\Distribution\DistributionStrategyTestCase
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testCallbackToGetNodeHash()
|
||||
{
|
||||
$node = '127.0.0.1:7000';
|
||||
$replicas = HashRing::DEFAULT_REPLICAS;
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
|
||||
$callable->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($node)
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$ring = new HashRing($replicas, $callable);
|
||||
$ring->add($node);
|
||||
|
||||
$this->getNodes($ring);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,4 +130,24 @@ class KetamaPureRingTest extends DistributionStrategyTestCase
|
||||
$this->assertSame($expected2, $actual2);
|
||||
$this->assertSame($expected3, $actual3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo This tests should be moved in Predis\Cluster\Distribution\DistributionStrategyTestCase
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testCallbackToGetNodeHash()
|
||||
{
|
||||
$node = '127.0.0.1:7000';
|
||||
$callable = $this->getMock('stdClass', array('__invoke'));
|
||||
|
||||
$callable->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($node)
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$ring = new KetamaPureRing($callable);
|
||||
$ring->add($node);
|
||||
|
||||
$this->getNodes($ring);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ class PredisClusterHashStrategyTest extends StandardTestCase
|
||||
*/
|
||||
public function testSupportsKeyTags()
|
||||
{
|
||||
$expected = -1938594527;
|
||||
// NOTE: 32 and 64 bits PHP runtimes can produce different hash values.
|
||||
$expected = PHP_INT_SIZE == 4 ? -1938594527 : 2356372769;
|
||||
|
||||
$strategy = $this->getHashStrategy();
|
||||
|
||||
$this->assertSame($expected, $strategy->getKeyHash('{foo}'));
|
||||
|
||||
@@ -140,4 +140,35 @@ class CommandTest extends StandardTestCase
|
||||
|
||||
$this->assertEquals($expected, (string) $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testNormalizeArguments()
|
||||
{
|
||||
$arguments = array('arg1', 'arg2', 'arg3', 'arg4');
|
||||
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments));
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments(array($arguments)));
|
||||
|
||||
$arguments = array(array(), array());
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments));
|
||||
|
||||
$arguments = array(new \stdClass());
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testNormalizeVariadic()
|
||||
{
|
||||
$arguments = array('key', 'value1', 'value2', 'value3');
|
||||
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeVariadic($arguments));
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeVariadic(array('key', array('value1', 'value2', 'value3'))));
|
||||
|
||||
$arguments = array(new \stdClass());
|
||||
$this->assertSame($arguments, AbstractCommand::normalizeVariadic($arguments));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ class HashDeleteTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -91,7 +91,7 @@ class HashExistsTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -92,7 +92,7 @@ class HashGetAllTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -108,7 +108,7 @@ class HashGetMultipleTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ class HashGetTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -113,7 +113,7 @@ class HashIncrementByFloatTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -113,7 +113,7 @@ class HashIncrementByTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -92,7 +92,7 @@ class HashKeysTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ class HashLengthTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -114,7 +114,7 @@ class HashSetMultipleTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -91,7 +91,7 @@ class HashSetPreserveTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ class HashSetTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -92,7 +92,7 @@ class HashValuesTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -86,16 +86,6 @@ class KeyPreciseTimeToLiveTest extends CommandTestCase
|
||||
$this->assertLessThanOrEqual(10000, $redis->pttl('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testReturnsLessThanZeroOnNonExistingKeys()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->assertSame(-1, $redis->pttl('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
@@ -106,4 +96,16 @@ class KeyPreciseTimeToLiveTest extends CommandTestCase
|
||||
$redis->set('foo', 'bar');
|
||||
$this->assertSame(-1, $redis->pttl('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @todo PTTL changed in Redis >= 2.8 to return -2 on non existing keys, we
|
||||
* should handle this case with a better solution than the current one.
|
||||
*/
|
||||
public function testReturnsLessThanZeroOnNonExistingKeys()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->assertLessThanOrEqual(-1, $redis->pttl('foo'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ class KeySortTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -86,16 +86,6 @@ class KeyTimeToLiveTest extends CommandTestCase
|
||||
$this->assertSame(10, $redis->ttl('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testReturnsLessThanZeroOnNonExistingKeys()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->assertSame(-1, $redis->ttl('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
@@ -106,4 +96,16 @@ class KeyTimeToLiveTest extends CommandTestCase
|
||||
$redis->set('foo', 'bar');
|
||||
$this->assertSame(-1, $redis->ttl('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @todo TTL changed in Redis >= 2.8 to return -2 on non existing keys, we
|
||||
* should handle this case with a better solution than the current one.
|
||||
*/
|
||||
public function testReturnsLessThanZeroOnNonExistingKeys()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->assertLessThanOrEqual(-1, $redis->ttl('foo'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ class ListIndexTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -111,7 +111,7 @@ class ListInsertTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@ class ListLengthTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@ class ListPopFirstTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -117,7 +117,7 @@ class ListPopLastPushHeadTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongTypeOfSourceKey()
|
||||
{
|
||||
@@ -130,7 +130,7 @@ class ListPopLastPushHeadTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongTypeOfDestinationKey()
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@ class ListPopLastTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ class ListPushHeadTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ class ListPushHeadXTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ class ListPushTailTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ class ListPushTailXTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -142,7 +142,7 @@ class ListRangeTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -126,7 +126,7 @@ class ListRemoveTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
@@ -100,7 +100,7 @@ class ListSetTest extends CommandTestCase
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
* @expectedExceptionMessage Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user