Compare commits

..

45 Commits

Author SHA1 Message Date
Nicolas Grekas deee2b6d60 Fix deprecation when using "static" in callables (#1403) 2023-09-19 09:11:21 -07:00
Till Krüss bb8cce7bcf adjust travis config 2023-01-10 08:48:39 -08:00
Stefano Borghi dc14604f3e Check resource before reading (#803) 2022-09-20 09:13:12 -07:00
Stefano Borghi b000013f22 check resource before writing (#799) 2022-09-19 12:27:07 -07:00
angeljqv d6da14daa8 Don't export changeling and contribution notes 2022-04-05 09:13:30 -07:00
Andrii Dembitskyi acb2460f4c PHP 8.1 and symfony/error handler deprecations (#748)
* Be sure that position always have type integer

* Annotate properly return types for SPL interfaces implementation

It is allows avoiding deprecation messages from `symfony/error-handler` like a '[info] User Deprecated: Method "Iterator::rewind()" might add "void" as a native return type declaration in the future. Do the same in implementation "Predis\Collection\Iterator\CursorBasedIterator" now to avoid errors or add an explicit @return annotation to suppress this message.'

Fixed via `symfony/error-handler` patch script: ` SYMFONY_PATCH_TYPE_DECLARATIONS="force=phpdoc&php=5.3" ./vendor/bin/patch-type-declarations` and some additional manual work

Some details about why this is necessary and how checks with trigger deprecations works: https://wouterj.nl/2021/09/symfony-6-native-typing
2022-03-15 10:50:51 -07:00
Karol Hrusza 213f00042f Add clear method to pipeline (#749)
* Add clear method to pipeline

Ability to clean pipeline and responses when reusing pipelines.
Allows pipeline to be executed using chunks without out-of-control
increase in memory usage.

* spacing

Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
2022-03-11 08:48:10 -08:00
Julian Haupt ab0c46332c throw exception if connection->read() returns an error object in cons… (#746)
* throw exception if connection->read() returns an error object in consumer

* Add test case for Consumer throwing a ServerException when no subscription could be established

* spacing

Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
2022-02-17 10:13:02 -08:00
Ondřej Ešler ed19ec3483 #742 create new context for socket connection (#743)
Co-authored-by: Ondřej Ešler <ondrej.esler@peoplepath.com>
2022-02-04 08:41:14 -08:00
fluffycondor 90496e76b5 Fix wrong return iterator value type: implementation returns \stdClass but it's typehinted as array (#740) 2022-01-26 09:22:03 -08:00
Till Krüss 4231c35e09 back to dev 2022-01-05 09:49:10 -08:00
Till Krüss a2fb02d738 bump version to 1.1.10 stable 2022-01-05 09:46:08 -08:00
Pim Jansen ca1f398f7c Fix for changing return types for PHP8.1 (#730)
Co-authored-by: Pim Jansen <pjansen@senet.nl>
2021-12-18 11:23:39 -08:00
kgasienica 5e07be785a bugfix/cannot-use-object-of-type-error-as-array-722 (#724)
Co-authored-by: Karol Gąsienica-Fronek <karol.gasienica-fronek@lppsa.com>
2021-12-01 10:18:59 -08:00
Till Krüss b3cd02e2ba back to dev 2021-10-05 12:03:21 -07:00
Till Krüss c50c3393bb update changelog 2021-10-05 12:02:38 -07:00
Till Krüss 4aa3014bb0 tag 1.1.9 2021-10-05 11:55:45 -07:00
Dries Vints 92adf32e88 Fix PHP 8.1 strlen breakage (#713)
* Fix PHP 8.1 strlen breakage

This adds a fallback to an empty string if the argument is `null` for some reason.

* Update StreamConnection.php

* use `strval()`

Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
2021-09-30 09:09:37 -07:00
Till Krüss c4560304cf back to dev version 2021-09-29 10:50:22 -07:00
Till Krüss cf5c118a07 tag 1.1.8
tests pass locally PHP 8.1.0RC4-dev
2021-09-29 10:48:39 -07:00
Till Krüss bb9a670c83 add php 8.1 patches for phpunit 2021-09-29 10:43:13 -07:00
Till Krüss 3e56e880e8 nope; and nightly is php 8.0 🤦‍♂️ 2021-09-29 10:06:50 -07:00
Till Krüss 1c71a4e36e does travis do 8.1 yet?
seemingly no docs on this...
2021-09-29 10:02:37 -07:00
Vadim Borodavko 5004f5d6fc Add PHP 8.1 support (#712)
* Add PHP 8.1 support

* Update AbortedMultiExecException.php

* Update CommunicationException.php

* Update ServerSentinel.php

* Update CursorBasedIterator.php

* Update ReplicationStrategy.php

Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
2021-09-12 15:07:16 -07:00
John Paul E. Balandan, CPA e616f85679 Add ReturnTypeWillChange attribute to CursorBasedIterator (#708) 2021-08-24 10:25:19 -07:00
Alexander M. Turek 9cd093be24 Add ReturnTypeWillChange (#706) 2021-08-05 11:02:38 -07:00
Nick Doulgeridis 305d167b08 Prevent PHP warning
https://github.com/predis/predis/issues/691
2021-05-12 08:29:35 -07:00
Till Krüss 3271e1edcb back to dev 2021-04-04 12:51:10 -07:00
Till Krüss b240daa106 tag v1.1.7 2021-04-04 12:34:46 -07:00
Till Krüss 8fee6ce8c3 Fix PHP 5.3 test and PHP 8 test runs
For some reason Xdebug causes a seg fault under PHP 8 on Travis CI.
2021-04-04 12:33:59 -07:00
Till Krüss 35dd44b222 Merge pull request #686 from remicollet/issue-redis62
fix test expectation for redis 6.2
2021-04-04 10:36:02 -07:00
Till Krüss 545177f09f Merge pull request #685 from BrianMwit/patch-1
Fix misleading argument name in SentinelReplication
2021-04-04 10:34:53 -07:00
Remi Collet 2f9337cb9b fix test expectation for redis 6.2 2021-03-18 11:08:37 +01:00
Pitchaya Boonsarngsuk 437d80a7a3 Fix misleading argument name in SentinelReplication
$this->retryWait is in milliseconds. It's setter misleadingly document it as seconds.
Fixing by renaming the argument variable name without altering the functionality.
2021-03-17 03:41:03 +00:00
Till Krüss 3a14a39d92 Merge pull request #678 from nicolas-grekas/ret-type
Add some return types
2021-02-09 10:09:19 -08:00
Till Krüss 5c9457cc2e Merge pull request #673 from roborourke/apply-patches-on-update
Apply patches on initial install/update
2021-02-09 09:44:11 -08:00
Nicolas Grekas c551fc21f9 Add some return types 2021-02-04 12:06:26 +01:00
Robert O'Rourke 0d84606723 Switch to old array style syntax to support PHP 5.3 2020-11-30 11:07:54 +00:00
Robert O'Rourke c021e380d6 Apply patches on initial install/update
The patches to get PHPUnit working are causing problems for other projects that use both `cweagans/composer-patch-installers` and `predis/predis` along with PHPUnit.

This change moves the patch application to a simple PHP script run on the `post-update-cmd` composer event and removes the dependency on the patch installers package.
2020-11-27 17:24:00 +00:00
Daniele Alessandri 5f4b87080f Tweak tests. 2020-09-20 17:16:49 +02:00
Daniele Alessandri 5ae4ac6b49 Clear pending responses in reader buffer on disconnect.
When using the phpiredis-based connection backends, failed pipelines led
to spurious responses returned after reconnecting to Redis because the
underlying reader was not properly reset by discarding buffered replies
after disconnecting.

Fixes a couple of issues reported in #363.
2020-09-20 16:58:18 +02:00
Daniele Alessandri 521ac8f0eb Fix PhpiredisSocketConnection for PHP 8.
Removed is_resource() check as socket_create() now returns an object.
2020-09-20 15:27:35 +02:00
Daniele Alessandri fbbef2a0a2 Back to development. 2020-09-11 21:20:11 +02:00
Daniele Alessandri 9930e933c6 Update CHANGELOG and bump VERSION. 2020-09-11 21:18:05 +02:00
Daniele Alessandri 16957f3b39 Revert support for redis-sentinel authentication.
Authentication for sentinels was implemented in v1.1.5 (commit 2e76410)
but ended up being bugged (see ISSUE #658). This is now postponed as it
requires a more thorough investigation.
2020-09-11 21:10:40 +02:00
542 changed files with 18175 additions and 19011 deletions
+7 -1
View File
@@ -1,9 +1,15 @@
* text=auto
/tests export-ignore
/tests/PHPUnit export-ignore
/tests/Predis export-ignore
/tests/bootstrap.php export-ignore
/.github export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.php_cs.dist export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/phpunit.xml.travisci export-ignore
/CHANGELOG.md export-ignore
/CONTRIBUTING.md export-ignore
-6
View File
@@ -1,6 +0,0 @@
The Predis code of conduct is derived from the Ruby code of conduct. Any violations of the code of conduct may be reported to [Till Krüss](https://till.im):
- Participants will be tolerant of opposing views.
- Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
- When interpreting the words and actions of others, participants should always assume good intentions.
- Behavior that can be reasonably considered harassment will not be tolerated.
-52
View File
@@ -1,52 +0,0 @@
name: Tests
on:
- push
- pull_request
jobs:
predis:
name: PHP ${{ matrix.php-versions }} (Redis ${{ matrix.redis-versions }})
runs-on: ubuntu-latest
services:
redis:
image: redis:${{ matrix.redis-versions }}
ports:
- 6379:6379
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
fail-fast: false
matrix:
php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2']
redis-versions: ['3', '4', '5', '6', '7']
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP with Composer and extensions
with:
php-version: ${{ matrix.php-versions }}
uses: shivammathur/setup-php@v2
- name: Get Composer cache directory
id: composercache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache Composer dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composercache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
env:
PHP_VERSION: ${{ matrix.php-versions }}
run: composer install --no-progress --prefer-dist --optimize-autoloader $(if [ "$PHP_VERSION" == "8.0" ]; then echo "--ignore-platform-reqs"; fi;)
- name: Test with PHPUnit
run: vendor/bin/phpunit
+6 -2
View File
@@ -1,6 +1,10 @@
/vendor
*.tgz
*.phar
.php-version
.php_cs.cache
.phpunit.result.cache
composer.lock
phpunit.xml
package.xml
composer.lock
experiments/
vendor/
+36
View File
@@ -0,0 +1,36 @@
language: php
branches:
except:
- main
- v2.0
before_install:
- docker run -d --rm -p 127.0.0.1:6379:6379 redis:3
before_script:
- phpenv config-rm xdebug.ini
- composer self-update
- composer install --no-interaction --prefer-source --dev
script:
- travis_retry vendor/bin/phpunit -c phpunit.xml.travisci
matrix:
fast_finish: true
include:
- php: 5.3
dist: precise
services: redis-server
before_install: skip
- php: 5.4
dist: trusty
- php: 5.5
dist: trusty
- php: 5.6
- php: 7.0
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
- php: 8.0
+1076 -106
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2009-2021 Daniele Alessandri
Copyright (c) 2009-2016 Daniele Alessandri
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
+60 -69
View File
@@ -4,16 +4,20 @@
[![Latest stable][ico-version-stable]][link-packagist]
[![Latest development][ico-version-dev]][link-packagist]
[![Monthly installs][ico-downloads-monthly]][link-downloads]
[![Build status][ico-build]][link-actions]
[![Build status][ico-travis]][link-travis]
A flexible and feature-complete [Redis](http://redis.io) client for PHP 7.2 and newer.
Flexible and feature-complete [Redis](http://redis.io) client for PHP >= 5.3 and HHVM >= 2.3.0.
Predis does not require any additional C extension by default, but it can be optionally paired with
[phpiredis](https://github.com/nrk/phpiredis) to lower the overhead of the serialization and parsing
of the [Redis RESP Protocol](http://redis.io/topics/protocol).
More details about this project can be found on the [frequently asked questions](FAQ.md).
## Main features ##
- Support for Redis from __3.0__ to __7.0__.
- Support for different versions of Redis (from __2.0__ to __3.2__) using profiles.
- Support for clustering using client-side sharding and pluggable keyspace distributors.
- Support for [redis-cluster](http://redis.io/topics/cluster-tutorial) (Redis >= 3.0).
- Support for master-slave replication setups and [redis-sentinel](http://redis.io/topics/sentinel).
@@ -26,18 +30,15 @@ More details about this project can be found on the [frequently asked questions]
- Connections can be established via TCP/IP (also TLS/SSL-encrypted) or UNIX domain sockets.
- Support for [Webdis](http://webd.is) (requires both `ext-curl` and `ext-phpiredis`).
- Support for custom connection classes for providing different network or protocol backends.
- Flexible system for defining custom commands and override the default ones.
- Flexible system for defining custom commands and profiles and override the default ones.
## How to _install_ and use Predis ##
This library can be found on [Packagist](http://packagist.org/packages/predis/predis) for an easier
management of projects dependencies using [Composer](http://packagist.org/about-composer).
Compressed archives of each release are [available on GitHub](https://github.com/predis/predis/releases).
```shell
composer require predis/predis
```
management of projects dependencies using [Composer](http://packagist.org/about-composer) or on our
[own PEAR channel](http://pear.nrk.io) for a more traditional installation using PEAR. Ultimately,
compressed archives of each release are [available on GitHub](https://github.com/predis/predis/releases).
### Loading the library ###
@@ -54,6 +55,10 @@ require 'Predis/Autoloader.php';
Predis\Autoloader::register();
```
It is also possible to create a [phar](http://www.php.net/manual/en/intro.phar.php) archive directly
from the repository by launching the `bin/create-phar` script. The generated phar already contains a
stub defining its own autoloader, so you just need to `require()` it to start using the library.
### Connecting to Redis ###
@@ -117,16 +122,14 @@ the rules described on their respective IANA provisional registration documents.
The actual list of supported connection parameters can vary depending on each connection backend so
it is recommended to refer to their specific documentation or implementation for details.
Predis can aggregate multiple connections when providing an array of connection parameters and the
appropriate option to instruct the client about how to aggregate them (clustering, replication or a
custom aggregation logic). Named arrays and URI strings can be mixed when providing configurations
When an array of connection parameters is provided, Predis automatically works in cluster mode using
client-side sharding. Both named arrays and URI strings can be mixed when providing configurations
for each node:
```php
$client = new Predis\Client([
'tcp://10.0.0.1?alias=first-node', ['host' => '10.0.0.2', 'alias' => 'second-node'],
], [
'cluster' => 'predis',
'tcp://10.0.0.1?alias=first-node',
['host' => '10.0.0.2', 'alias' => 'second-node'],
]);
```
@@ -145,20 +148,20 @@ Many aspects and behaviors of the client can be configured by passing specific c
second argument of `Predis\Client::__construct()`:
```php
$client = new Predis\Client($parameters, ['prefix' => 'sample:']);
$client = new Predis\Client($parameters, ['profile' => '2.8', 'prefix' => 'sample:']);
```
Options are managed using a mini DI-alike container and their values can be lazily initialized only
when needed. The client options supported by default in Predis are:
- `prefix`: prefix string applied to every key found in commands.
- `profile`: specifies the profile to use to match a specific version of Redis.
- `prefix`: prefix string automatically applied to keys found in commands.
- `exceptions`: whether the client should throw or return responses upon Redis errors.
- `connections`: list of connection backends or a connection factory instance.
- `cluster`: specifies a cluster backend (`predis`, `redis` or callable).
- `replication`: specifies a replication backend (`predis`, `sentinel` or callable).
- `aggregate`: configures the client with a custom aggregate connection (callable).
- `cluster`: specifies a cluster backend (`predis`, `redis` or callable object).
- `replication`: specifies a replication backend (`TRUE`, `sentinel` or callable object).
- `aggregate`: overrides `cluster` and `replication` to provide a custom connections aggregator.
- `parameters`: list of default connection parameters for aggregate connections.
- `commands`: specifies a command factory instance to use through the library.
Users can also provide custom options with values or callable objects (for lazy initialization) that
are stored in the options container for later use through the library.
@@ -169,18 +172,18 @@ are stored in the options container for later use through the library.
Aggregate connections are the foundation upon which Predis implements clustering and replication and
they are used to group multiple connections to single Redis nodes and hide the specific logic needed
to handle them properly depending on the context. Aggregate connections usually require an array of
connection parameters along with the appropriate client option when creating a new client instance.
connection parameters when creating a new client instance.
#### Cluster ####
Predis can be configured to work in clustering mode with a traditional client-side sharding approach
to create a cluster of independent nodes and distribute the keyspace among them. This approach needs
some sort of external health monitoring of nodes and requires the keyspace to be rebalanced manually
when nodes are added or removed:
By default, when no specific client options are set and an array of connection parameters is passed
to the client's constructor, Predis configures itself to work in clustering mode using a traditional
client-side sharding approach to create a cluster of independent nodes and distribute the keyspace
among them. This approach needs some form of external health monitoring of nodes and requires manual
operations to rebalance the keyspace when changing its configuration by adding or removing nodes:
```php
$parameters = ['tcp://10.0.0.1', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options = ['cluster' => 'predis'];
$client = new Predis\Client($parameters);
```
@@ -210,12 +213,12 @@ the value of a key. Instead of raising a connection error when a slave fails, th
fall back to a different slave among the ones provided in the configuration.
The basic configuration needed to use the client in replication mode requires one Redis server to be
identified as the master (this can be done via connection parameters by setting the `role` parameter
to `master`) and one or more slaves (in this case setting `role` to `slave` for slaves is optional):
identified as the master (this can be done via connection parameters using the `alias` parameter set
to `master`) and one or more servers acting as slaves:
```php
$parameters = ['tcp://10.0.0.1?role=master', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options = ['replication' => 'predis'];
$parameters = ['tcp://10.0.0.1?alias=master', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options = ['replication' => true];
$client = new Predis\Client($parameters, $options);
```
@@ -256,13 +259,13 @@ when certain Lua scripts do not perform write operations it is possible to provi
the client to stick with slaves for their execution:
```php
$parameters = ['tcp://10.0.0.1?role=master', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$parameters = ['tcp://10.0.0.1?alias=master', 'tcp://10.0.0.2', 'tcp://10.0.0.3'];
$options = ['replication' => function () {
// Set scripts that won't trigger a switch from a slave to the master node.
$strategy = new Predis\Replication\ReplicationStrategy();
$strategy->setScriptReadOnly($LUA_SCRIPT);
return new Predis\Connection\Replication\MasterSlaveReplication($strategy);
return new Predis\Connection\Aggregate\MasterSlaveReplication($strategy);
}];
$client = new Predis\Client($parameters, $options);
@@ -321,7 +324,7 @@ of a transaction using CAS you can see [the following example](examples/transact
While we try to update Predis to stay up to date with all the commands available in Redis, you might
prefer to stick with an old version of the library or provide a different way to filter arguments or
parse responses for specific commands. To achieve that, Predis provides the ability to implement new
command classes to define or override commands in the default command factory used by the client:
command classes to define or override commands in the default server profiles used by the client:
```php
// Define a new command by extending Predis\Command\Command:
@@ -333,12 +336,9 @@ class BrandNewRedisCommand extends Predis\Command\Command
}
}
// Inject your command in the current command factory:
$client = new Predis\Client($parameters, [
'commands' => [
'newcmd' => 'BrandNewRedisCommand',
],
]);
// Inject your command in the current profile:
$client = new Predis\Client();
$client->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
$response = $client->newcmd();
```
@@ -357,7 +357,7 @@ $response = $client->executeRaw(['SET', 'foo', 'bar']);
While it is possible to leverage [Lua scripting](http://redis.io/commands/eval) on Redis 2.6+ using
directly [`EVAL`](http://redis.io/commands/eval) and [`EVALSHA`](http://redis.io/commands/evalsha),
Predis offers script commands as an higher level abstraction built upon them to make things simple.
Script commands can be registered in the command factory used by the client and are accessible as if
Script commands can be registered in the server profile used by the client and are accessible as if
they were plain Redis commands, but they define Lua scripts that get transmitted to the server for
remote execution. Internally they use [`EVALSHA`](http://redis.io/commands/evalsha) by default and
identify a script by its SHA1 hash to save bandwidth, but [`EVAL`](http://redis.io/commands/eval)
@@ -383,12 +383,9 @@ LUA;
}
}
// Inject the script command in the current command factory:
$client = new Predis\Client($parameters, [
'commands' => [
'lpushrand' => 'ListPushRandomValue',
],
]);
// Inject the script command in the current profile:
$client = new Predis\Client();
$client->getProfile()->defineCommand('lpushrand', 'ListPushRandomValue');
$response = $client->lpushrand('random_values', $seed = mt_rand());
```
@@ -410,17 +407,6 @@ $client = new Predis\Client('tcp://127.0.0.1', [
]);
```
The client can also be configured to rely on a [phpiredis](https://github.com/nrk/phpiredis)-backend
by specifying a descriptive string for the `connections` client option. Supported string values are:
- `phpiredis-stream` maps `tcp`, `redis` and `unix` to `Predis\Connection\PhpiredisStreamConnection`
- `phpiredis-socket` maps `tcp`, `redis` and `unix` to `Predis\Connection\PhpiredisSocketConnection`
- `phpiredis` is simply an alias of `phpiredis-stream`
```php
$client = new Predis\Client('tcp://127.0.0.1', ['connections' => 'phpiredis']);
```
Developers can create their own connection classes to support whole new network backends, extend
existing classes or provide completely different implementations. Connection classes must implement
`Predis\Connection\NodeConnectionInterface` or extend `Predis\Connection\AbstractConnection`:
@@ -457,14 +443,18 @@ stay consistent while working on the project.
__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running
in production environments or containing data you are interested in!
Predis has a comprehensive test suite covering every aspect of the library and that can optionally
perform integration tests against a running instance of Redis (required >= 2.4.0 in order to verify
the correct behavior of the implementation of each command. Integration tests for unsupported Redis
commands are automatically skipped. If you do not have Redis up and running, integration tests can
be disabled. See [the tests README](tests/README.md) for more details about testing this library.
Predis has a comprehensive test suite covering every aspect of the library. This test suite performs
integration tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct
behavior of the implementation of each command and automatically skips commands not defined in the
specified Redis profile. If you do not have Redis up and running, integration tests can be disabled.
By default the test suite is configured to execute integration tests using the profile for Redis 3.2
(which is the current stable version of Redis) but can optionally target a Redis instance built from
the `unstable` branch by modifying `phpunit.xml` and setting `REDIS_SERVER_VERSION` to `dev` so that
the development server profile will be used. You can refer to [the tests README](tests/README.md)
for more detailed information about testing Predis.
Predis uses GitHub Actions for continuous integration and the history for past and current builds can be
found [on its actions page](https://github.com/predis/predis/actions).
Predis uses Travis CI for continuous integration and the history for past and current builds can be
found [on its project page](http://travis-ci.org/predis/predis).
## Other ##
@@ -475,12 +465,12 @@ found [on its actions page](https://github.com/predis/predis/actions).
- [Source code](https://github.com/predis/predis)
- [Wiki](https://github.com/predis/predis/wiki)
- [Issue tracker](https://github.com/predis/predis/issues)
- [PEAR channel](http://pear.nrk.io)
### Author ###
- [Daniele Alessandri](mailto:suppakilla@gmail.com) ([twitter](http://twitter.com/JoL1hAHN))
- [Till Krüss](https://till.im) ([Twitter](http://twitter.com/tillkruss))
### License ###
@@ -491,8 +481,9 @@ The code for Predis is distributed under the terms of the MIT license (see [LICE
[ico-version-stable]: https://img.shields.io/packagist/v/predis/predis.svg?style=flat-square
[ico-version-dev]: https://img.shields.io/packagist/vpre/predis/predis.svg?style=flat-square
[ico-downloads-monthly]: https://img.shields.io/packagist/dm/predis/predis.svg?style=flat-square
[ico-build]: https://img.shields.io/github/workflow/status/predis/predis/Tests/main?style=flat-square
[ico-travis]: https://img.shields.io/travis/predis/predis.svg?style=flat-square
[ico-hhvm]: https://img.shields.io/hhvm/predis/predis.svg?style=flat-square
[link-packagist]: https://packagist.org/packages/predis/predis
[link-actions]: https://github.com/predis/predis/actions
[link-travis]: https://travis-ci.org/predis/predis
[link-downloads]: https://packagist.org/packages/predis/predis/stats
+1 -1
View File
@@ -1 +1 @@
2.0.2
1.1.11-dev
+21 -24
View File
@@ -15,7 +15,7 @@
// of a test case to test a Redis command by specifying the name of the class
// in the Predis\Command namespace (only classes in this namespace are valid).
// For example, to generate a test case for SET (which is represented by the
// Predis\Command\Redis\StringSet class):
// Predis\Command\StringSet class):
//
// $ ./bin/generate-command-test --class=StringSet
//
@@ -45,11 +45,6 @@ class CommandTestCaseGenerator
if (!isset($options['class'])) {
throw new RuntimeException("Missing 'class' option.");
}
if (!isset($options['realm'])) {
throw new RuntimeException("Missing 'realm' option.");
}
$this->options = $options;
}
@@ -97,12 +92,8 @@ class CommandTestCaseGenerator
throw new RuntimeException("Missing 'class' option.");
}
if (!isset($options['realm'])) {
throw new RuntimeException("Missing 'realm' option.");
}
$options['fqn'] = "Predis\\Command\\Redis\\{$options['class']}";
$options['path'] = "Command/Redis/{$options['class']}.php";
$options['fqn'] = "Predis\\Command\\{$options['class']}";
$options['path'] = "Command/{$options['class']}.php";
$source = __DIR__.'/../src/'.$options['path'];
if (!file_exists($source)) {
@@ -110,7 +101,7 @@ class CommandTestCaseGenerator
}
if (!isset($options['output'])) {
$options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', '_Test.php', $options['path']));
$options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', 'Test.php', $options['path']));
}
return new self($options);
@@ -118,11 +109,18 @@ class CommandTestCaseGenerator
protected function getTestRealm()
{
if (empty($this->options['realm'])) {
throw new RuntimeException('Invalid value for realm has been sepcified (empty).');
if (isset($this->options['realm'])) {
if (!$this->options['realm']) {
throw new RuntimeException('Invalid value for realm has been sepcified (empty).');
}
return $this->options['realm'];
}
return $this->options['realm'];
$fqnParts = explode('\\', $this->options['fqn']);
$class = array_pop($fqnParts);
list($realm,) = preg_split('/([[:upper:]][[:lower:]]+)/', $class, 2, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
return strtolower($realm);
}
public function generate()
@@ -132,7 +130,6 @@ class CommandTestCaseGenerator
if (!$reflection->isInstantiable()) {
throw new RuntimeException("Class $class must be instantiable, abstract classes or interfaces are not allowed.");
}
if (!$reflection->implementsInterface('Predis\Command\CommandInterface')) {
throw new RuntimeException("Class $class must implement Predis\Command\CommandInterface.");
}
@@ -176,7 +173,7 @@ class CommandTestCaseGenerator
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
namespace Predis\Command;
/**
* @group commands
@@ -187,7 +184,7 @@ class $class extends PredisCommandTestCase
/**
* {@inheritdoc}
*/
protected function getExpectedCommand(): string
protected function getExpectedCommand()
{
return '$fqn';
}
@@ -195,7 +192,7 @@ class $class extends PredisCommandTestCase
/**
* {@inheritdoc}
*/
protected function getExpectedId(): string
protected function getExpectedId()
{
return '$id';
}
@@ -203,7 +200,7 @@ class $class extends PredisCommandTestCase
/**
* @group disconnected
*/
public function testFilterArguments(): void
public function testFilterArguments()
{
\$this->markTestIncomplete('This test has not been implemented yet.');
@@ -219,7 +216,7 @@ class $class extends PredisCommandTestCase
/**
* @group disconnected
*/
public function testParseResponse(): void
public function testParseResponse()
{
\$this->markTestIncomplete('This test has not been implemented yet.');
@@ -239,7 +236,7 @@ PHP;
/**
* @group disconnected
*/
public function testPrefixKeys(): void
public function testPrefixKeys()
{
\$this->markTestIncomplete('This test has not been implemented yet.');
@@ -255,7 +252,7 @@ PHP;
/**
* @group disconnected
*/
public function testPrefixKeysIgnoredOnEmptyArguments(): void
public function testPrefixKeysIgnoredOnEmptyArguments()
{
\$command = \$this->getCommand();
\$command->prefixKeys('prefix:');
+233
View File
@@ -0,0 +1,233 @@
#!/usr/bin/env php
<?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.
*/
// -------------------------------------------------------------------------- //
// In order to be able to execute this script to create a PEAR package of Predis
// the `pear` binary must be available and executable in your $PATH.
// The parts used to parse author and version strings are taken from Onion (used
// by this library in the past) just to keep on relying on the package.ini file
// to simplify things. We might consider to switch to using the PEAR classes
// directly in the future.
// -------------------------------------------------------------------------- //
function executeWithBackup($file, $callback)
{
$exception = null;
$backup = "$file.backup";
copy($file, $backup);
try {
call_user_func($callback, $file);
} catch (Exception $exception) {
// NOOP
}
unlink($file);
rename($backup, $file);
if ($exception) {
throw $exception;
}
}
function parseAuthor($string)
{
$author = array();
if (preg_match('/^\s*(.+?)\s*(?:"(\S+)"\s*)?<(\S+)>\s*$/x', $string , $regs)) {
if (count($regs) == 4) {
list($_,$name,$user,$email) = $regs;
$author['name'] = $name;
$author['user'] = $user;
$author['email'] = $email;
} elseif (count($regs) == 3) {
list($_,$name,$email) = $regs;
$author['name'] = $name;
$author['email'] = $email;
}
} else {
$author['name'] = $string;
}
return $author;
}
function parseVersion($string)
{
$version_pattern = '([0-9.]+)';
if (preg_match("/^\s*$version_pattern\s*\$/x", $string, $regs)) {
return array('min' => $regs[1] ?: '0.0.0');
} elseif (preg_match("/^\s*[>=]+\s*$version_pattern\s*\$/x", $string, $regs)) {
return array('min' => $regs[1] ?: '0.0.0');
} elseif (preg_match("/^\s*[<=]+\s*$version_pattern\s*\$/x", $string, $regs)) {
return array('max' => $regs[1]);
} elseif (preg_match("/^\s*$version_pattern\s*<=>\s*$version_pattern\s*\$/x", $string, $regs)) {
return array(
'min' => $regs[1] ?: '0.0.0',
'max' => $regs[2],
);
}
return null;
}
function addRolePath($pkg, $path, $role)
{
if (is_dir($path)) {
$dirRoot = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$dirTree = new RecursiveIteratorIterator($dirRoot, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($dirTree as $fileinfo) {
if ($fileinfo->isFile()) {
addPackageFile($pkg, $fileinfo, $role, $path);
}
}
} else {
foreach (glob($path) as $filename) {
addPackageFile($pkg, new SplFileInfo($filename), $role);
}
}
}
function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
{
$fileNode = $pkg->contents->dir->addChild('file');
$fileNode->addAttribute('name', $filepath = $fileinfo->getPathname());
$fileNode->addAttribute('role', $role);
$fileNode->addAttribute('md5sum', md5_file($filepath));
$installNode = $pkg->phprelease->filelist->addChild('install');
$installNode->addAttribute('name', $filepath);
$installNode->addAttribute('as', !$baseDir ? basename($filepath) : substr($filepath, strlen($baseDir) + 1));
}
function generatePackageXml($packageINI)
{
$XML = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.4.10" version="2.0"
xmlns="http://pear.php.net/dtd/package-2.0"
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
http://pear.php.net/dtd/tasks-1.0.xsd
http://pear.php.net/dtd/package-2.0
http://pear.php.net/dtd/package-2.0.xsd" />
XML;
$cfg = parse_ini_file($packageINI, true);
$pkg = new SimpleXMLElement($XML);
$pkg->name = $cfg['package']['name'];
$pkg->channel = $cfg['package']['channel'];
$pkg->summary = $cfg['package']['desc'];
$pkg->description = $cfg['package']['desc'];
$author = parseAuthor($cfg['package']['author']);
$pkg->addChild('lead');
$pkg->lead->name = $author['name'];
$pkg->lead->user = $author['user'];
$pkg->lead->email = $author['email'];
$pkg->lead->active = 'yes';
$datetime = new DateTime('now');
$pkg->date = $datetime->format('Y-m-d');
$pkg->time = $datetime->format('H:i:s');
$pkg->addChild('version');
$pkg->version->release = $cfg['package']['version'];
$pkg->version->api = $cfg['package']['version'];
$pkg->addChild('stability');
$pkg->stability->release = $cfg['package']['stability'];
$pkg->stability->api = $cfg['package']['stability'];
$pkg->license = $cfg['package']['license'];
$pkg->notes = '-';
$pkg->addChild('contents')->addChild('dir')->addAttribute('name', '/');
$pkg->addChild('dependencies')->addChild('required');
foreach ($cfg['require'] as $required => $version) {
$version = parseVersion($version);
$pkg->dependencies->required->addChild($required);
if (isset($version['min'])) {
$pkg->dependencies->required->$required->min = $version['min'];
}
if (isset($version['max'])) {
$pkg->dependencies->required->$required->min = $version['max'];
}
}
$pkg->addChild('phprelease')->addChild('filelist');
$pathToRole = array(
'doc' => 'doc', 'docs' => 'doc', 'examples' => 'doc',
'lib' => 'php', 'src' => 'php',
'test' => 'test', 'tests' => 'test',
);
foreach (array_merge($pathToRole, $cfg['roles'] ?: array()) as $path => $role) {
addRolePath($pkg, $path, $role);
}
return $pkg;
}
function rewritePackageInstallAs($pkg)
{
foreach ($pkg->phprelease->filelist->install as $file) {
if (preg_match('/^src\//', $file['name'])) {
$file['as'] = "Predis/{$file['as']}";
}
}
}
function savePackageXml($xml)
{
$dom = new DOMDocument("1.0", "UTF-8");
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
file_put_contents('package.xml', $dom->saveXML());
}
function buildPackage()
{
passthru('pear -q package && rm package.xml');
}
function modifyPhpunitXml($file)
{
$cfg = new SimpleXMLElement($file, null, true);
$cfg[0]['bootstrap'] = str_replace('tests/', '', $cfg[0]['bootstrap']);
$cfg->testsuites->testsuite->directory = str_replace('tests/', '', $cfg->testsuites->testsuite->directory);
$cfg->saveXml($file);
}
// -------------------------------------------------------------------------- //
executeWithBackup(__DIR__.'/../phpunit.xml.dist', function ($file) {
modifyPhpunitXml($file);
$pkg = generatePackageXml('package.ini');
rewritePackageInstallAs($pkg);
savePackageXml($pkg);
buildPackage();
});
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env php
<?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.
*/
// -------------------------------------------------------------------------- //
// In order to be able to execute this script to create a Phar archive of Predis,
// the Phar module must be loaded and the "phar.readonly" directive php.ini must
// be set to "off". You can change the values in the $options array to customize
// the creation of the Phar archive to better suit your needs.
// -------------------------------------------------------------------------- //
$options = array(
'name' => 'predis',
'project_path' => __DIR__ . '/../src',
'compression' => Phar::NONE,
'append_version' => true,
);
function getPharFilename($options)
{
$filename = $options['name'];
// NOTE: do not consider "append_version" with Phar compression do to a bug in
// Phar::compress() when renaming phar archives containing dots in their name.
if ($options['append_version'] && $options['compression'] === Phar::NONE) {
$versionFile = @fopen(__DIR__ . '/../VERSION', 'r');
if ($versionFile === false) {
throw new Exception("Could not locate the VERSION file.");
}
$version = trim(fgets($versionFile));
fclose($versionFile);
$filename .= "_$version";
}
return "$filename.phar";
}
function getPharStub($options)
{
return <<<EOSTUB
<?php
Phar::mapPhar('predis.phar');
spl_autoload_register(function (\$class) {
if (strpos(\$class, 'Predis\\\\') === 0) {
\$file = 'phar://predis.phar/'.strtr(substr(\$class, 7), '\\\', '/').'.php';
if (file_exists(\$file)) {
require \$file;
return true;
}
}
});
__halt_compiler();
EOSTUB;
}
// -------------------------------------------------------------------------- //
$phar = new Phar(getPharFilename($options));
$phar->compress($options['compression']);
$phar->setStub(getPharStub($options));
$phar->buildFromDirectory($options['project_path']);
+662
View File
@@ -0,0 +1,662 @@
#!/usr/bin/env php
<?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.
*/
// -------------------------------------------------------------------------- //
// This script can be used to automatically glue all the .php files of Predis
// into a single monolithic script file that can be used without an autoloader,
// just like the other previous versions of the library.
//
// Much of its complexity is due to the fact that we cannot simply join PHP
// files, but namespaces and classes definitions must follow a precise order
// when dealing with subclassing and inheritance.
//
// The current implementation is pretty naïve, but it should do for now.
// -------------------------------------------------------------------------- //
class CommandLine
{
public static function getOptions()
{
$parameters = array(
's:' => 'source:',
'o:' => 'output:',
'e:' => 'exclude:',
'E:' => 'exclude-classes:',
);
$getops = getopt(implode(array_keys($parameters)), $parameters);
$options = array(
'source' => __DIR__ . "/../src",
'output' => PredisFile::NS_ROOT . '.php',
'exclude' => array(),
);
foreach ($getops as $option => $value) {
switch ($option) {
case 's':
case 'source':
$options['source'] = $value;
break;
case 'o':
case 'output':
$options['output'] = $value;
break;
case 'E':
case 'exclude-classes':
$options['exclude'] = @file($value, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: $value;
break;
case 'e':
case 'exclude':
$options['exclude'] = is_array($value) ? $value : array($value);
break;
}
}
return $options;
}
}
class PredisFile
{
const NS_ROOT = 'Predis';
private $namespaces;
public function __construct()
{
$this->namespaces = array();
}
public static function from($libraryPath, array $exclude = array())
{
$predisFile = new PredisFile();
$libIterator = new RecursiveDirectoryIterator($libraryPath);
foreach (new RecursiveIteratorIterator($libIterator) as $classFile)
{
if (!$classFile->isFile()) {
continue;
}
$namespace = self::NS_ROOT.strtr(str_replace($libraryPath, '', $classFile->getPath()), '/', '\\');
if (in_array(sprintf('%s\\%s', $namespace, $classFile->getBasename('.php')), $exclude)) {
continue;
}
$phpNamespace = $predisFile->getNamespace($namespace);
if ($phpNamespace === false) {
$phpNamespace = new PhpNamespace($namespace);
$predisFile->addNamespace($phpNamespace);
}
$phpClass = new PhpClass($phpNamespace, $classFile);
}
return $predisFile;
}
public function addNamespace(PhpNamespace $namespace)
{
if (isset($this->namespaces[(string)$namespace])) {
throw new InvalidArgumentException("Duplicated namespace");
}
$this->namespaces[(string)$namespace] = $namespace;
}
public function getNamespaces()
{
return $this->namespaces;
}
public function getNamespace($namespace)
{
if (!isset($this->namespaces[$namespace])) {
return false;
}
return $this->namespaces[$namespace];
}
public function getClassByFQN($classFqn)
{
if (($nsLastPos = strrpos($classFqn, '\\')) !== false) {
$namespace = $this->getNamespace(substr($classFqn, 0, $nsLastPos));
if ($namespace === false) {
return null;
}
$className = substr($classFqn, $nsLastPos + 1);
return $namespace->getClass($className);
}
return null;
}
private function calculateDependencyScores(&$classes, $fqn)
{
if (!isset($classes[$fqn])) {
$classes[$fqn] = 0;
}
$classes[$fqn] += 1;
if (($phpClass = $this->getClassByFQN($fqn)) === null) {
throw new RuntimeException(
"Cannot found the class $fqn which is required by other subclasses. Are you missing a file?"
);
}
foreach ($phpClass->getDependencies() as $fqn) {
$this->calculateDependencyScores($classes, $fqn);
}
}
private function getDependencyScores()
{
$classes = array();
foreach ($this->getNamespaces() as $phpNamespace) {
foreach ($phpNamespace->getClasses() as $phpClass) {
$this->calculateDependencyScores($classes, $phpClass->getFQN());
}
}
return $classes;
}
private function getOrderedNamespaces($dependencyScores)
{
$namespaces = array_fill_keys(array_unique(
array_map(
function ($fqn) { return PhpNamespace::extractName($fqn); },
array_keys($dependencyScores)
)
), 0);
foreach ($dependencyScores as $classFqn => $score) {
$namespaces[PhpNamespace::extractName($classFqn)] += $score;
}
arsort($namespaces);
return array_keys($namespaces);
}
private function getOrderedClasses(PhpNamespace $phpNamespace, $classes)
{
$nsClassesFQNs = array_map(function ($cl) { return $cl->getFQN(); }, $phpNamespace->getClasses());
$nsOrderedClasses = array();
foreach ($nsClassesFQNs as $nsClassFQN) {
$nsOrderedClasses[$nsClassFQN] = $classes[$nsClassFQN];
}
arsort($nsOrderedClasses);
return array_keys($nsOrderedClasses);
}
public function getPhpCode()
{
$buffer = array("<?php\n\n", PhpClass::LICENSE_HEADER, "\n\n");
$classes = $this->getDependencyScores();
$namespaces = $this->getOrderedNamespaces($classes);
foreach ($namespaces as $namespace) {
$phpNamespace = $this->getNamespace($namespace);
// generate namespace directive
$buffer[] = $phpNamespace->getPhpCode();
$buffer[] = "\n";
// generate use directives
$useDirectives = $phpNamespace->getUseDirectives();
if (count($useDirectives) > 0) {
$buffer[] = $useDirectives->getPhpCode();
$buffer[] = "\n";
}
// generate classes bodies
$nsClasses = $this->getOrderedClasses($phpNamespace, $classes);
foreach ($nsClasses as $classFQN) {
$buffer[] = $this->getClassByFQN($classFQN)->getPhpCode();
$buffer[] = "\n\n";
}
$buffer[] = "/* " . str_repeat("-", 75) . " */";
$buffer[] = "\n\n";
}
return implode($buffer);
}
public function saveTo($outputFile)
{
// TODO: add more sanity checks
if ($outputFile === null || $outputFile === '') {
throw new InvalidArgumentException('You must specify a valid output file');
}
file_put_contents($outputFile, $this->getPhpCode());
}
}
class PhpNamespace implements IteratorAggregate
{
private $namespace;
private $classes;
public function __construct($namespace)
{
$this->namespace = $namespace;
$this->classes = array();
$this->useDirectives = new PhpUseDirectives($this);
}
public static function extractName($fqn)
{
$nsSepLast = strrpos($fqn, '\\');
if ($nsSepLast === false) {
return $fqn;
}
$ns = substr($fqn, 0, $nsSepLast);
return $ns !== '' ? $ns : null;
}
public function addClass(PhpClass $class)
{
$this->classes[$class->getName()] = $class;
}
public function getClass($className)
{
if (isset($this->classes[$className])) {
return $this->classes[$className];
}
}
public function getClasses()
{
return array_values($this->classes);
}
public function getIterator()
{
return new \ArrayIterator($this->getClasses());
}
public function getUseDirectives()
{
return $this->useDirectives;
}
public function getPhpCode()
{
return "namespace $this->namespace;\n";
}
public function __toString()
{
return $this->namespace;
}
}
class PhpUseDirectives implements Countable, IteratorAggregate
{
private $use;
private $aliases;
private $reverseAliases;
private $namespace;
public function __construct(PhpNamespace $namespace)
{
$this->namespace = $namespace;
$this->use = array();
$this->aliases = array();
$this->reverseAliases = array();
}
public function add($use, $as = null)
{
if (in_array($use, $this->use)) {
return;
}
$rename = null;
$this->use[] = $use;
$aliasedClassName = $as ?: PhpClass::extractName($use);
if (isset($this->aliases[$aliasedClassName])) {
$parentNs = $this->getParentNamespace();
if ($parentNs && false !== $pos = strrpos($parentNs, '\\')) {
$parentNs = substr($parentNs, $pos);
}
$newAlias = "{$parentNs}_{$aliasedClassName}";
$rename = (object) array(
'namespace' => $this->namespace,
'from' => $aliasedClassName,
'to' => $newAlias,
);
$this->aliases[$newAlias] = $use;
$as = $newAlias;
} else {
$this->aliases[$aliasedClassName] = $use;
}
if ($as !== null) {
$this->reverseAliases[$use] = $as;
}
return $rename;
}
public function getList()
{
return $this->use;
}
public function getIterator()
{
return new \ArrayIterator($this->getList());
}
public function getPhpCode()
{
$reverseAliases = $this->reverseAliases;
$reducer = function ($str, $use) use ($reverseAliases) {
if (isset($reverseAliases[$use])) {
return $str .= "use $use as {$reverseAliases[$use]};\n";
} else {
return $str .= "use $use;\n";
}
};
return array_reduce($this->getList(), $reducer, '');
}
public function getNamespace()
{
return $this->namespace;
}
public function getParentNamespace()
{
if (false !== $pos = strrpos($this->namespace, '\\')) {
return substr($this->namespace, 0, $pos);
}
return '';
}
public function getFQN($className)
{
if (($nsSepFirst = strpos($className, '\\')) === false) {
if (isset($this->aliases[$className])) {
return $this->aliases[$className];
}
return (string)$this->getNamespace() . "\\$className";
}
if ($nsSepFirst != 0) {
throw new InvalidArgumentException("Partially qualified names are not supported");
}
return $className;
}
public function count()
{
return count($this->use);
}
}
class PhpClass
{
const LICENSE_HEADER = <<<LICENSE
/*
* 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.
*/
LICENSE;
private $namespace;
private $file;
private $body;
private $implements;
private $extends;
private $name;
public function __construct(PhpNamespace $namespace, SplFileInfo $classFile)
{
$this->namespace = $namespace;
$this->file = $classFile;
$this->implements = array();
$this->extends = array();
$this->extractData();
$namespace->addClass($this);
}
public static function extractName($fqn)
{
$nsSepLast = strrpos($fqn, '\\');
if ($nsSepLast === false) {
return $fqn;
}
return substr($fqn, $nsSepLast + 1);
}
private function extractData()
{
$renames = array();
$useDirectives = $this->getNamespace()->getUseDirectives();
$useExtractor = function ($m) use ($useDirectives, &$renames) {
array_shift($m);
if (isset($m[1])) {
$m[1] = str_replace(" as ", '', $m[1]);
}
if ($rename = call_user_func_array(array($useDirectives, 'add'), $m)) {
$renames[] = $rename;
}
};
$classBuffer = stream_get_contents(fopen($this->getFile()->getPathname(), 'r'));
$classBuffer = str_replace(self::LICENSE_HEADER, '', $classBuffer);
$classBuffer = preg_replace('/<\?php\s?\\n\s?/', '', $classBuffer);
$classBuffer = preg_replace('/\s?\?>\n?/ms', '', $classBuffer);
$classBuffer = preg_replace('/namespace\s+[\w\d_\\\\]+;\s?/', '', $classBuffer);
$classBuffer = preg_replace_callback('/use\s+([\w\d_\\\\]+)(\s+as\s+.*)?;\s?\n?/', $useExtractor, $classBuffer);
foreach ($renames as $rename) {
$classBuffer = str_replace($rename->from, $rename->to, $classBuffer);
}
$this->body = trim($classBuffer);
$this->extractHierarchy();
}
private function extractHierarchy()
{
$implements = array();
$extends = array();
$extractor = function ($iterator, $callback) {
$className = '';
$iterator->seek($iterator->key() + 1);
while ($iterator->valid()) {
$token = $iterator->current();
if (is_string($token)) {
if (preg_match('/\s?,\s?/', $token)) {
$callback(trim($className));
$className = '';
} else if ($token == '{') {
$callback(trim($className));
return;
}
}
switch ($token[0]) {
case T_NS_SEPARATOR:
$className .= '\\';
break;
case T_STRING:
$className .= $token[1];
break;
case T_IMPLEMENTS:
case T_EXTENDS:
$callback(trim($className));
$iterator->seek($iterator->key() - 1);
return;
}
$iterator->next();
}
};
$tokens = token_get_all("<?php\n" . trim($this->getPhpCode()));
$iterator = new ArrayIterator($tokens);
while ($iterator->valid()) {
$token = $iterator->current();
if (is_string($token)) {
$iterator->next();
continue;
}
switch ($token[0]) {
case T_CLASS:
case T_INTERFACE:
$iterator->seek($iterator->key() + 2);
$tk = $iterator->current();
$this->name = $tk[1];
break;
case T_IMPLEMENTS:
$extractor($iterator, function ($fqn) use (&$implements) {
$implements[] = $fqn;
});
break;
case T_EXTENDS:
$extractor($iterator, function ($fqn) use (&$extends) {
$extends[] = $fqn;
});
break;
}
$iterator->next();
}
$this->implements = $this->guessFQN($implements);
$this->extends = $this->guessFQN($extends);
}
public function guessFQN($classes)
{
$useDirectives = $this->getNamespace()->getUseDirectives();
return array_map(array($useDirectives, 'getFQN'), $classes);
}
public function getImplementedInterfaces($all = false)
{
if ($all) {
return $this->implements;
}
return array_filter(
$this->implements,
function ($cn) { return strpos($cn, 'Predis\\') === 0; }
);
}
public function getExtendedClasses($all = false)
{
if ($all) {
return $this->extemds;
}
return array_filter(
$this->extends,
function ($cn) { return strpos($cn, 'Predis\\') === 0; }
);
}
public function getDependencies($all = false)
{
return array_merge(
$this->getImplementedInterfaces($all),
$this->getExtendedClasses($all)
);
}
public function getNamespace()
{
return $this->namespace;
}
public function getFile()
{
return $this->file;
}
public function getName()
{
return $this->name;
}
public function getFQN()
{
return (string)$this->getNamespace() . '\\' . $this->name;
}
public function getPhpCode()
{
return $this->body;
}
public function __toString()
{
return "class " . $this->getName() . '{ ... }';
}
}
/* -------------------------------------------------------------------------- */
$options = CommandLine::getOptions();
$predisFile = PredisFile::from($options['source'], $options['exclude']);
$predisFile->saveTo($options['output']);
+5 -7
View File
@@ -1,7 +1,7 @@
{
"name": "predis/predis",
"type": "library",
"description": "A flexible and feature-complete Redis client for PHP.",
"description": "Flexible and feature-complete Redis client for PHP and HHVM",
"keywords": ["nosql", "redis", "predis"],
"homepage": "http://github.com/predis/predis",
"license": "MIT",
@@ -28,10 +28,10 @@
}
],
"require": {
"php": "^7.2 || ^8.0"
"php": ">=5.3.9"
},
"require-dev": {
"phpunit/phpunit": "^8.0 || ~9.4.4"
"phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol",
@@ -42,9 +42,7 @@
"Predis\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-main": "2.0-dev"
}
"scripts": {
"post-update-cmd": "@php -f tests/apply-patches.php"
}
}
+3 -3
View File
@@ -18,7 +18,7 @@ require __DIR__.'/shared.php';
use Predis\Cluster\Distributor\DistributorInterface;
use Predis\Cluster\Hash\HashGeneratorInterface;
use Predis\Cluster\PredisStrategy;
use Predis\Connection\Cluster\PredisCluster;
use Predis\Connection\Aggregate\PredisCluster;
class NaiveDistributor implements DistributorInterface, HashGeneratorInterface
{
@@ -104,8 +104,8 @@ for ($i = 0; $i < 100; ++$i) {
$client->get("key:$i");
}
$server1 = $client->getClientBy('alias', 'first')->info();
$server2 = $client->getClientBy('alias', 'second')->info();
$server1 = $client->getClientFor('first')->info();
$server2 = $client->getClientFor('second')->info();
if (isset($server1['Keyspace'], $server2['Keyspace'])) {
$server1 = $server1['Keyspace'];
+2 -2
View File
@@ -51,7 +51,7 @@ class EventsListener implements Countable
return $this->events;
}
public function __invoke($payload, $dispatcher)
public function __invoke($payload)
{
$this->events[] = $payload;
}
@@ -61,7 +61,7 @@ class EventsListener implements Countable
$dispatcher->attachCallback('events', ($events = new EventsListener()));
// Attach a function to control the dispatcher loop termination with a message.
$dispatcher->attachCallback('control', function ($payload, $dispatcher) {
$dispatcher->attachCallback('control', function ($payload) use ($dispatcher) {
if ($payload === 'terminate_dispatcher') {
$dispatcher->stop();
}
+11 -7
View File
@@ -13,10 +13,11 @@ require __DIR__.'/shared.php';
// This example will not work with versions of Redis < 2.6.
//
// Additionally to the EVAL command, the Predis\Command\ScriptCommand class can
// be used to leverage an higher level abstraction for Lua scripting that makes
// scripts appear just like any other command on the client-side. This is basic
// example on how a script-based INCREX command can be defined:
// Additionally to the EVAL command defined in the current development profile,
// the Predis\Command\ScriptCommand class can be used to build an higher level
// abstraction for "scriptable" commands so that they will appear just like any
// other command on the client-side. This is a quick example used to implement
// INCREX.
use Predis\Command\ScriptCommand;
@@ -49,9 +50,12 @@ LUA;
}
$client = new Predis\Client($single_server, array(
'commands' => array(
'increxby' => 'IncrementExistingKeysBy',
),
'profile' => function ($options) {
$profile = $options->getDefault('profile');
$profile->defineCommand('increxby', 'IncrementExistingKeysBy');
return $profile;
},
));
$client->mset('foo', 10, 'foobar', 100);
+3 -2
View File
@@ -13,7 +13,7 @@ require __DIR__.'/shared.php';
use Predis\Collection\Iterator;
// Starting with Redis 2.8, clients can iterate incrementally over collections
// Starting from Redis 2.8, clients can iterate incrementally over collections
// without blocking the server like it happens when a command such as KEYS is
// executed on a Redis instance storing millions of keys. These commands are:
//
@@ -29,7 +29,8 @@ use Predis\Collection\Iterator;
// See http://redis.io/commands/scan for more details.
//
$client = new Predis\Client($single_server);
// Create a client using `2.8` as a server profile (needs Redis 2.8!)
$client = new Predis\Client($single_server, array('profile' => '2.8'));
// Prepare some keys for our example
$client->del('predis:set', 'predis:zset', 'predis:hash');
+13 -10
View File
@@ -14,12 +14,12 @@ require __DIR__.'/shared.php';
// Predis allows to set Lua scripts as read-only operations for replication.
// This works for both EVAL and EVALSHA and also for the client-side abstraction
// built upon them (Predis\Command\ScriptCommand). This example shows a slightly
// more complex configuration that injects a new script command in the command
// factory used by the client and marks it as a read-only operation so that it
// will be executed on slaves.
// more complex configuration that injects a new script command in the server
// profile used by the new client instance and marks it marks it as a read-only
// operation for replication so that it will be executed on slaves.
use Predis\Command\ScriptCommand;
use Predis\Connection\Replication\MasterSlaveReplication;
use Predis\Connection\Aggregate\MasterSlaveReplication;
use Predis\Replication\ReplicationStrategy;
// ------------------------------------------------------------------------- //
@@ -47,14 +47,17 @@ LUA;
// ------------------------------------------------------------------------- //
$parameters = array(
'tcp://127.0.0.1:6381?role=master&database=15',
'tcp://127.0.0.1:6382?role=slave&alias=slave-01&database=15',
'tcp://127.0.0.1:6379/?alias=master',
'tcp://127.0.0.1:6380/?alias=slave',
);
$options = array(
'commands' => array(
'hmgetall' => 'HashMultipleGetAll',
),
'profile' => function ($options, $option) {
$profile = $options->getDefault($option);
$profile->defineCommand('hmgetall', 'HashMultipleGetAll');
return $profile;
},
'replication' => function () {
$strategy = new ReplicationStrategy();
$strategy->setScriptReadOnly(HashMultipleGetAll::BODY);
@@ -76,7 +79,7 @@ $client = new Predis\Client($parameters, $options);
$hashes = $client->hmgetall('metavars', 'servers');
$replication = $client->getConnection();
$stillOnSlave = $replication->getCurrent() === $replication->getConnectionByAlias('slave-01');
$stillOnSlave = $replication->getCurrent() === $replication->getConnectionById('slave');
echo 'Is still on slave? ', $stillOnSlave ? 'YES!' : 'NO!', PHP_EOL;
var_export($hashes);
+3 -3
View File
@@ -39,17 +39,17 @@ $client = new Predis\Client($sentinels, array(
// Read operation.
$exists = $client->exists('foo') ? 'yes' : 'no';
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Does 'foo' exist on {$current->role}? $exists.", PHP_EOL;
echo "Does 'foo' exist on {$current->alias}? $exists.", PHP_EOL;
// Write operation.
$client->set('foo', 'bar');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Now 'foo' has been set to 'bar' on {$current->role}!", PHP_EOL;
echo "Now 'foo' has been set to 'bar' on {$current->alias}!", PHP_EOL;
// Read operation.
$bar = $client->get('foo');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "We fetched 'foo' from {$current->role} and its value is '$bar'.", PHP_EOL;
echo "We fetched 'foo' from {$current->alias} and its value is '$bar'.", PHP_EOL;
/* OUTPUT:
Does 'foo' exist on slave-127.0.0.1:6381? yes.
+6 -6
View File
@@ -22,28 +22,28 @@ require __DIR__.'/shared.php';
//
$parameters = array(
'tcp://127.0.0.1:6381?role=master&database=15',
'tcp://127.0.0.1:6382?role=slave&database=15',
'tcp://127.0.0.1:6379?database=15&alias=master',
'tcp://127.0.0.1:6380?database=15&alias=slave',
);
$options = array('replication' => 'predis');
$options = array('replication' => true);
$client = new Predis\Client($parameters, $options);
// Read operation.
$exists = $client->exists('foo') ? 'yes' : 'no';
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Does 'foo' exist on {$current->role}? $exists.", PHP_EOL;
echo "Does 'foo' exist on {$current->alias}? $exists.", PHP_EOL;
// Write operation.
$client->set('foo', 'bar');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "Now 'foo' has been set to 'bar' on {$current->role}!", PHP_EOL;
echo "Now 'foo' has been set to 'bar' on {$current->alias}!", PHP_EOL;
// Read operation.
$bar = $client->get('foo');
$current = $client->getConnection()->getCurrent()->getParameters();
echo "We fetched 'foo' from {$current->role} and its value is '$bar'.", PHP_EOL;
echo "We fetched 'foo' from {$current->alias} and its value is '$bar'.", PHP_EOL;
/* OUTPUT:
Does 'foo' exist on slave? yes.
+36
View File
@@ -0,0 +1,36 @@
; This file is meant to be used with Onion http://c9s.github.com/Onion/
; For instructions on how to build a PEAR package of Predis please follow
; the instructions at this URL:
;
; https://github.com/c9s/Onion#a-quick-tutorial-for-building-pear-package
;
[package]
name = "Predis"
desc = "Flexible and feature-complete Redis client for PHP and HHVM"
homepage = "http://github.com/nrk/predis"
license = "MIT"
version = "1.1.11"
stability = "devel"
channel = "pear.nrk.io"
author = "Daniele Alessandri \"nrk\" <suppakilla@gmail.com>"
[require]
php = ">= 5.3.9"
pearinstaller = "1.4.1"
[roles]
*.xml.dist = test
*.md = doc
LICENSE = doc
[optional phpiredis]
hint = "Add support for faster protocol handling with phpiredis"
extensions[] = socket
extensions[] = phpiredis
[optional webdis]
hint = "Add support for Webdis"
extensions[] = curl
extensions[] = phpiredis
+3
View File
@@ -8,6 +8,8 @@
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
syntaxCheck="true"
beStrictAboutTestSize="true"
beStrictAboutTestsThatDoNotTestAnything="true">
<testsuites>
@@ -36,6 +38,7 @@
<php>
<!-- Redis -->
<const name="REDIS_SERVER_VERSION" value="3.2" />
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_SERVER_DBNUM" value="15" />
+50
View File
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
syntaxCheck="true"
beStrictAboutTestSize="true"
beStrictAboutTestsThatDoNotTestAnything="true">
<testsuites>
<testsuite name="Predis Test Suite">
<directory>tests/Predis/</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>ext-phpiredis</group>
<group>ext-curl</group>
<group>realm-webdis</group>
<!-- <group>connected</group> -->
<!-- <group>disconnected</group> -->
<!-- <group>commands</group> -->
<!-- <group>slow</group> -->
</exclude>
</groups>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<php>
<!-- Redis -->
<const name="REDIS_SERVER_VERSION" value="3.2" />
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
<const name="REDIS_SERVER_PORT" value="6379" />
<const name="REDIS_SERVER_DBNUM" value="15" />
<!-- Webdis -->
<const name="WEBDIS_SERVER_HOST" value="127.0.0.1" />
<const name="WEBDIS_SERVER_PORT" value="7379" />
</php>
</phpunit>
-1
View File
@@ -16,7 +16,6 @@ namespace Predis;
*
* @author Eric Naeseth <eric@thumbtack.com>
* @author Daniele Alessandri <suppakilla@gmail.com>
* @codeCoverageIgnore
*/
class Autoloader
{
+120 -104
View File
@@ -16,8 +16,8 @@ use Predis\Command\RawCommand;
use Predis\Command\ScriptCommand;
use Predis\Configuration\Options;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\AggregateConnectionInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Connection\Parameters;
use Predis\Connection\ParametersInterface;
use Predis\Monitor\Consumer as MonitorConsumer;
use Predis\Pipeline\Pipeline;
@@ -40,16 +40,11 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
*/
class Client implements ClientInterface, \IteratorAggregate
{
const VERSION = '2.0.2';
const VERSION = '1.1.11-dev';
/** @var OptionsInterface */
private $options;
/** @var ConnectionInterface */
private $connection;
/** @var Command\FactoryInterface */
private $commands;
protected $connection;
protected $options;
private $profile;
/**
* @param mixed $parameters Connection parameters for one or more servers.
@@ -57,101 +52,131 @@ class Client implements ClientInterface, \IteratorAggregate
*/
public function __construct($parameters = null, $options = null)
{
$this->options = static::createOptions($options ?? new Options);
$this->connection = static::createConnection($this->options, $parameters ?? new Parameters);
$this->commands = $this->options->commands;
$this->options = $this->createOptions($options ?: array());
$this->connection = $this->createConnection($parameters ?: array());
$this->profile = $this->options->profile;
}
/**
* Creates a new set of client options for the client.
* Creates a new instance of Predis\Configuration\Options from different
* types of arguments or simply returns the passed argument if it is an
* instance of Predis\Configuration\OptionsInterface.
*
* @param array|OptionsInterface $options Set of client options
* @param mixed $options Client options.
*
* @throws \InvalidArgumentException
*
* @return OptionsInterface
*/
protected static function createOptions($options)
protected function createOptions($options)
{
if (is_array($options)) {
return new Options($options);
} elseif ($options instanceof OptionsInterface) {
return $options;
} else {
throw new \InvalidArgumentException('Invalid type for client options');
}
if ($options instanceof OptionsInterface) {
return $options;
}
throw new \InvalidArgumentException('Invalid type for client options.');
}
/**
* Creates single or aggregate connections from supplied arguments.
* Creates single or aggregate connections from different types of arguments
* (string, array) or returns the passed argument if it is an instance of a
* class implementing Predis\Connection\ConnectionInterface.
*
* This method accepts the following types to create a connection instance:
* Accepted types for connection parameters are:
*
* - Array (dictionary: single connection, indexed: aggregate connections)
* - String (URI for a single connection)
* - Callable (connection initializer callback)
* - Instance of Predis\Connection\ParametersInterface (used as-is)
* - Instance of Predis\Connection\ConnectionInterface (returned as-is)
* - Instance of Predis\Connection\ConnectionInterface.
* - Instance of Predis\Connection\ParametersInterface.
* - Array
* - String
* - Callable
*
* When a callable is passed, it receives the original set of client options
* and must return an instance of Predis\Connection\ConnectionInterface.
*
* Connections are created using the connection factory (in case of single
* connections) or a specialized aggregate connection initializer (in case
* of cluster and replication) retrieved from the supplied client options.
*
* @param OptionsInterface $options Client options container
* @param mixed $parameters Connection parameters
* @param mixed $parameters Connection parameters or connection instance.
*
* @throws \InvalidArgumentException
*
* @return ConnectionInterface
*/
protected static function createConnection(OptionsInterface $options, $parameters)
protected function createConnection($parameters)
{
if ($parameters instanceof ConnectionInterface) {
return $parameters;
}
if ($parameters instanceof ParametersInterface || is_string($parameters)) {
return $options->connections->create($parameters);
return $this->options->connections->create($parameters);
}
if (is_array($parameters)) {
if (!isset($parameters[0])) {
return $options->connections->create($parameters);
} elseif ($options->defined('cluster') && $initializer = $options->cluster) {
return $initializer($parameters, true);
} elseif ($options->defined('replication') && $initializer = $options->replication) {
return $initializer($parameters, true);
} elseif ($options->defined('aggregate') && $initializer = $options->aggregate) {
return $initializer($parameters, false);
} else {
throw new \InvalidArgumentException(
'Array of connection parameters requires `cluster`, `replication` or `aggregate` client option'
);
return $this->options->connections->create($parameters);
}
}
if (is_callable($parameters)) {
$connection = call_user_func($parameters, $options);
$options = $this->options;
if (!$connection instanceof ConnectionInterface) {
throw new \InvalidArgumentException('Callable parameters must return a valid connection');
if ($options->defined('aggregate')) {
$initializer = $this->getConnectionInitializerWrapper($options->aggregate);
$connection = $initializer($parameters, $options);
} elseif ($options->defined('replication')) {
$replication = $options->replication;
if ($replication instanceof AggregateConnectionInterface) {
$connection = $replication;
$options->connections->aggregate($connection, $parameters);
} else {
$initializer = $this->getConnectionInitializerWrapper($replication);
$connection = $initializer($parameters, $options);
}
} else {
$connection = $options->cluster;
$options->connections->aggregate($connection, $parameters);
}
return $connection;
}
throw new \InvalidArgumentException('Invalid type for connection parameters');
if (is_callable($parameters)) {
$initializer = $this->getConnectionInitializerWrapper($parameters);
$connection = $initializer($this->options);
return $connection;
}
throw new \InvalidArgumentException('Invalid type for connection parameters.');
}
/**
* Wraps a callable to make sure that its returned value represents a valid
* connection type.
*
* @param mixed $callable
*
* @return \Closure
*/
protected function getConnectionInitializerWrapper($callable)
{
return function () use ($callable) {
$connection = call_user_func_array($callable, func_get_args());
if (!$connection instanceof ConnectionInterface) {
throw new \UnexpectedValueException(
'The callable connection initializer returned an invalid type.'
);
}
return $connection;
};
}
/**
* {@inheritdoc}
*/
public function getCommandFactory()
public function getProfile()
{
return $this->commands;
return $this->profile;
}
/**
@@ -163,53 +188,23 @@ class Client implements ClientInterface, \IteratorAggregate
}
/**
* Creates a new client using a specific underlying connection.
* Creates a new client instance for the specified connection ID or alias,
* only when working with an aggregate connection (cluster, replication).
* The new client instances uses the same options of the original one.
*
* This method allows to create a new client instance by picking a specific
* connection out of an aggregate one, with the same options of the original
* client instance.
* @param string $connectionID Identifier of a connection.
*
* The specified selector defines which logic to use to look for a suitable
* connection by the specified value. Supported selectors are:
* @throws \InvalidArgumentException
*
* - `id`
* - `key`
* - `slot`
* - `command`
* - `alias`
* - `role`
*
* Internally the client relies on duck-typing and follows this convention:
*
* $selector string => getConnectionBy$selector($value) method
*
* This means that support for specific selectors may vary depending on the
* actual logic implemented by connection classes and there is no interface
* binding a connection class to implement any of these.
*
* @param string $selector Type of selector.
* @param mixed $value Value to be used by the selector.
*
* @return ClientInterface
* @return Client
*/
public function getClientBy($selector, $value)
public function getClientFor($connectionID)
{
$selector = strtolower($selector);
if (!in_array($selector, array('id', 'key', 'slot', 'role', 'alias', 'command'))) {
throw new \InvalidArgumentException("Invalid selector type: `$selector`");
if (!$connection = $this->getConnectionById($connectionID)) {
throw new \InvalidArgumentException("Invalid connection ID: $connectionID.");
}
if (!method_exists($this->connection, $method = "getConnectionBy$selector")) {
$class = get_class($this->connection);
throw new \InvalidArgumentException("Selecting connection by $selector is not supported by $class");
}
if (!$connection = $this->connection->$method($value)) {
throw new \InvalidArgumentException("Cannot find a connection by $selector matching `$value`");
}
return new static($connection, $this->getOptions());
return new static($connection, $this->options);
}
/**
@@ -257,6 +252,27 @@ class Client implements ClientInterface, \IteratorAggregate
return $this->connection;
}
/**
* Retrieves the specified connection from the aggregate connection when the
* client is in cluster or replication mode.
*
* @param string $connectionID Index or alias of the single connection.
*
* @throws NotSupportedException
*
* @return Connection\NodeConnectionInterface
*/
public function getConnectionById($connectionID)
{
if (!$this->connection instanceof AggregateConnectionInterface) {
throw new NotSupportedException(
'Retrieving connections by ID is supported only by aggregate connections.'
);
}
return $this->connection->getConnectionById($connectionID);
}
/**
* Executes a command without filtering its arguments, parsing the response,
* applying any prefix to keys or throwing exceptions on Redis errors even
@@ -273,10 +289,9 @@ class Client implements ClientInterface, \IteratorAggregate
public function executeRaw(array $arguments, &$error = null)
{
$error = false;
$commandID = array_shift($arguments);
$response = $this->connection->executeCommand(
new RawCommand($commandID, $arguments)
new RawCommand($arguments)
);
if ($response instanceof ResponseInterface) {
@@ -305,7 +320,7 @@ class Client implements ClientInterface, \IteratorAggregate
*/
public function createCommand($commandID, $arguments = array())
{
return $this->commands->create($commandID, $arguments);
return $this->profile->createCommand($commandID, $arguments);
}
/**
@@ -339,7 +354,10 @@ class Client implements ClientInterface, \IteratorAggregate
protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $response)
{
if ($command instanceof ScriptCommand && $response->getErrorType() === 'NOSCRIPT') {
$response = $this->executeCommand($command->getEvalCommand());
$eval = $this->createCommand('EVAL');
$eval->setRawArguments($command->getEvalArguments());
$response = $this->executeCommand($eval);
if (!$response instanceof ResponseInterface) {
$response = $command->parseResponse($response);
@@ -382,11 +400,9 @@ class Client implements ClientInterface, \IteratorAggregate
return $this->$initializer($arg0, $arg1);
// @codeCoverageIgnoreStart
default:
return $this->$initializer($this, $argv);
}
// @codeCoverageIgnoreEnd
}
/**
@@ -511,7 +527,7 @@ class Client implements ClientInterface, \IteratorAggregate
}
/**
* {@inheritdoc}
* @return \Traversable<string, static>
*/
#[\ReturnTypeWillChange]
public function getIterator()
+152 -156
View File
@@ -12,10 +12,9 @@
namespace Predis;
use Predis\Command\CommandInterface;
use Predis\Command\FactoryInterface;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Response\Status;
use Predis\Profile\ProfileInterface;
/**
* Interface defining a client able to execute commands against Redis.
@@ -25,168 +24,165 @@ use Predis\Response\Status;
* and more friendly interface to ease programming which is described in the
* following list of methods:
*
* @method int del(string[]|string $keyOrKeys, string ...$keys = null)
* @method string|null dump(string $key)
* @method int exists(string $key)
* @method int expire(string $key, int $seconds)
* @method int expireat(string $key, int $timestamp)
* @method array keys(string $pattern)
* @method int move(string $key, int $db)
* @method mixed object($subcommand, string $key)
* @method int persist(string $key)
* @method int pexpire(string $key, int $milliseconds)
* @method int pexpireat(string $key, int $timestamp)
* @method int pttl(string $key)
* @method string|null randomkey()
* @method mixed rename(string $key, string $target)
* @method int renamenx(string $key, string $target)
* @method array scan($cursor, array $options = null)
* @method array sort(string $key, array $options = null)
* @method int ttl(string $key)
* @method mixed type(string $key)
* @method int append(string $key, $value)
* @method int bitcount(string $key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array|null bitfield(string $key, $subcommand, ...$subcommandArg)
* @method int bitpos(string $key, $bit, $start = null, $end = null)
* @method int decr(string $key)
* @method int decrby(string $key, int $decrement)
* @method string|null get(string $key)
* @method int getbit(string $key, $offset)
* @method string getrange(string $key, $start, $end)
* @method string|null getset(string $key, $value)
* @method int incr(string $key)
* @method int incrby(string $key, int $increment)
* @method string incrbyfloat(string $key, int|float $increment)
* @method array mget(string[]|string $keyOrKeys, string ...$keys = null)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method Status psetex(string $key, $milliseconds, $value)
* @method Status set(string $key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit(string $key, $offset, $value)
* @method Status setex(string $key, $seconds, $value)
* @method int setnx(string $key, $value)
* @method int setrange(string $key, $offset, $value)
* @method int strlen(string $key)
* @method int hdel(string $key, array $fields)
* @method int hexists(string $key, string $field)
* @method string|null hget(string $key, string $field)
* @method array hgetall(string $key)
* @method int hincrby(string $key, string $field, int $increment)
* @method string hincrbyfloat(string $key, string $field, int|float $increment)
* @method array hkeys(string $key)
* @method int hlen(string $key)
* @method array hmget(string $key, array $fields)
* @method mixed hmset(string $key, array $dictionary)
* @method array hscan(string $key, $cursor, array $options = null)
* @method int hset(string $key, string $field, string $value)
* @method int hsetnx(string $key, string $field, string $value)
* @method array hvals(string $key)
* @method int hstrlen(string $key, string $field)
* @method array|null blpop(array|string $keys, int|float $timeout)
* @method array|null brpop(array|string $keys, int|float $timeout)
* @method string|null brpoplpush(string $source, string $destination, int|float $timeout)
* @method string|null lindex(string $key, int $index)
* @method int linsert(string $key, $whence, $pivot, $value)
* @method int llen(string $key)
* @method string|null lpop(string $key)
* @method int lpush(string $key, array $values)
* @method int lpushx(string $key, array $values)
* @method string[] lrange(string $key, int $start, int $stop)
* @method int lrem(string $key, int $count, string $value)
* @method mixed lset(string $key, int $index, string $value)
* @method mixed ltrim(string $key, int $start, int $stop)
* @method string|null rpop(string $key)
* @method string|null rpoplpush(string $source, string $destination)
* @method int rpush(string $key, array $values)
* @method int rpushx(string $key, array $values)
* @method int sadd(string $key, array $members)
* @method int scard(string $key)
* @method string[] sdiff(array|string $keys)
* @method int sdiffstore(string $destination, array|string $keys)
* @method string[] sinter(array|string $keys)
* @method int sinterstore(string $destination, array|string $keys)
* @method int sismember(string $key, string $member)
* @method string[] smembers(string $key)
* @method int smove(string $source, string $destination, string $member)
* @method string|array|null spop(string $key, int $count = null)
* @method string|null srandmember(string $key, int $count = null)
* @method int srem(string $key, array|string $member)
* @method array sscan(string $key, int $cursor, array $options = null)
* @method string[] sunion(array|string $keys)
* @method int sunionstore(string $destination, array|string $keys)
* @method int touch(string[]|string $keyOrKeys, string ...$keys = null)
* @method int zadd(string $key, array $membersAndScoresDictionary)
* @method int zcard(string $key)
* @method string zcount(string $key, int|string $min, int|string $max)
* @method string zincrby(string $key, int $increment, string $member)
* @method int zinterstore(string $destination, array|string $keys, array $options = null)
* @method array zpopmin(string $key, int $count = 1)
* @method array zpopmax(string $key, int $count = 1)
* @method array zrange(string $key, int|string $start, int|string $stop, array $options = null)
* @method array zrangebyscore(string $key, int|string $min, int|string $max, array $options = null)
* @method int|null zrank(string $key, string $member)
* @method int zrem(string $key, string ...$member)
* @method int zremrangebyrank(string $key, int|string $start, int|string $stop)
* @method int zremrangebyscore(string $key, int|string $min, int|string $max)
* @method array zrevrange(string $key, int|string $start, int|string $stop, array $options = null)
* @method array zrevrangebyscore(string $key, int|string $max, int|string $min, array $options = null)
* @method int|null zrevrank(string $key, string $member)
* @method int zunionstore(string $destination, array|string $keys, array $options = null)
* @method string|null zscore(string $key, string $member)
* @method array zscan(string $key, int $cursor, array $options = null)
* @method array zrangebylex(string $key, string $start, string $stop, array $options = null)
* @method array zrevrangebylex(string $key, string $start, string $stop, array $options = null)
* @method int zremrangebylex(string $key, string $min, string $max)
* @method int zlexcount(string $key, string $min, string $max)
* @method int pfadd(string $key, array $elements)
* @method mixed pfmerge(string $destinationKey, array|string $sourceKeys)
* @method int pfcount(string[]|string $keyOrKeys, string ...$keys = null)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array|null exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch(string $key)
* @method mixed eval(string $script, int $numkeys, string ...$keyOrArg = null)
* @method mixed evalsha(string $script, int $numkeys, string ...$keyOrArg = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth(string $password)
* @method string echo(string $message)
* @method mixed ping(string $message = null)
* @method mixed select(int $database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof(string $host, int $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd(string $key, $longitude, $latitude, $member)
* @method array geohash(string $key, array $members)
* @method array geopos(string $key, array $members)
* @method string|null geodist(string $key, $member1, $member2, $unit = null)
* @method array georadius(string $key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember(string $key, $member, $radius, $unit, array $options = null)
* @method int del(array|string $keys)
* @method string|null dump($key)
* @method int exists($key)
* @method int expire($key, $seconds)
* @method int expireat($key, $timestamp)
* @method array keys($pattern)
* @method int move($key, $db)
* @method mixed object($subcommand, $key)
* @method int persist($key)
* @method int pexpire($key, $milliseconds)
* @method int pexpireat($key, $timestamp)
* @method int pttl($key)
* @method string|null randomkey()
* @method mixed rename($key, $target)
* @method int renamenx($key, $target)
* @method array scan($cursor, array $options = null)
* @method array sort($key, array $options = null)
* @method int ttl($key)
* @method mixed type($key)
* @method int append($key, $value)
* @method int bitcount($key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array|null bitfield($key, $subcommand, ...$subcommandArg)
* @method int bitpos($key, $bit, $start = null, $end = null)
* @method int decr($key)
* @method int decrby($key, $decrement)
* @method string|null get($key)
* @method int getbit($key, $offset)
* @method string getrange($key, $start, $end)
* @method string|null getset($key, $value)
* @method int incr($key)
* @method int incrby($key, $increment)
* @method string incrbyfloat($key, $increment)
* @method array mget(array $keys)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method mixed psetex($key, $milliseconds, $value)
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit($key, $offset, $value)
* @method int setex($key, $seconds, $value)
* @method int setnx($key, $value)
* @method int setrange($key, $offset, $value)
* @method int strlen($key)
* @method int hdel($key, array $fields)
* @method int hexists($key, $field)
* @method string|null hget($key, $field)
* @method array hgetall($key)
* @method int hincrby($key, $field, $increment)
* @method string hincrbyfloat($key, $field, $increment)
* @method array hkeys($key)
* @method int hlen($key)
* @method array hmget($key, array $fields)
* @method mixed hmset($key, array $dictionary)
* @method array hscan($key, $cursor, array $options = null)
* @method int hset($key, $field, $value)
* @method int hsetnx($key, $field, $value)
* @method array hvals($key)
* @method int hstrlen($key, $field)
* @method array|null blpop(array|string $keys, $timeout)
* @method array|null brpop(array|string $keys, $timeout)
* @method string|null brpoplpush($source, $destination, $timeout)
* @method string|null lindex($key, $index)
* @method int linsert($key, $whence, $pivot, $value)
* @method int llen($key)
* @method string|null lpop($key)
* @method int lpush($key, array $values)
* @method int lpushx($key, array $values)
* @method array lrange($key, $start, $stop)
* @method int lrem($key, $count, $value)
* @method mixed lset($key, $index, $value)
* @method mixed ltrim($key, $start, $stop)
* @method string|null rpop($key)
* @method string|null rpoplpush($source, $destination)
* @method int rpush($key, array $values)
* @method int rpushx($key, array $values)
* @method int sadd($key, array $members)
* @method int scard($key)
* @method array sdiff(array|string $keys)
* @method int sdiffstore($destination, array|string $keys)
* @method array sinter(array|string $keys)
* @method int sinterstore($destination, array|string $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method string|null spop($key, $count = null)
* @method string|null srandmember($key, $count = null)
* @method int srem($key, $member)
* @method array sscan($key, $cursor, array $options = null)
* @method array sunion(array|string $keys)
* @method int sunionstore($destination, array|string $keys)
* @method int zadd($key, array $membersAndScoresDictionary)
* @method int zcard($key)
* @method string zcount($key, $min, $max)
* @method string zincrby($key, $increment, $member)
* @method int zinterstore($destination, array|string $keys, array $options = null)
* @method array zrange($key, $start, $stop, array $options = null)
* @method array zrangebyscore($key, $min, $max, array $options = null)
* @method int|null zrank($key, $member)
* @method int zrem($key, $member)
* @method int zremrangebyrank($key, $start, $stop)
* @method int zremrangebyscore($key, $min, $max)
* @method array zrevrange($key, $start, $stop, array $options = null)
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
* @method int|null zrevrank($key, $member)
* @method int zunionstore($destination, array|string $keys, array $options = null)
* @method string|null zscore($key, $member)
* @method array zscan($key, $cursor, array $options = null)
* @method array zrangebylex($key, $start, $stop, array $options = null)
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
* @method int zremrangebylex($key, $min, $max)
* @method int zlexcount($key, $min, $max)
* @method int pfadd($key, array $elements)
* @method mixed pfmerge($destinationKey, array|string $sourceKeys)
* @method int pfcount(array|string $keys)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array|null exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch($key)
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth($password)
* @method string echo($message)
* @method mixed ping($message = null)
* @method mixed select($database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof($host, $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd($key, $longitude, $latitude, $member)
* @method array geohash($key, array $members)
* @method array geopos($key, array $members)
* @method string|null geodist($key, $member1, $member2, $unit = null)
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
interface ClientInterface
{
/**
* Returns the command factory used by the client.
* Returns the server profile used by the client.
*
* @return FactoryInterface
* @return ProfileInterface
*/
public function getCommandFactory();
public function getProfile();
/**
* Returns the client options specified upon initialization.
+2 -1
View File
@@ -239,8 +239,9 @@ class HashRing implements DistributorInterface, HashGeneratorInterface
public function get($value)
{
$hash = $this->hash($value);
$node = $this->getByHash($hash);
return $this->getByHash($hash);
return $node;
}
/**
-44
View File
@@ -1,44 +0,0 @@
<?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\Cluster\Hash;
use Predis\NotSupportedException;
/**
* Hash generator implementing the CRC-CCITT-16 algorithm used by redis-cluster.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PhpiredisCRC16 implements HashGeneratorInterface
{
/**
*
*/
public function __construct()
{
if (!function_exists('phpiredis_utils_crc16')) {
// @codeCoverageIgnoreStart
throw new NotSupportedException(
'This hash generator requires a compatible version of ext-phpiredis'
);
// @codeCoverageIgnoreEnd
}
}
/**
* {@inheritdoc}
*/
public function hash($value)
{
return phpiredis_utils_crc16($value);
}
}
+2 -1
View File
@@ -40,8 +40,9 @@ class PredisStrategy extends ClusterStrategy
{
$key = $this->extractKeyTag($key);
$hash = $this->distributor->hash($key);
$slot = $this->distributor->getSlot($hash);
return $this->distributor->getSlot($hash);
return $slot;
}
/**
+5 -3
View File
@@ -41,8 +41,9 @@ class RedisStrategy extends ClusterStrategy
public function getSlotByKey($key)
{
$key = $this->extractKeyTag($key);
$slot = $this->hashGenerator->hash($key) & 0x3FFF;
return $this->hashGenerator->hash($key) & 0x3FFF;
return $slot;
}
/**
@@ -50,7 +51,8 @@ class RedisStrategy extends ClusterStrategy
*/
public function getDistributor()
{
$class = get_class($this);
throw new NotSupportedException("$class does not provide an external distributor");
throw new NotSupportedException(
'This cluster strategy does not provide an external distributor'
);
}
}
-201
View File
@@ -1,201 +0,0 @@
<?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\Cluster;
/**
* Slot map for redis-cluster.
*/
class SlotMap implements \ArrayAccess, \IteratorAggregate, \Countable
{
private $slots = array();
/**
* Checks if the given slot is valid.
*
* @param int $first Slot index.
*
* @return bool
*/
public static function isValid($slot)
{
return $slot >= 0x0000 && $slot <= 0x3FFF;
}
/**
* Checks if the given slot range is valid.
*
* @param int $first Initial slot of the range.
* @param int $last Last slot of the range.
*
* @return bool
*/
public static function isValidRange($first, $last)
{
return $first >= 0x0000 && $first <= 0x3FFF && $last >= 0x0000 && $last <= 0x3FFF && $first <= $last;
}
/**
* Resets the slot map.
*/
public function reset()
{
$this->slots = array();
}
/**
* Checks if the slot map is empty.
*
* @return bool
*/
public function isEmpty()
{
return empty($this->slots);
}
/**
* Returns the current slot map as a dictionary of $slot => $node.
*
* The order of the slots in the dictionary is not guaranteed.
*
* @return array
*/
public function toArray()
{
return $this->slots;
}
/**
* Returns the list of unique nodes in the slot map.
*
* @return array
*/
public function getNodes()
{
return array_keys(array_flip($this->slots));
}
/**
* Assigns the specified slot range to a node.
*
* @param int $first Initial slot of the range.
* @param int $last Last slot of the range.
* @param NodeConnectionInterface|string $connection ID or connection instance.
*
* @throws \OutOfBoundsException
*/
public function setSlots($first, $last, $connection)
{
if (!static::isValidRange($first, $last)) {
throw new \OutOfBoundsException("Invalid slot range $first-$last for `$connection`");
}
$this->slots += array_fill($first, $last - $first + 1, (string) $connection);
}
/**
* Returns the specified slot range.
*
* @param int $first Initial slot of the range.
* @param int $last Last slot of the range.
*
* @return array
*/
public function getSlots($first, $last)
{
if (!static::isValidRange($first, $last)) {
throw new \OutOfBoundsException("Invalid slot range $first-$last");
}
return array_intersect_key($this->slots, array_fill($first, $last - $first + 1, null));
}
/**
* Checks if the specified slot is assigned.
*
* @param int $slot Slot index.
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($slot)
{
return isset($this->slots[$slot]);
}
/**
* Returns the node assigned to the specified slot.
*
* @param int $slot Slot index.
*
* @return string
*/
#[\ReturnTypeWillChange]
public function offsetGet($slot)
{
if (isset($this->slots[$slot])) {
return $this->slots[$slot];
}
}
/**
* Assigns the specified slot to a node.
*
* @param int $slot Slot index.
* @param NodeConnectionInterface|string $connection ID or connection instance.
*
* @return string
*/
#[\ReturnTypeWillChange]
public function offsetSet($slot, $connection)
{
if (!static::isValid($slot)) {
throw new \OutOfBoundsException("Invalid slot $slot for `$connection`");
}
$this->slots[(int) $slot] = (string) $connection;
}
/**
* Returns the node assigned to the specified slot.
*
* @param int $slot Slot index.
*
* @return string
*/
#[\ReturnTypeWillChange]
public function offsetUnset($slot)
{
unset($this->slots[$slot]);
}
/**
* Returns the current number of assigned slots.
*
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return count($this->slots);
}
/**
* Returns an iterator over the slot map.
*
* @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new \ArrayIterator($this->slots);
}
}
@@ -65,8 +65,8 @@ abstract class CursorBasedIterator implements \Iterator
*/
protected function requiredCommand(ClientInterface $client, $commandID)
{
if (!$client->getCommandFactory()->supports($commandID)) {
throw new NotSupportedException("'$commandID' is not supported by the current command factory.");
if (!$client->getProfile()->supportsCommand($commandID)) {
throw new NotSupportedException("The current profile does not support '$commandID'.");
}
}
@@ -138,6 +138,7 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
@@ -148,6 +149,7 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current()
@@ -157,6 +159,7 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
@@ -166,6 +169,7 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function next()
@@ -187,6 +191,7 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function valid()
+7 -2
View File
@@ -73,8 +73,8 @@ class ListKey implements \Iterator
*/
protected function requiredCommand(ClientInterface $client, $commandID)
{
if (!$client->getCommandFactory()->supports($commandID)) {
throw new NotSupportedException("'$commandID' is not supported by the current command factory.");
if (!$client->getProfile()->supportsCommand($commandID)) {
throw new NotSupportedException("The current profile does not support '$commandID'.");
}
}
@@ -127,6 +127,7 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
@@ -137,6 +138,7 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current()
@@ -146,6 +148,7 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
@@ -155,6 +158,7 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function next()
@@ -172,6 +176,7 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function valid()
+13 -1
View File
@@ -21,12 +21,24 @@ abstract class Command implements CommandInterface
private $slot;
private $arguments = array();
/**
* Returns a filtered array of the arguments.
*
* @param array $arguments List of arguments.
*
* @return array
*/
protected function filterArguments(array $arguments)
{
return $arguments;
}
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
$this->arguments = $this->filterArguments($arguments);
unset($this->slot);
}
+1 -1
View File
@@ -73,7 +73,7 @@ interface CommandInterface
/**
* Parses a raw response and returns a PHP object.
*
* @param string|array|null $data Binary string containing the whole response.
* @param string $data Binary string containing the whole response.
*
* @return mixed
*/
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/auth
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class AUTH extends RedisCommand
class ConnectionAuth extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/echo
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ECHO_ extends RedisCommand
class ConnectionEcho extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/ping
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PING extends RedisCommand
class ConnectionPing extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/quit
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class QUIT extends RedisCommand
class ConnectionQuit extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/select
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class SELECT extends RedisCommand
class ConnectionSelect extends Command
{
/**
* {@inheritdoc}
-145
View File
@@ -1,145 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command;
use Predis\ClientException;
use Predis\Command\Processor\ProcessorInterface;
/**
* Base command factory class.
*
* This class provides all of the common functionalities required for a command
* factory to create new instances of Redis commands objects. It also allows to
* define or undefine command handler classes for each command ID.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
abstract class Factory implements FactoryInterface
{
protected $commands = [];
protected $processor;
/**
* {@inheritdoc}
*/
public function supports(string ...$commandIDs): bool
{
foreach ($commandIDs as $commandID) {
if ($this->getCommandClass($commandID) === null) {
return false;
}
}
return true;
}
/**
* Returns the FQCN of a class that represents the specified command ID.
*
* @codeCoverageIgnore
*
* @param string $commandID Command ID
*
* @return ?string
*/
public function getCommandClass(string $commandID): ?string
{
if (isset($this->commands[$commandID = strtoupper($commandID)])) {
return $this->commands[$commandID];
}
}
/**
* {@inheritdoc}
*/
public function create(string $commandID, array $arguments = []): CommandInterface
{
if (!$commandClass = $this->getCommandClass($commandID)) {
$commandID = strtoupper($commandID);
throw new ClientException("Command `$commandID` is not a registered Redis command.");
}
$command = new $commandClass();
$command->setArguments($arguments);
if (isset($this->processor)) {
$this->processor->process($command);
}
return $command;
}
/**
* Defines a command in the factory.
*
* Only classes implementing Predis\Command\CommandInterface are allowed to
* handle a command. If the command specified by its ID is already handled
* by the factory, the underlying command class is replaced by the new one.
*
* @param string $commandID Command ID
* @param string $commandClass FQCN of a class implementing Predis\Command\CommandInterface
*
* @throws \InvalidArgumentException
*/
public function define(string $commandID, string $commandClass): void
{
if (!is_a($commandClass, 'Predis\Command\CommandInterface', true)) {
throw new \InvalidArgumentException(
"Class $commandClass must implement Predis\Command\CommandInterface"
);
}
$this->commands[strtoupper($commandID)] = $commandClass;
}
/**
* Undefines a command in the factory.
*
* When the factory already has a class handler associated to the specified
* command ID it is removed from the map of known commands. Nothing happens
* when the command is not handled by the factory.
*
* @param string $commandID Command ID
*/
public function undefine(string $commandID): void
{
unset($this->commands[strtoupper($commandID)]);
}
/**
* Sets a command processor for processing command arguments.
*
* Command processors are used to process and transform arguments of Redis
* commands before their newly created instances are returned to the caller
* of "create()".
*
* A NULL value can be used to effectively unset any processor if previously
* set for the command factory.
*
* @param ProcessorInterface|null $processor Command processor or NULL value.
*/
public function setProcessor(?ProcessorInterface $processor): void
{
$this->processor = $processor;
}
/**
* Returns the current command processor.
*
* @return ?ProcessorInterface
*/
public function getProcessor(): ?ProcessorInterface
{
return $this->processor;
}
}
-43
View File
@@ -1,43 +0,0 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command;
/**
* Command factory interface.
*
* A command factory is used through the library to create instances of commands
* classes implementing Predis\Command\CommandInterface mapped to Redis commands
* by their command ID string (SET, GET, etc...).
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
interface FactoryInterface
{
/**
* Checks if the command factory supports the specified list of commands.
*
* @param array $commandIDs List of command IDs
*
* @return bool
*/
public function supports(string ...$commandIDs): bool;
/**
* Creates a new command instance.
*
* @param string $commandID Command ID
* @param array $arguments Arguments for the command
*
* @return CommandInterface
*/
public function create(string $commandID, array $arguments = array()): CommandInterface;
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/geoadd
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GEOADD extends RedisCommand
class GeospatialGeoAdd extends Command
{
/**
* {@inheritdoc}
@@ -31,7 +29,7 @@ class GEOADD extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
foreach (array_pop($arguments) as $item) {
@@ -39,6 +37,6 @@ class GEOADD extends RedisCommand
}
}
parent::setArguments($arguments);
return $arguments;
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/geodist
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GEODIST extends RedisCommand
class GeospatialGeoDist extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/geohash
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GEOHASH extends RedisCommand
class GeospatialGeoHash extends Command
{
/**
* {@inheritdoc}
@@ -31,13 +29,13 @@ class GEOHASH extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$members = array_pop($arguments);
$arguments = array_merge($arguments, $members);
}
parent::setArguments($arguments);
return $arguments;
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/geopos
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GEOPOS extends RedisCommand
class GeospatialGeoPos extends Command
{
/**
* {@inheritdoc}
@@ -31,13 +29,13 @@ class GEOPOS extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$members = array_pop($arguments);
$arguments = array_merge($arguments, $members);
}
parent::setArguments($arguments);
return $arguments;
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/georadius
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GEORADIUS extends RedisCommand
class GeospatialGeoRadius extends Command
{
/**
* {@inheritdoc}
@@ -31,7 +29,7 @@ class GEORADIUS extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if ($arguments && is_array(end($arguments))) {
$options = array_change_key_case(array_pop($arguments), CASE_UPPER);
@@ -68,6 +66,6 @@ class GEORADIUS extends RedisCommand
}
}
parent::setArguments($arguments);
return $arguments;
}
}
@@ -9,14 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
namespace Predis\Command;
/**
* @link http://redis.io/commands/georadiusbymember
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class GEORADIUSBYMEMBER extends GEORADIUS
class GeospatialGeoRadiusByMember extends GeospatialGeoRadius
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hdel
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HDEL extends RedisCommand
class HashDelete extends Command
{
/**
* {@inheritdoc}
@@ -31,10 +29,8 @@ class HDEL extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
$arguments = self::normalizeVariadic($arguments);
parent::setArguments($arguments);
return self::normalizeVariadic($arguments);
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hexists
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HEXISTS extends RedisCommand
class HashExists extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hget
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HGET extends RedisCommand
class HashGet extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hgetall
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HGETALL extends RedisCommand
class HashGetAll extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hmget
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HMGET extends RedisCommand
class HashGetMultiple extends Command
{
/**
* {@inheritdoc}
@@ -31,10 +29,8 @@ class HMGET extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
$arguments = self::normalizeVariadic($arguments);
parent::setArguments($arguments);
return self::normalizeVariadic($arguments);
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hincrby
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HINCRBY extends RedisCommand
class HashIncrementBy extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hincrbyfloat
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HINCRBYFLOAT extends RedisCommand
class HashIncrementByFloat extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hkeys
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HKEYS extends RedisCommand
class HashKeys extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hlen
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HLEN extends RedisCommand
class HashLength extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hscan
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HSCAN extends RedisCommand
class HashScan extends Command
{
/**
* {@inheritdoc}
@@ -31,14 +29,14 @@ class HSCAN extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 3 && is_array($arguments[2])) {
$options = $this->prepareOptions(array_pop($arguments));
$arguments = array_merge($arguments, $options);
}
parent::setArguments($arguments);
return $arguments;
}
/**
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hset
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HSET extends RedisCommand
class HashSet extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hmset
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HMSET extends RedisCommand
class HashSetMultiple extends Command
{
/**
* {@inheritdoc}
@@ -31,7 +29,7 @@ class HMSET extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$flattenedKVs = array($arguments[0]);
@@ -42,9 +40,9 @@ class HMSET extends RedisCommand
$flattenedKVs[] = $v;
}
$arguments = $flattenedKVs;
return $flattenedKVs;
}
parent::setArguments($arguments);
return $arguments;
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hsetnx
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HSETNX extends RedisCommand
class HashSetPreserve extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hstrlen
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HSTRLEN extends RedisCommand
class HashStringLength extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/hvals
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class HVALS extends RedisCommand
class HashValues extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/pfadd
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PFADD extends RedisCommand
class HyperLogLogAdd extends Command
{
/**
* {@inheritdoc}
@@ -31,10 +29,8 @@ class PFADD extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
$arguments = self::normalizeVariadic($arguments);
parent::setArguments($arguments);
return self::normalizeVariadic($arguments);
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/pfcount
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PFCOUNT extends RedisCommand
class HyperLogLogCount extends Command
{
/**
* {@inheritdoc}
@@ -31,10 +29,8 @@ class PFCOUNT extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
$arguments = self::normalizeArguments($arguments);
parent::setArguments($arguments);
return self::normalizeArguments($arguments);
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/pfmerge
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PFMERGE extends RedisCommand
class HyperLogLogMerge extends Command
{
/**
* {@inheritdoc}
@@ -31,10 +29,8 @@ class PFMERGE extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
$arguments = self::normalizeArguments($arguments);
parent::setArguments($arguments);
return self::normalizeArguments($arguments);
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/del
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class DEL extends RedisCommand
class KeyDelete extends Command
{
/**
* {@inheritdoc}
@@ -31,10 +29,8 @@ class DEL extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
$arguments = self::normalizeArguments($arguments);
parent::setArguments($arguments);
return self::normalizeArguments($arguments);
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/dump
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class DUMP extends RedisCommand
class KeyDump extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/exists
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class EXISTS extends RedisCommand
class KeyExists extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/expire
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class EXPIRE extends RedisCommand
class KeyExpire extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/expireat
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class EXPIREAT extends RedisCommand
class KeyExpireAt extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/keys
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class KEYS extends RedisCommand
class KeyKeys extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/migrate
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class MIGRATE extends RedisCommand
class KeyMigrate extends Command
{
/**
* {@inheritdoc}
@@ -31,7 +29,7 @@ class MIGRATE extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (is_array(end($arguments))) {
foreach (array_pop($arguments) as $modifier => $value) {
@@ -47,6 +45,6 @@ class MIGRATE extends RedisCommand
}
}
parent::setArguments($arguments);
return $arguments;
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/move
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class MOVE extends RedisCommand
class KeyMove extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/persist
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PERSIST extends RedisCommand
class KeyPersist extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/pexpire
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PEXPIRE extends RedisCommand
class KeyPreciseExpire extends KeyExpire
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/pexpireat
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PEXPIREAT extends RedisCommand
class KeyPreciseExpireAt extends KeyExpireAt
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/pttl
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class PTTL extends RedisCommand
class KeyPreciseTimeToLive extends KeyTimeToLive
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/randomkey
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RANDOMKEY extends RedisCommand
class KeyRandom extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/rename
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RENAME extends RedisCommand
class KeyRename extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/renamenx
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RENAMENX extends RedisCommand
class KeyRenamePreserve extends KeyRename
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/restore
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RESTORE extends RedisCommand
class KeyRestore extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/scan
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class SCAN extends RedisCommand
class KeyScan extends Command
{
/**
* {@inheritdoc}
@@ -31,14 +29,14 @@ class SCAN extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[1])) {
$options = $this->prepareOptions(array_pop($arguments));
$arguments = array_merge($arguments, $options);
}
parent::setArguments($arguments);
return $arguments;
}
/**
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/sort
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class SORT extends RedisCommand
class KeySort extends Command
{
/**
* {@inheritdoc}
@@ -31,12 +29,10 @@ class SORT extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 1) {
parent::setArguments($arguments);
return;
return $arguments;
}
$query = array($arguments[0]);
@@ -82,6 +78,6 @@ class SORT extends RedisCommand
$query[] = $sortParams['STORE'];
}
parent::setArguments($query);
return $query;
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/ttl
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class TTL extends RedisCommand
class KeyTimeToLive extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/type
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class TYPE extends RedisCommand
class KeyType extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/lindex
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class LINDEX extends RedisCommand
class ListIndex extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/linsert
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class LINSERT extends RedisCommand
class ListInsert extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/llen
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class LLEN extends RedisCommand
class ListLength extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/lpop
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class LPOP extends RedisCommand
class ListPopFirst extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/blpop
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class BLPOP extends RedisCommand
class ListPopFirstBlocking extends Command
{
/**
* {@inheritdoc}
@@ -31,13 +29,13 @@ class BLPOP extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
if (count($arguments) === 2 && is_array($arguments[0])) {
list($arguments, $timeout) = $arguments;
array_push($arguments, $timeout);
}
parent::setArguments($arguments);
return $arguments;
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/rpop
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RPOP extends RedisCommand
class ListPopLast extends Command
{
/**
* {@inheritdoc}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command;
/**
* @link http://redis.io/commands/brpop
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ListPopLastBlocking extends ListPopFirstBlocking
{
/**
* {@inheritdoc}
*/
public function getId()
{
return 'BRPOP';
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/rpoplpush
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RPOPLPUSH extends RedisCommand
class ListPopLastPushHead extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/brpoplpush
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class BRPOPLPUSH extends RedisCommand
class ListPopLastPushHeadBlocking extends Command
{
/**
* {@inheritdoc}
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command;
/**
* @link http://redis.io/commands/lpush
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class ListPushHead extends ListPushTail
{
/**
* {@inheritdoc}
*/
public function getId()
{
return 'LPUSH';
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/lpushx
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class LPUSHX extends RedisCommand
class ListPushHeadX extends Command
{
/**
* {@inheritdoc}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/rpush
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RPUSH extends RedisCommand
class ListPushTail extends Command
{
/**
* {@inheritdoc}
@@ -31,10 +29,8 @@ class RPUSH extends RedisCommand
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments)
protected function filterArguments(array $arguments)
{
$arguments = self::normalizeVariadic($arguments);
parent::setArguments($arguments);
return self::normalizeVariadic($arguments);
}
}
@@ -9,16 +9,14 @@
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
namespace Predis\Command;
/**
* @link http://redis.io/commands/rpushx
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
class RPUSHX extends RedisCommand
class ListPushTailX extends Command
{
/**
* {@inheritdoc}

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