mirror of
https://github.com/predis/predis.git
synced 2026-08-18 09:42:27 +00:00
Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f49e13ee3a | |||
| 6e3e2c0e78 | |||
| c35c422eda | |||
| 1b5ed7d516 | |||
| 5df852f227 | |||
| 9418df1924 | |||
| 0e4b3829a7 | |||
| 65f6127fab | |||
| 7ff24b19ae | |||
| 2babfc91d7 | |||
| fdd52d0284 | |||
| 48a861053e | |||
| 7bf1f6eb29 | |||
| 067b051900 | |||
| df4a318b80 | |||
| a904a3a273 | |||
| 8b240d15a5 | |||
| 02e2a7e1cc | |||
| 9a22450a65 | |||
| ac933cc548 | |||
| 355faa099f | |||
| 549889b198 | |||
| d1c657aac5 | |||
| b196809d3a | |||
| 52489ea703 | |||
| ba66e22c92 | |||
| 37aa6fb515 | |||
| deed24c418 | |||
| 93895d02b6 | |||
| 275606843e | |||
| 976c9daa4f | |||
| 205ae75bd8 | |||
| a5f46d0913 | |||
| b36c2f928f | |||
| bf6e97e7fb | |||
| da40e1253c | |||
| bac46bfdb7 | |||
| 7631d317fd | |||
| aaec13d074 | |||
| 52bdcf0c1f | |||
| 1726db0f47 | |||
| 8fbd34c6b3 | |||
| 0a92618fa1 | |||
| d8bb9ac46e | |||
| 274e0c17cd | |||
| c27dafa40d | |||
| 8c2aac4f66 | |||
| 5d22ed775a | |||
| c5fdfc81ef | |||
| cbef71090b | |||
| 4dc72458e8 | |||
| e83b393e09 | |||
| ed90750c1f | |||
| 45b18eb2e0 | |||
| d44f07339a | |||
| a9d18b182c | |||
| 5c8b19ebaa | |||
| 577bd39872 | |||
| 6372661dbf | |||
| 4846e2ab94 | |||
| 92b284967e | |||
| 08d5298080 | |||
| d88153b63e | |||
| b1d3255ed9 | |||
| cbf394b882 | |||
| c6bf644872 | |||
| 16bdd83d23 | |||
| 912af82bfd | |||
| 2d74db1bde | |||
| c5ee202179 | |||
| 5f2b410a74 | |||
| f6cf2afe47 | |||
| 311cd2b79e | |||
| ffd31cfdef | |||
| 1b2fd527ed | |||
| 4172d2265f | |||
| a3311d6869 | |||
| df14e11c3a | |||
| 7c2e8e01d8 | |||
| 0b6ab4dea4 | |||
| dd64569e06 | |||
| 90da582efc | |||
| 732abc88a2 | |||
| 33b70b971a | |||
| e46d56c45c | |||
| c57a6744bb | |||
| df83c94bb3 | |||
| a711ef96e2 | |||
| 3c322fc4e3 | |||
| 95c23fb94d | |||
| 946c4b7bd7 | |||
| 538c65946d | |||
| e8ea05dafe | |||
| bf2075a176 | |||
| d2cd99492d | |||
| 971e47672d | |||
| f9b755ece9 | |||
| 98d4f80263 | |||
| 0e019cc08d | |||
| b898172009 | |||
| f68543af37 |
+1
-1
@@ -3,4 +3,4 @@ skip=./.git
|
||||
check-hidden=
|
||||
check-filenames=
|
||||
builtin=clear,rare,informal,usage,code,names
|
||||
ignore-words-list=master,masters,slave,slaves,whitelist,cas,exat,smove
|
||||
ignore-words-list=master,masters,slave,slaves,whitelist,cas,exat,smove,SUGGET,sugget,ro,DOF,dof
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
coverage_clover: build/logs/clover-*.xml
|
||||
+4
-1
@@ -14,9 +14,12 @@ block_comment_end = */
|
||||
[*.php]
|
||||
max_line_length = 150
|
||||
|
||||
[*.{md,yml,yaml,neon}]
|
||||
[*.{md,yml,yaml,neon,sh}]
|
||||
indent_size = 2
|
||||
|
||||
[VERSION]
|
||||
insert_final_newline = false
|
||||
|
||||
[tests/**.php]
|
||||
max_line_length = unset
|
||||
|
||||
|
||||
+6
-3
@@ -1,9 +1,11 @@
|
||||
* text=auto
|
||||
|
||||
/.github/ export-ignore
|
||||
/examples/ export-ignore
|
||||
/tests/ export-ignore
|
||||
/.github export-ignore
|
||||
/bin export-ignore
|
||||
/examples export-ignore
|
||||
/tests export-ignore
|
||||
/.codespellrc export-ignore linguist-language=INI
|
||||
/.coveralls.yml export-ignore
|
||||
/.editorconfig export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
@@ -12,6 +14,7 @@
|
||||
/CONTRIBUTING.md export-ignore linguist-documentation
|
||||
/FAQ.md export-ignore linguist-documentation
|
||||
/VERSION export-ignore
|
||||
/phpunit.relay.xml export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/phpstan.dist.neon export-ignore
|
||||
/phpstan-tests.dist.neon export-ignore
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
|
||||
services:
|
||||
|
||||
redis-official:
|
||||
image: ${REDIS_IMAGE_NAME:-redis:7.4}
|
||||
container_name: redis-standalone
|
||||
healthcheck:
|
||||
test: [ "CMD", "redis-cli", "PING" ]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
ports:
|
||||
- "6379:6379"
|
||||
profiles:
|
||||
- all
|
||||
- official
|
||||
- standalone
|
||||
|
||||
redis-clients:
|
||||
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:7.4.2}
|
||||
container_name: redis-standalone
|
||||
environment:
|
||||
- TLS_ENABLED=yes
|
||||
- REDIS_CLUSTER=no
|
||||
- PORT=6379
|
||||
- TLS_PORT=6666
|
||||
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save ""}
|
||||
ports:
|
||||
- 6379:6379
|
||||
- 6666:6666 # TLS port
|
||||
volumes:
|
||||
- "./dockers/standalone:/redis/work"
|
||||
profiles:
|
||||
- all
|
||||
- clients
|
||||
- standalone
|
||||
|
||||
redis-cluster:
|
||||
image: ${REDIS_IMAGE_NAME:-redislabs/client-libs-test:7.4.2}
|
||||
container_name: redis-cluster
|
||||
environment:
|
||||
- REDIS_CLUSTER=yes
|
||||
- NODES=6
|
||||
- REPLICAS=1
|
||||
- TLS_ENABLED=yes
|
||||
- PORT=16379
|
||||
- TLS_PORT=27379
|
||||
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save ""}
|
||||
ports:
|
||||
- "6372-6377:16379-16384"
|
||||
volumes:
|
||||
- "./dockers/cluster:/redis/work"
|
||||
profiles:
|
||||
- all
|
||||
- clients
|
||||
- cluster
|
||||
|
||||
redis-stack:
|
||||
image: ${REDIS_STACK_IMAGE_NAME:-redislabs/client-libs-test:rs-7.4.0-v2}
|
||||
container_name: redis-stack
|
||||
ports:
|
||||
- "6479:6379"
|
||||
environment:
|
||||
- REDIS_CLUSTER=no
|
||||
- PORT=6379
|
||||
command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --save ""}
|
||||
volumes:
|
||||
- "./dockers/redis-stack:/redis/work"
|
||||
profiles:
|
||||
- all
|
||||
- clients
|
||||
- stack
|
||||
@@ -165,3 +165,32 @@ jobs:
|
||||
|
||||
- name: Search for misspellings
|
||||
run: $(python -m site --user-base)/bin/codespell
|
||||
|
||||
changelog:
|
||||
|
||||
name: Changelog
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
if: >-
|
||||
github.event_name == 'pull_request' &&
|
||||
!contains(github.event.head_commit.message, 'nochangelog') &&
|
||||
!contains(github.event.head_commit.message, 'no-changelog') &&
|
||||
!contains(github.event.head_commit.message, 'no changelog') &&
|
||||
!contains(github.event.pull_request.labels.*.name, 'no-changelog')
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check for CHANGELOG entry
|
||||
env:
|
||||
TARGET: ${{ github.event.pull_request.base.ref }}
|
||||
run: |
|
||||
FILES_CHANGED=$(git diff --name-only origin/$TARGET...HEAD | grep -E 'CHANGELOG\.md' -c)
|
||||
if [ "$FILES_CHANGED" != "1" ]; then
|
||||
echo "CHANGELOG.md was not updated";
|
||||
exit 1;
|
||||
fi;
|
||||
|
||||
+139
-31
@@ -14,7 +14,7 @@ concurrency:
|
||||
jobs:
|
||||
|
||||
predis:
|
||||
name: PHP ${{ matrix.php }} Redis ${{ matrix.redis }}
|
||||
name: PHP ${{ matrix.php }} (Redis ${{ matrix.redis }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
@@ -22,35 +22,86 @@ jobs:
|
||||
matrix:
|
||||
php:
|
||||
- '7.2'
|
||||
- '7.3'
|
||||
- '8.0'
|
||||
- '8.3'
|
||||
- '8.4'
|
||||
redis:
|
||||
- '4.0'
|
||||
- '6.2'
|
||||
- '7.2'
|
||||
- '7.4'
|
||||
- '8.0'
|
||||
- '8.1'
|
||||
- '8.2'
|
||||
redis:
|
||||
- '3'
|
||||
- '4'
|
||||
- '5'
|
||||
- '6'
|
||||
- '7'
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:${{ matrix.redis }}
|
||||
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
ports:
|
||||
- 6379:6379
|
||||
|
||||
steps:
|
||||
|
||||
- name: Resolve container name
|
||||
run: |
|
||||
# Mapping of original redis versions to client test containers
|
||||
declare -A redis_clients_version_mapping=(
|
||||
["8.0"]="8.0-RC2-pre"
|
||||
["7.4"]="7.4.2"
|
||||
["7.2"]="7.2.7"
|
||||
["6.2"]="6.2.17"
|
||||
)
|
||||
|
||||
# Mapping of redis version to stack version
|
||||
declare -A redis_stack_version_mapping=(
|
||||
["7.4"]="rs-7.4.0-v3"
|
||||
["7.2"]="rs-7.2.0-v15"
|
||||
["6.2"]="rs-6.2.6-v19"
|
||||
)
|
||||
|
||||
if [[ -v redis_clients_version_mapping[${{ matrix.redis }}] ]]; then
|
||||
echo "REDIS_IMAGE_NAME=redislabs/client-libs-test:${redis_clients_version_mapping[${{ matrix.redis }}]}" >> $GITHUB_ENV
|
||||
echo "REDIS_STACK_IMAGE_NAME=redislabs/client-libs-test:${redis_stack_version_mapping[${{ matrix.redis }}]}" >> $GITHUB_ENV
|
||||
echo "DOCKER_SERVICE=redis-clients" >> $GITHUB_ENV
|
||||
|
||||
redis_major_version=$(echo "${{ matrix.redis }}" | grep -oP '^\d+')
|
||||
|
||||
# Some configuration options available since Redis > 7
|
||||
if (( redis_major_version < 7 )); then
|
||||
echo "REDIS_EXTRA_ARGS="--tls-auth-clients optional --save ''"" >> $GITHUB_ENV
|
||||
else
|
||||
# Since 8.0 modules are bundled with core
|
||||
echo "REDIS_STACK_SERVER_PORT=6379" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
else
|
||||
echo "REDIS_IMAGE_NAME=redis:${{ matrix.redis }}" >> $GITHUB_ENV
|
||||
echo "DOCKER_SERVICE=redis-official" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP with Composer and extensions
|
||||
- name: Start Redis standalone image
|
||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||
with:
|
||||
compose-file: .github/docker-compose.yml
|
||||
services: ${{ env.DOCKER_SERVICE }}
|
||||
|
||||
- name: Start Redis stack image
|
||||
id: stack_infra
|
||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||
if: ${{ matrix.redis >= '6.2' && matrix.redis < '8.0' }}
|
||||
with:
|
||||
compose-file: .github/docker-compose.yml
|
||||
services: redis-stack
|
||||
|
||||
- name: Start Redis cluster image
|
||||
id: cluster_infra
|
||||
uses: hoverkraft-tech/compose-action@v2.0.1
|
||||
if: ${{ matrix.redis > '4.0' }}
|
||||
with:
|
||||
compose-file: .github/docker-compose.yml
|
||||
services: redis-cluster
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: ${{ (matrix.php == '8.1' && matrix.redis == '7') && 'xdebug' || 'none' }}
|
||||
extensions: relay
|
||||
coverage: ${{ (matrix.php == '8.4' && matrix.redis == '7.4') && 'xdebug' || 'none' }}
|
||||
|
||||
- name: Install Composer dependencies
|
||||
uses: ramsey/composer-install@v2
|
||||
@@ -58,18 +109,75 @@ jobs:
|
||||
dependency-versions: highest
|
||||
composer-options: ${{ matrix.php == '8.0' && '--ignore-platform-reqs' || '' }}
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
if: ${{ matrix.php != '8.1' || matrix.redis != '7' }}
|
||||
run: vendor/bin/phpunit --verbose
|
||||
- name: Run tests
|
||||
if: ${{ matrix.php != '8.4' || matrix.redis != '7.4' }}
|
||||
run: vendor/bin/phpunit
|
||||
|
||||
- name: Run PHPUnit tests with coverage
|
||||
if: ${{ matrix.php == '8.1' && matrix.redis == '7' }}
|
||||
run: vendor/bin/phpunit --verbose --coverage-clover build/logs/clover.xml --coverage-filter ./src
|
||||
- name: Run tests with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
|
||||
run: vendor/bin/phpunit --coverage-php build/cov/coverage-predis.cov --coverage-filter ./src
|
||||
|
||||
- name: Run tests using Relay
|
||||
if: ${{ matrix.php != '8.4' && matrix.redis >= '6.2' }}
|
||||
run: vendor/bin/phpunit -c phpunit.relay.xml
|
||||
|
||||
- name: Run tests using Relay with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
|
||||
run: vendor/bin/phpunit -c phpunit.relay.xml --coverage-php build/cov/coverage-relay.cov --coverage-filter ./src
|
||||
|
||||
- name: Run stack tests
|
||||
if: ${{ (matrix.php != '8.4' || matrix.redis != '7.4') && matrix.redis >= '6.2' }}
|
||||
run: vendor/bin/phpunit --group realm-stack
|
||||
|
||||
- name: Run stack tests with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' && steps.stack_infra.conclusion == 'success' }}
|
||||
run: vendor/bin/phpunit --group realm-stack --coverage-php build/cov/coverage-stack.cov --coverage-filter ./src
|
||||
env:
|
||||
REDIS_STACK_SERVER_PORT: 6479
|
||||
|
||||
- name: Run stack tests using Relay
|
||||
if: ${{ matrix.php != '8.4' && matrix.redis == '7.4' }}
|
||||
run: vendor/bin/phpunit --group realm-stack -c phpunit.relay.xml
|
||||
|
||||
- name: Run stack tests using Relay with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
|
||||
run: vendor/bin/phpunit --group realm-stack -c phpunit.relay.xml --coverage-php build/cov/coverage-stack-relay.cov --coverage-filter ./src
|
||||
env:
|
||||
REDIS_STACK_SERVER_PORT: 6479
|
||||
|
||||
- name: Run tests against cluster
|
||||
if: ${{ (matrix.php != '8.4' || matrix.redis != '7.4') && steps.cluster_infra.conclusion == 'success' }}
|
||||
run: |
|
||||
vendor/bin/phpunit --group cluster
|
||||
|
||||
- name: Run tests against cluster with coverage
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' && steps.cluster_infra.conclusion == 'success' }}
|
||||
run: |
|
||||
vendor/bin/phpunit --group cluster --coverage-php build/cov/coverage-cluster.cov --coverage-filter ./src
|
||||
|
||||
- name: Run tests against cluster using Relay
|
||||
if: ${{ matrix.php != '8.4' && matrix.redis == '7.4' }}
|
||||
run: |
|
||||
vendor/bin/phpunit -c phpunit.relay.xml --group cluster
|
||||
|
||||
- name: Merge coverage reports
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
|
||||
run: php vendor/bin/phpcov merge --clover build/logs/clover.xml build/cov
|
||||
|
||||
- name: Send coverage to Coveralls
|
||||
env:
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: ${{ env.COVERALLS_REPO_TOKEN && matrix.php == '8.1' && matrix.redis == '7' }}
|
||||
run: |
|
||||
wget "https://github.com/php-coveralls/php-coveralls/releases/download/v2.5.3/php-coveralls.phar"
|
||||
php ./php-coveralls.phar -v
|
||||
uses: coverallsapp/github-action@v2
|
||||
if: ${{ matrix.php == '8.4' && matrix.redis == '7.4' }}
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
parallel: true
|
||||
|
||||
finish:
|
||||
name: Finish Coverall
|
||||
needs: predis
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
parallel-finished: true
|
||||
|
||||
+25
-16
@@ -4,27 +4,34 @@ $PREDIS_HEADER = <<<EOS
|
||||
This file is part of the Predis package.
|
||||
|
||||
(c) 2009-2020 Daniele Alessandri
|
||||
(c) 2021-2023 Till Krüss
|
||||
(c) 2021-2025 Till Krüss
|
||||
|
||||
For the full copyright and license information, please view the LICENSE
|
||||
file that was distributed with this source code.
|
||||
EOS;
|
||||
|
||||
return (new PhpCsFixer\Config)
|
||||
->setRules([
|
||||
'@PHP71Migration' => true,
|
||||
'header_comment' => ['header' => $PREDIS_HEADER],
|
||||
'@Symfony' => true,
|
||||
'phpdoc_separation' => false,
|
||||
'phpdoc_annotation_without_dot' => false,
|
||||
'no_superfluous_phpdoc_tags' => false,
|
||||
'no_unneeded_curly_braces' => false,
|
||||
'global_namespace_import' => true,
|
||||
'yoda_style' => false,
|
||||
'single_line_throw' => false,
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'increment_style' => false,
|
||||
])
|
||||
$fixer = new PhpCsFixer\Config;
|
||||
|
||||
$fixer->setParallelConfig(
|
||||
\PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()
|
||||
);
|
||||
|
||||
$fixer->setRules([
|
||||
'@PHP71Migration' => true,
|
||||
'header_comment' => ['header' => $PREDIS_HEADER],
|
||||
'@Symfony' => true,
|
||||
'phpdoc_separation' => false,
|
||||
'phpdoc_annotation_without_dot' => false,
|
||||
'no_superfluous_phpdoc_tags' => false,
|
||||
'no_unneeded_curly_braces' => false,
|
||||
'no_unneeded_braces' => false,
|
||||
'global_namespace_import' => true,
|
||||
'yoda_style' => false,
|
||||
'single_line_throw' => false,
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'increment_style' => false,
|
||||
'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['array_destructuring', 'arrays']]
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->in(__DIR__ . '/bin')
|
||||
@@ -32,3 +39,5 @@ return (new PhpCsFixer\Config)
|
||||
->in(__DIR__ . '/src')
|
||||
->in(__DIR__ . '/tests')
|
||||
);
|
||||
|
||||
return $fixer;
|
||||
|
||||
+94
-9
@@ -1,8 +1,93 @@
|
||||
## Changelog
|
||||
|
||||
## v2.4.0 (2025-04-30)
|
||||
### Added
|
||||
- Added new hash-field expiration commands (#1520)
|
||||
- Added missing `FT._LIST` and `BITFIELD_RO` commands (#1521)
|
||||
|
||||
### Changed
|
||||
- Update `WATCH` command to accept `string|string[]` (#1476)
|
||||
- Optimize cluster slotmap with compact slot range object (#1493)
|
||||
|
||||
### Fixed
|
||||
- Fixed `EVAL_RO` cluster support (#1449)
|
||||
- Fixed PHP 8.4 compatibility with `stream_context_set_option()` (#1503)
|
||||
- Prevent named arguments runtime failure (#1509)
|
||||
- Mark `GEOSEARCH` as read-only to ensure execution on replica (#1481)
|
||||
- Fixed protocol loss during redis cluster `MOVED` / `ASK` (#1530)
|
||||
|
||||
### Maintenance
|
||||
- Added CI testing with Redis 8.0 (#1510)
|
||||
- Added test coverage for compatibility with Redis 8.0 (#1513)
|
||||
- Use parallel on PHP-CS-Fixer (#1489)
|
||||
|
||||
## v2.3.0 (2024-11-21)
|
||||
### Added
|
||||
- Added `GeoShapeField` field (#1467)
|
||||
- Added hash expiration commands (#1456)
|
||||
- Added support for time series `IGNORE` filter (#1458)
|
||||
- Added `XREAD` commands (#1459)
|
||||
- Added `NOVALUES` argument support to `HSCAN` (#1459)
|
||||
- Added support for search `INDEXMISSING` and `INDEXEMPTY` arguments (#1464)
|
||||
|
||||
### Changed
|
||||
- Explicitly mark nullable parameters as nullable (#1448)
|
||||
- Filter out available replicas based on link status flag (#1440)
|
||||
- Respect `prefix` for `ZPOPMIN`, `ZPOPMAX`, `ZMSCORE`, `LMOVE`, `BLMOVE`, `SMISMEMBER` and `GEOSEARCH` (#1451, #1453, #1455, #1468)
|
||||
- Updated test infrastructure (#1510)
|
||||
|
||||
### Fixed
|
||||
- Fixed Relay support when using Redis Cluster (#1397)
|
||||
- Fixed `cmsincrby()` type annotation (#1333)
|
||||
- Fixed `set()` type annotation (#1394)
|
||||
- Fixed operator precedence in connection factory (#1405)
|
||||
- Fixed a bug with `null` arguments in `set()` method (#1470, #1471)
|
||||
|
||||
## v2.2.2 (2023-09-13)
|
||||
|
||||
### Added
|
||||
- Added `client_info` client parameter
|
||||
- Added support for `CLUSTER` container command
|
||||
|
||||
### Fixed
|
||||
- Fixed `EXPIRETIME` not using `prefix`
|
||||
- Disabled `CLIENT SETINFO` calls by default
|
||||
|
||||
## v2.2.1 (2023-08-15)
|
||||
|
||||
### Added
|
||||
- Added support for `WAITAOF` command (#1357)
|
||||
- Added support for `SHUTDOWN` command (#1359)
|
||||
- Added support for `FUNCTION` command (#1332)
|
||||
- Added support for new optional `PEXPIRE`, `PEXPIREAT` and `COMMAND`
|
||||
- Added missing Redis Stack commands to `KeyPrefixProcessor` (#1358)
|
||||
|
||||
### Changed
|
||||
- Set client name and version when establishing a connection (#1347)
|
||||
|
||||
## v2.2.0 (2023-06-14)
|
||||
|
||||
Predis v2.2.0 introduces official support for [Redis Stack](https://redis.io/docs/stack/) as well as a [Relay](https://github.com/cachewerk/relay) integration for substantially [faster read performance](https://github.com/predis/predis/wiki/Using-Relay).
|
||||
|
||||
### Added
|
||||
- Added support for [Relay](https://github.com/predis/predis/wiki/Using-Relay) (#1263)
|
||||
- Added support for `FCALL_RO` command (#1191)
|
||||
- Added support for Redis `JSON`, `Bloom`, `Search` and `TimeSeries` module (#1253)
|
||||
- Added support for `ACL SETUSER, GETUSER, DRYRUN` commands (#1193)
|
||||
|
||||
### Changed
|
||||
- Minor code style and type-hint changes (#1311)
|
||||
|
||||
### Fixed
|
||||
- Fixed prefixes for `XTRIM` and `XREVRANGE` commands (#1230)
|
||||
- Fixed `fclose()` being called on invalid stream resource (#1199)
|
||||
- Fixed `BitByte` and `ExpireOptions` traits skip processing on null values (#1169)
|
||||
- Fixed missing `@return` annotations (#1265)
|
||||
- Fixed `GETDEL` prefixing (#1306)
|
||||
|
||||
## v2.1.2 (2023-03-02)
|
||||
|
||||
## Added
|
||||
### Added
|
||||
- Added stream commands to `KeyPrefixProcessor` (#1051)
|
||||
- Added `ReplicationStrategy::$loadBalancing` option to disable replica reads (#1168)
|
||||
- Added support for `FCALL` and `FUNCTIONS` commands (#1049)
|
||||
@@ -16,28 +101,28 @@
|
||||
- Added support for new arguments for `BITPOS` and `BITCOUNT` commands (#1045)
|
||||
- Added support for new arguments for `EXPIRE` and `EXPIREAT` commands (#1046)
|
||||
|
||||
## Bug Fixes
|
||||
### Bug Fixes
|
||||
- Fixed deprecated function call syntax
|
||||
|
||||
## Deprecated
|
||||
### Deprecated
|
||||
- Further deprecated phpiredis and webdis integration (#1179)
|
||||
|
||||
## Maintenance
|
||||
### Maintenance
|
||||
- Applied coding standards
|
||||
- Pass PHPStan level 2
|
||||
|
||||
## v2.1.1 (2023-01-17)
|
||||
|
||||
## Bug Fixes
|
||||
### Bug Fixes
|
||||
- Fix `@template` in `Predis\Client` (#1017)
|
||||
- Fix support options array in `ZINTERSTORE` and `ZUNIONSTORE` (#1018)
|
||||
|
||||
## Deprecated
|
||||
### Deprecated
|
||||
- Deprecated phpiredis and webdis connections
|
||||
|
||||
## v2.1.0 (2023-01-16)
|
||||
|
||||
## New Features
|
||||
### New Features
|
||||
- Implemented `GETEX` command (#872)
|
||||
- Implemented `GETDEL` command (#869)
|
||||
- Implemented `COPY` command (#866)
|
||||
@@ -63,10 +148,10 @@
|
||||
- Implemented `GEOSEARCH` command (#867)
|
||||
- Implemented `GEOSEARCHSTORE` command (#873)
|
||||
|
||||
## Bug Fixes
|
||||
### Bug Fixes
|
||||
- Added annotations to suppress PHP 8.1 return type deprecation warning (#810)
|
||||
|
||||
## Maintenance
|
||||
### Maintenance
|
||||
- Added mixin annotations for traits (#835)
|
||||
|
||||
## v2.0.3 (2022-10-11)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Some frequently asked questions about Predis #
|
||||
________________________________________________
|
||||
# Frequently asked questions about Predis #
|
||||
|
||||
### What is the point of Predis? ###
|
||||
## What is the point of Predis? ##
|
||||
|
||||
The main point of Predis is about offering a highly customizable and extensible client for Redis,
|
||||
that can be easily extended by developers while still being reasonably fast. With Predis you can
|
||||
@@ -13,12 +12,12 @@ a great asset since it allows developers to add new and still missing features o
|
||||
the standard behaviour of the library without the need to break dependencies in production code (at
|
||||
least to some degree).
|
||||
|
||||
### Does Predis support UNIX domain sockets and persistent connections? ###
|
||||
## Does Predis support UNIX domain sockets and persistent connections? ##
|
||||
|
||||
Yes. Obviously persistent connections actually work only when using PHP configured as a persistent
|
||||
process reused by the web server (see [PHP-FPM](http://php-fpm.org)).
|
||||
|
||||
### Does Predis support SSL-encrypted connections? ###
|
||||
## Does Predis support SSL-encrypted connections? ##
|
||||
|
||||
Yes. Encrypted connections are mostly useful when connecting to Redis instances exposed by various
|
||||
cloud hosting providers without the need to configure an SSL proxy, but you should also take into
|
||||
@@ -26,16 +25,21 @@ account the general performances degradation especially during the connect() ope
|
||||
handshake must be performed to secure the connection. Persistent SSL-encrypted connections may help
|
||||
in that respect, but they are supported only when running on PHP >= 7.0.0.
|
||||
|
||||
### Does Predis support transparent (de)serialization of values? ###
|
||||
## Does Predis support transparent (de)serialization of values? ##
|
||||
|
||||
No and it will not ever do that by default. The reason behind this decision is that serialization is
|
||||
usually something that developers prefer to customize depending on their needs and can not be easily
|
||||
generalized when using Redis because of the many possible access patterns for your data. This does
|
||||
not mean that it is impossible to have such a feature since you can leverage the extensibility of
|
||||
this library to define your own serialization-aware commands. You can find more details about how to
|
||||
do that [on this issue](http://github.com/predis/predis/issues/29#issuecomment-1202624).
|
||||
When using [Relay](https://github.com/cachewerk/relay) as the underlying client, several
|
||||
serialization and compression algorithms are supported. This slightly increases CPU usage,
|
||||
but significantly reduces bytes sent over the network and Redis memory usage.
|
||||
|
||||
### How can I force Predis to connect to Redis before sending any command? ###
|
||||
Without Relay, Predis will not serialize data and will never do that by default. The reason
|
||||
behind this decision is that serialization is usually something that developers prefer to
|
||||
customize depending on their needs and can not be easily generalized when using Redis because
|
||||
of the many possible access patterns for your data. This does not mean that it is impossible
|
||||
to have such a feature since you can leverage the extensibility of this library to define
|
||||
your own serialization-aware commands. You can find more details about how to do that
|
||||
[on this issue](http://github.com/predis/predis/issues/29#issuecomment-1202624).
|
||||
|
||||
## How can I force Predis to connect to Redis before sending any command? ##
|
||||
|
||||
Explicitly connecting to Redis is usually not needed since the client initializes connections lazily
|
||||
only when they are needed. Admittedly, this behavior can be inconvenient in certain scenarios when
|
||||
@@ -55,7 +59,7 @@ try {
|
||||
$client->info();
|
||||
```
|
||||
|
||||
### How Predis abstracts Redis commands? ###
|
||||
## How Predis abstracts Redis commands? ##
|
||||
|
||||
The approach used to implement Redis commands is quite simple: by default each command follows the
|
||||
same signature as defined on the [Redis documentation](http://redis.io/commands) which makes things
|
||||
@@ -75,103 +79,19 @@ $client->hmset('my:hash', ['field1'=>'value1', 'field2'=>'value2']); // single n
|
||||
An exception to this rule is [`SORT`](http://redis.io/commands/sort) for which modifiers are passed
|
||||
[using a named array](tests/Predis/Command/KeySortTest.php#L54-L75).
|
||||
|
||||
## When should I use Relay? ##
|
||||
|
||||
# Speaking about performances... #
|
||||
_________________________________________________
|
||||
If you care about performance, __always__. [Relay][relay] is free to use.
|
||||
|
||||
## When should I use PhpRedis? ###
|
||||
|
||||
### Predis is a pure-PHP implementation: it can not be fast enough! ###
|
||||
Predis is fast enough when Redis is located on the same machine as PHP.
|
||||
|
||||
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you a
|
||||
couple of easy numbers with a simple test that uses a single client and is executed by PHP 5.5.6
|
||||
against a local instance of Redis 2.8 that runs under Ubuntu 13.10 on a Intel Q6600:
|
||||
[PhpRedis][phpredis] and [Relay][relay] perform significantly better when network I/O is involved,
|
||||
due to its ability to compress data by ~75%. Fewer bytes and received sent over the network
|
||||
[means faster operations][performance], and potentially cost savings when network traffic isn't
|
||||
free (e.g. AWS ElastiCache Inter-AZ transfer costs).
|
||||
|
||||
```
|
||||
21000 SET/sec using 12 bytes for both key and value.
|
||||
21000 GET/sec while retrieving the very same values.
|
||||
0.130 seconds to fetch 30000 keys using _KEYS *_.
|
||||
```
|
||||
|
||||
How does it compare with [__phpredis__](http://github.com/nicolasff/phpredis), a nice C extension
|
||||
providing an efficient client for Redis?
|
||||
|
||||
```
|
||||
30100 SET/sec using 12 bytes for both key and value
|
||||
29400 GET/sec while retrieving the very same values
|
||||
0.035 seconds to fetch 30000 keys using "KEYS *"".
|
||||
```
|
||||
|
||||
Wow __phpredis__ seems much faster! Well, we are comparing a C extension with a pure-PHP library so
|
||||
lower numbers are quite expected but there is a fundamental flaw in them: is this really how you are
|
||||
going to use Redis in your application? Are you really going to send thousands of commands using a
|
||||
for-loop on each page request using a single client instance? If so... well I guess you are probably
|
||||
doing something wrong. Also, if you need to `SET` or `GET` multiple keys you should definitely use
|
||||
commands such as `MSET` and `MGET`. You can also use pipelining to get more performances when this
|
||||
technique can be used.
|
||||
|
||||
There is one more thing: we have tested the overhead of Predis by connecting on a localhost instance
|
||||
of Redis but how these numbers change when we hit the physical network by connecting to remote Redis
|
||||
instances?
|
||||
|
||||
```
|
||||
Using Predis:
|
||||
3200 SET/sec using 12 bytes for both key and value
|
||||
3200 GET/sec while retrieving the very same values
|
||||
0.132 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
Using phpredis:
|
||||
3500 SET/sec using 12 bytes for both key and value
|
||||
3500 GET/sec while retrieving the very same values
|
||||
0.045 seconds to fetch 30000 keys using "KEYS *".
|
||||
```
|
||||
|
||||
There you go, you get almost the same average numbers and the reason is simple: network latency is a
|
||||
real performance killer and you cannot do (almost) anything about that. As a disclaimer, remember
|
||||
that we are measuring the overhead of client libraries implementations and the effects of network
|
||||
round-trip times, so we are not really measuring how fast Redis is. Redis shines best with thousands
|
||||
of concurrent clients doing requests! Also, actual performances should be measured according to how
|
||||
your application will use Redis.
|
||||
|
||||
### I am convinced, but performances for multi-bulk responses are still worse ###
|
||||
|
||||
Fair enough, but there is an option available if you need even more speed and consists on installing
|
||||
__[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name) and let the
|
||||
client use it. __phpiredis__ is another C extension that wraps __hiredis__ (the official C client
|
||||
library for Redis) with a thin layer exposing its features to PHP. You can then choose between two
|
||||
different connection classes:
|
||||
|
||||
- `Predis\Connection\PhpiredisStreamConnection` (using native PHP streams).
|
||||
- `Predis\Connection\PhpiredisSocketConnection` (requires `ext-socket`).
|
||||
|
||||
You will now get the benefits of a faster protocol serializer and parser just by adding a couple of
|
||||
lines of code:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisStreamConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisSocketConnection',
|
||||
),
|
||||
));
|
||||
```
|
||||
|
||||
Dead simple. Nothing changes in the way you use the library in your application. So how fast is it
|
||||
our basic benchmark script now? There are not much improvements for inline or short bulk responses
|
||||
like the ones returned by `SET` and `GET`, but the speed for parsing multi-bulk responses is now on
|
||||
par with phpredis:
|
||||
|
||||
```
|
||||
Fatching 30000 keys with _KEYS *_ using Predis paired with phpiredis::
|
||||
|
||||
0.035 seconds from a local Redis instance
|
||||
0.047 seconds from a remote Redis instance
|
||||
```
|
||||
|
||||
### If I need an extension to get better performances, why not using phpredis? ###
|
||||
|
||||
Good question. Generically speaking if you need absolute uber-speed using Redis on the localhost and
|
||||
you do not care about abstractions built around some Redis features such as MULTI / EXEC, or if you
|
||||
do not need any kind of extensibility or guaranteed backwards compatibility with different versions
|
||||
of Redis (Predis currently supports from 1.2 up to 2.8 and the current development version), then
|
||||
using __phpredis__ makes absolutely sense. Otherwise, Predis is perfect for the job and by adding
|
||||
__phpiredis__ you can get a nice speed bump almost for free.
|
||||
[phpredis]: https://github.com/phpredis/phpredis
|
||||
[relay]: [https://github.com/phpredis/phpredis](https://github.com/cachewerk/relay)
|
||||
[performance]: https://akalongman.medium.com/phpredis-vs-predis-comparison-on-real-production-data-a819b48cbadb
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2009-2020 Daniele Alessandri (original work)
|
||||
Copyright (c) 2021-2023 Till Krüss (modified work)
|
||||
Copyright (c) 2021-2024 Till Krüss (modified work)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
[![Build status][ico-build]][link-actions]
|
||||
[![Coverage Status][ico-coverage]][link-coverage]
|
||||
|
||||
A flexible and feature-complete [Redis](http://redis.io) client for PHP 7.2 and newer.
|
||||
A flexible and feature-complete [Redis](http://redis.io) / [Valkey](https://github.com/valkey-io/valkey) client for PHP 7.2 and newer.
|
||||
|
||||
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 Redis from __3.0__ to __8.0__.
|
||||
- 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).
|
||||
@@ -396,6 +396,16 @@ $response = $client->lpushrand('random_values', $seed = mt_rand());
|
||||
|
||||
### Customizable connection backends ###
|
||||
|
||||
Predis can use different connection backends to connect to Redis. The builtin Relay integration
|
||||
leverages the [Relay](https://github.com/cachewerk/relay) extension for PHP for major performance
|
||||
gains, by caching a partial replica of the Redis dataset in PHP shared runtime memory.
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', [
|
||||
'connections' => 'relay',
|
||||
]);
|
||||
```
|
||||
|
||||
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`:
|
||||
@@ -439,23 +449,6 @@ be disabled. See [the tests README](tests/README.md) for more details about test
|
||||
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).
|
||||
|
||||
|
||||
## Other ##
|
||||
|
||||
|
||||
### Project related links ###
|
||||
|
||||
- [Source code](https://github.com/predis/predis)
|
||||
- [Wiki](https://github.com/predis/predis/wiki)
|
||||
- [Issue tracker](https://github.com/predis/predis/issues)
|
||||
|
||||
|
||||
### Author ###
|
||||
|
||||
- [Till Krüss](https://till.im) ([Twitter](http://twitter.com/tillkruss))
|
||||
- [Daniele Alessandri](mailto:suppakilla@gmail.com) ([twitter](http://twitter.com/JoL1hAHN))
|
||||
|
||||
|
||||
### License ###
|
||||
|
||||
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
|
||||
|
||||
+6
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "predis/predis",
|
||||
"type": "library",
|
||||
"description": "A flexible and feature-complete Redis client for PHP.",
|
||||
"description": "A flexible and feature-complete Redis/Valkey client for PHP.",
|
||||
"keywords": ["nosql", "redis", "predis"],
|
||||
"homepage": "http://github.com/predis/predis",
|
||||
"license": "MIT",
|
||||
@@ -27,7 +27,11 @@
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.3",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^8.0 || ~9.4.4"
|
||||
"phpunit/phpunit": "^8.0 || ^9.4",
|
||||
"phpunit/phpcov": "^6.0 || ^8.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
|
||||
},
|
||||
"scripts": {
|
||||
"phpstan": "phpstan analyse",
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of JSON.DEBUG command usage:
|
||||
|
||||
// 1. Set JSON object
|
||||
$client = new Client();
|
||||
|
||||
$client->jsonset('key', '$', '{"key1":"value1","key2":"value2"}');
|
||||
|
||||
// 2. Dump information about json memory usage in bytes
|
||||
$response = $client->jsondebug->memory('key', '$');
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\AggregateArguments;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\AbstractField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\NumericField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.AGGREGATE command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$ftCreateArguments = (new CreateArguments())->prefix(['user:']);
|
||||
$schema = [
|
||||
new TextField('name'),
|
||||
new TextField('country'),
|
||||
new NumericField('dob', '', AbstractField::SORTABLE),
|
||||
];
|
||||
|
||||
$client->ftcreate('idx', $schema, $ftCreateArguments);
|
||||
|
||||
// 2. Add documents
|
||||
$client->hset('user:0', 'name', 'Vlad', 'country', 'Ukraine', 'dob', 813801600);
|
||||
$client->hset('user:1', 'name', 'Vlad', 'country', 'Israel', 'dob', 782265600);
|
||||
$client->hset('user:2', 'name', 'Vlad', 'country', 'Ukraine', 'dob', 813801600);
|
||||
|
||||
// 3. Execute aggregation query
|
||||
$ftAggregateArguments = (new AggregateArguments())
|
||||
->apply('year(@dob)', 'birth')
|
||||
->groupBy('@country', '@birth')
|
||||
->reduce('COUNT', true, 'country_birth_Vlad_count')
|
||||
->sortBy(0, '@birth', 'DESC');
|
||||
|
||||
$response = $client->ftaggregate('idx', '@name: "Vlad"', $ftAggregateArguments);
|
||||
|
||||
// Response grouped by user country and birth year, with users count in each group, sorted by birth year from DESC.
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.ALTER command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$schema = [
|
||||
new TextField('text_field'),
|
||||
];
|
||||
$client->ftcreate('index_alter', $schema);
|
||||
|
||||
echo 'Default index attributes:' . "\n";
|
||||
$defaultAttributes = $client->ftinfo('index_alter');
|
||||
print_r($defaultAttributes[7]);
|
||||
|
||||
// 2. Add additional attribute to existing index
|
||||
$schema = [
|
||||
new TextField('new_field_name'),
|
||||
];
|
||||
|
||||
$client->ftalter('index_alter', $schema);
|
||||
|
||||
echo 'Updated index attributes:' . "\n";
|
||||
$updatedAttributes = $client->ftinfo('index_alter');
|
||||
print_r($updatedAttributes[7]);
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.CONFIG HELP command usage:
|
||||
|
||||
// 1. Dump helpful information about FT.CONFIG MAXEXPANSIONS option
|
||||
$client = new Client();
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r(
|
||||
$client->ftconfig->help('MAXEXPANSIONS')
|
||||
);
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.CONFIG SET command usage:
|
||||
|
||||
// 1. Change default timeout setting
|
||||
$client = new Client();
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
|
||||
print_r(
|
||||
$client->ftconfig->set('TIMEOUT', 42)
|
||||
);
|
||||
print_r(
|
||||
$client->ftconfig->get('TIMEOUT')
|
||||
);
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\AggregateArguments;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\AbstractField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\NumericField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.CURSOR DEL command usage
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$ftCreateArguments = (new CreateArguments())->prefix(['user:']);
|
||||
$schema = [
|
||||
new TextField('name'),
|
||||
new TextField('country'),
|
||||
new NumericField('dob', '', AbstractField::SORTABLE),
|
||||
];
|
||||
|
||||
$client->ftcreate('index_cursor_del', $schema, $ftCreateArguments);
|
||||
|
||||
// 2. Add documents
|
||||
$client->hset('user:0', 'name', 'Vlad', 'country', 'Ukraine', 'dob', 813801600);
|
||||
$client->hset('user:1', 'name', 'Vlad', 'country', 'Israel', 'dob', 782265600);
|
||||
$client->hset('user:2', 'name', 'Vlad', 'country', 'Ukraine', 'dob', 813801600);
|
||||
|
||||
// 3. Execute aggregation query
|
||||
$ftAggregateArguments = (new AggregateArguments())
|
||||
->apply('year(@dob)', 'birth')
|
||||
->groupBy('@country', '@birth')
|
||||
->reduce('COUNT', true, 'country_birth_Vlad_count')
|
||||
->sortBy(0, '@birth', 'DESC')
|
||||
->withCursor(1);
|
||||
|
||||
[$_, $cursor] = $client->ftaggregate('index_cursor_del', '@name: "Vlad"', $ftAggregateArguments);
|
||||
|
||||
// 4. Explicitly remove returned cursor
|
||||
$client->ftcursor->del('index_cursor_del', $cursor);
|
||||
|
||||
echo "Cursor with cursorId - {$cursor} was removed";
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\AggregateArguments;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\AbstractField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\NumericField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.CURSOR READ command usage
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$ftCreateArguments = (new CreateArguments())->prefix(['user:']);
|
||||
$schema = [
|
||||
new TextField('name'),
|
||||
new TextField('country'),
|
||||
new NumericField('dob', '', AbstractField::SORTABLE),
|
||||
];
|
||||
|
||||
$client->ftcreate('index_cursor_read', $schema, $ftCreateArguments);
|
||||
|
||||
// 2. Add documents
|
||||
$client->hset('user:0', 'name', 'Vlad', 'country', 'Ukraine', 'dob', 813801600);
|
||||
$client->hset('user:1', 'name', 'Vlad', 'country', 'Israel', 'dob', 782265600);
|
||||
$client->hset('user:2', 'name', 'Vlad', 'country', 'Ukraine', 'dob', 813801600);
|
||||
|
||||
// 3. Execute aggregation query
|
||||
$ftAggregateArguments = (new AggregateArguments())
|
||||
->apply('year(@dob)', 'birth')
|
||||
->groupBy('@country', '@birth')
|
||||
->reduce('COUNT', true, 'country_birth_Vlad_count')
|
||||
->sortBy(0, '@birth', 'DESC')
|
||||
->withCursor(1);
|
||||
|
||||
[$response, $cursor] = $client->ftaggregate('index_cursor_read', '@name: "Vlad"', $ftAggregateArguments);
|
||||
|
||||
// 4. Processing response in loop until cursorId exists
|
||||
$actualResponse = [];
|
||||
$cursors = [];
|
||||
|
||||
while ($cursor) {
|
||||
$actualResponse[] = $response[1];
|
||||
$cursors[] = $cursor;
|
||||
[$response, $cursor] = $client->ftcursor->read('index_cursor_read', $cursor);
|
||||
}
|
||||
|
||||
echo "Response: \n";
|
||||
print_r($actualResponse);
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.EXPLAIN command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$schema = [
|
||||
new TextField('text_field'),
|
||||
];
|
||||
$client->ftcreate('index_explain', $schema);
|
||||
|
||||
// 2. Run query explanations
|
||||
$response = $client->ftexplain('index_explain', '(foo bar)|(hello world) @date:[100 200]|@date:[500 +inf]');
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\ProfileArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.PROFILE command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$schema = [
|
||||
new TextField('text_field'),
|
||||
];
|
||||
$client->ftcreate('index_profile', $schema);
|
||||
|
||||
// 2. Create FT.PROFILE command arguments
|
||||
$arguments = (new ProfileArguments())
|
||||
->search()
|
||||
->query('query');
|
||||
|
||||
// 3. Run profile query
|
||||
$response = $client->ftprofile('index_profile', $arguments);
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
use Predis\Command\Argument\Search\SpellcheckArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.SPELLCHECK command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$schema = [
|
||||
new TextField('text_field'),
|
||||
];
|
||||
$client->ftcreate('index_spellcheck', $schema);
|
||||
|
||||
// 2. Add dictionary with terms
|
||||
$client->ftdictadd('dict', 'hello', 'help');
|
||||
|
||||
// 3. Perform spelling correction query
|
||||
$response = $client->ftspellcheck(
|
||||
'index_spellcheck',
|
||||
'held',
|
||||
(new SpellcheckArguments())->distance(2)->terms('dict')
|
||||
);
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\SugAddArguments;
|
||||
use Predis\Command\Argument\Search\SugGetArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.SUGADD, FT.SUGGET, FT.SUGDEL, FT.SUGLEN commands usage:
|
||||
|
||||
// 1. Add suggestion to key with payload
|
||||
$client = new Client();
|
||||
|
||||
$client->ftsugadd('key', 'hello', 2, (new SugAddArguments())->payload('payload'));
|
||||
|
||||
echo 'Suggestions dictionary length: ' . $client->ftsuglen('key') . "\n";
|
||||
|
||||
// 2. Perform fuzzy search by prefix to get previous suggestion with payload
|
||||
$response = $client->ftsugget('key', 'hellp', (new SugGetArguments())->fuzzy()->withPayloads());
|
||||
|
||||
echo 'Suggestion for "hellp" prefix:' . "\n";
|
||||
print_r($response);
|
||||
|
||||
// 3. Removes previous suggestion from key
|
||||
$client->ftsugdel('key', 'hello');
|
||||
$response = $client->ftsugget('key', 'hello');
|
||||
|
||||
echo 'Suggestions, after removing "hello" suggestion:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.SYNDUMP command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$schema = [
|
||||
new TextField('text_field'),
|
||||
];
|
||||
$client->ftcreate('index_syndump', $schema);
|
||||
|
||||
// 2. Add synonyms group with terms
|
||||
$client->ftsynupdate('index_syndump', 'synonym1', null, 'term1', 'term2');
|
||||
|
||||
// 3. Dump terms with synonyms
|
||||
$response = $client->ftsyndump('index_syndump');
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.SYNUPDATE command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$schema = [
|
||||
new TextField('text_field'),
|
||||
];
|
||||
$client->ftcreate('index_synupdate', $schema);
|
||||
|
||||
// 2. Add synonyms into synonym group
|
||||
$response = $client->ftsynupdate('index_synupdate', 'synonym1', null, 'term1', 'term2');
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TagField;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of FT.TAGVALS command usage:
|
||||
|
||||
// 1. Create index
|
||||
$client = new Client();
|
||||
|
||||
$schema = [
|
||||
new TagField('tag_field'),
|
||||
];
|
||||
$client->ftcreate('index_tagvals', $schema, (new CreateArguments())->prefix(['prefix:']));
|
||||
|
||||
// 2. Add indexed tags
|
||||
$client->hset('prefix:1', 'tag_field', 'Hello, World');
|
||||
$client->hset('prefix:2', 'tag_field', 'Hey, World');
|
||||
|
||||
// 3. Unique tags value query
|
||||
$response = $client->fttagvals('index_tagvals', 'tag_field');
|
||||
|
||||
echo 'Response:' . "\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\AddArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.ADD command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
// 2. Add sample into newly created time series
|
||||
$addArguments = (new AddArguments())
|
||||
->retentionMsecs(31536000000);
|
||||
|
||||
$response = $client->tsadd('temperature:2:32', 123123123123, 27, $addArguments);
|
||||
|
||||
echo "Timeseries was added with timestamp: {$response}";
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\AlterArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.ALTER command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$response = $client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
echo "Time series creation status: {$response}\n";
|
||||
|
||||
// 2. Update Duplicate policy for time series above
|
||||
$arguments = (new AlterArguments())
|
||||
->duplicatePolicy(CommonArguments::POLICY_FIRST);
|
||||
|
||||
$response = $client->tsalter('temperature:2:32', $arguments);
|
||||
$output = ($response == 'OK') ? 'Duplicate policy was successfully updated' : $response;
|
||||
|
||||
echo $output;
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.CREATE command usage:
|
||||
|
||||
// Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$response = $client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
echo "Time series creation status: {$response}";
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.CREATERULE command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->labels('type', 'temp', 'location', 'TLV');
|
||||
|
||||
$createResponse = $client->tscreate('temp:TLV', $arguments);
|
||||
echo "Original time series creation status: {$createResponse}\n";
|
||||
|
||||
$createResponse = $client->tscreate('dailyAvgTemp:TLV', $arguments);
|
||||
echo "Compacted time series creation status: {$createResponse}\n";
|
||||
|
||||
$createRuleResponse = $client->tscreaterule('temp:TLV', 'dailyAvgTemp:TLV', 'avg', 1000);
|
||||
echo "Compacted rule for compacted time series creation status: {$createRuleResponse}\n";
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\AddArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\DecrByArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.DECRBY command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
// 2. Add sample into newly created time series
|
||||
$addArguments = (new AddArguments())
|
||||
->retentionMsecs(31536000000);
|
||||
|
||||
$response = $client->tsadd('temperature:2:32', 123123123123, 27, $addArguments);
|
||||
|
||||
echo "Timeseries was added with timestamp: {$response}\n";
|
||||
|
||||
// 3. Increasing value and timestamp
|
||||
$client->tsdecrby('temperature:2:32', 1, (new DecrByArguments())->timestamp(123123123124));
|
||||
$response = $client->tsget('temperature:2:32');
|
||||
|
||||
echo "Decreased value to - {$response[1]} and timestamp to {$response[0]}";
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.GET command usage:
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
// 2. Add samples into time series
|
||||
$client->tsadd('temperature:2:32', 123123123123, 27);
|
||||
$client->tsadd('temperature:2:32', 123123123124, 28);
|
||||
$client->tsadd('temperature:2:32', 123123123125, 29);
|
||||
|
||||
$response = $client->tsget('temperature:2:32');
|
||||
|
||||
echo "Sample with highest timestamp - {$response[0]} and value {$response[1]}\n";
|
||||
|
||||
// 3. Removes 2 samples with the highest timestamps
|
||||
$response = $client->tsdel('temperature:2:32', 123123123124, 123123123125);
|
||||
|
||||
echo "Removed {$response} samples from timeseries.\n";
|
||||
|
||||
// 3. Retrieve a timestamp with the highest timestamp
|
||||
$response = $client->tsget('temperature:2:32');
|
||||
|
||||
echo "New sample with highest timestamp - {$response[0]} and value {$response[1]}";
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.CREATERULE command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->labels('type', 'temp', 'location', 'TLV');
|
||||
|
||||
$createResponse = $client->tscreate('temp:TLV', $arguments);
|
||||
echo "Original time series creation status: {$createResponse}\n";
|
||||
|
||||
$createResponse = $client->tscreate('dailyAvgTemp:TLV', $arguments);
|
||||
echo "Compacted time series creation status: {$createResponse}\n";
|
||||
|
||||
$createRuleResponse = $client->tscreaterule('temp:TLV', 'dailyAvgTemp:TLV', 'avg', 1000);
|
||||
echo "Compacted rule for compacted time series creation status: {$createRuleResponse}\n";
|
||||
|
||||
// 2. Remove compaction rule
|
||||
$deleteRuleResponse = $client->tsdeleterule('temp:TLV', 'dailyAvgTemp:TLV');
|
||||
echo "Compacted rule for compacted time series deletion status: {$deleteRuleResponse}\n";
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.GET command usage:
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
// 2. Add samples into time series
|
||||
$client->tsadd('temperature:2:32', 123123123123, 27);
|
||||
$client->tsadd('temperature:2:32', 123123123124, 28);
|
||||
$client->tsadd('temperature:2:32', 123123123125, 29);
|
||||
|
||||
// 3. Retrieve a timestamp with highest timestamp
|
||||
$response = $client->tsget('temperature:2:32');
|
||||
|
||||
echo "Sample with highest timestamp - {$response[0]} and value - {$response[1]}";
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\AddArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\IncrByArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.INCRBY command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
// 2. Add sample into newly created time series
|
||||
$addArguments = (new AddArguments())
|
||||
->retentionMsecs(31536000000);
|
||||
|
||||
$response = $client->tsadd('temperature:2:32', 123123123123, 27, $addArguments);
|
||||
|
||||
echo "Timeseries was added with timestamp: {$response}\n";
|
||||
|
||||
// 3. Increasing value and timestamp
|
||||
$client->tsincrby('temperature:2:32', 1, (new IncrByArguments())->timestamp(123123123124));
|
||||
$response = $client->tsget('temperature:2:32');
|
||||
|
||||
echo "Increased value to - {$response[1]} and timestamp to {$response[0]}";
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.CREATE command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
|
||||
// 2. Show info about given time series
|
||||
print_r($client->tsinfo('temperature:2:32'));
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.MADD command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
$client->tscreate('temperature:2:33', $arguments);
|
||||
|
||||
// 2. Add samples into few time series
|
||||
$response = $client->tsmadd('temperature:2:32', 123123123123, 27, 'temperature:2:33', 123123123124, 28);
|
||||
$stringResponse = implode(', ', $response);
|
||||
|
||||
echo "Samples was added to time series - timestamps: {$stringResponse}";
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CommonArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MGetArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.MGET command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->retentionMsecs(60000)
|
||||
->duplicatePolicy(CommonArguments::POLICY_MAX)
|
||||
->labels('type', 'temp', 'sensor_id', 2, 'area_id', 32);
|
||||
|
||||
$client->tscreate('temperature:2:32', $arguments);
|
||||
$client->tscreate('temperature:2:33', $arguments);
|
||||
|
||||
// 2. Add samples into time series
|
||||
$client->tsadd('temperature:2:32', 123123123123, 27);
|
||||
$client->tsadd('temperature:2:33', 123123123124, 27);
|
||||
|
||||
// 3. Get sample from multiple time series matching given filter expression, with selected labels only
|
||||
$response = $client->tsmget((new MGetArguments())->selectedLabels('type'), 'type=temp');
|
||||
|
||||
echo "Sample from time series, with label = 'type':\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MRangeArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.MRANGE command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$response = $client->tscreate('stock:A', (new CreateArguments())->labels('type', 'stock', 'name', 'A'));
|
||||
echo "Time series A creation status: {$response}\n";
|
||||
|
||||
$response = $client->tscreate('stock:B', (new CreateArguments())->labels('type', 'stock', 'name', 'B'));
|
||||
echo "Time series B creation status: {$response}\n";
|
||||
|
||||
// 2. Add samples into both time series
|
||||
$response = $client->tsmadd('stock:A', 1000, 100, 'stock:A', 1010, 110, 'stock:A', 1020, 120);
|
||||
$stringResponse = implode(', ', $response);
|
||||
echo "Added samples into time series A with following timestamps: {$stringResponse}\n";
|
||||
|
||||
$response = $client->tsmadd('stock:B', 1000, 120, 'stock:B', 1010, 110, 'stock:B', 1020, 100);
|
||||
$stringResponse = implode(', ', $response);
|
||||
echo "Added samples into time series B with following timestamps: {$stringResponse}\n";
|
||||
|
||||
// 3. Query range across both time series filtered by "type" and grouped by max type
|
||||
$mrangeArguments = (new MRangeArguments())
|
||||
->withLabels()
|
||||
->filter('type=stock')
|
||||
->groupBy('type', 'max');
|
||||
|
||||
$response = $client->tsmrange('-', '+', $mrangeArguments);
|
||||
|
||||
echo "Response:\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MRangeArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.MREVRANGE command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$response = $client->tscreate('stock:A', (new CreateArguments())->labels('type', 'stock', 'name', 'A'));
|
||||
echo "Time series A creation status: {$response}\n";
|
||||
|
||||
$response = $client->tscreate('stock:B', (new CreateArguments())->labels('type', 'stock', 'name', 'B'));
|
||||
echo "Time series B creation status: {$response}\n";
|
||||
|
||||
// 2. Add samples into both time series
|
||||
$response = $client->tsmadd('stock:A', 1000, 100, 'stock:A', 1010, 110, 'stock:A', 1020, 120);
|
||||
$stringResponse = implode(', ', $response);
|
||||
echo "Added samples into time series A with following timestamps: {$stringResponse}\n";
|
||||
|
||||
$response = $client->tsmadd('stock:B', 1000, 120, 'stock:B', 1010, 110, 'stock:B', 1020, 100);
|
||||
$stringResponse = implode(', ', $response);
|
||||
echo "Added samples into time series B with following timestamps: {$stringResponse}\n";
|
||||
|
||||
// 3. Query range across both time series filtered by "type" and grouped by max type
|
||||
$mrangeArguments = (new MRangeArguments())
|
||||
->withLabels()
|
||||
->filter('type=stock')
|
||||
->groupBy('type', 'max');
|
||||
|
||||
$response = $client->tsmrevrange('-', '+', $mrangeArguments);
|
||||
|
||||
echo "Response:\n";
|
||||
print_r($response);
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.QUERYINDEX command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$arguments = (new CreateArguments())
|
||||
->labels('type', 'temp', 'location', 'TLV');
|
||||
|
||||
$createResponse = $client->tscreate('temp:TLV', $arguments);
|
||||
echo "Time series with location TLV creation status: {$createResponse}\n";
|
||||
|
||||
$anotherArguments = (new CreateArguments())
|
||||
->labels('type', 'temp', 'location', 'JER');
|
||||
|
||||
$createResponse = $client->tscreate('temp:JER', $anotherArguments);
|
||||
echo "Time series with location JER creation status: {$createResponse}\n";
|
||||
|
||||
echo "Returns all keys with location=TLV:\n";
|
||||
print_r($client->tsqueryindex('location=TLV'));
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\RangeArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.RANGE command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$createArguments = (new CreateArguments())->labels('type', 'temp', 'location', 'TLV');
|
||||
$createResponse = $client->tscreate('temp:TLV', $createArguments);
|
||||
|
||||
echo "Time series creation status: {$createResponse}\n";
|
||||
|
||||
// 2. Add samples into time series
|
||||
$maddResponse = $client->tsmadd('temp:TLV', 1000, 30, 'temp:TLV', 1010, 35, 'temp:TLV', 1020, 9999, 'temp:TLV', 1030, 40);
|
||||
$stringResponse = implode(', ', $maddResponse);
|
||||
|
||||
echo "Samples was added with following timestamps: {$stringResponse}\n";
|
||||
|
||||
// 3. Query samples by values in the given range
|
||||
$rangeArguments = (new RangeArguments())->filterByValue(-100, 100);
|
||||
$rangeResponse = $client->tsrange('temp:TLV', '-', '+', $rangeArguments);
|
||||
|
||||
echo "Samples with temperature in range -100 to 100 degrees:\n";
|
||||
print_r($rangeResponse);
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\RangeArguments;
|
||||
|
||||
require __DIR__ . '/../../shared.php';
|
||||
|
||||
// Example of TS.REVRANGE command usage:
|
||||
|
||||
// 1. Create time series
|
||||
$client = new Client();
|
||||
|
||||
$createArguments = (new CreateArguments())->labels('type', 'temp', 'location', 'TLV');
|
||||
$createResponse = $client->tscreate('temp:TLV', $createArguments);
|
||||
|
||||
echo "Time series creation status: {$createResponse}\n";
|
||||
|
||||
// 2. Add samples into time series
|
||||
$maddResponse = $client->tsmadd('temp:TLV', 1000, 30, 'temp:TLV', 1010, 35, 'temp:TLV', 1020, 9999, 'temp:TLV', 1030, 40);
|
||||
$stringResponse = implode(', ', $maddResponse);
|
||||
|
||||
echo "Samples was added with following timestamps: {$stringResponse}\n";
|
||||
|
||||
// 3. Query samples by values in the given range
|
||||
$rangeArguments = (new RangeArguments())->filterByValue(-100, 100);
|
||||
$rangeResponse = $client->tsrevrange('temp:TLV', '-', '+', $rangeArguments);
|
||||
|
||||
echo "Samples with temperature in range -100 to 100 degrees in reverse order:\n";
|
||||
print_r($rangeResponse);
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../shared.php';
|
||||
|
||||
// Example of ACL DRYRUN command usage:
|
||||
|
||||
// 1. Set user with permissions to call only 'SET' command.
|
||||
$client = new Client($single_server);
|
||||
$response = $client->acl->setUser('Test_dry', '+SET', '~*');
|
||||
$created = ($response == 'OK') ? 'Yes' : 'No';
|
||||
|
||||
echo "User with username 'Test' was created: {$created}. Permissions only to use SET command\n";
|
||||
|
||||
// 2. Dry run 'SET' command under 'Test_dry' user
|
||||
$response = $client->acl->dryRun('Test_dry', 'SET', 'foo', 'bar');
|
||||
|
||||
echo 'Dry run "SET" command.' . "\n";
|
||||
echo 'Response: ' . $response . "\n";
|
||||
|
||||
// 3. Dry run 'GET' command under 'Test_dry' user
|
||||
$response = $client->acl->dryRun('Test_dry', 'GET', 'foo');
|
||||
|
||||
echo 'Dry run "GET" command.' . "\n";
|
||||
echo 'Response: ' . $response;
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../shared.php';
|
||||
|
||||
// Example of ACL GETUSER command usage:
|
||||
|
||||
// 1. Set user
|
||||
$client = new Client($single_server);
|
||||
$response = $client->acl->setUser('Test');
|
||||
|
||||
// 2. Retrieve user rules:
|
||||
|
||||
echo 'Rules: ' . "\n";
|
||||
print_r(
|
||||
$client->acl->getUser('Test')
|
||||
);
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../shared.php';
|
||||
|
||||
// Example of ACL SETUSER command usage:
|
||||
|
||||
// 1. Set user
|
||||
$client = new Client($single_server);
|
||||
$response = $client->acl->setUser('Test');
|
||||
$created = ($response == 'OK') ? 'Yes' : 'No';
|
||||
|
||||
echo "User with username 'Test' was created: {$created}";
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../shared.php';
|
||||
|
||||
// Example of FCALL_RO command usage:
|
||||
|
||||
// 1. Set key-value pair
|
||||
$client = new Client($single_server);
|
||||
$client->set('foo', 'bar');
|
||||
|
||||
echo "Set key 'foo' with value 'bar'\n";
|
||||
|
||||
// 2. Load redis function with 'no-writes' flag
|
||||
$client->function->load(
|
||||
"#!lua name=mylib
|
||||
redis.register_function{
|
||||
function_name='myfunc',
|
||||
callback=function(keys, args) return redis.call('GET', keys[1]) end,
|
||||
flags={'no-writes'}
|
||||
}"
|
||||
);
|
||||
|
||||
echo 'Loaded custom function that perform GET command against provided key.' . "\n";
|
||||
|
||||
// 3. Call function above with given key
|
||||
$response = $client->fcall_ro('myfunc', ['foo']);
|
||||
|
||||
echo "Function returned value against provided key 'foo' is '{$response}'";
|
||||
|
||||
// 4. Delete test library
|
||||
$client->function->delete('mylib');
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Predis\Client;
|
||||
|
||||
require __DIR__ . '/../shared.php';
|
||||
|
||||
// Example of WAITAOF command usage:
|
||||
|
||||
// 1. Enable appendonly mode if it's not (command works only in appendonly mode)
|
||||
$client = new Client($single_server);
|
||||
$info = $client->info();
|
||||
$enabled = false;
|
||||
|
||||
if ($info['Persistence']['aof_enabled'] === '0') {
|
||||
$client->config('set', 'appendonly', 'yes');
|
||||
$enabled = true;
|
||||
}
|
||||
|
||||
// 2. Set key value pair
|
||||
$response = $client->set('foo', 'bar');
|
||||
echo "Key-value pair set status: {$response}\n";
|
||||
|
||||
// 3. Run WAITAOF command to make sure that all previous writes was fsynced
|
||||
$response = $client->waitaof(1, 0, 0);
|
||||
|
||||
echo "Quantity of local instances that was fsynced - {$response[0]}, quantity of replicas - {$response[1]}";
|
||||
|
||||
// 4. Disable appendonly mode if it was enabled during script execution
|
||||
if ($enabled) {
|
||||
$client->config('set', 'appendonly', 'no');
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -24,10 +24,10 @@ $pubsub = $client->pubSubLoop();
|
||||
// Subscribe to your channels
|
||||
$pubsub->subscribe('control_channel', 'notifications');
|
||||
|
||||
// Start processing the pubsup messages. Open a terminal and use redis-cli
|
||||
// Start processing the pubsub messages. Open a terminal and use redis-cli
|
||||
// to push messages to the channels. Examples:
|
||||
// ./redis-cli PUBLISH notifications "this is a test"
|
||||
// ./redis-cli PUBLISH control_channel quit_loop
|
||||
// redis-cli PUBLISH notifications "this is a test"
|
||||
// redis-cli PUBLISH control_channel quit_loop
|
||||
foreach ($pubsub as $message) {
|
||||
switch ($message->kind) {
|
||||
case 'subscribe':
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/shared.php';
|
||||
|
||||
// Enable igbinary serializer as well as LZ4 compression
|
||||
$options = [
|
||||
'serializer' => 'igbinary',
|
||||
'compression' => 'lz4',
|
||||
];
|
||||
|
||||
$client = new Predis\Client($single_server + $options, [
|
||||
'connections' => 'relay',
|
||||
]);
|
||||
|
||||
$quote = (object) [
|
||||
'author' => 'Jean-Luc Picard',
|
||||
'text' => 'I look forward to your report Mr. Broccoli.',
|
||||
];
|
||||
|
||||
// Serialize object and apply LZ4 compression, then write key to Redis
|
||||
$client->set('quote', $client->pack($quote));
|
||||
|
||||
// NOTE: In Predis v3.x serialization and compression will happen
|
||||
// automatically without the need to call `pack()` and `unpack()`
|
||||
|
||||
// Retrieve raw binary value from Redis
|
||||
$raw = $client->get('quote');
|
||||
|
||||
// Decompress and unserialize binary value
|
||||
$data = $client->unpack($raw);
|
||||
|
||||
var_dump($quote == $data); // true
|
||||
|
||||
var_dump($data);
|
||||
|
||||
/*
|
||||
object(stdClass)#11 (2) {
|
||||
["author"]=>string(15) "Jean-Luc Picard"
|
||||
["text"]=>string(43) "I look forward to your report Mr. Broccoli."
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/shared.php';
|
||||
|
||||
$options = [
|
||||
'timeout' => 1.0,
|
||||
'read_write_timeout' => 1.0,
|
||||
|
||||
// Relay specific options
|
||||
'cache' => true,
|
||||
// 'compression' => 'lz4',
|
||||
// 'serializer' => 'igbinary',
|
||||
];
|
||||
|
||||
$client = new Predis\Client($single_server + $options, [
|
||||
'connections' => 'relay',
|
||||
]);
|
||||
|
||||
// Write key to Redis
|
||||
$client->set('torpedo', mt_rand());
|
||||
|
||||
// Retrieve key from Redis
|
||||
$client->get('torpedo');
|
||||
|
||||
// Retrieve key from Relay (without talking to Redis)
|
||||
// This key is now available to all PHP workers in this FPM pool
|
||||
$client->get('torpedo');
|
||||
|
||||
// For debugging only:
|
||||
var_export(
|
||||
$client->getConnection()->getClient()->_getKeys()
|
||||
);
|
||||
|
||||
/*
|
||||
array (
|
||||
'torpedo' => array (
|
||||
0 => array (
|
||||
'type' => 'string',
|
||||
'local-len' => 10,
|
||||
'remote-len' => 10,
|
||||
'size' => 10,
|
||||
),
|
||||
),
|
||||
)
|
||||
*/
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/shared.php';
|
||||
|
||||
$key = null;
|
||||
|
||||
$client = new Predis\Client($single_server, [
|
||||
'connections' => 'relay',
|
||||
]);
|
||||
|
||||
/** @var Predis\Connection\RelayConnection $relay */
|
||||
$relay = $client->getConnection();
|
||||
|
||||
// establish connection
|
||||
$client->ping();
|
||||
|
||||
// register `FLUSH*` callback
|
||||
$relay->onFlushed(
|
||||
static function (Relay\Event $event) use (&$key) {
|
||||
echo 'Redis was flushed, unsetting $key...' . PHP_EOL;
|
||||
$key = null;
|
||||
}
|
||||
);
|
||||
|
||||
// register `INVALIDATE` callback
|
||||
$relay->onInvalidated(
|
||||
static function (Relay\Event $event) use (&$key) {
|
||||
if ($event->key === 'library') {
|
||||
echo "The `{$event->key}` key was invalidated, unsetting \$key..." . PHP_EOL;
|
||||
$key = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Write key to Redis
|
||||
$client->set('library', mt_rand());
|
||||
|
||||
// Retrieve key once from Redis, then cached in Relay and $key
|
||||
$key = $client->get('library');
|
||||
|
||||
while (true) {
|
||||
echo '$key is: ' . var_export($key, true) . PHP_EOL;
|
||||
|
||||
// To trigger our event callbacks, we need to either interact with Relay:
|
||||
$client->get(mt_rand());
|
||||
|
||||
// ... or alternatively dispatch events directly on Relay:
|
||||
$relay->dispatchEvents();
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__ . '/shared.php';
|
||||
|
||||
// Create a Relay client and disable r/w timeout on the connection
|
||||
$client = new Predis\Client(
|
||||
$single_server + ['read_write_timeout' => 0],
|
||||
['connections' => 'relay']
|
||||
);
|
||||
|
||||
// Initialize a new pubsub consumer.
|
||||
$pubsub = $client->pubSubLoop();
|
||||
|
||||
// When using Relay you cannot use foreach-loops to iterate
|
||||
// over messages instead use a callback function
|
||||
$poorMansKafka = function ($message, $client) {
|
||||
switch ($message->kind) {
|
||||
case 'subscribe':
|
||||
echo "Subscribed to {$message->channel}", PHP_EOL;
|
||||
break;
|
||||
|
||||
case 'message':
|
||||
case 'pmessage':
|
||||
if ($message->channel == 'control_channel') {
|
||||
if ($message->payload == 'quit_loop') {
|
||||
echo 'Aborting pubsub loop...', PHP_EOL;
|
||||
$client->unsubscribe();
|
||||
} else {
|
||||
echo "Received an unrecognized command: {$message->payload}.", PHP_EOL;
|
||||
}
|
||||
} else {
|
||||
echo "Received the message from `{$message->channel}` channel:",
|
||||
PHP_EOL, " {$message->payload}", PHP_EOL, PHP_EOL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Subscribe to your channels and start processing the messages.
|
||||
$pubsub->subscribe('control_channel', 'notifications', $poorMansKafka);
|
||||
|
||||
// Open a terminal and use redis-cli to push messages to the channels. Examples:
|
||||
// redis-cli PUBLISH notifications "this is a test"
|
||||
// redis-cli PUBLISH control_channel quit_loop
|
||||
|
||||
// When using Relay, there is no need to unset the pubsub consumer instance when you are done
|
||||
|
||||
// Say goodbye :-)
|
||||
$version = redis_version($client->info());
|
||||
echo "Goodbye from Redis $version!", PHP_EOL;
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -32,7 +32,7 @@ function zpop($client, $key)
|
||||
'cas' => true, // Initialize with support for CAS operations
|
||||
'watch' => $key, // Key that needs to be WATCHed to detect changes
|
||||
'retry' => 3, // Number of retries on aborted transactions, after
|
||||
// which the client bails out with an exception.
|
||||
// which the client bails out with an exception.
|
||||
];
|
||||
|
||||
$client->transaction($options, function ($tx) use ($key, &$element) {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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"
|
||||
beStrictAboutTestsThatDoNotTestAnything="true"
|
||||
>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Predis Test Suite">
|
||||
<directory phpVersion="7.4">tests/Predis/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>relay-incompatible</group>
|
||||
<group>relay-resp3</group>
|
||||
<group>realm-webdis</group>
|
||||
<group>realm-stack</group>
|
||||
<group>ext-curl</group>
|
||||
<group>ext-phpiredis</group>
|
||||
<group>cluster</group>
|
||||
</exclude>
|
||||
</groups>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<php>
|
||||
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
|
||||
<const name="REDIS_SERVER_PORT" value="6379" />
|
||||
<const name="REDIS_SERVER_DBNUM" value="0" />
|
||||
<env name="USE_RELAY" value="true" />
|
||||
<env name="REDIS_STACK_SERVER_PORT" value="6479" />
|
||||
|
||||
<!-- Redis Cluster -->
|
||||
<!-- Only master nodes endpoints included -->
|
||||
<const name="REDIS_CLUSTER_ENDPOINTS" value="127.0.0.1:6372,127.0.0.1:6373,127.0.0.1:6374" />
|
||||
</php>
|
||||
</phpunit>
|
||||
+11
-7
@@ -28,9 +28,12 @@
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>ext-phpiredis</group>
|
||||
<group>ext-curl</group>
|
||||
<group>realm-webdis</group>
|
||||
<group>realm-stack</group>
|
||||
<group>ext-relay</group>
|
||||
<group>ext-curl</group>
|
||||
<group>ext-phpiredis</group>
|
||||
<group>cluster</group>
|
||||
<!-- <group>connected</group> -->
|
||||
<!-- <group>disconnected</group> -->
|
||||
<!-- <group>commands</group> -->
|
||||
@@ -45,13 +48,14 @@
|
||||
</filter>
|
||||
|
||||
<php>
|
||||
<!-- Redis -->
|
||||
<const name="REDIS_SERVER_HOST" value="127.0.0.1" />
|
||||
<const name="REDIS_SERVER_PORT" value="6379" />
|
||||
<const name="REDIS_SERVER_DBNUM" value="15" />
|
||||
<const name="REDIS_SERVER_DBNUM" value="0" />
|
||||
<env name="USE_RELAY" value="false" />
|
||||
<env name="REDIS_STACK_SERVER_PORT" value="6479" />
|
||||
|
||||
<!-- Webdis -->
|
||||
<const name="WEBDIS_SERVER_HOST" value="127.0.0.1" />
|
||||
<const name="WEBDIS_SERVER_PORT" value="7379" />
|
||||
<!-- Redis Cluster -->
|
||||
<!-- Only master nodes endpoints included -->
|
||||
<const name="REDIS_CLUSTER_ENDPOINTS" value="127.0.0.1:6372,127.0.0.1:6373,127.0.0.1:6374" />
|
||||
</php>
|
||||
</phpunit>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
+68
-22
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -25,9 +25,15 @@ use Predis\Configuration\OptionsInterface;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Connection\Parameters;
|
||||
use Predis\Connection\ParametersInterface;
|
||||
use Predis\Connection\RelayConnection;
|
||||
use Predis\Monitor\Consumer as MonitorConsumer;
|
||||
use Predis\Pipeline\Atomic;
|
||||
use Predis\Pipeline\FireAndForget;
|
||||
use Predis\Pipeline\Pipeline;
|
||||
use Predis\Pipeline\RelayAtomic;
|
||||
use Predis\Pipeline\RelayPipeline;
|
||||
use Predis\PubSub\Consumer as PubSubConsumer;
|
||||
use Predis\PubSub\RelayConsumer as RelayPubSubConsumer;
|
||||
use Predis\Response\ErrorInterface as ErrorResponseInterface;
|
||||
use Predis\Response\ResponseInterface;
|
||||
use Predis\Response\ServerException;
|
||||
@@ -47,7 +53,7 @@ use Traversable;
|
||||
*/
|
||||
class Client implements ClientInterface, IteratorAggregate
|
||||
{
|
||||
public const VERSION = '2.1.2';
|
||||
public const VERSION = '2.4.0';
|
||||
|
||||
/** @var OptionsInterface */
|
||||
private $options;
|
||||
@@ -262,6 +268,32 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured serializer and compression to given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function pack($value)
|
||||
{
|
||||
return $this->connection instanceof RelayConnection
|
||||
? $this->connection->pack($value)
|
||||
: $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes and decompresses to given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function unpack($value)
|
||||
{
|
||||
return $this->connection instanceof RelayConnection
|
||||
? $this->connection->unpack($value)
|
||||
: $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a command without filtering its arguments, parsing the response,
|
||||
* applying any prefix to keys or throwing exceptions on Redis errors even
|
||||
@@ -314,29 +346,29 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param string $name
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function __get($name)
|
||||
public function __get(string $name)
|
||||
{
|
||||
return ContainerFactory::create($this, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
public function __set(string $name, $value)
|
||||
{
|
||||
throw new RuntimeException('Not allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __isset($name)
|
||||
public function __isset(string $name)
|
||||
{
|
||||
throw new RuntimeException('Not allowed');
|
||||
}
|
||||
@@ -435,19 +467,29 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
/**
|
||||
* Actual pipeline context initializer method.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable used to execute the context.
|
||||
* @param array|null $options Options for the context.
|
||||
* @param mixed $callable Optional callable used to execute the context.
|
||||
*
|
||||
* @return Pipeline|array
|
||||
*/
|
||||
protected function createPipeline(array $options = null, $callable = null)
|
||||
protected function createPipeline(?array $options = null, $callable = null)
|
||||
{
|
||||
if (isset($options['atomic']) && $options['atomic']) {
|
||||
$class = 'Predis\Pipeline\Atomic';
|
||||
$class = Atomic::class;
|
||||
} elseif (isset($options['fire-and-forget']) && $options['fire-and-forget']) {
|
||||
$class = 'Predis\Pipeline\FireAndForget';
|
||||
$class = FireAndForget::class;
|
||||
} else {
|
||||
$class = 'Predis\Pipeline\Pipeline';
|
||||
$class = Pipeline::class;
|
||||
}
|
||||
|
||||
if ($this->connection instanceof RelayConnection) {
|
||||
if (isset($options['atomic']) && $options['atomic']) {
|
||||
$class = RelayAtomic::class;
|
||||
} elseif (isset($options['fire-and-forget']) && $options['fire-and-forget']) {
|
||||
throw new NotSupportedException('The "relay" extension does not support fire-and-forget pipelines.');
|
||||
} else {
|
||||
$class = RelayPipeline::class;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -478,12 +520,12 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
/**
|
||||
* Actual transaction context initializer method.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable used to execute the context.
|
||||
* @param array|null $options Options for the context.
|
||||
* @param mixed $callable Optional callable used to execute the context.
|
||||
*
|
||||
* @return MultiExecTransaction|array
|
||||
*/
|
||||
protected function createTransaction(array $options = null, $callable = null)
|
||||
protected function createTransaction(?array $options = null, $callable = null)
|
||||
{
|
||||
$transaction = new MultiExecTransaction($this, $options);
|
||||
|
||||
@@ -510,14 +552,18 @@ class Client implements ClientInterface, IteratorAggregate
|
||||
/**
|
||||
* Actual publish/subscribe context initializer method.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable used to execute the context.
|
||||
* @param array|null $options Options for the context.
|
||||
* @param mixed $callable Optional callable used to execute the context.
|
||||
*
|
||||
* @return PubSubConsumer|null
|
||||
*/
|
||||
protected function createPubSub(array $options = null, $callable = null)
|
||||
protected function createPubSub(?array $options = null, $callable = null)
|
||||
{
|
||||
$pubsub = new PubSubConsumer($this, $options);
|
||||
if ($this->connection instanceof RelayConnection) {
|
||||
$pubsub = new RelayPubSubConsumer($this, $options);
|
||||
} else {
|
||||
$pubsub = new PubSubConsumer($this, $options);
|
||||
}
|
||||
|
||||
if (!isset($callable)) {
|
||||
return $pubsub;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
class ClientConfiguration
|
||||
{
|
||||
/**
|
||||
* @var array{modules: array}|string[][]
|
||||
*/
|
||||
private static $config = [
|
||||
'modules' => [
|
||||
['name' => 'Json', 'commandPrefix' => 'JSON'],
|
||||
['name' => 'BloomFilter', 'commandPrefix' => 'BF'],
|
||||
['name' => 'CuckooFilter', 'commandPrefix' => 'CF'],
|
||||
['name' => 'CountMinSketch', 'commandPrefix' => 'CMS'],
|
||||
['name' => 'TDigest', 'commandPrefix' => 'TDIGEST'],
|
||||
['name' => 'TopK', 'commandPrefix' => 'TOPK'],
|
||||
['name' => 'Search', 'commandPrefix' => 'FT'],
|
||||
['name' => 'TimeSeries', 'commandPrefix' => 'TS'],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns available modules with configuration.
|
||||
*
|
||||
* @return array|string[][]
|
||||
*/
|
||||
public static function getModules(): array
|
||||
{
|
||||
return self::$config['modules'];
|
||||
}
|
||||
}
|
||||
+173
-15
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -14,10 +14,38 @@ namespace Predis;
|
||||
|
||||
use Predis\Command\Argument\Geospatial\ByInterface;
|
||||
use Predis\Command\Argument\Geospatial\FromInterface;
|
||||
use Predis\Command\Argument\Search\AggregateArguments;
|
||||
use Predis\Command\Argument\Search\AlterArguments;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\DropArguments;
|
||||
use Predis\Command\Argument\Search\ExplainArguments;
|
||||
use Predis\Command\Argument\Search\ProfileArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
|
||||
use Predis\Command\Argument\Search\SearchArguments;
|
||||
use Predis\Command\Argument\Search\SugAddArguments;
|
||||
use Predis\Command\Argument\Search\SugGetArguments;
|
||||
use Predis\Command\Argument\Search\SynUpdateArguments;
|
||||
use Predis\Command\Argument\Server\LimitOffsetCount;
|
||||
use Predis\Command\Argument\Server\To;
|
||||
use Predis\Command\Argument\TimeSeries\AddArguments;
|
||||
use Predis\Command\Argument\TimeSeries\AlterArguments as TSAlterArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments as TSCreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\DecrByArguments;
|
||||
use Predis\Command\Argument\TimeSeries\GetArguments;
|
||||
use Predis\Command\Argument\TimeSeries\IncrByArguments;
|
||||
use Predis\Command\Argument\TimeSeries\InfoArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MGetArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MRangeArguments;
|
||||
use Predis\Command\Argument\TimeSeries\RangeArguments;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\Redis\Container\ACL;
|
||||
use Predis\Command\Redis\Container\CLUSTER;
|
||||
use Predis\Command\Redis\Container\FunctionContainer;
|
||||
use Predis\Command\Redis\Container\Json\JSONDEBUG;
|
||||
use Predis\Command\Redis\Container\Search\FTCONFIG;
|
||||
use Predis\Command\Redis\Container\Search\FTCURSOR;
|
||||
use Predis\Command\Redis\HGETEX;
|
||||
use Predis\Command\Redis\HSETEX;
|
||||
|
||||
/**
|
||||
* Interface defining a client-side context such as a pipeline or transaction.
|
||||
@@ -39,24 +67,76 @@ use Predis\Command\Redis\Container\FunctionContainer;
|
||||
* @method $this randomkey()
|
||||
* @method $this rename($key, $target)
|
||||
* @method $this renamenx($key, $target)
|
||||
* @method $this scan($cursor, array $options = null)
|
||||
* @method $this sort($key, array $options = null)
|
||||
* @method $this scan($cursor, ?array $options = null)
|
||||
* @method $this sort($key, ?array $options = null)
|
||||
* @method $this sort_ro(string $key, ?string $byPattern = null, ?LimitOffsetCount $limit = null, array $getPatterns = [], ?string $sorting = null, bool $alpha = false)
|
||||
* @method $this ttl($key)
|
||||
* @method $this type($key)
|
||||
* @method $this append($key, $value)
|
||||
* @method $this bitcount($key, $start = null, $end = null, string $index = 'byte')
|
||||
* @method $this bfadd(string $key, $item)
|
||||
* @method $this bfexists(string $key, $item)
|
||||
* @method $this bfinfo(string $key, string $modifier = '')
|
||||
* @method $this bfinsert(string $key, int $capacity = -1, float $error = -1, int $expansion = -1, bool $noCreate = false, bool $nonScaling = false, string ...$item)
|
||||
* @method $this bfloadchunk(string $key, int $iterator, $data)
|
||||
* @method $this bfmadd(string $key, ...$item)
|
||||
* @method $this bfmexists(string $key, ...$item)
|
||||
* @method $this bfreserve(string $key, float $errorRate, int $capacity, int $expansion = -1, bool $nonScaling = false)
|
||||
* @method $this bfscandump(string $key, int $iterator)
|
||||
* @method $this bitcount(string $key, $start = null, $end = null, string $index = 'byte')
|
||||
* @method $this bitop($operation, $destkey, $key)
|
||||
* @method $this bitfield($key, $subcommand, ...$subcommandArg)
|
||||
* @method $this bitfield_ro(string $key, ?array $encodingOffsetMap = null)
|
||||
* @method $this bitpos($key, $bit, $start = null, $end = null, string $index = 'byte')
|
||||
* @method $this blmpop(int $timeout, array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method $this bzpopmax(array $keys, int $timeout)
|
||||
* @method $this bzpopmin(array $keys, int $timeout)
|
||||
* @method $this bzmpop(int $timeout, array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method $this cfadd(string $key, $item)
|
||||
* @method $this cfaddnx(string $key, $item)
|
||||
* @method $this cfcount(string $key, $item)
|
||||
* @method $this cfdel(string $key, $item)
|
||||
* @method $this cfexists(string $key, $item)
|
||||
* @method $this cfloadchunk(string $key, int $iterator, $data)
|
||||
* @method $this cfmexists(string $key, ...$item)
|
||||
* @method $this cfinfo(string $key)
|
||||
* @method $this cfinsert(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
|
||||
* @method $this cfinsertnx(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
|
||||
* @method $this cfreserve(string $key, int $capacity, int $bucketSize = -1, int $maxIterations = -1, int $expansion = -1)
|
||||
* @method $this cfscandump(string $key, int $iterator)
|
||||
* @method $this cmsincrby(string $key, string|int...$itemIncrementDictionary)
|
||||
* @method $this cmsinfo(string $key)
|
||||
* @method $this cmsinitbydim(string $key, int $width, int $depth)
|
||||
* @method $this cmsinitbyprob(string $key, float $errorRate, float $probability)
|
||||
* @method $this cmsmerge(string $destination, array $sources, array $weights = [])
|
||||
* @method $this cmsquery(string $key, string ...$item)
|
||||
* @method $this decr($key)
|
||||
* @method $this decrby($key, $decrement)
|
||||
* @method $this failover(?To $to = null, bool $abort = false, int $timeout = -1)
|
||||
* @method $this fcall(string $function, array $keys, ...$args)
|
||||
* @method $this fcall_ro(string $function, array $keys, ...$args)
|
||||
* @method $this ft_list()
|
||||
* @method $this ftaggregate(string $index, string $query, ?AggregateArguments $arguments = null)
|
||||
* @method $this ftaliasadd(string $alias, string $index)
|
||||
* @method $this ftaliasdel(string $alias)
|
||||
* @method $this ftaliasupdate(string $alias, string $index)
|
||||
* @method $this ftalter(string $index, FieldInterface[] $schema, ?AlterArguments $arguments = null)
|
||||
* @method $this ftcreate(string $index, FieldInterface[] $schema, ?CreateArguments $arguments = null)
|
||||
* @method $this ftdictadd(string $dict, ...$term)
|
||||
* @method $this ftdictdel(string $dict, ...$term)
|
||||
* @method $this ftdictdump(string $dict)
|
||||
* @method $this ftdropindex(string $index, ?DropArguments $arguments = null)
|
||||
* @method $this ftexplain(string $index, string $query, ?ExplainArguments $arguments = null)
|
||||
* @method $this ftinfo(string $index)
|
||||
* @method $this ftprofile(string $index, ProfileArguments $arguments)
|
||||
* @method $this ftsearch(string $index, string $query, ?SearchArguments $arguments = null)
|
||||
* @method $this ftspellcheck(string $index, string $query, ?SearchArguments $arguments = null)
|
||||
* @method $this ftsugadd(string $key, string $string, float $score, ?SugAddArguments $arguments = null)
|
||||
* @method $this ftsugdel(string $key, string $string)
|
||||
* @method $this ftsugget(string $key, string $prefix, ?SugGetArguments $arguments = null)
|
||||
* @method $this ftsuglen(string $key)
|
||||
* @method $this ftsyndump(string $index)
|
||||
* @method $this ftsynupdate(string $index, string $synonymGroupId, ?SynUpdateArguments $arguments = null, string ...$terms)
|
||||
* @method $this fttagvals(string $index, string $fieldName)
|
||||
* @method $this get($key)
|
||||
* @method $this getbit($key, $offset)
|
||||
* @method $this getex(string $key, $modifier = '', $value = false)
|
||||
@@ -78,8 +158,17 @@ use Predis\Command\Redis\Container\FunctionContainer;
|
||||
* @method $this strlen($key)
|
||||
* @method $this hdel($key, array $fields)
|
||||
* @method $this hexists($key, $field)
|
||||
* @method $this hexpire(string $key, int $seconds, array $fields, string $flag = null)
|
||||
* @method $this hexpireat(string $key, int $unixTimeSeconds, array $fields, string $flag = null)
|
||||
* @method $this hexpiretime(string $key, array $fields)
|
||||
* @method $this hpersist(string $key, array $fields)
|
||||
* @method $this hpexpire(string $key, int $milliseconds, array $fields, string $flag = null)
|
||||
* @method $this hpexpireat(string $key, int $unixTimeMilliseconds, array $fields, string $flag = null)
|
||||
* @method $this hpexpiretime(string $key, array $fields)
|
||||
* @method $this hget($key, $field)
|
||||
* @method $this hgetex(string $key, array $fields, string $modifier = HGETEX::NULL)
|
||||
* @method $this hgetall($key)
|
||||
* @method $this hgetdel(string $key, array $fields)
|
||||
* @method $this hincrby($key, $field, $increment)
|
||||
* @method $this hincrbyfloat($key, $field, $increment)
|
||||
* @method $this hkeys($key)
|
||||
@@ -87,11 +176,36 @@ use Predis\Command\Redis\Container\FunctionContainer;
|
||||
* @method $this hmget($key, array $fields)
|
||||
* @method $this hmset($key, array $dictionary)
|
||||
* @method $this hrandfield(string $key, int $count = 1, bool $withValues = false)
|
||||
* @method $this hscan($key, $cursor, array $options = null)
|
||||
* @method $this hscan($key, $cursor, ?array $options = null)
|
||||
* @method $this hset($key, $field, $value)
|
||||
* @method $this hsetex(string $key, array $fieldValueMap, string $setModifier = HSETEX::SET_NULL, string $ttlModifier = HSETEX::TTL_NULL, int|bool $ttlModifierValue = false)
|
||||
* @method $this hsetnx($key, $field, $value)
|
||||
* @method $this httl(string $key, array $fields)
|
||||
* @method $this hpttl(string $key, array $fields)
|
||||
* @method $this hvals($key)
|
||||
* @method $this hstrlen($key, $field)
|
||||
* @method $this jsonarrappend(string $key, string $path = '$', ...$value)
|
||||
* @method $this jsonarrindex(string $key, string $path, string $value, int $start = 0, int $stop = 0)
|
||||
* @method $this jsonarrinsert(string $key, string $path, int $index, string ...$value)
|
||||
* @method $this jsonarrlen(string $key, string $path = '$')
|
||||
* @method $this jsonarrpop(string $key, string $path = '$', int $index = -1)
|
||||
* @method $this jsonarrtrim(string $key, string $path, int $start, int $stop)
|
||||
* @method $this jsonclear(string $key, string $path = '$')
|
||||
* @method $this jsondel(string $key, string $path = '$')
|
||||
* @method $this jsonforget(string $key, string $path = '$')
|
||||
* @method $this jsonget(string $key, string $indent = '', string $newline = '', string $space = '', string ...$paths)
|
||||
* @method $this jsonnumincrby(string $key, string $path, int $value)
|
||||
* @method $this jsonmerge(string $key, string $path, string $value)
|
||||
* @method $this jsonmget(array $keys, string $path)
|
||||
* @method $this jsonmset(string ...$keyPathValue)
|
||||
* @method $this jsonobjkeys(string $key, string $path = '$')
|
||||
* @method $this jsonobjlen(string $key, string $path = '$')
|
||||
* @method $this jsonresp(string $key, string $path = '$')
|
||||
* @method $this jsonset(string $key, string $path, string $value, ?string $subcommand = null)
|
||||
* @method $this jsonstrappend(string $key, string $path, string $value)
|
||||
* @method $this jsonstrlen(string $key, string $path = '$')
|
||||
* @method $this jsontoggle(string $key, string $path)
|
||||
* @method $this jsontype(string $key, string $path = '$')
|
||||
* @method $this blmove(string $source, string $destination, string $where, string $to, int $timeout)
|
||||
* @method $this blpop(array|string $keys, $timeout)
|
||||
* @method $this brpop(array|string $keys, $timeout)
|
||||
@@ -127,9 +241,46 @@ use Predis\Command\Redis\Container\FunctionContainer;
|
||||
* @method $this spop($key, $count = null)
|
||||
* @method $this srandmember($key, $count = null)
|
||||
* @method $this srem($key, $member)
|
||||
* @method $this sscan($key, $cursor, array $options = null)
|
||||
* @method $this sscan($key, $cursor, ?array $options = null)
|
||||
* @method $this sunion(array|string $keys)
|
||||
* @method $this sunionstore($destination, array|string $keys)
|
||||
* @method $this tdigestadd(string $key, float ...$value)
|
||||
* @method $this tdigestbyrank(string $key, int ...$rank)
|
||||
* @method $this tdigestbyrevrank(string $key, int ...$reverseRank)
|
||||
* @method $this tdigestcdf(string $key, int ...$value)
|
||||
* @method $this tdigestcreate(string $key, int $compression = 0)
|
||||
* @method $this tdigestinfo(string $key)
|
||||
* @method $this tdigestmax(string $key)
|
||||
* @method $this tdigestmerge(string $destinationKey, array $sourceKeys, int $compression = 0, bool $override = false)
|
||||
* @method $this tdigestquantile(string $key, float ...$quantile)
|
||||
* @method $this tdigestmin(string $key)
|
||||
* @method $this tdigestrank(string $key, ...$value)
|
||||
* @method $this tdigestreset(string $key)
|
||||
* @method $this tdigestrevrank(string $key, float ...$value)
|
||||
* @method $this tdigesttrimmed_mean(string $key, float $lowCutQuantile, float $highCutQuantile)
|
||||
* @method $this topkadd(string $key, ...$items)
|
||||
* @method $this topkincrby(string $key, ...$itemIncrement)
|
||||
* @method $this topkinfo(string $key)
|
||||
* @method $this topklist(string $key, bool $withCount = false)
|
||||
* @method $this topkquery(string $key, ...$items)
|
||||
* @method $this topkreserve(string $key, int $topK, int $width = 8, int $depth = 7, float $decay = 0.9)
|
||||
* @method $this tsadd(string $key, int $timestamp, float $value, ?AddArguments $arguments = null)
|
||||
* @method $this tsalter(string $key, ?TSAlterArguments $arguments = null)
|
||||
* @method $this tscreate(string $key, ?TSCreateArguments $arguments = null)
|
||||
* @method $this tscreaterule(string $sourceKey, string $destKey, string $aggregator, int $bucketDuration, int $alignTimestamp = 0)
|
||||
* @method $this tsdecrby(string $key, float $value, ?DecrByArguments $arguments = null)
|
||||
* @method $this tsdel(string $key, int $fromTimestamp, int $toTimestamp)
|
||||
* @method $this tsdeleterule(string $sourceKey, string $destKey)
|
||||
* @method $this tsget(string $key, ?GetArguments $arguments = null)
|
||||
* @method $this tsincrby(string $key, float $value, ?IncrByArguments $arguments = null)
|
||||
* @method $this tsinfo(string $key, ?InfoArguments $arguments = null)
|
||||
* @method $this tsmadd(mixed ...$keyTimestampValue)
|
||||
* @method $this tsmget(MGetArguments $arguments, string ...$filterExpression)
|
||||
* @method $this tsmrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method $this tsmrevrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method $this tsqueryindex(string ...$filterExpression)
|
||||
* @method $this tsrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
|
||||
* @method $this tsrevrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
|
||||
* @method $this zadd($key, array $membersAndScoresDictionary)
|
||||
* @method $this zcard($key)
|
||||
* @method $this zcount($key, $min, $max)
|
||||
@@ -142,22 +293,22 @@ use Predis\Command\Redis\Container\FunctionContainer;
|
||||
* @method $this zmpop(array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method $this zmscore(string $key, string ...$member)
|
||||
* @method $this zrandmember(string $key, int $count = 1, bool $withScores = false)
|
||||
* @method $this zrange($key, $start, $stop, array $options = null)
|
||||
* @method $this zrangebyscore($key, $min, $max, array $options = null)
|
||||
* @method $this zrange($key, $start, $stop, ?array $options = null)
|
||||
* @method $this zrangebyscore($key, $min, $max, ?array $options = null)
|
||||
* @method $this zrangestore(string $destination, string $source, int|string $min, string|int $max, string|bool $by = false, bool $reversed = false, bool $limit = false, int $offset = 0, int $count = 0)
|
||||
* @method $this zrank($key, $member)
|
||||
* @method $this zrem($key, $member)
|
||||
* @method $this zremrangebyrank($key, $start, $stop)
|
||||
* @method $this zremrangebyscore($key, $min, $max)
|
||||
* @method $this zrevrange($key, $start, $stop, array $options = null)
|
||||
* @method $this zrevrangebyscore($key, $max, $min, array $options = null)
|
||||
* @method $this zrevrange($key, $start, $stop, ?array $options = null)
|
||||
* @method $this zrevrangebyscore($key, $max, $min, ?array $options = null)
|
||||
* @method $this zrevrank($key, $member)
|
||||
* @method $this zunion(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
|
||||
* @method $this zunionstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
|
||||
* @method $this zscore($key, $member)
|
||||
* @method $this zscan($key, $cursor, array $options = null)
|
||||
* @method $this zrangebylex($key, $start, $stop, array $options = null)
|
||||
* @method $this zrevrangebylex($key, $start, $stop, array $options = null)
|
||||
* @method $this zscan($key, $cursor, ?array $options = null)
|
||||
* @method $this zrangebylex($key, $start, $stop, ?array $options = null)
|
||||
* @method $this zrevrangebylex($key, $start, $stop, ?array $options = null)
|
||||
* @method $this zremrangebylex($key, $min, $max)
|
||||
* @method $this zlexcount($key, $min, $max)
|
||||
* @method $this pexpiretime(string $key)
|
||||
@@ -170,12 +321,14 @@ use Predis\Command\Redis\Container\FunctionContainer;
|
||||
* @method $this exec()
|
||||
* @method $this multi()
|
||||
* @method $this unwatch()
|
||||
* @method $this waitaof(int $numLocal, int $numReplicas, int $timeout)
|
||||
* @method $this watch($key)
|
||||
* @method $this eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
|
||||
* @method $this eval_ro(string $script, array $keys, ...$argument)
|
||||
* @method $this evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
|
||||
* @method $this evalsha_ro(string $sha1, array $keys, ...$argument)
|
||||
* @method $this script($subcommand, $argument = null)
|
||||
* @method $this shutdown(?bool $noSave = null, bool $now = false, bool $force = false, bool $abort = false)
|
||||
* @method $this auth($password)
|
||||
* @method $this echo($message)
|
||||
* @method $this ping($message = null)
|
||||
@@ -198,13 +351,18 @@ use Predis\Command\Redis\Container\FunctionContainer;
|
||||
* @method $this geohash($key, array $members)
|
||||
* @method $this geopos($key, array $members)
|
||||
* @method $this geodist($key, $member1, $member2, $unit = null)
|
||||
* @method $this georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
|
||||
* @method $this georadiusbymember($key, $member, $radius, $unit, array $options = null)
|
||||
* @method $this georadius($key, $longitude, $latitude, $radius, $unit, ?array $options = null)
|
||||
* @method $this georadiusbymember($key, $member, $radius, $unit, ?array $options = null)
|
||||
* @method $this geosearch(string $key, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $withCoord = false, bool $withDist = false, bool $withHash = false)
|
||||
* @method $this geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
|
||||
*
|
||||
* Container commands
|
||||
* @property CLUSTER $cluster
|
||||
* @property FunctionContainer $function
|
||||
* @property FTCONFIG $ftconfig
|
||||
* @property FTCURSOR $ftcursor
|
||||
* @property JSONDEBUG $jsondebug
|
||||
* @property ACL $acl
|
||||
*/
|
||||
interface ClientContextInterface
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
+182
-21
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -14,11 +14,39 @@ namespace Predis;
|
||||
|
||||
use Predis\Command\Argument\Geospatial\ByInterface;
|
||||
use Predis\Command\Argument\Geospatial\FromInterface;
|
||||
use Predis\Command\Argument\Search\AggregateArguments;
|
||||
use Predis\Command\Argument\Search\AlterArguments;
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\DropArguments;
|
||||
use Predis\Command\Argument\Search\ExplainArguments;
|
||||
use Predis\Command\Argument\Search\ProfileArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\FieldInterface;
|
||||
use Predis\Command\Argument\Search\SearchArguments;
|
||||
use Predis\Command\Argument\Search\SugAddArguments;
|
||||
use Predis\Command\Argument\Search\SugGetArguments;
|
||||
use Predis\Command\Argument\Search\SynUpdateArguments;
|
||||
use Predis\Command\Argument\Server\LimitOffsetCount;
|
||||
use Predis\Command\Argument\Server\To;
|
||||
use Predis\Command\Argument\TimeSeries\AddArguments;
|
||||
use Predis\Command\Argument\TimeSeries\AlterArguments as TSAlterArguments;
|
||||
use Predis\Command\Argument\TimeSeries\CreateArguments as TSCreateArguments;
|
||||
use Predis\Command\Argument\TimeSeries\DecrByArguments;
|
||||
use Predis\Command\Argument\TimeSeries\GetArguments;
|
||||
use Predis\Command\Argument\TimeSeries\IncrByArguments;
|
||||
use Predis\Command\Argument\TimeSeries\InfoArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MGetArguments;
|
||||
use Predis\Command\Argument\TimeSeries\MRangeArguments;
|
||||
use Predis\Command\Argument\TimeSeries\RangeArguments;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\FactoryInterface;
|
||||
use Predis\Command\Redis\Container\ACL;
|
||||
use Predis\Command\Redis\Container\CLUSTER;
|
||||
use Predis\Command\Redis\Container\FunctionContainer;
|
||||
use Predis\Command\Redis\Container\Json\JSONDEBUG;
|
||||
use Predis\Command\Redis\Container\Search\FTCONFIG;
|
||||
use Predis\Command\Redis\Container\Search\FTCURSOR;
|
||||
use Predis\Command\Redis\HGETEX;
|
||||
use Predis\Command\Redis\HSETEX;
|
||||
use Predis\Configuration\OptionsInterface;
|
||||
use Predis\Connection\ConnectionInterface;
|
||||
use Predis\Response\Status;
|
||||
@@ -48,24 +76,76 @@ use Predis\Response\Status;
|
||||
* @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 array scan($cursor, ?array $options = null)
|
||||
* @method array sort(string $key, ?array $options = null)
|
||||
* @method array sort_ro(string $key, ?string $byPattern = null, ?LimitOffsetCount $limit = null, array $getPatterns = [], ?string $sorting = null, bool $alpha = false)
|
||||
* @method int ttl(string $key)
|
||||
* @method mixed type(string $key)
|
||||
* @method int append(string $key, $value)
|
||||
* @method int bfadd(string $key, $item)
|
||||
* @method int bfexists(string $key, $item)
|
||||
* @method array bfinfo(string $key, string $modifier = '')
|
||||
* @method array bfinsert(string $key, int $capacity = -1, float $error = -1, int $expansion = -1, bool $noCreate = false, bool $nonScaling = false, string ...$item)
|
||||
* @method Status bfloadchunk(string $key, int $iterator, $data)
|
||||
* @method array bfmadd(string $key, ...$item)
|
||||
* @method array bfmexists(string $key, ...$item)
|
||||
* @method Status bfreserve(string $key, float $errorRate, int $capacity, int $expansion = -1, bool $nonScaling = false)
|
||||
* @method array bfscandump(string $key, int $iterator)
|
||||
* @method int bitcount(string $key, $start = null, $end = null, string $index = 'byte')
|
||||
* @method int bitop($operation, $destkey, $key)
|
||||
* @method array|null bitfield(string $key, $subcommand, ...$subcommandArg)
|
||||
* @method array|null bitfield_ro(string $key, ?array $encodingOffsetMap = null)
|
||||
* @method int bitpos(string $key, $bit, $start = null, $end = null, string $index = 'byte')
|
||||
* @method array blmpop(int $timeout, array $keys, string $modifier = 'left', int $count = 1)
|
||||
* @method array bzpopmax(array $keys, int $timeout)
|
||||
* @method array bzpopmin(array $keys, int $timeout)
|
||||
* @method array bzmpop(int $timeout, array $keys, string $modifier = 'min', int $count = 1)
|
||||
* @method int cfadd(string $key, $item)
|
||||
* @method int cfaddnx(string $key, $item)
|
||||
* @method int cfcount(string $key, $item)
|
||||
* @method int cfdel(string $key, $item)
|
||||
* @method int cfexists(string $key, $item)
|
||||
* @method Status cfloadchunk(string $key, int $iterator, $data)
|
||||
* @method int cfmexists(string $key, ...$item)
|
||||
* @method array cfinfo(string $key)
|
||||
* @method array cfinsert(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
|
||||
* @method array cfinsertnx(string $key, int $capacity = -1, bool $noCreate = false, string ...$item)
|
||||
* @method Status cfreserve(string $key, int $capacity, int $bucketSize = -1, int $maxIterations = -1, int $expansion = -1)
|
||||
* @method array cfscandump(string $key, int $iterator)
|
||||
* @method array cmsincrby(string $key, string|int ...$itemIncrementDictionary)
|
||||
* @method array cmsinfo(string $key)
|
||||
* @method Status cmsinitbydim(string $key, int $width, int $depth)
|
||||
* @method Status cmsinitbyprob(string $key, float $errorRate, float $probability)
|
||||
* @method Status cmsmerge(string $destination, array $sources, array $weights = [])
|
||||
* @method array cmsquery(string $key, string ...$item)
|
||||
* @method int decr(string $key)
|
||||
* @method int decrby(string $key, int $decrement)
|
||||
* @method Status failover(?To $to = null, bool $abort = false, int $timeout = -1)
|
||||
* @method mixed fcall(string $function, array $keys, ...$args)
|
||||
* @method mixed fcall_ro(string $function, array $keys, ...$args)
|
||||
* @method array ft_list()
|
||||
* @method array ftaggregate(string $index, string $query, ?AggregateArguments $arguments = null)
|
||||
* @method Status ftaliasadd(string $alias, string $index)
|
||||
* @method Status ftaliasdel(string $alias)
|
||||
* @method Status ftaliasupdate(string $alias, string $index)
|
||||
* @method Status ftalter(string $index, FieldInterface[] $schema, ?AlterArguments $arguments = null)
|
||||
* @method Status ftcreate(string $index, FieldInterface[] $schema, ?CreateArguments $arguments = null)
|
||||
* @method int ftdictadd(string $dict, ...$term)
|
||||
* @method int ftdictdel(string $dict, ...$term)
|
||||
* @method array ftdictdump(string $dict)
|
||||
* @method Status ftdropindex(string $index, ?DropArguments $arguments = null)
|
||||
* @method string ftexplain(string $index, string $query, ?ExplainArguments $arguments = null)
|
||||
* @method array ftinfo(string $index)
|
||||
* @method array ftprofile(string $index, ProfileArguments $arguments)
|
||||
* @method array ftsearch(string $index, string $query, ?SearchArguments $arguments = null)
|
||||
* @method array ftspellcheck(string $index, string $query, ?SearchArguments $arguments = null)
|
||||
* @method int ftsugadd(string $key, string $string, float $score, ?SugAddArguments $arguments = null)
|
||||
* @method int ftsugdel(string $key, string $string)
|
||||
* @method array ftsugget(string $key, string $prefix, ?SugGetArguments $arguments = null)
|
||||
* @method int ftsuglen(string $key)
|
||||
* @method array ftsyndump(string $index)
|
||||
* @method Status ftsynupdate(string $index, string $synonymGroupId, ?SynUpdateArguments $arguments = null, string ...$terms)
|
||||
* @method array fttagvals(string $index, string $fieldName)
|
||||
* @method string|null get(string $key)
|
||||
* @method int getbit(string $key, $offset)
|
||||
* @method int|null getex(string $key, $modifier = '', $value = false)
|
||||
@@ -79,7 +159,7 @@ use Predis\Response\Status;
|
||||
* @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 Status|null 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)
|
||||
@@ -87,8 +167,17 @@ use Predis\Response\Status;
|
||||
* @method int strlen(string $key)
|
||||
* @method int hdel(string $key, array $fields)
|
||||
* @method int hexists(string $key, string $field)
|
||||
* @method array|null hexpire(string $key, int $seconds, array $fields, string $flag = null)
|
||||
* @method array|null hexpireat(string $key, int $unixTimeSeconds, array $fields, string $flag = null)
|
||||
* @method array|null hexpiretime(string $key, array $fields)
|
||||
* @method array|null hpersist(string $key, array $fields)
|
||||
* @method array|null hpexpire(string $key, int $milliseconds, array $fields, string $flag = null)
|
||||
* @method array|null hpexpireat(string $key, int $unixTimeMilliseconds, array $fields, string $flag = null)
|
||||
* @method array|null hpexpiretime(string $key, array $fields)
|
||||
* @method string|null hget(string $key, string $field)
|
||||
* @method array|null hgetex(string $key, array $fields, string $modifier = HGETEX::NULL, int|bool $modifierValue = false)
|
||||
* @method array hgetall(string $key)
|
||||
* @method array hgetdel(string $key, array $fields)
|
||||
* @method int hincrby(string $key, string $field, int $increment)
|
||||
* @method string hincrbyfloat(string $key, string $field, int|float $increment)
|
||||
* @method array hkeys(string $key)
|
||||
@@ -96,11 +185,36 @@ use Predis\Response\Status;
|
||||
* @method array hmget(string $key, array $fields)
|
||||
* @method mixed hmset(string $key, array $dictionary)
|
||||
* @method array hrandfield(string $key, int $count = 1, bool $withValues = false)
|
||||
* @method array hscan(string $key, $cursor, array $options = null)
|
||||
* @method array hscan(string $key, $cursor, ?array $options = null)
|
||||
* @method int hset(string $key, string $field, string $value)
|
||||
* @method int hsetex(string $key, array $fieldValueMap, string $setModifier = HSETEX::SET_NULL, string $ttlModifier = HSETEX::TTL_NULL, int|bool $ttlModifierValue = false)
|
||||
* @method int hsetnx(string $key, string $field, string $value)
|
||||
* @method array|null httl(string $key, array $fields)
|
||||
* @method array|null hpttl(string $key, array $fields)
|
||||
* @method array hvals(string $key)
|
||||
* @method int hstrlen(string $key, string $field)
|
||||
* @method array jsonarrappend(string $key, string $path = '$', ...$value)
|
||||
* @method array jsonarrindex(string $key, string $path, string $value, int $start = 0, int $stop = 0)
|
||||
* @method array jsonarrinsert(string $key, string $path, int $index, string ...$value)
|
||||
* @method array jsonarrlen(string $key, string $path = '$')
|
||||
* @method array jsonarrpop(string $key, string $path = '$', int $index = -1)
|
||||
* @method int jsonclear(string $key, string $path = '$')
|
||||
* @method array jsonarrtrim(string $key, string $path, int $start, int $stop)
|
||||
* @method int jsondel(string $key, string $path = '$')
|
||||
* @method int jsonforget(string $key, string $path = '$')
|
||||
* @method string jsonget(string $key, string $indent = '', string $newline = '', string $space = '', string ...$paths)
|
||||
* @method string jsonnumincrby(string $key, string $path, int $value)
|
||||
* @method Status jsonmerge(string $key, string $path, string $value)
|
||||
* @method array jsonmget(array $keys, string $path)
|
||||
* @method Status jsonmset(string ...$keyPathValue)
|
||||
* @method array jsonobjkeys(string $key, string $path = '$')
|
||||
* @method array jsonobjlen(string $key, string $path = '$')
|
||||
* @method array jsonresp(string $key, string $path = '$')
|
||||
* @method string jsonset(string $key, string $path, string $value, ?string $subcommand = null)
|
||||
* @method array jsonstrappend(string $key, string $path, string $value)
|
||||
* @method array jsonstrlen(string $key, string $path = '$')
|
||||
* @method array jsontoggle(string $key, string $path)
|
||||
* @method array jsontype(string $key, string $path = '$')
|
||||
* @method string blmove(string $source, string $destination, string $where, string $to, int $timeout)
|
||||
* @method array|null blpop(array|string $keys, int|float $timeout)
|
||||
* @method array|null brpop(array|string $keys, int|float $timeout)
|
||||
@@ -133,19 +247,57 @@ use Predis\Response\Status;
|
||||
* @method string[] smembers(string $key)
|
||||
* @method array smismember(string $key, string ...$members)
|
||||
* @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 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 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 string xadd(string $key, array $dictionary, string $id = '*', array $options = null)
|
||||
* @method Status tdigestadd(string $key, float ...$value)
|
||||
* @method array tdigestbyrank(string $key, int ...$rank)
|
||||
* @method array tdigestbyrevrank(string $key, int ...$reverseRank)
|
||||
* @method array tdigestcdf(string $key, int ...$value)
|
||||
* @method Status tdigestcreate(string $key, int $compression = 0)
|
||||
* @method array tdigestinfo(string $key)
|
||||
* @method string tdigestmax(string $key)
|
||||
* @method Status tdigestmerge(string $destinationKey, array $sourceKeys, int $compression = 0, bool $override = false)
|
||||
* @method string[] tdigestquantile(string $key, float ...$quantile)
|
||||
* @method string tdigestmin(string $key)
|
||||
* @method array tdigestrank(string $key, float ...$value)
|
||||
* @method Status tdigestreset(string $key)
|
||||
* @method array tdigestrevrank(string $key, float ...$value)
|
||||
* @method string tdigesttrimmed_mean(string $key, float $lowCutQuantile, float $highCutQuantile)
|
||||
* @method array topkadd(string $key, ...$items)
|
||||
* @method array topkincrby(string $key, ...$itemIncrement)
|
||||
* @method array topkinfo(string $key)
|
||||
* @method array topklist(string $key, bool $withCount = false)
|
||||
* @method array topkquery(string $key, ...$items)
|
||||
* @method Status topkreserve(string $key, int $topK, int $width = 8, int $depth = 7, float $decay = 0.9)
|
||||
* @method int tsadd(string $key, int $timestamp, float $value, ?AddArguments $arguments = null)
|
||||
* @method Status tsalter(string $key, ?TSAlterArguments $arguments = null)
|
||||
* @method Status tscreate(string $key, ?TSCreateArguments $arguments = null)
|
||||
* @method Status tscreaterule(string $sourceKey, string $destKey, string $aggregator, int $bucketDuration, int $alignTimestamp = 0)
|
||||
* @method int tsdecrby(string $key, float $value, ?DecrByArguments $arguments = null)
|
||||
* @method int tsdel(string $key, int $fromTimestamp, int $toTimestamp)
|
||||
* @method Status tsdeleterule(string $sourceKey, string $destKey)
|
||||
* @method array tsget(string $key, ?GetArguments $arguments = null)
|
||||
* @method int tsincrby(string $key, float $value, ?IncrByArguments $arguments = null)
|
||||
* @method array tsinfo(string $key, ?InfoArguments $arguments = null)
|
||||
* @method array tsmadd(mixed ...$keyTimestampValue)
|
||||
* @method array tsmget(MGetArguments $arguments, string ...$filterExpression)
|
||||
* @method array tsmrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method array tsmrevrange($fromTimestamp, $toTimestamp, MRangeArguments $arguments)
|
||||
* @method array tsqueryindex(string ...$filterExpression)
|
||||
* @method array tsrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
|
||||
* @method array tsrevrange(string $key, $fromTimestamp, $toTimestamp, ?RangeArguments $arguments = null)
|
||||
* @method string xadd(string $key, array $dictionary, string $id = '*', ?array $options = null)
|
||||
* @method int xdel(string $key, string ...$id)
|
||||
* @method int xlen(string $key)
|
||||
* @method array xrevrange(string $key, string $end, string $start, ?int $count = null)
|
||||
* @method array xrange(string $key, string $start, string $end, ?int $count = null)
|
||||
* @method string xtrim(string $key, array|string $strategy, string $threshold, array $options = null)
|
||||
* @method string xtrim(string $key, array|string $strategy, string $threshold, ?array $options = null)
|
||||
* @method array|null xread(int $count = null, int $block = null, array $streams = null, string ...$id)
|
||||
* @method int zadd(string $key, array $membersAndScoresDictionary)
|
||||
* @method int zcard(string $key)
|
||||
* @method string zcount(string $key, int|string $min, int|string $max)
|
||||
@@ -160,22 +312,22 @@ use Predis\Response\Status;
|
||||
* @method array zpopmin(string $key, int $count = 1)
|
||||
* @method array zpopmax(string $key, int $count = 1)
|
||||
* @method mixed zrandmember(string $key, int $count = 1, bool $withScores = false)
|
||||
* @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 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 zrangestore(string $destination, string $source, int|string $min, int|string $max, string|bool $by = false, bool $reversed = false, bool $limit = false, int $offset = 0, int $count = 0)
|
||||
* @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 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 array zunion(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false)
|
||||
* @method int zunionstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum')
|
||||
* @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 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 pexpiretime(string $key)
|
||||
@@ -188,15 +340,17 @@ use Predis\Response\Status;
|
||||
* @method array|null exec()
|
||||
* @method mixed multi()
|
||||
* @method mixed unwatch()
|
||||
* @method mixed watch(string $key)
|
||||
* @method array waitaof(int $numLocal, int $numReplicas, int $timeout)
|
||||
* @method mixed watch(string[]|string $keyOrKeys)
|
||||
* @method mixed eval(string $script, int $numkeys, string ...$keyOrArg = null)
|
||||
* @method mixed eval_ro(string $script, array $keys, ...$argument)
|
||||
* @method mixed evalsha(string $script, int $numkeys, string ...$keyOrArg = null)
|
||||
* @method mixed evalsha_ro(string $sha1, array $keys, ...$argument)
|
||||
* @method mixed script($subcommand, $argument = null)
|
||||
* @method Status shutdown(?bool $noSave = null, bool $now = false, bool $force = false, bool $abort = false)
|
||||
* @method mixed auth(string $password)
|
||||
* @method string echo(string $message)
|
||||
* @method mixed ping(string $message = null)
|
||||
* @method mixed ping(?string $message = null)
|
||||
* @method mixed select(int $database)
|
||||
* @method mixed bgrewriteaof()
|
||||
* @method mixed bgsave()
|
||||
@@ -216,13 +370,20 @@ use Predis\Response\Status;
|
||||
* @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 array georadius(string $key, $longitude, $latitude, $radius, $unit, ?array $options = null)
|
||||
* @method array georadiusbymember(string $key, $member, $radius, $unit, ?array $options = null)
|
||||
* @method array geosearch(string $key, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $withCoord = false, bool $withDist = false, bool $withHash = false)
|
||||
* @method int geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
|
||||
*
|
||||
* Container commands
|
||||
* @property CLUSTER $cluster
|
||||
* @property FunctionContainer $function
|
||||
* @property FTCONFIG $ftconfig
|
||||
* @property FTCURSOR $ftcursor
|
||||
* @property JSONDEBUG $jsondebug
|
||||
* @property ACL $acl
|
||||
*
|
||||
* @no-named-arguments
|
||||
*/
|
||||
interface ClientInterface
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -53,6 +53,7 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
'SORT' => [$this, 'getKeyFromSortCommand'],
|
||||
'DUMP' => $getKeyFromFirstArgument,
|
||||
'RESTORE' => $getKeyFromFirstArgument,
|
||||
'FLUSHDB' => [$this, 'getFakeKey'],
|
||||
|
||||
/* commands operating on string values */
|
||||
'APPEND' => $getKeyFromFirstArgument,
|
||||
@@ -162,6 +163,11 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
/* scripting */
|
||||
'EVAL' => [$this, 'getKeyFromScriptingCommands'],
|
||||
'EVALSHA' => [$this, 'getKeyFromScriptingCommands'],
|
||||
'EVAL_RO' => [$this, 'getKeyFromScriptingCommands'],
|
||||
'EVALSHA_RO' => [$this, 'getKeyFromScriptingCommands'],
|
||||
|
||||
/* server */
|
||||
'INFO' => [$this, 'getFakeKey'],
|
||||
|
||||
/* commands performing geospatial operations */
|
||||
'GEOADD' => $getKeyFromFirstArgument,
|
||||
@@ -170,6 +176,9 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
'GEODIST' => $getKeyFromFirstArgument,
|
||||
'GEORADIUS' => [$this, 'getKeyFromGeoradiusCommands'],
|
||||
'GEORADIUSBYMEMBER' => [$this, 'getKeyFromGeoradiusCommands'],
|
||||
|
||||
/* cluster */
|
||||
'CLUSTER' => [$this, 'getFakeKey'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -216,6 +225,16 @@ abstract class ClusterStrategy implements StrategyInterface
|
||||
$this->commands[$commandID] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fake key for commands with no key argument.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFakeKey(): string
|
||||
{
|
||||
return 'key';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the key from the first argument of a command instance.
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Cluster;
|
||||
|
||||
/**
|
||||
* Represents the gap between slot ranges.
|
||||
*/
|
||||
class NullSlotRange extends SlotRange
|
||||
{
|
||||
public function __construct(int $start, int $end)
|
||||
{
|
||||
parent::__construct($start, $end, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -23,9 +23,9 @@ class PredisStrategy extends ClusterStrategy
|
||||
protected $distributor;
|
||||
|
||||
/**
|
||||
* @param DistributorInterface $distributor Optional distributor instance.
|
||||
* @param DistributorInterface|null $distributor Optional distributor instance.
|
||||
*/
|
||||
public function __construct(DistributorInterface $distributor = null)
|
||||
public function __construct(?DistributorInterface $distributor = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -25,9 +25,9 @@ class RedisStrategy extends ClusterStrategy
|
||||
protected $hashGenerator;
|
||||
|
||||
/**
|
||||
* @param HashGeneratorInterface $hashGenerator Hash generator instance.
|
||||
* @param HashGeneratorInterface|null $hashGenerator Hash generator instance.
|
||||
*/
|
||||
public function __construct(HashGeneratorInterface $hashGenerator = null)
|
||||
public function __construct(?HashGeneratorInterface $hashGenerator = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Cluster;
|
||||
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use OutOfBoundsException;
|
||||
use Predis\Connection\NodeConnectionInterface;
|
||||
use ReturnTypeWillChange;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Slot map for redis-cluster.
|
||||
*/
|
||||
class SimpleSlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
{
|
||||
private $slots = [];
|
||||
|
||||
/**
|
||||
* Checks if the given slot is valid.
|
||||
*
|
||||
* @param int $slot 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 = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|null
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetGet($slot)
|
||||
{
|
||||
return $this->slots[$slot] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the specified slot to a node.
|
||||
*
|
||||
* @param int $slot Slot index.
|
||||
* @param NodeConnectionInterface|string $connection ID or connection instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
#[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 void
|
||||
*/
|
||||
#[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 Traversable<int, string>
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->slots);
|
||||
}
|
||||
}
|
||||
+228
-19
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -19,13 +19,19 @@ use IteratorAggregate;
|
||||
use OutOfBoundsException;
|
||||
use Predis\Connection\NodeConnectionInterface;
|
||||
use ReturnTypeWillChange;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* Slot map for redis-cluster.
|
||||
* Compact slot map for redis-cluster.
|
||||
*/
|
||||
class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
{
|
||||
private $slots = [];
|
||||
/**
|
||||
* Slot ranges list.
|
||||
*
|
||||
* @var SlotRange[]
|
||||
*/
|
||||
private $slotRanges = [];
|
||||
|
||||
/**
|
||||
* Checks if the given slot is valid.
|
||||
@@ -36,7 +42,7 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
*/
|
||||
public static function isValid($slot)
|
||||
{
|
||||
return $slot >= 0x0000 && $slot <= 0x3FFF;
|
||||
return $slot >= 0 && $slot <= SlotRange::MAX_SLOTS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +55,7 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
*/
|
||||
public static function isValidRange($first, $last)
|
||||
{
|
||||
return $first >= 0x0000 && $first <= 0x3FFF && $last >= 0x0000 && $last <= 0x3FFF && $first <= $last;
|
||||
return SlotRange::isValidRange($first, $last);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +63,7 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->slots = [];
|
||||
$this->slotRanges = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +73,7 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return empty($this->slots);
|
||||
return empty($this->slotRanges);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +85,13 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->slots;
|
||||
return array_reduce(
|
||||
$this->slotRanges,
|
||||
function ($carry, $slotRange) {
|
||||
return $carry + $slotRange->toArray();
|
||||
},
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +101,22 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
*/
|
||||
public function getNodes()
|
||||
{
|
||||
return array_keys(array_flip($this->slots));
|
||||
return array_unique(array_map(
|
||||
function ($slotRange) {
|
||||
return $slotRange->getConnection();
|
||||
},
|
||||
$this->slotRanges
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of slot ranges.
|
||||
*
|
||||
* @return SlotRange[]
|
||||
*/
|
||||
public function getSlotRanges()
|
||||
{
|
||||
return $this->slotRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +134,31 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
throw new OutOfBoundsException("Invalid slot range $first-$last for `$connection`");
|
||||
}
|
||||
|
||||
$this->slots += array_fill($first, $last - $first + 1, (string) $connection);
|
||||
$targetSlotRange = new SlotRange($first, $last, (string) $connection);
|
||||
|
||||
// Get gaps of slot ranges list.
|
||||
$gaps = $this->getGaps($this->slotRanges);
|
||||
|
||||
$results = $this->slotRanges;
|
||||
|
||||
foreach ($gaps as $gap) {
|
||||
if (!$gap->hasIntersectionWith($targetSlotRange)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get intersection of the gap and target slot range.
|
||||
$results[] = new SlotRange(
|
||||
max($gap->getStart(), $targetSlotRange->getStart()),
|
||||
min($gap->getEnd(), $targetSlotRange->getEnd()),
|
||||
$targetSlotRange->getConnection()
|
||||
);
|
||||
}
|
||||
|
||||
$this->sortSlotRanges($results);
|
||||
|
||||
$results = $this->compactSlotRanges($results);
|
||||
|
||||
$this->slotRanges = $results;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +167,7 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
* @param int $first Initial slot of the range.
|
||||
* @param int $last Last slot of the range.
|
||||
*
|
||||
* @return array
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function getSlots($first, $last)
|
||||
{
|
||||
@@ -124,7 +175,28 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
throw new OutOfBoundsException("Invalid slot range $first-$last");
|
||||
}
|
||||
|
||||
return array_intersect_key($this->slots, array_fill($first, $last - $first + 1, null));
|
||||
$placeHolder = new NullSlotRange($first, $last);
|
||||
|
||||
$intersections = [];
|
||||
foreach ($this->slotRanges as $slotRange) {
|
||||
if (!$placeHolder->hasIntersectionWith($slotRange)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$intersections[] = new SlotRange(
|
||||
max($placeHolder->getStart(), $slotRange->getStart()),
|
||||
min($placeHolder->getEnd(), $slotRange->getEnd()),
|
||||
$slotRange->getConnection()
|
||||
);
|
||||
}
|
||||
|
||||
return array_reduce(
|
||||
$intersections,
|
||||
function ($carry, $slotRange) {
|
||||
return $carry + $slotRange->toArray();
|
||||
},
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +209,7 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetExists($slot)
|
||||
{
|
||||
return isset($this->slots[$slot]);
|
||||
return $this->findRangeBySlot($slot) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,7 +222,9 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetGet($slot)
|
||||
{
|
||||
return $this->slots[$slot] ?? null;
|
||||
$found = $this->findRangeBySlot($slot);
|
||||
|
||||
return $found ? $found->getConnection() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,7 +242,8 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
throw new OutOfBoundsException("Invalid slot $slot for `$connection`");
|
||||
}
|
||||
|
||||
$this->slots[(int) $slot] = (string) $connection;
|
||||
$this->offsetUnset($slot);
|
||||
$this->setSlots($slot, $slot, $connection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +256,26 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetUnset($slot)
|
||||
{
|
||||
unset($this->slots[$slot]);
|
||||
if (!static::isValid($slot)) {
|
||||
throw new OutOfBoundsException("Invalid slot $slot");
|
||||
}
|
||||
|
||||
$results = [];
|
||||
foreach ($this->slotRanges as $slotRange) {
|
||||
if (!$slotRange->hasSlot($slot)) {
|
||||
$results[] = $slotRange;
|
||||
}
|
||||
|
||||
if (static::isValidRange($slotRange->getStart(), $slot - 1)) {
|
||||
$results[] = new SlotRange($slotRange->getStart(), $slot - 1, $slotRange->getConnection());
|
||||
}
|
||||
|
||||
if (static::isValidRange($slot + 1, $slotRange->getEnd())) {
|
||||
$results[] = new SlotRange($slot + 1, $slotRange->getEnd(), $slotRange->getConnection());
|
||||
}
|
||||
}
|
||||
|
||||
$this->slotRanges = $results;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,17 +286,132 @@ class SlotMap implements ArrayAccess, IteratorAggregate, Countable
|
||||
#[ReturnTypeWillChange]
|
||||
public function count()
|
||||
{
|
||||
return count($this->slots);
|
||||
return array_sum(array_map(
|
||||
function ($slotRange) {
|
||||
return $slotRange->count();
|
||||
},
|
||||
$this->slotRanges
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the slot map.
|
||||
*
|
||||
* @return ArrayIterator
|
||||
* @return Traversable<int, string>
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->slots);
|
||||
return new ArrayIterator($this->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the slot range which contains the specific slot index.
|
||||
*
|
||||
* @param int $slot Slot index.
|
||||
*
|
||||
* @return SlotRange|false The slot range object or false if not found.
|
||||
*/
|
||||
protected function findRangeBySlot(int $slot)
|
||||
{
|
||||
foreach ($this->slotRanges as $slotRange) {
|
||||
if ($slotRange->hasSlot($slot)) {
|
||||
return $slotRange;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gaps between sorted slot ranges with NullSlotRange object.
|
||||
*
|
||||
* @param SlotRange[] $slotRanges
|
||||
*
|
||||
* @return SlotRange[]
|
||||
*/
|
||||
protected function getGaps(array $slotRanges)
|
||||
{
|
||||
if (empty($slotRanges)) {
|
||||
return [
|
||||
new NullSlotRange(0, SlotRange::MAX_SLOTS),
|
||||
];
|
||||
}
|
||||
$gaps = [];
|
||||
$count = count($slotRanges);
|
||||
$i = 0;
|
||||
foreach ($slotRanges as $key => $slotRange) {
|
||||
$start = $slotRange->getStart();
|
||||
$end = $slotRange->getEnd();
|
||||
if (static::isValidRange($i, $start - 1)) {
|
||||
$gaps[] = new NullSlotRange($i, $start - 1);
|
||||
}
|
||||
|
||||
$i = $end + 1;
|
||||
|
||||
if ($key === $count - 1) {
|
||||
if (static::isValidRange($i, SlotRange::MAX_SLOTS)) {
|
||||
$gaps[] = new NullSlotRange($i, SlotRange::MAX_SLOTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $gaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort slot ranges by start index.
|
||||
*
|
||||
* @param SlotRange[] $slotRanges
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function sortSlotRanges(array &$slotRanges)
|
||||
{
|
||||
usort(
|
||||
$slotRanges,
|
||||
function (SlotRange $a, SlotRange $b) {
|
||||
if ($a->getStart() == $b->getStart()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $a->getStart() < $b->getStart() ? -1 : 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact adjacent slot ranges with the same connection.
|
||||
*
|
||||
* @param SlotRange[] $slotRanges
|
||||
*
|
||||
* @return SlotRange[]
|
||||
*/
|
||||
protected function compactSlotRanges(array $slotRanges)
|
||||
{
|
||||
if (empty($slotRanges)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$compacted = [];
|
||||
$count = count($slotRanges);
|
||||
$i = 0;
|
||||
$carry = $slotRanges[0];
|
||||
while ($i < $count) {
|
||||
$next = $slotRanges[$i + 1] ?? null;
|
||||
if (
|
||||
!is_null($next)
|
||||
&& ($carry->getEnd() + 1) === $next->getStart()
|
||||
&& $carry->getConnection() === $next->getConnection()
|
||||
) {
|
||||
$carry = new SlotRange($carry->getStart(), $next->getEnd(), $carry->getConnection());
|
||||
} else {
|
||||
$compacted[] = $carry;
|
||||
$carry = $next;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return array_values($compacted);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Cluster;
|
||||
|
||||
use Countable;
|
||||
use OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Represents a range of slots in a Redis cluster.
|
||||
*/
|
||||
class SlotRange implements Countable
|
||||
{
|
||||
/**
|
||||
* Maximum number of slots in a Redis cluster is 16384.
|
||||
*/
|
||||
public const MAX_SLOTS = 0x3FFF;
|
||||
|
||||
/**
|
||||
* Starting slot of the range.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $start;
|
||||
|
||||
/**
|
||||
* Ending slot of the range.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $end;
|
||||
|
||||
/**
|
||||
* Connection to the server hosting this slot range.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
public function __construct(int $start, int $end, string $connection)
|
||||
{
|
||||
if (!static::isValidRange($start, $end)) {
|
||||
throw new OutOfBoundsException("Invalid slot range $start-$end for `$connection`");
|
||||
}
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a slot range is valid.
|
||||
*
|
||||
* @param int $first
|
||||
* @param int $last
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidRange($first, $last)
|
||||
{
|
||||
return $first >= 0 && $first <= self::MAX_SLOTS && $last >= 0x0000 && $last <= self::MAX_SLOTS && $first <= $last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start slot index of this range.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStart()
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end slot index of this range.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getEnd()
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection to the server hosting this slot range.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specific slot is contained in this range.
|
||||
*
|
||||
* @param int $slot
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasSlot(int $slot)
|
||||
{
|
||||
return $this->start <= $slot && $this->end >= $slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of connection strings for each slot in this range.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_fill($this->start, $this->end - $this->start + 1, $this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of slots in this range.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return $this->end - $this->start + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this range has an intersection with the given slot range.
|
||||
*
|
||||
* @param SlotRange $slotRange
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasIntersectionWith(SlotRange $slotRange): bool
|
||||
{
|
||||
return $this->start <= $slotRange->getEnd() && $this->end >= $slotRange->getStart();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -138,7 +138,7 @@ abstract class CursorBasedIterator implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
@@ -148,7 +148,7 @@ abstract class CursorBasedIterator implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return mixed
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -157,7 +157,7 @@ abstract class CursorBasedIterator implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return int|null
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function key()
|
||||
@@ -166,7 +166,7 @@ abstract class CursorBasedIterator implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
@@ -176,17 +176,17 @@ abstract class CursorBasedIterator implements Iterator
|
||||
$this->fetch();
|
||||
}
|
||||
|
||||
if ($this->elements) {
|
||||
$this->extractNext();
|
||||
} elseif ($this->cursor) {
|
||||
goto tryFetch;
|
||||
} else {
|
||||
$this->valid = false;
|
||||
}
|
||||
if ($this->elements) {
|
||||
$this->extractNext();
|
||||
} elseif ($this->cursor) {
|
||||
goto tryFetch;
|
||||
} else {
|
||||
$this->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return bool
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function valid()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -128,7 +128,7 @@ class ListKey implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
@@ -138,7 +138,7 @@ class ListKey implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return mixed
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
@@ -147,7 +147,7 @@ class ListKey implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return int|null
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function key()
|
||||
@@ -156,7 +156,7 @@ class ListKey implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return void
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
@@ -173,7 +173,7 @@ class ListKey implements Iterator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return bool
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function valid()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
* (c) 2021-2025 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user