mirror of
https://github.com/predis/predis.git
synced 2026-08-19 21:02:46 +00:00
Compare commits
338 Commits
v0.6.4-PHP5.2
...
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c33c74b35 | |||
| 0e69438c0b | |||
| 761e3a2527 | |||
| 316d3de10e | |||
| 5757318c9b | |||
| 340dca8f8d | |||
| c781e91c2e | |||
| d04a95395d | |||
| dad3704488 | |||
| d585b11bf5 | |||
| 9f21cb12a2 | |||
| f60208eb54 | |||
| f53ffbf42b | |||
| c2a6350ff2 | |||
| 57fc3cf30e | |||
| 2aecdf25e5 | |||
| 8ad161dc34 | |||
| 69a0ed6d2f | |||
| 1f663f06be | |||
| 5427bdcf22 | |||
| 6c512784cb | |||
| e70b8ed38b | |||
| 40d5b04278 | |||
| 71dab9a249 | |||
| f0d2551244 | |||
| 4c8ecc02e5 | |||
| 84cb28e3ac | |||
| 6e321a3530 | |||
| ea7e9a37c6 | |||
| 658272fe4b | |||
| fa6400dc22 | |||
| 376dfe3451 | |||
| a26932b3b5 | |||
| eab70fb134 | |||
| 23b68d9415 | |||
| 5def6bebe3 | |||
| 35f7ea2895 | |||
| 37d4aa3d94 | |||
| f1890c93a6 | |||
| d69a872359 | |||
| c01d185448 | |||
| e4aec82836 | |||
| 82619b4dd0 | |||
| b3f340f830 | |||
| f7bdd9d64b | |||
| 4f0f2ca3eb | |||
| 72ef71d2df | |||
| 1a9454a4f2 | |||
| f6b3912783 | |||
| a0f441f21b | |||
| 7312dbe7fc | |||
| 27ebb1ddb5 | |||
| 08afdfac1b | |||
| 0664bde7e9 | |||
| ddafa2a101 | |||
| 2787905024 | |||
| b623144881 | |||
| c73918b991 | |||
| b4e4ca0f0b | |||
| db6b8a3fc8 | |||
| 0d4426c052 | |||
| 08adcb478d | |||
| 513baa556c | |||
| ead414c530 | |||
| 290e51877c | |||
| de2d75e1d7 | |||
| 7e61ac6f30 | |||
| 4f25e568cf | |||
| 83ffdc8bc8 | |||
| 7f138dfcef | |||
| 55404a2400 | |||
| 69bce63453 | |||
| d79321ac8c | |||
| c227eedbb7 | |||
| 887fea87e5 | |||
| 4b2400b570 | |||
| a1c8568ccf | |||
| fa039fe500 | |||
| 9c587b6f1d | |||
| 2f6b24c098 | |||
| 23de93582e | |||
| e8a443200b | |||
| 2eb68a0fee | |||
| 77c8b702b6 | |||
| a092ad46a3 | |||
| b5e2b9eee9 | |||
| 7c2866f9fc | |||
| 801c4647fd | |||
| 0e224ec492 | |||
| b93b13133d | |||
| d9542c21c3 | |||
| 0a0afec0ec | |||
| 7ae94ca6fb | |||
| df9fef8900 | |||
| d369f8bb74 | |||
| 8ae5197a38 | |||
| b662b36e95 | |||
| ce790071fd | |||
| f729793a9a | |||
| ad2381a305 | |||
| 3121b1761e | |||
| 81aef81b55 | |||
| ea9c3388da | |||
| 24bf10c691 | |||
| ea75b168d1 | |||
| 9fc0fbdb8c | |||
| a35faf2df6 | |||
| 471102253a | |||
| 4cce99d388 | |||
| 39052b181e | |||
| fd0732ca33 | |||
| 14c9d36bdf | |||
| 323b6f9eff | |||
| 835f5a5cbc | |||
| fa22d9667c | |||
| 67a27a7f05 | |||
| bdf4dfb54e | |||
| a3ead444b2 | |||
| 9facda2678 | |||
| 8f50c5f69a | |||
| 0e52825d97 | |||
| 5842c57b28 | |||
| c89e222fd2 | |||
| c8509dd068 | |||
| 9e97c15a50 | |||
| c4341eafaa | |||
| a2617af24a | |||
| ea04aa67c6 | |||
| 994258b4c2 | |||
| 2272982364 | |||
| 3a44f766c2 | |||
| bac4be648f | |||
| a1c827cb2d | |||
| 1ba033879a | |||
| 79e7b0b209 | |||
| 6d5060b226 | |||
| a6c246ac7c | |||
| 18e181d9a1 | |||
| aafddece15 | |||
| 45ed2a9f96 | |||
| 958c0a3b33 | |||
| f7f9e3483c | |||
| 5040ce7d18 | |||
| 41f2065287 | |||
| 617d5f69b6 | |||
| c87fc91fb4 | |||
| 4cc43775b0 | |||
| 1b5e148d96 | |||
| 981b64fe21 | |||
| 6ea96dcfea | |||
| 435fdeab75 | |||
| 4f3ffe1217 | |||
| 486244be8d | |||
| 2cd056cab6 | |||
| 1c286f29d1 | |||
| 631832eaf9 | |||
| 17dff871bc | |||
| f3d7e5d31b | |||
| 2d8007448f | |||
| de1b8f45bc | |||
| a0350b2726 | |||
| 70907adcce | |||
| 8391326de6 | |||
| 9e417d9bcf | |||
| 13ae4c4ca0 | |||
| cd8674c2f7 | |||
| 5787b4b9fd | |||
| 0fed80279a | |||
| 1fe49863b4 | |||
| ee9868c123 | |||
| ce00cb14b9 | |||
| daf6dbd7c2 | |||
| ff103b385d | |||
| 4dc9affda2 | |||
| e9e2b8ca5a | |||
| 1394df5625 | |||
| 5b039c8ee8 | |||
| 90078b95c7 | |||
| 83ab54e9fc | |||
| ea9f83d4c0 | |||
| 95664719a6 | |||
| f02b5494c7 | |||
| c95125bae1 | |||
| 53970bd006 | |||
| 3b150d4d86 | |||
| 83c071b7ff | |||
| cadb7f8a3f | |||
| 52a1c06ac2 | |||
| b21b6f8029 | |||
| fa62b75b9a | |||
| 52815adc0f | |||
| 4e4c26c4e6 | |||
| 38e8c94f8b | |||
| c281891641 | |||
| 425c9ade31 | |||
| d03c7c42b2 | |||
| 9086cfc284 | |||
| d8b0c7f40c | |||
| 51c7ef4566 | |||
| 84ea64a9ee | |||
| e04ed827d4 | |||
| 5cae45282d | |||
| 011d544d06 | |||
| c6f97a7946 | |||
| c06f9e34bf | |||
| ac8172235f | |||
| 5aaec9d11b | |||
| 3e0d9c8400 | |||
| 9ac0d26a48 | |||
| 4645e7508e | |||
| 46d2344d42 | |||
| 28bac3b3b0 | |||
| 0b229a5057 | |||
| 460dfce7f6 | |||
| 138a171f6c | |||
| 03ce35f5d9 | |||
| c325707559 | |||
| e114f86d64 | |||
| 8a79343f12 | |||
| f0d5dad2c1 | |||
| 6e5c495b26 | |||
| f65cb529ec | |||
| 47db5075ec | |||
| c8554f2c8b | |||
| 4c6dedabe0 | |||
| 5ad2abd149 | |||
| 7f8ba42717 | |||
| ad540776ac | |||
| 90d7b252ae | |||
| 90dc794780 | |||
| 21abe8bf02 | |||
| 806ef6058d | |||
| e229153800 | |||
| 7579b2c6b7 | |||
| ee5e978a6c | |||
| dac4d87a60 | |||
| 47d34531e3 | |||
| 0cd7b446c6 | |||
| 8df4eaf7b3 | |||
| 701e06443c | |||
| a1aaf73b78 | |||
| b7203d97e7 | |||
| a4720dc721 | |||
| 2b0bd88d8f | |||
| 4ee965ab83 | |||
| 40df90007d | |||
| 2c7a99df55 | |||
| 6e3b1c835d | |||
| f5f06d643f | |||
| 1be9bef159 | |||
| 7fa935f827 | |||
| afdc79f97f | |||
| 6cb9663539 | |||
| 8622dd8b05 | |||
| 21acb300a7 | |||
| 35016ba4b0 | |||
| ab2842c100 | |||
| 91543d776f | |||
| 84fb4390f9 | |||
| 8b152f0ea3 | |||
| e01feda91f | |||
| 15c81fca6f | |||
| 75fad0a027 | |||
| 46dd3d6f19 | |||
| d51e8e0c25 | |||
| 1d3e8cea59 | |||
| 03886d9a78 | |||
| 2577f6a2cb | |||
| 5641983059 | |||
| 0bac9308b5 | |||
| d12694c271 | |||
| 362cdf4d5a | |||
| 04c481b3d7 | |||
| 238baf7dc8 | |||
| 9dae351819 | |||
| d34fc18ea8 | |||
| cd8604b489 | |||
| 99ad5aa4a5 | |||
| 2e5549b316 | |||
| d719a26406 | |||
| 2a06d84a7b | |||
| 1f9e6143bf | |||
| 77f885c233 | |||
| db6e40df98 | |||
| e637881c2d | |||
| 31234d694e | |||
| a4e067891a | |||
| bf19df180c | |||
| 7c6e03edae | |||
| ee739ff843 | |||
| fcecd2579a | |||
| f3aeecef37 | |||
| 55c40afcd8 | |||
| 1626f9658c | |||
| f4b0f664e7 | |||
| 5c95b9cdcc | |||
| a13d0e4d72 | |||
| abbc9108e0 | |||
| b757afe492 | |||
| 75a06019f8 | |||
| 51710682c7 | |||
| f82d11a8db | |||
| 6814845e3f | |||
| e8a0f3f627 | |||
| 6e39491692 | |||
| e5c3123d88 | |||
| 6d43827af9 | |||
| 4a4e4b5a72 | |||
| 8eb51ec0d1 | |||
| 47bb83bbb2 | |||
| e64333d77b | |||
| 627433cef8 | |||
| 822a3e56e2 | |||
| d9b304f9e3 | |||
| 81484b3351 | |||
| d3a62d68bb | |||
| 20e416306c | |||
| 3ccbff4277 | |||
| 6e76fbf660 | |||
| 88cda9e52c | |||
| 876ac2ec7c | |||
| e57348720f | |||
| f811877c87 | |||
| d3115e6259 | |||
| ca7f3e294c | |||
| bcfa64f431 | |||
| 3428529be6 | |||
| b1edc31af3 | |||
| 344ec44059 | |||
| 8d4958a516 | |||
| b777daa535 | |||
| 177120e1a2 | |||
| a84c9bdac7 | |||
| c7cd2b67e0 | |||
| cfcb635c24 | |||
| d0d51257c9 | |||
| a70c5b0800 | |||
| af810d9613 |
@@ -0,0 +1,124 @@
|
||||
v0.6.0 (2010-05-24)
|
||||
* Switched to the new multi-bulk request protocol for all of the commands
|
||||
in the Redis 1.2 and Redis 2.0 profiles. Inline and bulk requests are now
|
||||
deprecated as they will be removed in future releases of Redis.
|
||||
|
||||
* The default server profile is "2.0" (targeting Redis 2.0.x). If you are
|
||||
using older versions of Redis, it is highly recommended that you specify
|
||||
which server profile the client should use (e.g. "1.2" when connecting
|
||||
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.
|
||||
|
||||
* New commands added to the Redis 2.0 profile since Predis 0.5.1:
|
||||
- Strings: SETEX, APPEND, SUBSTR
|
||||
- ZSets : ZCOUNT, ZRANK, ZUNIONSTORE, ZINTERSTORE, ZREMBYRANK, ZREVRANK
|
||||
- Hashes : HSET, HSETNX, HMSET, HINCRBY, HGET, HMGET, HDEL, HEXISTS,
|
||||
HLEN, HKEYS, HVALS, HGETALL
|
||||
- PubSub : PUBLISH, SUBSCRIBE, UNSUBSCRIBE
|
||||
- Misc. : DISCARD, CONFIG
|
||||
|
||||
* Introduced client-level options with the new Predis\ClientOptions class.
|
||||
Options can be passed to Predis\Client::__construct in its second argument
|
||||
as an array or an instance of Predis\ClientOptions. For brevity's sake and
|
||||
compatibility with older versions, the constructor of Predis\Client still
|
||||
accepts an instance of Predis\RedisServerProfile in its second argument.
|
||||
The currently supported client options are:
|
||||
- profile [default: "2.0" as of Predis 0.6.0]
|
||||
specifies which server profile to use when connecting to Redis. This
|
||||
option accepts an instance of Predis\RedisServerProfile or a string
|
||||
that indicates the target version.
|
||||
- key_distribution [default: Predis\Distribution\HashRing]
|
||||
specifies which key distribution strategy to use to distribute keys
|
||||
among the servers that compose a cluster. This option accepts an
|
||||
instance of Predis\Distribution\IDistributionStrategy so that users
|
||||
can implement their own key distribution strategy. Optionally, the new
|
||||
Predis\Distribution\KetamaPureRing class also provides a pure-PHP
|
||||
implementation of the same algorithm used by libketama.
|
||||
- throw_on_error [default: TRUE]
|
||||
server errors can optionally be handled "silently": instead of throwing
|
||||
an exception, the client returns an error response type.
|
||||
- iterable_multibulk [EXPERIMENTAL - default: FALSE]
|
||||
in addition to the classic way of fetching a whole multibulk reply
|
||||
into an array, the client can now optionally stream a multibulk reply
|
||||
down to the user code by using PHP iterators. It is just a little bit
|
||||
slower, but it can save a lot of memory in certain scenarios.
|
||||
|
||||
* New parameters for connections:
|
||||
- alias [default: not set]
|
||||
every connection can now be identified by an alias that is useful to
|
||||
get a certain connection when connected to a cluster of Redis servers.
|
||||
- weight [default: not set]
|
||||
allows the client to balance the keys asymmetrically across multiple
|
||||
servers. This might be useful when you have servers with different
|
||||
amounts of memory and you want to distribute the load of your keys
|
||||
accordingly.
|
||||
- connection_async [default: FALSE]
|
||||
estabilish connections to servers in a non-blocking way, so that the
|
||||
client is not blocked while the underlying resource performs the actual
|
||||
connection.
|
||||
- connection_persistent [default: FALSE]
|
||||
the underlying connection resource is left open when a script ends its
|
||||
lifecycle. Persistent connections can lead to unpredictable or strange
|
||||
behaviours, so they should be used with extreme care.
|
||||
|
||||
* Introduced the Predis\Pipeline\IPipelineExecutor interface. Classes that
|
||||
implements this interface are used internally by the Predis\CommandPipeline
|
||||
class to change the behaviour of the pipeline when writing/reading commands
|
||||
from one or multiple servers. Here is the list of the default executors:
|
||||
- Predis\Pipeline\StandardExecutor
|
||||
Exceptions generated by server errors might be thrown depending on the
|
||||
options passed to the client (see "throw_on_error"). Instead, protocol
|
||||
or network errors always throw exceptions. This is the default executor
|
||||
for single and clustered connections and shares the same behaviour of
|
||||
Predis 0.5.x.
|
||||
- Predis\Pipeline\SafeExecutor
|
||||
Exceptions generated by server, protocol or network errors are not
|
||||
thrown, instead they are returned in the response array as instances of
|
||||
ResponseError or CommunicationException.
|
||||
- Predis\Pipeline\SafeClusterExecutor
|
||||
This executor shares the same behaviour of Predis\Pipeline\SafeExecutor
|
||||
but it is geared towards clustered connections.
|
||||
|
||||
* Support for PUBSUB is handled by the new Predis\PubSubContext class, which
|
||||
could also be used to build a callback dispatcher for PUBSUB scenarios.
|
||||
|
||||
* When connected to a cluster of connections, it is now possible to get a
|
||||
new Predis\Client instance for a single connection of the cluster by
|
||||
passing its alias/index to the new Predis\Client::getClientFor() method.
|
||||
|
||||
* CommandPipeline and MultiExecBlock return their instances when invoking
|
||||
commands, thus allowing method chaining in pipelines and multi-exec blocks.
|
||||
|
||||
* MultiExecBlock instances can handle the new DISCARD command.
|
||||
|
||||
* Connections now support float values for the connection_timeout parameter
|
||||
to express timeouts with a microsecond resolution.
|
||||
|
||||
* FIX: TCP connections now respect the read/write timeout parameter when
|
||||
reading the payload of server responses. Previously, stream_get_contents()
|
||||
was being used internally to read data from a connection but it looks like
|
||||
PHP does not honour the specified timeout for socket streams when inside
|
||||
this function.
|
||||
|
||||
* FIX: The GET parameter for the SORT command now accepts also multiple key
|
||||
patterns by passing an array of strings. (ISSUE #1).
|
||||
|
||||
* FIX: Replies to the DEL command return the number of elements deleted by
|
||||
the server and not 0 or 1 interpreted as a boolean response. (ISSUE #4).
|
||||
|
||||
v0.5.1 (2010-01-23)
|
||||
* RPOPLPUSH has been changed from bulk command to inline command in Redis
|
||||
1.2.1, so ListPopLastPushHead now extends InlineCommand. The old RPOPLPUSH
|
||||
behavior is still available via the ListPopLastPushHeadBulk class so that
|
||||
you can override the server profile if you need the old (and uncorrect)
|
||||
behaviour when connecting to a Redis 1.2.0 instance.
|
||||
|
||||
* Added missing support for BGREWRITEAOF for Redis >= 1.2.0
|
||||
|
||||
* Implemented a factory method for the RedisServerProfile class to ease the
|
||||
creation of new server profile instances based on a version string.
|
||||
|
||||
v0.5.0 (2010-01-09)
|
||||
* First versioned release of Predis
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009 Daniele Alessandri
|
||||
Copyright (c) 2009-2010 Daniele Alessandri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
@@ -19,4 +19,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
+25
-14
@@ -3,26 +3,32 @@
|
||||
## About ##
|
||||
|
||||
Predis is a flexible and feature-complete PHP client library for the Redis key-value
|
||||
database.
|
||||
database. It currently comes in two flavors:
|
||||
|
||||
Predis is currently a work-in-progress and it targets PHP >= 5.3, though it is highly
|
||||
due to be backported to PHP >= 5.2.6 as soon as the public API and the internal design
|
||||
on the main branch will be considered stable enough.
|
||||
- the mainline client library, which targets PHP 5.3.x and leverages a lot of the
|
||||
features introduced in this new version of the PHP interpreter.
|
||||
- a backport to PHP 5.2.x for those who can not upgrade their environment yet
|
||||
(it admittedly has a lower priority compared to the mainline library, although we
|
||||
try to keep the two versions aligned as much as possible).
|
||||
|
||||
Please refer to the TODO file to see which issues are still pending and what is due
|
||||
to be implemented soon in Predis.
|
||||
|
||||
|
||||
## Features ##
|
||||
## Main features ##
|
||||
|
||||
- Client-side sharding (support for consistent hashing of keys)
|
||||
- Command pipelining on single and multiple connections (transparent)
|
||||
- Lazy connections (connections to Redis instances are only established just in time)
|
||||
- Flexible system to define and register your own set of commands to a client instance
|
||||
- Full support for Redis 2.0. Different versions of Redis are supported via server profiles.
|
||||
- Client-side sharding (support for consistent hashing and custom distribution strategies).
|
||||
- Command pipelining on single and multiple connections (transparent).
|
||||
- Lazy connections (connections to Redis instances are only established just in time).
|
||||
- Flexible system to define and register your own set of commands to a client instance.
|
||||
|
||||
|
||||
## Quick examples ##
|
||||
|
||||
See the [official wiki](http://wiki.github.com/nrk/predis) of the project for a more
|
||||
complete coverage of all the features available in Predis.
|
||||
|
||||
### Connecting to a local instance of Redis ###
|
||||
|
||||
You don't have to specify a tcp host and port when connecting to Redis instances
|
||||
@@ -38,7 +44,7 @@ running on the localhost on the default port:
|
||||
Pipelining helps with performances when there is the need to issue many commands
|
||||
to a server in one go:
|
||||
|
||||
$redis = new Predis\Client('10.0.0.1', 6379);
|
||||
$redis = new Predis\Client('redis://10.0.0.1:6379/');
|
||||
$replies = $redis->pipeline(function($pipe) {
|
||||
$pipe->ping();
|
||||
$pipe->incrby('counter', 10);
|
||||
@@ -76,12 +82,12 @@ its way into a stable Predis release, then you can start off by creating 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:
|
||||
|
||||
class BrandNewRedisCommand extends \Predis\InlineCommand {
|
||||
class BrandNewRedisCommand extends \Predis\MultiBulkCommand {
|
||||
public function getCommandId() { return 'NEWCMD'; }
|
||||
}
|
||||
|
||||
$redis = new Predis\Client();
|
||||
$redis->registerCommand('BrandNewRedisCommand', 'newcmd');
|
||||
$redis->getProfile()->registerCommand('BrandNewRedisCommand', 'newcmd');
|
||||
$redis->newcmd();
|
||||
|
||||
|
||||
@@ -100,18 +106,20 @@ they are not the preferred way to contribute to Predis.
|
||||
|
||||
When modifying Predis please be sure that no warnings or notices are emitted by PHP
|
||||
by running the interpreter in your development environment with the "error_reporting"
|
||||
variable set to E_ALL.
|
||||
variable set to E_ALL | E_STRICT.
|
||||
|
||||
|
||||
## Dependencies ##
|
||||
|
||||
- PHP >= 5.3
|
||||
- PHP >= 5.3.0 (for the mainline client library)
|
||||
- PHP >= 5.2.6 (for the backported client library)
|
||||
- PHPUnit (needed to run the test suite)
|
||||
|
||||
## Links ##
|
||||
|
||||
### Project ###
|
||||
- [Source code](http://github.com/nrk/predis/)
|
||||
- [Wiki](http://wiki.github.com/nrk/predis/)
|
||||
- [Issue tracker](http://github.com/nrk/predis/issues)
|
||||
|
||||
### Related ###
|
||||
@@ -124,6 +132,9 @@ variable set to E_ALL.
|
||||
|
||||
[Daniele Alessandri](mailto:suppakilla@gmail.com)
|
||||
|
||||
## Contributors ##
|
||||
|
||||
[Lorenzo Castelli](http://github.com/lcastelli)
|
||||
|
||||
## License ##
|
||||
|
||||
|
||||
@@ -1,21 +1,7 @@
|
||||
* Authentication and database selection should be handled transparently by
|
||||
the client.
|
||||
* Documentation! The README is obviously not enought to show how to use
|
||||
Predis as it does not cover all of its features.
|
||||
|
||||
* The current behaviour of sending, by default, unshardable commands to the
|
||||
first registered connection of a ConnectionCluster instance needs to be
|
||||
verified.
|
||||
|
||||
* The included test suite covers almost all the Redis server commands, but a
|
||||
full battery of tests targeting specific functions of this library is still
|
||||
missing.
|
||||
|
||||
* Support for pipelining commands on one or more connections works, but it
|
||||
could be optimized for better performances with a cache of computed commands
|
||||
hashes, but the memory impact still needs to be evalued.
|
||||
|
||||
* Add the possibility of flushing the command buffer from inside of a pipeline.
|
||||
|
||||
* Switching to/from instances of Connection and ConnectionCluster should be
|
||||
transparent to the user. Using a ConnectionCluster instance when there is
|
||||
only one active connection has an unnecessary overhead.
|
||||
* Add more tests targeting specific functions of the library.
|
||||
|
||||
* Missing tests for commands:
|
||||
PUBLISH, SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
require_once 'SharedConfigurations.php';
|
||||
|
||||
// when you have a whole set of consecutive commands to send to
|
||||
// When you have a whole set of consecutive commands to send to
|
||||
// a redis server, you can use a pipeline to improve performances.
|
||||
|
||||
$redis = Predis\Client::create($configurations);
|
||||
$redis = new Predis\Client($single_server);
|
||||
|
||||
$replies = $redis->pipeline(function($pipe) {
|
||||
$pipe->ping();
|
||||
@@ -35,4 +35,4 @@ Array
|
||||
|
||||
)
|
||||
*/
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
require_once 'SharedConfigurations.php';
|
||||
|
||||
// Developers can customize the distribution strategy used by the client
|
||||
// to distribute keys among a cluster of servers simply by creating a class
|
||||
// that implements the Predis\Distribution\IDistributionAlgorithm interface.
|
||||
|
||||
class NaiveDistributionStrategy
|
||||
implements Predis\Distribution\IDistributionStrategy {
|
||||
|
||||
private $_nodes, $_nodesCount;
|
||||
|
||||
public function __constructor() {
|
||||
$this->_nodes = array();
|
||||
$this->_nodesCount = 0;
|
||||
}
|
||||
|
||||
public function add($node, $weight = null) {
|
||||
$this->_nodes[] = $node;
|
||||
$this->_nodesCount++;
|
||||
}
|
||||
|
||||
public function remove($node) {
|
||||
$this->_nodes = array_filter($this->_nodes, function($n) use($node) {
|
||||
return $n !== $node;
|
||||
});
|
||||
$this->_nodesCount = count($this->_nodes);
|
||||
}
|
||||
|
||||
public function get($key) {
|
||||
$count = $this->_nodesCount;
|
||||
if ($count === 0) {
|
||||
throw new RuntimeException('No connections');
|
||||
}
|
||||
return $this->_nodes[$count > 1 ? abs(crc32($key) % $count) : 0];
|
||||
}
|
||||
|
||||
public function generateKey($value) {
|
||||
return crc32($value);
|
||||
}
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'key_distribution' => new NaiveDistributionStrategy(),
|
||||
);
|
||||
|
||||
$redis = new Predis\Client($multiple_servers, $options);
|
||||
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$redis->set("key:$i", str_pad($i, 4, '0', 0));
|
||||
$redis->get("key:$i");
|
||||
}
|
||||
|
||||
$server1 = $redis->getClientFor('first')->info();
|
||||
$server2 = $redis->getClientFor('second')->info();
|
||||
|
||||
printf("Server '%s' has %d keys while server '%s' has %d keys.\n",
|
||||
'first', $server1['db15']['keys'], 'second', $server2['db15']['keys']
|
||||
);
|
||||
?>
|
||||
@@ -11,7 +11,7 @@ $mkv = array(
|
||||
'usr:0003' => 'Third user'
|
||||
);
|
||||
|
||||
$redis = Predis\Client::create($configurations);
|
||||
$redis = new Predis\Client($single_server);
|
||||
|
||||
$redis->mset($mkv);
|
||||
$retval = $redis->mget(array_keys($mkv));
|
||||
@@ -26,4 +26,4 @@ Array
|
||||
[2] => Third user
|
||||
)
|
||||
*/
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
require_once 'SharedConfigurations.php';
|
||||
|
||||
// Redis 2.0 features new commands that allow clients to subscribe for
|
||||
// events published on certain channels (PUBSUB).
|
||||
|
||||
// Create a client and disable r/w timeout on the socket
|
||||
$redis = new Predis\Client($single_server + array('read_write_timeout' => -1));
|
||||
|
||||
// Initialize a new pubsub context
|
||||
$pubsub = $redis->pubSubContext();
|
||||
|
||||
// Subscribe to your channels
|
||||
$pubsub->subscribe('control_channel');
|
||||
$pubsub->subscribe('notifications');
|
||||
|
||||
// Start processing the pubsup messages. Open a terminal and use redis-cli
|
||||
// to push messages to the channels. Examples:
|
||||
// ./redis-cli PUBLISH notifications "this is a test"
|
||||
// ./redis-cli PUBLISH control_channel quit_loop
|
||||
foreach ($pubsub as $message) {
|
||||
switch ($message->kind) {
|
||||
case 'subscribe':
|
||||
echo "Subscribed to {$message->channel}\n";
|
||||
break;
|
||||
case 'message':
|
||||
if ($message->channel == 'control_channel') {
|
||||
if ($message->payload == 'quit_loop') {
|
||||
echo "Aborting pubsub loop...\n";
|
||||
$pubsub->unsubscribe();
|
||||
}
|
||||
else {
|
||||
echo "Received an unrecognized command: {$message->payload}.\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo "Received the following message from {$message->channel}:\n",
|
||||
" {$message->payload}\n\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Always unset the pubsub context instance when you are done! The
|
||||
// class destructor will take care of cleanups and prevent protocol
|
||||
// desynchronizations between the client and the server.
|
||||
unset($pubsub);
|
||||
|
||||
// Say goodbye :-)
|
||||
$info = $redis->info();
|
||||
print_r("Goodbye from Redis v{$info['redis_version']}!\n");
|
||||
?>
|
||||
@@ -1,9 +1,24 @@
|
||||
<?php
|
||||
require_once '../lib/Predis.php';
|
||||
|
||||
$configurations = array(
|
||||
$single_server = array(
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'database' => 15
|
||||
);
|
||||
?>
|
||||
|
||||
$multiple_servers = array(
|
||||
array(
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'database' => 15,
|
||||
'alias' => 'first',
|
||||
),
|
||||
array(
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6380,
|
||||
'database' => 15,
|
||||
'alias' => 'second',
|
||||
),
|
||||
);
|
||||
?>
|
||||
|
||||
@@ -3,7 +3,7 @@ require_once 'SharedConfigurations.php';
|
||||
|
||||
// simple set and get scenario
|
||||
|
||||
$redis = Predis\Client::create($configurations);
|
||||
$redis = new Predis\Client($single_server);
|
||||
|
||||
$redis->set('library', 'predis');
|
||||
$retval = $redis->get('library');
|
||||
@@ -13,4 +13,4 @@ print_r($retval);
|
||||
/* OUTPUT
|
||||
predis
|
||||
*/
|
||||
?>
|
||||
?>
|
||||
|
||||
+2112
-626
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,500 @@
|
||||
<?php
|
||||
namespace Predis;
|
||||
|
||||
RedisServerProfile::registerProfile('\Predis\RedisServer_v1_0', '1.0');
|
||||
|
||||
class RedisServer_v1_0 extends \Predis\RedisServerProfile {
|
||||
public function getVersion() { return '1.0'; }
|
||||
public function getSupportedCommands() {
|
||||
return array(
|
||||
/* miscellaneous commands */
|
||||
'ping' => '\Predis\Compatibility\v1_0\Commands\Ping',
|
||||
'echo' => '\Predis\Compatibility\v1_0\Commands\DoEcho',
|
||||
'auth' => '\Predis\Compatibility\v1_0\Commands\Auth',
|
||||
|
||||
/* connection handling */
|
||||
'quit' => '\Predis\Compatibility\v1_0\Commands\Quit',
|
||||
|
||||
/* commands operating on string values */
|
||||
'set' => '\Predis\Compatibility\v1_0\Commands\Set',
|
||||
'setnx' => '\Predis\Compatibility\v1_0\Commands\SetPreserve',
|
||||
'setPreserve' => '\Predis\Compatibility\v1_0\Commands\SetPreserve',
|
||||
'get' => '\Predis\Compatibility\v1_0\Commands\Get',
|
||||
'mget' => '\Predis\Compatibility\v1_0\Commands\GetMultiple',
|
||||
'getMultiple' => '\Predis\Compatibility\v1_0\Commands\GetMultiple',
|
||||
'getset' => '\Predis\Compatibility\v1_0\Commands\GetSet',
|
||||
'getSet' => '\Predis\Compatibility\v1_0\Commands\GetSet',
|
||||
'incr' => '\Predis\Compatibility\v1_0\Commands\Increment',
|
||||
'increment' => '\Predis\Compatibility\v1_0\Commands\Increment',
|
||||
'incrby' => '\Predis\Compatibility\v1_0\Commands\IncrementBy',
|
||||
'incrementBy' => '\Predis\Compatibility\v1_0\Commands\IncrementBy',
|
||||
'decr' => '\Predis\Compatibility\v1_0\Commands\Decrement',
|
||||
'decrement' => '\Predis\Compatibility\v1_0\Commands\Decrement',
|
||||
'decrby' => '\Predis\Compatibility\v1_0\Commands\DecrementBy',
|
||||
'decrementBy' => '\Predis\Compatibility\v1_0\Commands\DecrementBy',
|
||||
'exists' => '\Predis\Compatibility\v1_0\Commands\Exists',
|
||||
'del' => '\Predis\Compatibility\v1_0\Commands\Delete',
|
||||
'delete' => '\Predis\Compatibility\v1_0\Commands\Delete',
|
||||
'type' => '\Predis\Compatibility\v1_0\Commands\Type',
|
||||
|
||||
/* commands operating on the key space */
|
||||
'keys' => '\Predis\Compatibility\v1_0\Commands\Keys',
|
||||
'randomkey' => '\Predis\Compatibility\v1_0\Commands\RandomKey',
|
||||
'randomKey' => '\Predis\Compatibility\v1_0\Commands\RandomKey',
|
||||
'rename' => '\Predis\Compatibility\v1_0\Commands\Rename',
|
||||
'renamenx' => '\Predis\Compatibility\v1_0\Commands\RenamePreserve',
|
||||
'renamePreserve' => '\Predis\Compatibility\v1_0\Commands\RenamePreserve',
|
||||
'expire' => '\Predis\Compatibility\v1_0\Commands\Expire',
|
||||
'expireat' => '\Predis\Compatibility\v1_0\Commands\ExpireAt',
|
||||
'expireAt' => '\Predis\Compatibility\v1_0\Commands\ExpireAt',
|
||||
'dbsize' => '\Predis\Compatibility\v1_0\Commands\DatabaseSize',
|
||||
'databaseSize' => '\Predis\Compatibility\v1_0\Commands\DatabaseSize',
|
||||
'ttl' => '\Predis\Compatibility\v1_0\Commands\TimeToLive',
|
||||
'timeToLive' => '\Predis\Compatibility\v1_0\Commands\TimeToLive',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpush' => '\Predis\Compatibility\v1_0\Commands\ListPushTail',
|
||||
'pushTail' => '\Predis\Compatibility\v1_0\Commands\ListPushTail',
|
||||
'lpush' => '\Predis\Compatibility\v1_0\Commands\ListPushHead',
|
||||
'pushHead' => '\Predis\Compatibility\v1_0\Commands\ListPushHead',
|
||||
'llen' => '\Predis\Compatibility\v1_0\Commands\ListLength',
|
||||
'listLength' => '\Predis\Compatibility\v1_0\Commands\ListLength',
|
||||
'lrange' => '\Predis\Compatibility\v1_0\Commands\ListRange',
|
||||
'listRange' => '\Predis\Compatibility\v1_0\Commands\ListRange',
|
||||
'ltrim' => '\Predis\Compatibility\v1_0\Commands\ListTrim',
|
||||
'listTrim' => '\Predis\Compatibility\v1_0\Commands\ListTrim',
|
||||
'lindex' => '\Predis\Compatibility\v1_0\Commands\ListIndex',
|
||||
'listIndex' => '\Predis\Compatibility\v1_0\Commands\ListIndex',
|
||||
'lset' => '\Predis\Compatibility\v1_0\Commands\ListSet',
|
||||
'listSet' => '\Predis\Compatibility\v1_0\Commands\ListSet',
|
||||
'lrem' => '\Predis\Compatibility\v1_0\Commands\ListRemove',
|
||||
'listRemove' => '\Predis\Compatibility\v1_0\Commands\ListRemove',
|
||||
'lpop' => '\Predis\Compatibility\v1_0\Commands\ListPopFirst',
|
||||
'popFirst' => '\Predis\Compatibility\v1_0\Commands\ListPopFirst',
|
||||
'rpop' => '\Predis\Compatibility\v1_0\Commands\ListPopLast',
|
||||
'popLast' => '\Predis\Compatibility\v1_0\Commands\ListPopLast',
|
||||
|
||||
/* commands operating on sets */
|
||||
'sadd' => '\Predis\Compatibility\v1_0\Commands\SetAdd',
|
||||
'setAdd' => '\Predis\Compatibility\v1_0\Commands\SetAdd',
|
||||
'srem' => '\Predis\Compatibility\v1_0\Commands\SetRemove',
|
||||
'setRemove' => '\Predis\Compatibility\v1_0\Commands\SetRemove',
|
||||
'spop' => '\Predis\Compatibility\v1_0\Commands\SetPop',
|
||||
'setPop' => '\Predis\Compatibility\v1_0\Commands\SetPop',
|
||||
'smove' => '\Predis\Compatibility\v1_0\Commands\SetMove',
|
||||
'setMove' => '\Predis\Compatibility\v1_0\Commands\SetMove',
|
||||
'scard' => '\Predis\Compatibility\v1_0\Commands\SetCardinality',
|
||||
'setCardinality' => '\Predis\Compatibility\v1_0\Commands\SetCardinality',
|
||||
'sismember' => '\Predis\Compatibility\v1_0\Commands\SetIsMember',
|
||||
'setIsMember' => '\Predis\Compatibility\v1_0\Commands\SetIsMember',
|
||||
'sinter' => '\Predis\Compatibility\v1_0\Commands\SetIntersection',
|
||||
'setIntersection' => '\Predis\Compatibility\v1_0\Commands\SetIntersection',
|
||||
'sinterstore' => '\Predis\Compatibility\v1_0\Commands\SetIntersectionStore',
|
||||
'setIntersectionStore' => '\Predis\Compatibility\v1_0\Commands\SetIntersectionStore',
|
||||
'sunion' => '\Predis\Compatibility\v1_0\Commands\SetUnion',
|
||||
'setUnion' => '\Predis\Compatibility\v1_0\Commands\SetUnion',
|
||||
'sunionstore' => '\Predis\Compatibility\v1_0\Commands\SetUnionStore',
|
||||
'setUnionStore' => '\Predis\Compatibility\v1_0\Commands\SetUnionStore',
|
||||
'sdiff' => '\Predis\Compatibility\v1_0\Commands\SetDifference',
|
||||
'setDifference' => '\Predis\Compatibility\v1_0\Commands\SetDifference',
|
||||
'sdiffstore' => '\Predis\Compatibility\v1_0\Commands\SetDifferenceStore',
|
||||
'setDifferenceStore' => '\Predis\Compatibility\v1_0\Commands\SetDifferenceStore',
|
||||
'smembers' => '\Predis\Compatibility\v1_0\Commands\SetMembers',
|
||||
'setMembers' => '\Predis\Compatibility\v1_0\Commands\SetMembers',
|
||||
'srandmember' => '\Predis\Compatibility\v1_0\Commands\SetRandomMember',
|
||||
'setRandomMember' => '\Predis\Compatibility\v1_0\Commands\SetRandomMember',
|
||||
|
||||
/* multiple databases handling commands */
|
||||
'select' => '\Predis\Compatibility\v1_0\Commands\SelectDatabase',
|
||||
'selectDatabase' => '\Predis\Compatibility\v1_0\Commands\SelectDatabase',
|
||||
'move' => '\Predis\Compatibility\v1_0\Commands\MoveKey',
|
||||
'moveKey' => '\Predis\Compatibility\v1_0\Commands\MoveKey',
|
||||
'flushdb' => '\Predis\Compatibility\v1_0\Commands\FlushDatabase',
|
||||
'flushDatabase' => '\Predis\Compatibility\v1_0\Commands\FlushDatabase',
|
||||
'flushall' => '\Predis\Compatibility\v1_0\Commands\FlushAll',
|
||||
'flushDatabases' => '\Predis\Compatibility\v1_0\Commands\FlushAll',
|
||||
|
||||
/* sorting */
|
||||
'sort' => '\Predis\Compatibility\v1_0\Commands\Sort',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => '\Predis\Compatibility\v1_0\Commands\Info',
|
||||
'slaveof' => '\Predis\Compatibility\v1_0\Commands\SlaveOf',
|
||||
'slaveOf' => '\Predis\Compatibility\v1_0\Commands\SlaveOf',
|
||||
|
||||
/* persistence control commands */
|
||||
'save' => '\Predis\Compatibility\v1_0\Commands\Save',
|
||||
'bgsave' => '\Predis\Compatibility\v1_0\Commands\BackgroundSave',
|
||||
'backgroundSave' => '\Predis\Compatibility\v1_0\Commands\BackgroundSave',
|
||||
'lastsave' => '\Predis\Compatibility\v1_0\Commands\LastSave',
|
||||
'lastSave' => '\Predis\Compatibility\v1_0\Commands\LastSave',
|
||||
'shutdown' => '\Predis\Compatibility\v1_0\Commands\Shutdown',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
namespace Predis\Compatibility\v1_0\Commands;
|
||||
|
||||
/* miscellaneous commands */
|
||||
class Ping extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'PING'; }
|
||||
public function parseResponse($data) {
|
||||
return $data === 'PONG' ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
class DoEcho extends \Predis\BulkCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'ECHO'; }
|
||||
}
|
||||
|
||||
class Auth extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'AUTH'; }
|
||||
}
|
||||
|
||||
/* connection handling */
|
||||
class Quit extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'QUIT'; }
|
||||
public function closesConnection() { return true; }
|
||||
}
|
||||
|
||||
/* commands operating on string values */
|
||||
class Set extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'SET'; }
|
||||
}
|
||||
|
||||
class SetPreserve extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'SETNX'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class Get extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'GET'; }
|
||||
}
|
||||
|
||||
class GetMultiple extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'MGET'; }
|
||||
}
|
||||
|
||||
class GetSet extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'GETSET'; }
|
||||
}
|
||||
|
||||
class Increment extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'INCR'; }
|
||||
}
|
||||
|
||||
class IncrementBy extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'INCRBY'; }
|
||||
}
|
||||
|
||||
class Decrement extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'DECR'; }
|
||||
}
|
||||
|
||||
class DecrementBy extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'DECRBY'; }
|
||||
}
|
||||
|
||||
class Exists extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'EXISTS'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class Delete extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'DEL'; }
|
||||
}
|
||||
|
||||
class Type extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'TYPE'; }
|
||||
}
|
||||
|
||||
/* commands operating on the key space */
|
||||
class Keys extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'KEYS'; }
|
||||
public function parseResponse($data) {
|
||||
return strlen($data) > 0 ? explode(' ', $data) : array();
|
||||
}
|
||||
}
|
||||
|
||||
class RandomKey extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'RANDOMKEY'; }
|
||||
public function parseResponse($data) { return $data !== '' ? $data : null; }
|
||||
}
|
||||
|
||||
class Rename extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'RENAME'; }
|
||||
}
|
||||
|
||||
class RenamePreserve extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'RENAMENX'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class Expire extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'EXPIRE'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class ExpireAt extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'EXPIREAT'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class DatabaseSize extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'DBSIZE'; }
|
||||
}
|
||||
|
||||
class TimeToLive extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'TTL'; }
|
||||
}
|
||||
|
||||
/* commands operating on lists */
|
||||
class ListPushTail extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'RPUSH'; }
|
||||
}
|
||||
|
||||
class ListPushHead extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'LPUSH'; }
|
||||
}
|
||||
|
||||
class ListLength extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'LLEN'; }
|
||||
}
|
||||
|
||||
class ListRange extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'LRANGE'; }
|
||||
}
|
||||
|
||||
class ListTrim extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'LTRIM'; }
|
||||
}
|
||||
|
||||
class ListIndex extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'LINDEX'; }
|
||||
}
|
||||
|
||||
class ListSet extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'LSET'; }
|
||||
}
|
||||
|
||||
class ListRemove extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'LREM'; }
|
||||
}
|
||||
|
||||
class ListPopFirst extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'LPOP'; }
|
||||
}
|
||||
|
||||
class ListPopLast extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'RPOP'; }
|
||||
}
|
||||
|
||||
/* commands operating on sets */
|
||||
class SetAdd extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'SADD'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class SetRemove extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'SREM'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class SetPop extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SPOP'; }
|
||||
}
|
||||
|
||||
class SetMove extends \Predis\BulkCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'SMOVE'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class SetCardinality extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SCARD'; }
|
||||
}
|
||||
|
||||
class SetIsMember extends \Predis\BulkCommand {
|
||||
public function getCommandId() { return 'SISMEMBER'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class SetIntersection extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SINTER'; }
|
||||
}
|
||||
|
||||
class SetIntersectionStore extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SINTERSTORE'; }
|
||||
}
|
||||
|
||||
class SetUnion extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SUNION'; }
|
||||
}
|
||||
|
||||
class SetUnionStore extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SUNIONSTORE'; }
|
||||
}
|
||||
|
||||
class SetDifference extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SDIFF'; }
|
||||
}
|
||||
|
||||
class SetDifferenceStore extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SDIFFSTORE'; }
|
||||
}
|
||||
|
||||
class SetMembers extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SMEMBERS'; }
|
||||
}
|
||||
|
||||
class SetRandomMember extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SRANDMEMBER'; }
|
||||
}
|
||||
|
||||
/* multiple databases handling commands */
|
||||
class SelectDatabase extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'SELECT'; }
|
||||
}
|
||||
|
||||
class MoveKey extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'MOVE'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class FlushDatabase extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'FLUSHDB'; }
|
||||
}
|
||||
|
||||
class FlushAll extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'FLUSHALL'; }
|
||||
}
|
||||
|
||||
/* sorting */
|
||||
class Sort extends \Predis\InlineCommand {
|
||||
public function getCommandId() { return 'SORT'; }
|
||||
public function filterArguments(Array $arguments) {
|
||||
if (count($arguments) === 1) {
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
// TODO: add more parameters checks
|
||||
$query = array($arguments[0]);
|
||||
$sortParams = $arguments[1];
|
||||
|
||||
if (isset($sortParams['by'])) {
|
||||
$query[] = 'BY';
|
||||
$query[] = $sortParams['by'];
|
||||
}
|
||||
if (isset($sortParams['get'])) {
|
||||
$getargs = $sortParams['get'];
|
||||
if (is_array($getargs)) {
|
||||
foreach ($getargs as $getarg) {
|
||||
$query[] = 'GET';
|
||||
$query[] = $getarg;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$query[] = 'GET';
|
||||
$query[] = $getargs;
|
||||
}
|
||||
}
|
||||
if (isset($sortParams['limit']) && is_array($sortParams['limit'])) {
|
||||
$query[] = 'LIMIT';
|
||||
$query[] = $sortParams['limit'][0];
|
||||
$query[] = $sortParams['limit'][1];
|
||||
}
|
||||
if (isset($sortParams['sort'])) {
|
||||
$query[] = strtoupper($sortParams['sort']);
|
||||
}
|
||||
if (isset($sortParams['alpha']) && $sortParams['alpha'] == true) {
|
||||
$query[] = 'ALPHA';
|
||||
}
|
||||
if (isset($sortParams['store']) && $sortParams['store'] == true) {
|
||||
$query[] = 'STORE';
|
||||
$query[] = $sortParams['store'];
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
|
||||
/* persistence control commands */
|
||||
class Save extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'SAVE'; }
|
||||
}
|
||||
|
||||
class BackgroundSave extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'BGSAVE'; }
|
||||
public function parseResponse($data) {
|
||||
if ($data == 'Background saving started') {
|
||||
return true;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
class LastSave extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'LASTSAVE'; }
|
||||
}
|
||||
|
||||
class Shutdown extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'SHUTDOWN'; }
|
||||
public function closesConnection() { return true; }
|
||||
}
|
||||
|
||||
/* remote server control commands */
|
||||
class Info extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'INFO'; }
|
||||
public function parseResponse($data) {
|
||||
$info = array();
|
||||
$infoLines = explode("\r\n", $data, -1);
|
||||
foreach ($infoLines as $row) {
|
||||
list($k, $v) = explode(':', $row);
|
||||
if (!preg_match('/^db\d+$/', $k)) {
|
||||
$info[$k] = $v;
|
||||
}
|
||||
else {
|
||||
$db = array();
|
||||
foreach (explode(',', $v) as $dbvar) {
|
||||
list($dbvk, $dbvv) = explode('=', $dbvar);
|
||||
$db[trim($dbvk)] = $dbvv;
|
||||
}
|
||||
$info[$k] = $db;
|
||||
}
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
|
||||
class SlaveOf extends \Predis\InlineCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'SLAVEOF'; }
|
||||
public function filterArguments(Array $arguments) {
|
||||
if (count($arguments) === 0 || $arguments[0] === 'NO ONE') {
|
||||
return array('NO', 'ONE');
|
||||
}
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,475 @@
|
||||
<?php
|
||||
define('I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE', false);
|
||||
|
||||
require_once 'PHPUnit/Framework.php';
|
||||
require_once 'PredisShared.php';
|
||||
require_once '../lib/Predis_Compatibility.php';
|
||||
|
||||
class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
|
||||
public $redis;
|
||||
|
||||
protected function setUp() {
|
||||
$this->redis = RC::getConnection();
|
||||
$this->redis->flushDatabase();
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
}
|
||||
|
||||
protected function onNotSuccessfulTest(Exception $exception) {
|
||||
// drops and reconnect to a redis server on uncaught exceptions
|
||||
RC::resetConnection();
|
||||
parent::onNotSuccessfulTest($exception);
|
||||
}
|
||||
|
||||
|
||||
/* ConnectionParameters */
|
||||
|
||||
function testConnectionParametersDefaultValues() {
|
||||
$params = new \Predis\ConnectionParameters();
|
||||
|
||||
$this->assertEquals(\Predis\ConnectionParameters::DEFAULT_HOST, $params->host);
|
||||
$this->assertEquals(\Predis\ConnectionParameters::DEFAULT_PORT, $params->port);
|
||||
$this->assertEquals(\Predis\ConnectionParameters::DEFAULT_TIMEOUT, $params->connection_timeout);
|
||||
$this->assertNull($params->read_write_timeout);
|
||||
$this->assertNull($params->database);
|
||||
$this->assertNull($params->password);
|
||||
$this->assertNull($params->alias);
|
||||
}
|
||||
|
||||
function testConnectionParametersSetupValuesArray() {
|
||||
$paramsArray = RC::getConnectionParametersArgumentsArray();
|
||||
$params = new \Predis\ConnectionParameters($paramsArray);
|
||||
|
||||
$this->assertEquals($paramsArray['host'], $params->host);
|
||||
$this->assertEquals($paramsArray['port'], $params->port);
|
||||
$this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout);
|
||||
$this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout);
|
||||
$this->assertEquals($paramsArray['database'], $params->database);
|
||||
$this->assertEquals($paramsArray['password'], $params->password);
|
||||
$this->assertEquals($paramsArray['alias'], $params->alias);
|
||||
}
|
||||
|
||||
function testConnectionParametersSetupValuesString() {
|
||||
$paramsArray = RC::getConnectionParametersArgumentsArray();
|
||||
$paramsString = RC::getConnectionParametersArgumentsString($paramsArray);
|
||||
$params = new \Predis\ConnectionParameters($paramsArray);
|
||||
|
||||
$this->assertEquals($paramsArray['host'], $params->host);
|
||||
$this->assertEquals($paramsArray['port'], $params->port);
|
||||
$this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout);
|
||||
$this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout);
|
||||
$this->assertEquals($paramsArray['database'], $params->database);
|
||||
$this->assertEquals($paramsArray['password'], $params->password);
|
||||
$this->assertEquals($paramsArray['alias'], $params->alias);
|
||||
}
|
||||
|
||||
|
||||
/* Command and derivates */
|
||||
|
||||
function testCommand_TestArguments() {
|
||||
$cmdArgs = array('key1', 'key2', 'key3');
|
||||
|
||||
$cmd = new \Predis\Commands\GetMultiple();
|
||||
$cmd->setArgumentsArray($cmdArgs);
|
||||
$this->assertEquals($cmdArgs[0], $cmd->getArgument(0));
|
||||
$this->assertEquals($cmdArgs[1], $cmd->getArgument(1));
|
||||
$this->assertEquals($cmdArgs[2], $cmd->getArgument(2));
|
||||
|
||||
$cmd = new \Predis\Commands\GetMultiple();
|
||||
$cmd->setArguments('key1', 'key2', 'key3');
|
||||
$this->assertEquals($cmdArgs[0], $cmd->getArgument(0));
|
||||
$this->assertEquals($cmdArgs[1], $cmd->getArgument(1));
|
||||
$this->assertEquals($cmdArgs[2], $cmd->getArgument(2));
|
||||
|
||||
$cmd = new \Predis\Commands\Ping();
|
||||
$this->assertNull($cmd->getArgument(0));
|
||||
}
|
||||
|
||||
function testCommand_InlineWithNoArguments() {
|
||||
$cmd = new \Predis\Compatibility\v1_0\Commands\Ping();
|
||||
|
||||
$this->assertType('\Predis\InlineCommand', $cmd);
|
||||
$this->assertEquals('PING', $cmd->getCommandId());
|
||||
$this->assertFalse($cmd->closesConnection());
|
||||
$this->assertFalse($cmd->canBeHashed());
|
||||
$this->assertNull($cmd->getHash(new \Predis\Distribution\HashRing()));
|
||||
$this->assertEquals("PING\r\n", $cmd());
|
||||
}
|
||||
|
||||
function testCommand_InlineWithArguments() {
|
||||
$cmd = new \Predis\Compatibility\v1_0\Commands\Get();
|
||||
$cmd->setArgumentsArray(array('key'));
|
||||
|
||||
$this->assertType('\Predis\InlineCommand', $cmd);
|
||||
$this->assertEquals('GET', $cmd->getCommandId());
|
||||
$this->assertFalse($cmd->closesConnection());
|
||||
$this->assertTrue($cmd->canBeHashed());
|
||||
$this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
|
||||
$this->assertEquals("GET key\r\n", $cmd());
|
||||
}
|
||||
|
||||
function testCommand_BulkWithArguments() {
|
||||
$cmd = new \Predis\Compatibility\v1_0\Commands\Set();
|
||||
$cmd->setArgumentsArray(array('key', 'value'));
|
||||
|
||||
$this->assertType('\Predis\BulkCommand', $cmd);
|
||||
$this->assertEquals('SET', $cmd->getCommandId());
|
||||
$this->assertFalse($cmd->closesConnection());
|
||||
$this->assertTrue($cmd->canBeHashed());
|
||||
$this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
|
||||
$this->assertEquals("SET key 5\r\nvalue\r\n", $cmd());
|
||||
}
|
||||
|
||||
function testCommand_MultiBulkWithArguments() {
|
||||
$cmd = new \Predis\Commands\SetMultiple();
|
||||
$cmd->setArgumentsArray(array('key1', 'value1', 'key2', 'value2'));
|
||||
|
||||
$this->assertType('\Predis\MultiBulkCommand', $cmd);
|
||||
$this->assertEquals('MSET', $cmd->getCommandId());
|
||||
$this->assertFalse($cmd->closesConnection());
|
||||
$this->assertFalse($cmd->canBeHashed());
|
||||
$this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
|
||||
$this->assertEquals("*5\r\n$4\r\nMSET\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n$4\r\nkey2\r\n$6\r\nvalue2\r\n", $cmd());
|
||||
}
|
||||
|
||||
function testCommand_ParseResponse() {
|
||||
// default parser
|
||||
$cmd = new \Predis\Commands\Get();
|
||||
$this->assertEquals('test', $cmd->parseResponse('test'));
|
||||
|
||||
// overridden parser (boolean)
|
||||
$cmd = new \Predis\Commands\Exists();
|
||||
$this->assertTrue($cmd->parseResponse('1'));
|
||||
$this->assertFalse($cmd->parseResponse('0'));
|
||||
|
||||
// overridden parser (boolean)
|
||||
$cmd = new \Predis\Commands\Ping();
|
||||
$this->assertTrue($cmd->parseResponse('PONG'));
|
||||
|
||||
// overridden parser (complex)
|
||||
// TODO: emulate a respons to INFO
|
||||
}
|
||||
|
||||
|
||||
/* RedisServerProfile and derivates */
|
||||
|
||||
function testRedisServerProfile_GetSpecificVersions() {
|
||||
$this->assertType('\Predis\RedisServer_v1_0', \Predis\RedisServerProfile::get('1.0'));
|
||||
$this->assertType('\Predis\RedisServer_v1_2', \Predis\RedisServerProfile::get('1.2'));
|
||||
$this->assertType('\Predis\RedisServer_v2_0', \Predis\RedisServerProfile::get('2.0'));
|
||||
$this->assertType('\Predis\RedisServer_vNext', \Predis\RedisServerProfile::get('dev'));
|
||||
$this->assertType('\Predis\RedisServerProfile', \Predis\RedisServerProfile::get('default'));
|
||||
$this->assertEquals(\Predis\RedisServerProfile::get('default'), \Predis\RedisServerProfile::getDefault());
|
||||
}
|
||||
|
||||
function testRedisServerProfile_SupportedCommands() {
|
||||
$profile_10 = \Predis\RedisServerProfile::get('1.0');
|
||||
$profile_12 = \Predis\RedisServerProfile::get('1.2');
|
||||
|
||||
$this->assertTrue($profile_10->supportsCommand('info'));
|
||||
$this->assertTrue($profile_12->supportsCommand('info'));
|
||||
|
||||
$this->assertFalse($profile_10->supportsCommand('mset'));
|
||||
$this->assertTrue($profile_12->supportsCommand('mset'));
|
||||
|
||||
$this->assertFalse($profile_10->supportsCommand('multi'));
|
||||
$this->assertFalse($profile_12->supportsCommand('multi'));
|
||||
}
|
||||
|
||||
function testRedisServerProfile_CommandsCreation() {
|
||||
$profile = \Predis\RedisServerProfile::get('1.0');
|
||||
|
||||
$cmdNoArgs = $profile->createCommand('info');
|
||||
$this->assertType('\Predis\Compatibility\v1_0\Commands\Info', $cmdNoArgs);
|
||||
$this->assertNull($cmdNoArgs->getArgument());
|
||||
|
||||
$args = array('key1', 'key2');
|
||||
$cmdWithArgs = $profile->createCommand('mget', $args);
|
||||
$this->assertType('\Predis\Compatibility\v1_0\Commands\GetMultiple', $cmdWithArgs);
|
||||
$this->assertEquals($args[0], $cmdWithArgs->getArgument()); // TODO: why?
|
||||
$this->assertEquals($args[0], $cmdWithArgs->getArgument(0));
|
||||
$this->assertEquals($args[1], $cmdWithArgs->getArgument(1));
|
||||
|
||||
$bogusCommand = 'not_existing_command';
|
||||
$expectedMessage = "'$bogusCommand' is not a registered Redis command";
|
||||
RC::testForClientException($this, $expectedMessage, function()
|
||||
use($profile, $bogusCommand) {
|
||||
|
||||
$profile->createCommand($bogusCommand);
|
||||
});
|
||||
}
|
||||
|
||||
function testRedisServerProfile_CommandsRegistration() {
|
||||
$profile = \Predis\RedisServerProfile::get('1.0');
|
||||
$cmdId = 'mset';
|
||||
$cmdClass = '\Predis\Commands\SetMultiple';
|
||||
|
||||
$this->assertFalse($profile->supportsCommand($cmdId));
|
||||
$profile->registerCommand(new $cmdClass(), $cmdId);
|
||||
$this->assertTrue($profile->supportsCommand($cmdId));
|
||||
$this->assertType($cmdClass, $profile->createCommand($cmdId));
|
||||
}
|
||||
|
||||
|
||||
/* ResponseQueued */
|
||||
|
||||
function testResponseQueued() {
|
||||
$response = new \Predis\ResponseQueued();
|
||||
$this->assertTrue($response->queued);
|
||||
$this->assertEquals(\Predis\Protocol::QUEUED, (string)$response);
|
||||
}
|
||||
|
||||
|
||||
/* ResponseError */
|
||||
|
||||
function testResponseError() {
|
||||
$errorMessage = 'ERROR MESSAGE';
|
||||
$response = new \Predis\ResponseError($errorMessage);
|
||||
|
||||
$this->assertTrue($response->error);
|
||||
$this->assertEquals($errorMessage, $response->message);
|
||||
$this->assertEquals($errorMessage, (string)$response);
|
||||
}
|
||||
|
||||
|
||||
/* Connection */
|
||||
|
||||
function testConnection_StringCastReturnsIPAndPort() {
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
$this->assertEquals(RC::SERVER_HOST . ':' . RC::SERVER_PORT, (string) $connection);
|
||||
}
|
||||
|
||||
function testConnection_ConnectDisconnect() {
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
|
||||
$this->assertFalse($connection->isConnected());
|
||||
$connection->connect();
|
||||
$this->assertTrue($connection->isConnected());
|
||||
$connection->disconnect();
|
||||
$this->assertFalse($connection->isConnected());
|
||||
}
|
||||
|
||||
function testConnection_WriteAndReadCommand() {
|
||||
$cmd = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
$connection->connect();
|
||||
|
||||
$connection->writeCommand($cmd);
|
||||
$this->assertTrue($connection->readResponse($cmd));
|
||||
}
|
||||
|
||||
function testConnection_WriteCommandAndCloseConnection() {
|
||||
$cmd = \Predis\RedisServerProfile::getDefault()->createCommand('quit');
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
$connection->connect();
|
||||
|
||||
$this->assertTrue($connection->isConnected());
|
||||
$connection->writeCommand($cmd);
|
||||
$exceptionMessage = 'Error while reading line from the server';
|
||||
RC::testForCommunicationException($this, $exceptionMessage, function() use($connection, $cmd) {
|
||||
$connection->readResponse($cmd);
|
||||
});
|
||||
//$this->assertFalse($connection->isConnected());
|
||||
}
|
||||
|
||||
function testConnection_GetSocketOpensConnection() {
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
|
||||
$this->assertFalse($connection->isConnected());
|
||||
$this->assertType('resource', $connection->getSocket());
|
||||
$this->assertTrue($connection->isConnected());
|
||||
}
|
||||
|
||||
function testConnection_LazyConnect() {
|
||||
$cmd = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
|
||||
$this->assertFalse($connection->isConnected());
|
||||
$connection->writeCommand($cmd);
|
||||
$this->assertTrue($connection->isConnected());
|
||||
$this->assertTrue($connection->readResponse($cmd));
|
||||
}
|
||||
|
||||
function testConnection_RawCommand() {
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
$this->assertEquals('PONG', $connection->rawCommand("PING\r\n"));
|
||||
}
|
||||
|
||||
function testConnection_Alias() {
|
||||
$connection1 = new \Predis\Connection(RC::getConnectionParameters());
|
||||
$this->assertNull($connection1->getParameters()->alias);
|
||||
|
||||
$args = array_merge(RC::getConnectionArguments(), array('alias' => 'servername'));
|
||||
$connection2 = new \Predis\Connection(new \Predis\ConnectionParameters($args));
|
||||
$this->assertEquals('servername', $connection2->getParameters()->alias);
|
||||
}
|
||||
|
||||
function testConnection_ConnectionTimeout() {
|
||||
$timeout = 3;
|
||||
$args = array('host' => '1.0.0.1', 'connection_timeout' => $timeout);
|
||||
$connection = new \Predis\Connection(new \Predis\ConnectionParameters($args));
|
||||
|
||||
$start = time();
|
||||
RC::testForCommunicationException($this, null, function() use($connection) {
|
||||
$connection->connect();
|
||||
});
|
||||
$this->assertEquals((float)(time() - $start), $timeout, '', 1);
|
||||
}
|
||||
|
||||
function testConnection_ReadTimeout() {
|
||||
$timeout = 1;
|
||||
$args = array_merge(RC::getConnectionArguments(), array('read_write_timeout' => $timeout));
|
||||
$cmdFake = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
|
||||
$connection = new \Predis\Connection(new \Predis\ConnectionParameters($args));
|
||||
|
||||
$expectedMessage = 'Error while reading line from the server';
|
||||
$start = time();
|
||||
RC::testForCommunicationException($this, $expectedMessage, function() use($connection, $cmdFake) {
|
||||
$connection->readResponse($cmdFake);
|
||||
});
|
||||
$this->assertEquals((float)(time() - $start), $timeout, '', 1);
|
||||
}
|
||||
|
||||
|
||||
/* ResponseReader */
|
||||
|
||||
function testResponseReader_OptionIterableMultiBulkReplies() {
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
$responseReader = $connection->getResponseReader();
|
||||
|
||||
$responseReader->setHandler(
|
||||
\Predis\Protocol::PREFIX_MULTI_BULK,
|
||||
new \Predis\ResponseMultiBulkHandler()
|
||||
);
|
||||
$this->assertType('array', $connection->rawCommand("KEYS *\r\n"));
|
||||
|
||||
$responseReader->setHandler(
|
||||
\Predis\Protocol::PREFIX_MULTI_BULK,
|
||||
new \Predis\ResponseMultiBulkStreamHandler()
|
||||
);
|
||||
$this->assertType('\Iterator', $connection->rawCommand("KEYS *\r\n"));
|
||||
}
|
||||
|
||||
function testResponseReader_OptionExceptionOnError() {
|
||||
$connection = new \Predis\Connection(RC::getConnectionParameters());
|
||||
$responseReader = $connection->getResponseReader();
|
||||
$connection->rawCommand("SET key 5\r\nvalue\r\n");
|
||||
$rawCmdUnexpected = "LPUSH key 5\r\nvalue\r\n";
|
||||
|
||||
$responseReader->setHandler(
|
||||
\Predis\Protocol::PREFIX_ERROR,
|
||||
new \Predis\ResponseErrorSilentHandler()
|
||||
);
|
||||
$errorReply = $connection->rawCommand($rawCmdUnexpected);
|
||||
$this->assertType('\Predis\ResponseError', $errorReply);
|
||||
$this->assertEquals(RC::EXCEPTION_WRONG_TYPE, $errorReply->message);
|
||||
|
||||
$responseReader->setHandler(
|
||||
\Predis\Protocol::PREFIX_ERROR,
|
||||
new \Predis\ResponseErrorHandler()
|
||||
);
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function()
|
||||
use ($connection, $rawCmdUnexpected) {
|
||||
|
||||
$connection->rawCommand($rawCmdUnexpected);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Client + CommandPipeline */
|
||||
|
||||
function testCommandPipeline_Simple() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$pipe = $client->pipeline();
|
||||
|
||||
$this->assertType('\Predis\CommandPipeline', $pipe);
|
||||
$this->assertType('\Predis\CommandPipeline', $pipe->set('foo', 'bar'));
|
||||
$this->assertType('\Predis\CommandPipeline', $pipe->set('hoge', 'piyo'));
|
||||
$this->assertType('\Predis\CommandPipeline', $pipe->mset(array(
|
||||
'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo'
|
||||
)));
|
||||
$this->assertType('\Predis\CommandPipeline', $pipe->mget(array(
|
||||
'foo', 'hoge', 'foofoo', 'hogehoge'
|
||||
)));
|
||||
|
||||
$replies = $pipe->execute();
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertEquals(4, count($replies));
|
||||
$this->assertEquals(4, count($replies[3]));
|
||||
$this->assertEquals('barbar', $replies[3][2]);
|
||||
}
|
||||
|
||||
function testCommandPipeline_FluentInterface() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$replies = $client->pipeline()->ping()->set('foo', 'bar')->get('foo')->execute();
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertEquals('bar', $replies[2]);
|
||||
}
|
||||
|
||||
function testCommandPipeline_CallableAnonymousBlock() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$replies = $client->pipeline(function($pipe) {
|
||||
$pipe->ping();
|
||||
$pipe->set('foo', 'bar');
|
||||
$pipe->get('foo');
|
||||
});
|
||||
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertEquals('bar', $replies[2]);
|
||||
}
|
||||
|
||||
function testCommandPipeline_ClientExceptionInCallableBlock() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
RC::testForClientException($this, 'TEST', function() use($client) {
|
||||
$client->pipeline(function($pipe) {
|
||||
$pipe->ping();
|
||||
$pipe->set('foo', 'bar');
|
||||
throw new \Predis\ClientException("TEST");
|
||||
});
|
||||
});
|
||||
$this->assertFalse($client->exists('foo'));
|
||||
}
|
||||
|
||||
function testCommandPipeline_ServerExceptionInCallableBlock() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
$client->getResponseReader()->setHandler('-', new \Predis\ResponseErrorSilentHandler());
|
||||
|
||||
$replies = $client->pipeline(function($pipe) {
|
||||
$pipe->set('foo', 'bar');
|
||||
$pipe->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR
|
||||
$pipe->set('hoge', 'piyo');
|
||||
});
|
||||
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertType('\Predis\ResponseError', $replies[1]);
|
||||
$this->assertTrue($client->exists('foo'));
|
||||
$this->assertTrue($client->exists('hoge'));
|
||||
}
|
||||
|
||||
function testCommandPipeline_Flush() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$pipe = $client->pipeline();
|
||||
$pipe->set('foo', 'bar')->set('hoge', 'piyo');
|
||||
$pipe->flushPipeline();
|
||||
$pipe->ping()->mget(array('foo', 'hoge'));
|
||||
$replies = $pipe->execute();
|
||||
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertEquals(4, count($replies));
|
||||
$this->assertEquals('bar', $replies[3][0]);
|
||||
$this->assertEquals('piyo', $replies[3][1]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
+84
-9
@@ -21,13 +21,26 @@ class RC {
|
||||
const EXCEPTION_NO_SUCH_KEY = 'no such key';
|
||||
const EXCEPTION_OUT_OF_RANGE = 'index out of range';
|
||||
const EXCEPTION_INVALID_DB_IDX = 'invalid DB index';
|
||||
const EXCEPTION_VALUE_NOT_INT = 'value is not an integer';
|
||||
const EXCEPTION_EXEC_NO_MULTI = 'EXEC without MULTI';
|
||||
const EXCEPTION_SETEX_TTL = 'invalid expire time in SETEX';
|
||||
const EXCEPTION_HASH_VALNOTINT = 'hash value is not an integer';
|
||||
|
||||
private static $_connection;
|
||||
|
||||
public static function getConnectionArguments() {
|
||||
return array('host' => RC::SERVER_HOST, 'port' => RC::SERVER_PORT);
|
||||
}
|
||||
|
||||
public static function getConnectionParameters() {
|
||||
return new Predis\ConnectionParameters(array('host' => RC::SERVER_HOST, 'port' => RC::SERVER_PORT));
|
||||
}
|
||||
|
||||
private static function createConnection() {
|
||||
$connection = new Predis\Client(RC::SERVER_HOST, RC::SERVER_PORT);
|
||||
$serverProfile = Predis\RedisServerProfile::get('dev');
|
||||
$connection = new Predis\Client(RC::getConnectionArguments(), $serverProfile);
|
||||
$connection->connect();
|
||||
$connection->selectDatabase(RC::DEFAULT_DATABASE);
|
||||
$connection->select(RC::DEFAULT_DATABASE);
|
||||
return $connection;
|
||||
}
|
||||
|
||||
@@ -45,6 +58,22 @@ class RC {
|
||||
}
|
||||
}
|
||||
|
||||
public static function helperForBlockingPops($op) {
|
||||
// TODO: I admit that this helper is kinda lame and it does not run
|
||||
// in a separate process to properly test BLPOP/BRPOP
|
||||
$redisUri = sprintf('redis://%s:%d/?database=%d', RC::SERVER_HOST, RC::SERVER_PORT, RC::DEFAULT_DATABASE);
|
||||
$handle = popen('php', 'w');
|
||||
fwrite($handle, "<?php
|
||||
require '../lib/Predis.php';
|
||||
\$redis = Predis\Client::create('$redisUri');
|
||||
\$redis->rpush('{$op}1', 'a');
|
||||
\$redis->rpush('{$op}2', 'b');
|
||||
\$redis->rpush('{$op}3', 'c');
|
||||
\$redis->rpush('{$op}1', 'd');
|
||||
?>");
|
||||
pclose($handle);
|
||||
}
|
||||
|
||||
public static function getArrayOfNumbers() {
|
||||
return array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
}
|
||||
@@ -87,25 +116,55 @@ class RC {
|
||||
$thrownException = $exception;
|
||||
}
|
||||
$testcaseInstance->assertType('Predis\ServerException', $thrownException);
|
||||
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
|
||||
if (isset($expectedMessage)) {
|
||||
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static function testForClientException($testcaseInstance, $expectedMessage, $wrapFunction) {
|
||||
$thrownException = null;
|
||||
try {
|
||||
$wrapFunction($testcaseInstance);
|
||||
}
|
||||
catch (Predis\ClientException $exception) {
|
||||
$thrownException = $exception;
|
||||
}
|
||||
$testcaseInstance->assertType('Predis\ClientException', $thrownException);
|
||||
if (isset($expectedMessage)) {
|
||||
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static function testForCommunicationException($testcaseInstance, $expectedMessage, $wrapFunction) {
|
||||
$thrownException = null;
|
||||
try {
|
||||
$wrapFunction($testcaseInstance);
|
||||
}
|
||||
catch (Predis\CommunicationException $exception) {
|
||||
$thrownException = $exception;
|
||||
}
|
||||
$testcaseInstance->assertType('Predis\CommunicationException', $thrownException);
|
||||
if (isset($expectedMessage)) {
|
||||
$testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static function pushTailAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
|
||||
if ($wipeOut == true) {
|
||||
$client->delete($keyName);
|
||||
$client->del($keyName);
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$client->pushTail($keyName, $value);
|
||||
$client->rpush($keyName, $value);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function setAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
|
||||
if ($wipeOut == true) {
|
||||
$client->delete($keyName);
|
||||
$client->del($keyName);
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$client->setAdd($keyName, $value);
|
||||
$client->sadd($keyName, $value);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
@@ -113,12 +172,28 @@ class RC {
|
||||
public static function zsetAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) {
|
||||
// $values: array(SCORE => VALUE, ...);
|
||||
if ($wipeOut == true) {
|
||||
$client->delete($keyName);
|
||||
$client->del($keyName);
|
||||
}
|
||||
foreach ($values as $value => $score) {
|
||||
$client->zsetAdd($keyName, $score, $value);
|
||||
$client->zadd($keyName, $score, $value);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function getConnectionParametersArgumentsArray() {
|
||||
return array(
|
||||
'host' => '10.0.0.1', 'port' => 6380, 'connection_timeout' => 10, 'read_write_timeout' => 30,
|
||||
'database' => 5, 'password' => 'dbpassword', 'alias' => 'connection_alias'
|
||||
);
|
||||
}
|
||||
|
||||
public static function getConnectionParametersArgumentsString($arguments = null) {
|
||||
// TODO: must be improved
|
||||
$args = $arguments ?: RC::getConnectionParametersArgumentsArray();
|
||||
$paramsString = "redis://{$args['host']}:{$args['port']}/";
|
||||
$paramsString .= "?connection_timeout={$args['connection_timeout']}&read_write_timeout={$args['read_write_timeout']}";
|
||||
$paramsString .= "&database={$args['database']}&password={$args['password']}&alias={$args['alias']}";
|
||||
return $paramsString;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
+841
-307
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user