Compare commits

...

151 Commits

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

* Annotate properly return types for SPL interfaces implementation

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

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

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

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

* spacing

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

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

* spacing

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

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

* Update StreamConnection.php

* use `strval()`

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

* Update AbortedMultiExecException.php

* Update CommunicationException.php

* Update ServerSentinel.php

* Update CursorBasedIterator.php

* Update ReplicationStrategy.php

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

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

Fixes a couple of issues reported in #363.
2020-09-20 16:58:18 +02:00
Daniele Alessandri 521ac8f0eb Fix PhpiredisSocketConnection for PHP 8.
Removed is_resource() check as socket_create() now returns an object.
2020-09-20 15:27:35 +02:00
Daniele Alessandri fbbef2a0a2 Back to development. 2020-09-11 21:20:11 +02:00
Daniele Alessandri 9930e933c6 Update CHANGELOG and bump VERSION. 2020-09-11 21:18:05 +02:00
Daniele Alessandri 16957f3b39 Revert support for redis-sentinel authentication.
Authentication for sentinels was implemented in v1.1.5 (commit 2e76410)
but ended up being bugged (see ISSUE #658). This is now postponed as it
requires a more thorough investigation.
2020-09-11 21:10:40 +02:00
Daniele Alessandri 9e5371f5ce Back to development.
[ci skip]
2020-09-10 15:40:46 +02:00
Daniele Alessandri 8ca99f91e4 Update CHANGELOG and bump VERSION (v1.1.5) 2020-09-10 15:35:23 +02:00
Qusonann c778843b0d Fix zrevrangebyscore pipeline annotation
[ci skip]
2020-09-09 23:42:03 +02:00
Daniele Alessandri dca201291c Fix CHANGELOG for broken Markdown rendering.
[ci skip]
2020-09-05 16:50:25 +02:00
Daniele Alessandri 2e76410e65 Support password-based authentication for sentinel instances.
Password-based authentication for sentinels has been added in Redis 5.
Predis was actively ignoring any "password" parameter for sentinels when
creating connections to them to avoid issues when this parameter is set
in the default "parameters" array passed via client options, as they are
applied to **every** connection created by Predis (see #346).

We need to find a better way to specify a common password for sentinels
to be handled in a different way than the ones for Redis nodes. For now
each sentinel node protected by password must have an explicit password
set in its parameters list even if this password, by design, is the same
for all sentinels. Since we cannot use default "parameters" as explained
above but we still need to pass a common value for all sentinels an idea
could be using a dedicated client option like we did with "service", but
we will see later.

In this commit we also explicitly reset any "username" parameter as it
would trigger an `AUTH $username $password` but sentinels do not support
ACL authentication.

Fixes #594.
2020-09-05 16:25:06 +02:00
Daniele Alessandri ca468b785c Throw exception on FALSE passed to "replication" option.
While "replication" do accept values evaluating to TRUE, the same cannot
be said for values evaluating to FALSE. TRUE is used to tell the client
that we want replication handled using the default backend for unmanaged
replication setups. For using redis-sentinel the "sentinel" string value
must be passed.

Setting "replication" to FALSE led to a failure (and a PHP warning) on
client initialization because this condition was not handled properly.
Being able to do so would not make sense anyway: when the client does
not need to be set up to rely on replication, users simply have to omit
the option. Furthermore, users must always specify either "replication"
or "cluster" and not both with one of them set to FALSE.

Unfortunately options for aggregate connections in Predis v1.1 are a bit
of a mess, they did not scale well with the addition of new features and
are also quite inconsistent (e.g. "cluster" does not accept TRUE).

This has been largely fixed in Predis v2.0-dev but required implementing
a few breaking changes. It also means that this change does not need to
be ported to the main branch.

Addresses #381 using a different approach.
2020-09-05 14:18:30 +02:00
Daniele Alessandri 4a7fb55058 [tests] Add utility method to skip tests on CI environment.
We still have disabled all PUB/SUB related tests on CI for now, until we
understand why they fail at random.

Backported from main branch (ref. 5133706, f723f67, eb8a89e)
2020-09-04 18:42:38 +02:00
Daniele Alessandri fdf663ebba Fix WebdisConnection with IPv4 hosts.
Apparently something changed since last time in cURL internals and now
an IPv4 wrapped by square brackets (which are used for IPv6 addresses)
returns a malformed request error.

m
2020-09-04 18:06:36 +02:00
Daniele Alessandri 880ad09cad Restore broken change from a few years ago.
After this change there was no check to prevent the user from using SSL
with PhpiredisStreamConnection (it does not work due to the fact that
internally is uses stream_socket_recvfrom()).

Pretty obvious phpiredis was not installed on my system when I made that
change or the test suite would have caught the wrong behaviour (like it
just happened now that I build it from scratch).
2020-09-04 18:05:26 +02:00
Daniele Alessandri 5eccc65d42 Fix handling of username when using "redis://".
The username is now correctly retrieved from the userinfo fragment of
the URI when using the "redis" scheme and a "username:password" pair is
present. Values retrieved from the userinfo fragment always override the
ones specified in `username` and `password` if those fields are present
in the query string.
2020-09-01 11:40:30 +02:00
Daniele Alessandri f225c55a01 Back to development.
[ci skip]
2020-08-31 12:39:52 +02:00
Daniele Alessandri 8be2418f01 Update CHANGELOG and bump VERSION (v1.1.4) 2020-08-30 00:15:08 +02:00
Daniele Alessandri b9ebe8a376 [tests] Fix mistype in TODO comments.
... and yay for copypasting it too!
2020-08-30 23:26:42 +02:00
Daniele Alessandri e2d26926d2 Update README. 2020-08-30 21:33:14 +02:00
Daniele Alessandri 309248042f Update .gitignore
Removing annoying .phpunit.result.cache left around when switching back
and forth branches from main to v1.1 for development.
2020-08-30 10:38:47 +02:00
Daniele Alessandri 87452e62d0 Fix authentication to support ACL with Redis 6.0.
When passing both "username" and "password" to connection parameters the
client now uses the extended AUTH command to support ACL authentication
with Redis 6.0.

The plain old authentication method is still supported like usual simply
by passing only "password" to connection parameters.
2020-08-29 14:11:55 +02:00
Daniele Alessandri 31baa9b241 Do not push AUTH and SELECT on empty "password" and "database".
NULL or zero-length string values passed to "password" and "database" in
the connection parameters list do not trigger spurious AUTH and SELECT
commands anymore when connecting to Redis.

Fixes #436.
2020-08-29 13:39:12 +02:00
Daniele Alessandri 6f942400a1 [tests] Skip integration tests for PUB/SUB consumer on CI.
Changes backported from the main branch (ref. 04d5c10, 5afadb5).

This is just a temporary solution, we will revert this change as soon as
the actual cause for the spurious failures is identified.
2020-08-27 17:44:23 +02:00
Daniele Alessandri 5e220a0b57 Update CHANGELOG. 2020-08-25 15:57:51 +02:00
Daniele Alessandri 0eb2633348 Merge remote-tracking branch 'github/pr/554' into v1.1 2020-08-25 15:42:13 +02:00
Daniele Alessandri cbbd6bba88 Update CHANGELOG.
[ci skip]
2020-08-24 22:33:48 +02:00
Daniele Alessandri 3702f24efc Fix more @method tags in interfaces. 2020-08-24 22:27:21 +02:00
Daniele Alessandri 82fefe057b Merge remote-tracking branch 'github/pr/456' into v1.1-annotations 2020-08-24 21:56:13 +02:00
Daniele Alessandri 42336537dc Merge remote-tracking branch 'github/pr/497' into v1.1 2020-08-24 17:10:28 +02:00
Daniele Alessandri 802abac55e Fix pear builder script to generate UTF-8 encoded package.xml.
Fixes issue #531.

[ci skip]
2020-08-24 16:20:06 +02:00
Daniele Alessandri 61e75816ce Apply few changes in .gitattributes file.
Remove .github from directories exported in our release packages and fix
to ignore .php_cs.dist (the actual file commited) instead of .php_cs.

[ci skip]
2020-08-24 14:04:10 +02:00
Daniele Alessandri 17f0c08cb6 [tests] Fix expected response for COMMAND INFO (Redis >= 6.0).
Starting with Redis 6.0 and the introduction of Access Control Lists,
COMMAND INFO returns an additional array for each specified command in
the request with a list of the ACL categories associated to a command.
2020-08-24 11:45:20 +02:00
Daniele Alessandri 2b8af1eef2 Update CHANGELOG. 2020-08-23 18:38:07 +02:00
Daniele Alessandri c5f2b441b4 Merge branch 'github/pr/545' into v1.1 2020-08-23 18:11:49 +02:00
GITSRC 2440a61cba Fix HashRing to use method defined by HashGeneratorInterface. 2020-08-23 18:09:09 +02:00
Daniele Alessandri 7100884201 Update CHANGELOG. 2020-08-23 17:48:38 +02:00
Daniele Alessandri 2a932d7292 Merge remote-tracking branch 'github/pr/556' into v1.1 2020-08-23 17:47:26 +02:00
Daniele Alessandri 0a6306b73e Back to development. 2020-08-23 17:46:12 +02:00
Peter Gribanov 4363345f7c iterate not iterable connections #552 2020-08-23 15:00:22 +03:00
Till Krüss 2ce537d75e bump version to v1.1.3 2020-08-18 14:00:59 -07:00
Till Krüss 7489690306 include patch files in exports just to be safe
See #642
2020-08-18 13:55:36 -07:00
Till Krüss 7376902b20 update org references 2020-08-14 10:11:49 -07:00
Till Krüss a6bd25412e remove gitter badge 2020-08-12 12:00:08 -07:00
Till Krüss 60cc950a58 remove Predis\Async from readme 2020-08-12 11:53:52 -07:00
Till Krüss db82dd9f23 format psr-4 2020-08-12 11:53:12 -07:00
Till Krüss 1bc08d9bcc add funding to composer.json; update authors 2020-08-12 11:50:57 -07:00
Till Krüss 11e4bb44d0 more reference updates to predishq 2020-08-12 11:50:07 -07:00
Till Krüss cddb849812 remove gitter 2020-08-12 11:49:42 -07:00
Till Krüss f2298dd186 update references to predishq 2020-08-12 11:49:37 -07:00
Till Krüss bceda1d8e6 Merge pull request #625 from AhmedRaafat14/add-php8-support
Support PHP 8.0 in v1.1.x
2020-08-12 08:42:08 -07:00
Till Krüss 9f87c849c5 Update .travis.yml 2020-08-12 08:41:50 -07:00
Ahmed Raafat 1382146b03 Add php 8.0 (nightly) to the lines that is allowed to faoil (allow_failures) 2020-08-12 12:22:42 +02:00
Ahmed Raafat cbc08aa5e7 Add php 8.0 to travis 2020-08-12 11:45:43 +02:00
Till Krüss de9cd905bb Update issue templates 2020-08-11 12:05:47 -07:00
Till Krüss 6dd55d7f96 move cweagans/composer-patches as dev dep 2020-08-11 11:08:18 -07:00
Till Krüss 82eb18c6c3 bump version to 1.1.2 2020-08-11 10:28:15 -07:00
Till Krüss ac6b813ba9 Merge pull request #616 from nrk/support-php-74
Support PHP 7.4 in v1.1.x
2020-08-11 09:48:35 -07:00
Till Krüss 6482956d96 patch tests
Taken from: https://github.com/yiisoft/yii/pull/4306 by @samdark
2020-08-11 09:41:04 -07:00
Till Krüss cf15dd9857 add 7.4 to travis matrix 2020-08-11 08:55:49 -07:00
Till Krüss 597c61a098 fix out of range exception test 2020-08-11 08:43:17 -07:00
Till Krüss 9aa99349b1 Merge pull request #574 from matthewbaggett/v1.1-travis-fixup
V1.1 travis fixup
2020-08-11 08:30:12 -07:00
Till Krüss b6f60f0d72 add funding 2020-08-10 17:02:18 -07:00
Till Krüss 10235d62dc adjust error message regex 2020-08-10 13:48:17 -07:00
Till Krüss ec2b1eacd2 Merge pull request #614 from nrk/revert-611-patch-2
Revert "Bring travis config up to date"
2020-08-10 13:31:37 -07:00
Till Krüss 9c3605ab33 Merge pull request #613 from nrk/revert-610-patch-1
Revert "Add more build targets"
2020-08-10 13:31:20 -07:00
Till Krüss 55e6094954 Revert "Bring travis config up to date" 2020-08-10 13:31:03 -07:00
Till Krüss 15314b726b Revert "Add more build targets" 2020-08-10 13:30:45 -07:00
Till Krüss 292604edbf fix HHVM lowercase issue
Fatal error: Uncaught Error: Keyword __HALT_COMPILER must be written in lowercase
2020-08-10 13:02:49 -07:00
Till Krüss fc8f9f5604 Merge pull request #585 from gladx/v1.1
Fix test error exception for SELECT command
2020-08-10 12:41:25 -07:00
Till Krüss 77132e6c6b Merge pull request #589 from funivan/patch-1
Fix wiki link
2020-08-10 12:40:46 -07:00
Till Krüss a7571ef0c7 Merge pull request #583 from Miljan9602/v1.1
Fixed wrong annotation for spop method.
2020-08-10 12:40:27 -07:00
Till Krüss 4901408b08 Merge pull request #611 from hannesvdvreken/patch-2
Bring travis config up to date
2020-08-10 12:29:13 -07:00
Till Krüss dd3897b755 Merge pull request #610 from hannesvdvreken/patch-1
Add more build targets
2020-08-10 12:28:53 -07:00
Hannes Van De Vreken 6e7dbe05fb Bring travis config up to date 2020-07-29 03:33:50 +02:00
Hannes Van De Vreken f0f9d68a8e Add more build targets 2020-07-29 03:18:56 +02:00
Ivan Shcherbak bb6f1ee0e3 Fix wiki link 2019-11-25 14:23:35 +02:00
Ali Yousefi ffcc4bba8c Fix test error exception for SELECT command 2019-10-06 22:10:17 +03:30
Miljan Rakita 83359dff9a Fixed wrong annotation for spop method.
Spop method has return annotation string, but it returns array.
2019-09-10 19:26:00 +02:00
Matthew Baggett 710b4f901b Apparently 5.4 and 5.5 aren't available outside of trusty? 2019-08-09 11:54:35 +02:00
Matthew Baggett f3e46683b9 Sometimes, timing-related tests (read: KeyExpireAtTest::testCanExpireKeys) can fail but then succeed on a retry. So lets automate that retry. 2019-08-09 11:07:43 +02:00
Matthew Baggett 945e05819b Rejig. 2019-08-09 10:54:47 +02:00
Matthew Baggett a64b7354e1 Travis fixup 2019-08-09 10:37:19 +02:00
Mark Fettig 39ff616e86 update sort command to be a write operation 2019-03-18 12:10:26 -04:00
Geoffrey Hoffman 738ec0c50f Correcting the return type hint for BRPOPLPUSH method 2018-04-10 18:09:42 -07:00
Teoh Han Hui 1828222e27 Add null return value to PHPDoc 2017-08-14 19:36:11 +08:00
Daniele Alessandri 111d100ee3 Make examples scripts executable only via CLI.
This is meant as a basic layer of protection for those cases where the whole
Predis repository is cloned into a path which is publicly exposed by the web
server.

Closes #408
2017-07-12 16:39:17 +02:00
Daniele Alessandri 893215a1d4 Push same changes of #446 to Predis\ClientContextInterface.
This also adds a couple of missing changes into the original PR.
2017-07-12 15:34:57 +02:00
Daniele Alessandri f5d8b9fe2d Merge remote-tracking branch 'github/pr/446' into v1.1 2017-07-12 15:24:15 +02:00
Daniele Alessandri 722b513cea Upgrade .php_cs configuration file for php-cs-fixer 2.x 2017-07-12 15:22:58 +02:00
Daniele Alessandri 62774c6cc5 Merge remote-tracking branch 'github/pr/442' into v1.1 2017-07-12 13:37:06 +02:00
Daniele Alessandri 8aa2ded5b0 Merge remote-tracking branch 'github/pr/445' into v1.1 2017-07-12 13:36:17 +02:00
Daniele Alessandri 795c3e41b0 Merge remote-tracking branch 'github/pr/434' into v1.1 2017-07-12 13:31:24 +02:00
Daniele Alessandri 59e616b124 Remove broken badge.
Looks like hhvm.h4cc.de is dead.

[ci skip]
2017-07-12 13:30:52 +02:00
Daniele Alessandri 157f658f0b Fix iterators abstractions for HSCAN and ZSCAN when using PHP 7.2.
Closes #488.
2017-07-12 11:59:35 +02:00
Daniele Alessandri 343afd312a Fix wrong CRC16 calculated on integer value.
Closes #450.
2017-07-12 11:29:25 +02:00
Daniele Alessandri d77b77bbd9 Merge remote-tracking branch 'github/pr/443' into v1.1 2017-07-12 10:59:41 +02:00
gitomato 34b678192f Add string type to $keys argument
Reveals the ability to use a string for $keys argument.
2017-06-29 10:25:14 +02:00
Jorrit Schippers 4de246cfee Correct link to GitHub releases page 2017-06-27 09:35:15 +02:00
Anatoly Pashin 6fd6933580 Create .travis.yml 2017-06-11 00:28:43 +10:00
Anatoly Pashin c7b38abe71 use trusty dist 2017-06-09 18:05:11 +10:00
Anatoly Pashin 574ef78f86 fix typehint 2017-06-09 17:57:00 +10:00
Andrii Volin 1ebabaf8f8 fix typo in tests/README.md 2017-05-01 17:12:25 +03:00
Daniele Alessandri 98ec0cc27e Merge remote-tracking branch 'github/pr/376' into v1.1
[ci skip]
2016-11-22 15:32:30 +01:00
Daniele Alessandri caf8a46cbb Merge remote-tracking branch 'github/pr/373' into v1.1
[ci skip]
2016-11-22 15:30:42 +01:00
Daniele Alessandri 944a16d7c0 Merge remote-tracking branch 'github/pr/393' into v1.1 2016-11-17 17:55:23 +01:00
Remi Collet d1290dfde0 fix test for ArgumentCountError exception with PHP 7.1 2016-11-17 15:24:54 +01:00
Remi Collet 9489d9e5aa enable 7.1 on travis 2016-11-17 15:12:24 +01:00
Fabien Villepinte 94ccb2cc3b Fix PHPDoc of \Predis\Connection\Aggregate\SentinelReplication::assertConnectionRole() 2016-09-14 17:20:55 +02:00
orvice 6c848db2a0 fix typo 2016-08-19 16:48:00 +08:00
Daniele Alessandri 6ab10b2b70 [tests] Fix preassigned slots in cluster tests. 2016-06-18 21:51:10 +02:00
Daniele Alessandri 2d4377fc81 Back to development. 2016-06-18 21:37:42 +02:00
83 changed files with 1378 additions and 449 deletions
+7 -2
View File
@@ -1,10 +1,15 @@
* text=auto
/tests export-ignore
/tests/PHPUnit export-ignore
/tests/Predis export-ignore
/tests/bootstrap.php export-ignore
/.github export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.php_cs export-ignore
/.php_cs.dist export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/phpunit.xml.travisci export-ignore
/CHANGELOG.md export-ignore
/CONTRIBUTING.md export-ignore
+2
View File
@@ -0,0 +1,2 @@
github: tillkruss
custom: "https://www.paypal.me/tillkruss"
+31
View File
@@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Run command '...'
2. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Versions (please complete the following information):**
- Predis: [e.g. 1.1.2]
- PHP [e.g. 8.0.0]
- Redis Server [e.g. 6.0.0]
- OS [e.g. Ubuntu 20.10]
**Code sample**
If applicable, a small snippet of code that reproduces the issue.
**Additional context**
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+1
View File
@@ -2,6 +2,7 @@
*.phar
.php-version
.php_cs.cache
.phpunit.result.cache
phpunit.xml
package.xml
composer.lock
-34
View File
@@ -1,34 +0,0 @@
<?php
$PREDIS_HEADER = <<<EOS
This file is part of the Predis package.
(c) Daniele Alessandri <suppakilla@gmail.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOS;
Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($PREDIS_HEADER);
return Symfony\CS\Config\Config::create()
->setUsingCache(true)
->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL)
->fixers(array(
// Symfony
'-unalign_equals',
'-unalign_double_arrow',
// Contribs
'header_comment',
'ordered_use',
'phpdoc_order',
'long_array_syntax',
))
->finder(
Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__.'/bin')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->in(__DIR__.'/examples')
);
+33
View File
@@ -0,0 +1,33 @@
<?php
$PREDIS_HEADER = <<<EOS
This file is part of the Predis package.
(c) Daniele Alessandri <suppakilla@gmail.com>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOS;
return PhpCsFixer\Config::create()
->setUsingCache(true)
->setRules(array(
'@Symfony' => true,
'header_comment' => array(
'header' => $PREDIS_HEADER,
),
'ordered_imports' => true,
'phpdoc_order' => true,
'binary_operator_spaces' => array(
'align_double_arrow' => false,
'align_equals' => false,
),
'array_syntax' => array('syntax' => 'long'),
))
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__.'/bin')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
->in(__DIR__.'/examples')
);
+27 -14
View File
@@ -1,23 +1,36 @@
language: php
sudo: false
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
branches:
except:
- v0.5
- v0.6
- v0.6-PHP_5.2
- documentation
services: redis-server
- main
- v2.0
before_install:
- docker run -d --rm -p 127.0.0.1:6379:6379 redis:3
before_script:
- phpenv config-rm xdebug.ini
- composer self-update
- composer install --no-interaction --prefer-source --dev
script:
- vendor/bin/phpunit -c phpunit.xml.travisci
- travis_retry vendor/bin/phpunit -c phpunit.xml.travisci
matrix:
fast_finish: true
include:
- php: 5.3
dist: precise
services: redis-server
before_install: skip
- php: 5.4
dist: trusty
- php: 5.5
dist: trusty
- php: 5.6
- php: 7.0
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
- php: 8.0
+124
View File
@@ -1,3 +1,127 @@
v1.1.10 (2022-01-05)
================================================================================
- __FIX__: Avoid PHP 8.1 deprecation notices in `Session/Handler`
- __FIX__: Fixed "Cannot use object of type Predis\Response\Error as array"
error in `Connection/Aggregate/SentinelReplication`
v1.1.9 (2021-10-05)
================================================================================
- __FIX__: Fixed PHP 8.1 compatibility in `StreamConnection`
v1.1.8 (2021-09-29)
================================================================================
- __FIX__: Ensure compatibility with PHP 8.1.
v1.1.7 (2021-04-04)
================================================================================
- __FIX__: with the phpiredis-based connection backends, failed pipelines led to
spurious responses returned after reconnecting to Redis because the underlying
reader was not properly reset by discarding buffered replies after disconnecting
(ISSUE #363).
- __FIX__: removed `cweagans/composer-patches` dev dependency and apply patches
using `post-update-cmd` script.
v1.1.6 (2020-09-11)
================================================================================
- __FIX__: reverted support for sentinels authentication implemented in v1.1.5
as it was bugged (see ISSUE #658), sorry for the trouble. This is now postponed
as it requires a more thorough investigation.
v1.1.5 (2020-09-10)
================================================================================
- __FIX__:~~authentication for sentinels is now supported, previously it was not
possible to specify a `password` for sentinels as its value was stripped during
initialization because sentinels did not support authentication until Redis 5.
**Please note** that with the current implementation each sentinel must have
its own `password` parameter set in the parameters list despite this password is
the same for all sentinels (read how `requirepass` works on the Redis docs). In
this case you should avoid using the global `parameters` client option used to
set default parameters for every connection created by Predis as this would end
up using the same password even when connecting to actual Redis nodes.~~
- __FIX__: the username is now correctly retrieved from the userinfo fragment of
the URI when using the "redis" scheme and a "username:password" pair is present.
Values retrieved from the userinfo fragment always override the ones specified
in `username` and `password` if those fields are present in the query string.
- __FIX__: `Predis\Connection\WebdisConnection` was unable to connect to Webdis
when using an IPv4 address in the URL and this is probably due to some change in
cURL internals since the last time we tested it.
- __FIX__: an exception is thrown whe passing `FALSE` or any value evaluating to
`FALSE` to the `replication` client option. This was supposed to be unsupported,
in fact it actually breaks client initialization and raises a PHP warning. Now
the user is alerted with an `InvalidArgumentException` and a proper message.
(PR #381).
v1.1.4 (2020-08-31)
================================================================================
- Improved @method annotations for methods responding to Redis commands defined
by `Predis\ClientInterface` and `Predis\ClientContextInterface`. (PR #456 and
PR #497, other fixes applied after further analysys).
- __FIX__: the client can now handle ACL authentication when connecting to Redis
6.x simply by passing both `username` and `password` to connection parameters.
See [the Redis docs](https://redis.io/topics/acl) for details on this topic.
- __FIX__: NULL or zero-length string values passed to `password` and `database`
in the connection parameters list do not trigger spurious `AUTH` and `SELECT`
commands anymore when connecting to Redis (ISSUE #436).
- __FIX__: initializing an iteration over a client instance when it is connected
to a standalone Redis server will not throw an exception anymore, instead it
will return an iterator that will run for just one loop returning a new client
instance using the underlying single-node connection (ISSUE #552, PR #556).
- __FIX__: `Predis\Cluster\Distributor\HashRingaddNodeToRing()` was calculating
the hash required for distribution by using `crc32()` directly instead of the
method `Predis\Cluster\Hash\HashGeneratorInterface::hash()` implemented by the
class itself. This bug fix does not have any impact on existing clusters that
use client-side sharding based on this distributor simply because it does not
take any external hash generators so distribution is not going to be affected.
- __FIX__: `SORT` now always trigger a switch to the master node in replication
configurations instead of just when the `STORE` modifier is specified, this is
because `SORT` is always considered to be a write operation and actually fails
with a `-READONLY` error response when executed against a replica node. (ISSUE
#554).
v1.1.3 (2020-08-18)
================================================================================
- Ensure compatibility with PHP 8.
- Moved repository from `github.com/nrk/predis` to `github.com/predis/predis`.
- __FIX__: Moved `cweagans/composer-patches` dependency to `require-dev`.
- __FIX__: Include PHPUnit `.patch` files in exports.
v1.1.2 (2020-08-11)
================================================================================
- __FIX__: pure CRC16 implementation failed to calculate the correct hash when
the input value passed to the `hash()` method is an integer (PR #450).
- __FIX__: make PHP iterator abstractions for `ZSCAN` and `HSCAN` working with
PHP 7.2 due to a breaking change, namely the removal of `each()` (PR #448).
v1.1.1 (2016-06-16)
================================================================================
+1 -1
View File
@@ -1,6 +1,6 @@
## Filing bug reports ##
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/nrk/predis/issues)
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/predis/predis/issues)
section of the project.
When reporting bugs, in addition to the obvious description of your issue you __must__ always provide
+1 -1
View File
@@ -33,7 +33,7 @@ usually something that developers prefer to customize depending on their needs a
generalized when using Redis because of the many possible access patterns for your data. This does
not mean that it is impossible to have such a feature since you can leverage the extensibility of
this library to define your own serialization-aware commands. You can find more details about how to
do that [on this issue](http://github.com/nrk/predis/issues/29#issuecomment-1202624).
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? ###
+13 -16
View File
@@ -5,15 +5,12 @@
[![Latest development][ico-version-dev]][link-packagist]
[![Monthly installs][ico-downloads-monthly]][link-downloads]
[![Build status][ico-travis]][link-travis]
[![HHVM support][ico-hhvm]][link-hhvm]
[![Gitter room][ico-gitter]][link-gitter]
Flexible and feature-complete [Redis](http://redis.io) client for PHP >= 5.3 and HHVM >= 2.3.0.
Predis does not require any additional C extension by default, but it can be optionally paired with
[phpiredis](https://github.com/nrk/phpiredis) to lower the overhead of the serialization and parsing
of the [Redis RESP Protocol](http://redis.io/topics/protocol). For an __experimental__ asynchronous
implementation of the client you can refer to [Predis\Async](https://github.com/nrk/predis-async).
of the [Redis RESP Protocol](http://redis.io/topics/protocol).
More details about this project can be found on the [frequently asked questions](FAQ.md).
@@ -41,7 +38,7 @@ More details about this project can be found on the [frequently asked questions]
This library can be found on [Packagist](http://packagist.org/packages/predis/predis) for an easier
management of projects dependencies using [Composer](http://packagist.org/about-composer) or on our
[own PEAR channel](http://pear.nrk.io) for a more traditional installation using PEAR. Ultimately,
compressed archives of each release are [available on GitHub](https://github.com/nrk/predis/tags).
compressed archives of each release are [available on GitHub](https://github.com/predis/predis/releases).
### Loading the library ###
@@ -90,6 +87,9 @@ $client = new Predis\Client([
$client = new Predis\Client('tcp://10.0.0.1:6379');
```
Password protected servers can be accessed by adding `password` to the parameters set. When ACLs are
enabled on Redis >= 6.0, both `username` and `password` are required for user authentication.
It is also possible to connect to local instances of Redis using UNIX domain sockets, in this case
the parameters must use the `unix` scheme and specify a path for the socket file:
@@ -108,7 +108,7 @@ of suitable [options](http://php.net/manual/context.ssl.php) passed via the `ssl
$client = new Predis\Client([
'scheme' => 'tls',
'ssl' => ['cafile' => 'private.pem', 'verify_peer' => true],
]
]);
// Same set of parameters, but using an URI string:
$client = new Predis\Client('tls://127.0.0.1?ssl[cafile]=private.pem&ssl[verify_peer]=1');
@@ -454,7 +454,7 @@ the development server profile will be used. You can refer to [the tests README]
for more detailed information about testing Predis.
Predis uses Travis CI for continuous integration and the history for past and current builds can be
found [on its project page](http://travis-ci.org/nrk/predis).
found [on its project page](http://travis-ci.org/predis/predis).
## Other ##
@@ -462,9 +462,9 @@ found [on its project page](http://travis-ci.org/nrk/predis).
### Project related links ###
- [Source code](https://github.com/nrk/predis)
- [Wiki](https://wiki.github.com/nrk/predis)
- [Issue tracker](https://github.com/nrk/predis/issues)
- [Source code](https://github.com/predis/predis)
- [Wiki](https://github.com/predis/predis/wiki)
- [Issue tracker](https://github.com/predis/predis/issues)
- [PEAR channel](http://pear.nrk.io)
@@ -477,16 +477,13 @@ found [on its project page](http://travis-ci.org/nrk/predis).
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
[ico-license]: https://img.shields.io/github/license/nrk/predis.svg?style=flat-square
[ico-license]: https://img.shields.io/github/license/predis/predis.svg?style=flat-square
[ico-version-stable]: https://img.shields.io/packagist/v/predis/predis.svg?style=flat-square
[ico-version-dev]: https://img.shields.io/packagist/vpre/predis/predis.svg?style=flat-square
[ico-downloads-monthly]: https://img.shields.io/packagist/dm/predis/predis.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/nrk/predis.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/predis/predis.svg?style=flat-square
[ico-hhvm]: https://img.shields.io/hhvm/predis/predis.svg?style=flat-square
[ico-gitter]: https://img.shields.io/gitter/room/nrk/predis.svg?style=flat-square
[link-packagist]: https://packagist.org/packages/predis/predis
[link-travis]: https://travis-ci.org/nrk/predis
[link-travis]: https://travis-ci.org/predis/predis
[link-downloads]: https://packagist.org/packages/predis/predis/stats
[link-hhvm]: http://hhvm.h4cc.de/package/predis/predis
[link-gitter]: https://gitter.im/nrk/predis
+1 -1
View File
@@ -1 +1 @@
1.1.1
1.1.11-dev
+2 -2
View File
@@ -115,7 +115,7 @@ function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
function generatePackageXml($packageINI)
{
$XML = <<<XML
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.4.10" version="2.0"
xmlns="http://pear.php.net/dtd/package-2.0"
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
@@ -197,7 +197,7 @@ function rewritePackageInstallAs($pkg)
function savePackageXml($xml)
{
$dom = new DOMDocument("1.0");
$dom = new DOMDocument("1.0", "UTF-8");
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
+1 -1
View File
@@ -59,7 +59,7 @@ spl_autoload_register(function (\$class) {
}
}
});
__HALT_COMPILER();
__halt_compiler();
EOSTUB;
}
+21 -4
View File
@@ -3,16 +3,28 @@
"type": "library",
"description": "Flexible and feature-complete Redis client for PHP and HHVM",
"keywords": ["nosql", "redis", "predis"],
"homepage": "http://github.com/nrk/predis",
"homepage": "http://github.com/predis/predis",
"license": "MIT",
"support": {
"issues": "https://github.com/nrk/predis/issues"
"issues": "https://github.com/predis/predis/issues"
},
"authors": [
{
"name": "Daniele Alessandri",
"email": "suppakilla@gmail.com",
"homepage": "http://clorophilla.net"
"homepage": "http://clorophilla.net",
"role": "Creator & Maintainer"
},
{
"name": "Till Krüss",
"homepage": "https://till.im",
"role": "Maintainer"
}
],
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/tillkruss"
}
],
"require": {
@@ -26,6 +38,11 @@
"ext-curl": "Allows access to Webdis when paired with phpiredis"
},
"autoload": {
"psr-4": {"Predis\\": "src/"}
"psr-4": {
"Predis\\": "src/"
}
},
"scripts": {
"post-update-cmd": "@php -f tests/apply-patches.php"
}
}
+4
View File
@@ -9,6 +9,10 @@
* file that was distributed with this source code.
*/
if (PHP_SAPI !== 'cli') {
die("Example scripts are meant to be executed locally via CLI.");
}
require __DIR__.'/../autoload.php';
function redis_version($info)
+2 -2
View File
@@ -10,8 +10,8 @@ name = "Predis"
desc = "Flexible and feature-complete Redis client for PHP and HHVM"
homepage = "http://github.com/nrk/predis"
license = "MIT"
version = "1.1.1"
stability = "stable"
version = "1.1.11"
stability = "devel"
channel = "pear.nrk.io"
author = "Daniele Alessandri \"nrk\" <suppakilla@gmail.com>"
-4
View File
@@ -36,10 +36,6 @@
</whitelist>
</filter>
<logging>
<log type="coverage-text" target="php://stdout" />
</logging>
<php>
<!-- Redis -->
<const name="REDIS_SERVER_VERSION" value="3.2" />
+6 -3
View File
@@ -40,7 +40,7 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
*/
class Client implements ClientInterface, \IteratorAggregate
{
const VERSION = '1.1.1';
const VERSION = '1.1.11-dev';
protected $connection;
protected $options;
@@ -527,15 +527,18 @@ class Client implements ClientInterface, \IteratorAggregate
}
/**
* {@inheritdoc}
* @return \Traversable<string, static>
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
$clients = array();
$connection = $this->getConnection();
if (!$connection instanceof \Traversable) {
throw new ClientException('The underlying connection is not traversable');
return new \ArrayIterator(array(
(string) $connection => new static($connection, $this->getOptions())
));
}
foreach ($connection as $node) {
+17 -16
View File
@@ -16,7 +16,7 @@ use Predis\Command\CommandInterface;
/**
* Interface defining a client-side context such as a pipeline or transaction.
*
* @method $this del(array $keys)
* @method $this del(array|string $keys)
* @method $this dump($key)
* @method $this exists($key)
* @method $this expire($key, $seconds)
@@ -39,6 +39,7 @@ use Predis\Command\CommandInterface;
* @method $this bitcount($key, $start = null, $end = null)
* @method $this bitop($operation, $destkey, $key)
* @method $this bitfield($key, $subcommand, ...$subcommandArg)
* @method $this bitpos($key, $bit, $start = null, $end = null)
* @method $this decr($key)
* @method $this decrby($key, $decrement)
* @method $this get($key)
@@ -73,15 +74,15 @@ use Predis\Command\CommandInterface;
* @method $this hsetnx($key, $field, $value)
* @method $this hvals($key)
* @method $this hstrlen($key, $field)
* @method $this blpop(array $keys, $timeout)
* @method $this brpop(array $keys, $timeout)
* @method $this blpop(array|string $keys, $timeout)
* @method $this brpop(array|string $keys, $timeout)
* @method $this brpoplpush($source, $destination, $timeout)
* @method $this lindex($key, $index)
* @method $this linsert($key, $whence, $pivot, $value)
* @method $this llen($key)
* @method $this lpop($key)
* @method $this lpush($key, array $values)
* @method $this lpushx($key, $value)
* @method $this lpushx($key, array $values)
* @method $this lrange($key, $start, $stop)
* @method $this lrem($key, $count, $value)
* @method $this lset($key, $index, $value)
@@ -89,13 +90,13 @@ use Predis\Command\CommandInterface;
* @method $this rpop($key)
* @method $this rpoplpush($source, $destination)
* @method $this rpush($key, array $values)
* @method $this rpushx($key, $value)
* @method $this rpushx($key, array $values)
* @method $this sadd($key, array $members)
* @method $this scard($key)
* @method $this sdiff(array $keys)
* @method $this sdiffstore($destination, array $keys)
* @method $this sinter(array $keys)
* @method $this sinterstore($destination, array $keys)
* @method $this sdiff(array|string $keys)
* @method $this sdiffstore($destination, array|string $keys)
* @method $this sinter(array|string $keys)
* @method $this sinterstore($destination, array|string $keys)
* @method $this sismember($key, $member)
* @method $this smembers($key)
* @method $this smove($source, $destination, $member)
@@ -103,13 +104,13 @@ use Predis\Command\CommandInterface;
* @method $this srandmember($key, $count = null)
* @method $this srem($key, $member)
* @method $this sscan($key, $cursor, array $options = null)
* @method $this sunion(array $keys)
* @method $this sunionstore($destination, array $keys)
* @method $this sunion(array|string $keys)
* @method $this sunionstore($destination, array|string $keys)
* @method $this zadd($key, array $membersAndScoresDictionary)
* @method $this zcard($key)
* @method $this zcount($key, $min, $max)
* @method $this zincrby($key, $increment, $member)
* @method $this zinterstore($destination, array $keys, array $options = null)
* @method $this zinterstore($destination, array|string $keys, array $options = null)
* @method $this zrange($key, $start, $stop, array $options = null)
* @method $this zrangebyscore($key, $min, $max, array $options = null)
* @method $this zrank($key, $member)
@@ -117,9 +118,9 @@ use Predis\Command\CommandInterface;
* @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, $min, $max, array $options = null)
* @method $this zrevrangebyscore($key, $max, $min, array $options = null)
* @method $this zrevrank($key, $member)
* @method $this zunionstore($destination, array $keys, array $options = null)
* @method $this zunionstore($destination, array|string $keys, array $options = null)
* @method $this zscore($key, $member)
* @method $this zscan($key, $cursor, array $options = null)
* @method $this zrangebylex($key, $start, $stop, array $options = null)
@@ -127,8 +128,8 @@ use Predis\Command\CommandInterface;
* @method $this zremrangebylex($key, $min, $max)
* @method $this zlexcount($key, $min, $max)
* @method $this pfadd($key, array $elements)
* @method $this pfmerge($destinationKey, array $sourceKeys)
* @method $this pfcount(array $keys)
* @method $this pfmerge($destinationKey, array|string $sourceKeys)
* @method $this pfcount(array|string $keys)
* @method $this pubsub($subcommand, $argument)
* @method $this publish($channel, $message)
* @method $this discard()
+148 -147
View File
@@ -24,153 +24,154 @@ use Predis\Profile\ProfileInterface;
* and more friendly interface to ease programming which is described in the
* following list of methods:
*
* @method int del(array $keys)
* @method string dump($key)
* @method int exists($key)
* @method int expire($key, $seconds)
* @method int expireat($key, $timestamp)
* @method array keys($pattern)
* @method int move($key, $db)
* @method mixed object($subcommand, $key)
* @method int persist($key)
* @method int pexpire($key, $milliseconds)
* @method int pexpireat($key, $timestamp)
* @method int pttl($key)
* @method string randomkey()
* @method mixed rename($key, $target)
* @method int renamenx($key, $target)
* @method array scan($cursor, array $options = null)
* @method array sort($key, array $options = null)
* @method int ttl($key)
* @method mixed type($key)
* @method int append($key, $value)
* @method int bitcount($key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array bitfield($key, $subcommand, ...$subcommandArg)
* @method int decr($key)
* @method int decrby($key, $decrement)
* @method string get($key)
* @method int getbit($key, $offset)
* @method string getrange($key, $start, $end)
* @method string getset($key, $value)
* @method int incr($key)
* @method int incrby($key, $increment)
* @method string incrbyfloat($key, $increment)
* @method array mget(array $keys)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method mixed psetex($key, $milliseconds, $value)
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit($key, $offset, $value)
* @method int setex($key, $seconds, $value)
* @method int setnx($key, $value)
* @method int setrange($key, $offset, $value)
* @method int strlen($key)
* @method int hdel($key, array $fields)
* @method int hexists($key, $field)
* @method string hget($key, $field)
* @method array hgetall($key)
* @method int hincrby($key, $field, $increment)
* @method string hincrbyfloat($key, $field, $increment)
* @method array hkeys($key)
* @method int hlen($key)
* @method array hmget($key, array $fields)
* @method mixed hmset($key, array $dictionary)
* @method array hscan($key, $cursor, array $options = null)
* @method int hset($key, $field, $value)
* @method int hsetnx($key, $field, $value)
* @method array hvals($key)
* @method int hstrlen($key, $field)
* @method array blpop(array $keys, $timeout)
* @method array brpop(array $keys, $timeout)
* @method array brpoplpush($source, $destination, $timeout)
* @method string lindex($key, $index)
* @method int linsert($key, $whence, $pivot, $value)
* @method int llen($key)
* @method string lpop($key)
* @method int lpush($key, array $values)
* @method int lpushx($key, $value)
* @method array lrange($key, $start, $stop)
* @method int lrem($key, $count, $value)
* @method mixed lset($key, $index, $value)
* @method mixed ltrim($key, $start, $stop)
* @method string rpop($key)
* @method string rpoplpush($source, $destination)
* @method int rpush($key, array $values)
* @method int rpushx($key, $value)
* @method int sadd($key, array $members)
* @method int scard($key)
* @method array sdiff(array $keys)
* @method int sdiffstore($destination, array $keys)
* @method array sinter(array $keys)
* @method int sinterstore($destination, array $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method string spop($key, $count = null)
* @method string srandmember($key, $count = null)
* @method int srem($key, $member)
* @method array sscan($key, $cursor, array $options = null)
* @method array sunion(array $keys)
* @method int sunionstore($destination, array $keys)
* @method int zadd($key, array $membersAndScoresDictionary)
* @method int zcard($key)
* @method string zcount($key, $min, $max)
* @method string zincrby($key, $increment, $member)
* @method int zinterstore($destination, array $keys, array $options = null)
* @method array zrange($key, $start, $stop, array $options = null)
* @method array zrangebyscore($key, $min, $max, array $options = null)
* @method int zrank($key, $member)
* @method int zrem($key, $member)
* @method int zremrangebyrank($key, $start, $stop)
* @method int zremrangebyscore($key, $min, $max)
* @method array zrevrange($key, $start, $stop, array $options = null)
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
* @method int zrevrank($key, $member)
* @method int zunionstore($destination, array $keys, array $options = null)
* @method string zscore($key, $member)
* @method array zscan($key, $cursor, array $options = null)
* @method array zrangebylex($key, $start, $stop, array $options = null)
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
* @method int zremrangebylex($key, $min, $max)
* @method int zlexcount($key, $min, $max)
* @method int pfadd($key, array $elements)
* @method mixed pfmerge($destinationKey, array $sourceKeys)
* @method int pfcount(array $keys)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch($key)
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth($password)
* @method string echo($message)
* @method mixed ping($message = null)
* @method mixed select($database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof($host, $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd($key, $longitude, $latitude, $member)
* @method array geohash($key, array $members)
* @method array geopos($key, array $members)
* @method string geodist($key, $member1, $member2, $unit = null)
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
* @method int del(array|string $keys)
* @method string|null dump($key)
* @method int exists($key)
* @method int expire($key, $seconds)
* @method int expireat($key, $timestamp)
* @method array keys($pattern)
* @method int move($key, $db)
* @method mixed object($subcommand, $key)
* @method int persist($key)
* @method int pexpire($key, $milliseconds)
* @method int pexpireat($key, $timestamp)
* @method int pttl($key)
* @method string|null randomkey()
* @method mixed rename($key, $target)
* @method int renamenx($key, $target)
* @method array scan($cursor, array $options = null)
* @method array sort($key, array $options = null)
* @method int ttl($key)
* @method mixed type($key)
* @method int append($key, $value)
* @method int bitcount($key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array|null bitfield($key, $subcommand, ...$subcommandArg)
* @method int bitpos($key, $bit, $start = null, $end = null)
* @method int decr($key)
* @method int decrby($key, $decrement)
* @method string|null get($key)
* @method int getbit($key, $offset)
* @method string getrange($key, $start, $end)
* @method string|null getset($key, $value)
* @method int incr($key)
* @method int incrby($key, $increment)
* @method string incrbyfloat($key, $increment)
* @method array mget(array $keys)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method mixed psetex($key, $milliseconds, $value)
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit($key, $offset, $value)
* @method int setex($key, $seconds, $value)
* @method int setnx($key, $value)
* @method int setrange($key, $offset, $value)
* @method int strlen($key)
* @method int hdel($key, array $fields)
* @method int hexists($key, $field)
* @method string|null hget($key, $field)
* @method array hgetall($key)
* @method int hincrby($key, $field, $increment)
* @method string hincrbyfloat($key, $field, $increment)
* @method array hkeys($key)
* @method int hlen($key)
* @method array hmget($key, array $fields)
* @method mixed hmset($key, array $dictionary)
* @method array hscan($key, $cursor, array $options = null)
* @method int hset($key, $field, $value)
* @method int hsetnx($key, $field, $value)
* @method array hvals($key)
* @method int hstrlen($key, $field)
* @method array|null blpop(array|string $keys, $timeout)
* @method array|null brpop(array|string $keys, $timeout)
* @method string|null brpoplpush($source, $destination, $timeout)
* @method string|null lindex($key, $index)
* @method int linsert($key, $whence, $pivot, $value)
* @method int llen($key)
* @method string|null lpop($key)
* @method int lpush($key, array $values)
* @method int lpushx($key, array $values)
* @method array lrange($key, $start, $stop)
* @method int lrem($key, $count, $value)
* @method mixed lset($key, $index, $value)
* @method mixed ltrim($key, $start, $stop)
* @method string|null rpop($key)
* @method string|null rpoplpush($source, $destination)
* @method int rpush($key, array $values)
* @method int rpushx($key, array $values)
* @method int sadd($key, array $members)
* @method int scard($key)
* @method array sdiff(array|string $keys)
* @method int sdiffstore($destination, array|string $keys)
* @method array sinter(array|string $keys)
* @method int sinterstore($destination, array|string $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method string|null spop($key, $count = null)
* @method string|null srandmember($key, $count = null)
* @method int srem($key, $member)
* @method array sscan($key, $cursor, array $options = null)
* @method array sunion(array|string $keys)
* @method int sunionstore($destination, array|string $keys)
* @method int zadd($key, array $membersAndScoresDictionary)
* @method int zcard($key)
* @method string zcount($key, $min, $max)
* @method string zincrby($key, $increment, $member)
* @method int zinterstore($destination, array|string $keys, array $options = null)
* @method array zrange($key, $start, $stop, array $options = null)
* @method array zrangebyscore($key, $min, $max, array $options = null)
* @method int|null zrank($key, $member)
* @method int zrem($key, $member)
* @method int zremrangebyrank($key, $start, $stop)
* @method int zremrangebyscore($key, $min, $max)
* @method array zrevrange($key, $start, $stop, array $options = null)
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
* @method int|null zrevrank($key, $member)
* @method int zunionstore($destination, array|string $keys, array $options = null)
* @method string|null zscore($key, $member)
* @method array zscan($key, $cursor, array $options = null)
* @method array zrangebylex($key, $start, $stop, array $options = null)
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
* @method int zremrangebylex($key, $min, $max)
* @method int zlexcount($key, $min, $max)
* @method int pfadd($key, array $elements)
* @method mixed pfmerge($destinationKey, array|string $sourceKeys)
* @method int pfcount(array|string $keys)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array|null exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch($key)
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth($password)
* @method string echo($message)
* @method mixed ping($message = null)
* @method mixed select($database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof($host, $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd($key, $longitude, $latitude, $member)
* @method array geohash($key, array $members)
* @method array geopos($key, array $members)
* @method string|null geodist($key, $member1, $member2, $unit = null)
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
+1 -1
View File
@@ -161,7 +161,7 @@ class HashRing implements DistributorInterface, HashGeneratorInterface
$replicas = (int) round($weightRatio * $totalNodes * $replicas);
for ($i = 0; $i < $replicas; ++$i) {
$key = crc32("$nodeHash:$i");
$key = $this->hash("$nodeHash:$i");
$ring[$key] = $nodeObject;
}
}
+2
View File
@@ -61,6 +61,8 @@ class CRC16 implements HashGeneratorInterface
// CRC-CCITT-16 algorithm
$crc = 0;
$CCITT_16 = self::$CCITT_16;
$value = (string) $value;
$strlen = strlen($value);
for ($i = 0; $i < $strlen; ++$i) {
@@ -92,7 +92,7 @@ abstract class CursorBasedIterator implements \Iterator
{
$options = array();
if (strlen($this->match) > 0) {
if (strlen(strval($this->match)) > 0) {
$options['MATCH'] = $this->match;
}
@@ -138,7 +138,9 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
{
$this->reset();
@@ -147,7 +149,9 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current()
{
return $this->current;
@@ -155,7 +159,9 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
{
return $this->position;
@@ -163,7 +169,9 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function next()
{
tryFetch: {
@@ -183,7 +191,9 @@ abstract class CursorBasedIterator implements \Iterator
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function valid()
{
return $this->valid;
+3 -5
View File
@@ -50,11 +50,9 @@ class HashKey extends CursorBasedIterator
*/
protected function extractNext()
{
if ($kv = each($this->elements)) {
$this->position = $kv[0];
$this->current = $kv[1];
$this->position = key($this->elements);
$this->current = current($this->elements);
unset($this->elements[$this->position]);
}
unset($this->elements[$this->position]);
}
}
+10
View File
@@ -127,7 +127,9 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
{
$this->reset();
@@ -136,7 +138,9 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current()
{
return $this->current;
@@ -144,7 +148,9 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
{
return $this->position;
@@ -152,7 +158,9 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function next()
{
if (!$this->elements && $this->fetchmore) {
@@ -168,7 +176,9 @@ class ListKey implements \Iterator
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function valid()
{
return $this->valid;
+3 -5
View File
@@ -50,11 +50,9 @@ class SortedSetKey extends CursorBasedIterator
*/
protected function extractNext()
{
if ($kv = each($this->elements)) {
$this->position = $kv[0];
$this->current = $kv[1];
$this->position = key($this->elements);
$this->current = current($this->elements);
unset($this->elements[$this->position]);
}
unset($this->elements[$this->position]);
}
}
+1 -1
View File
@@ -104,7 +104,7 @@ abstract class Command implements CommandInterface
*/
public static function normalizeArguments(array $arguments)
{
if (count($arguments) === 1 && is_array($arguments[0])) {
if (count($arguments) === 1 && isset($arguments[0]) && is_array($arguments[0])) {
return $arguments[0];
}
+7 -1
View File
@@ -197,7 +197,13 @@ class KeyPrefixProcessor implements ProcessorInterface
if ($command instanceof PrefixableCommandInterface) {
$command->prefixKeys($this->prefix);
} elseif (isset($this->commands[$commandID = strtoupper($command->getId())])) {
call_user_func($this->commands[$commandID], $command, $this->prefix);
$callable = $this->commands[$commandID];
if (is_string($callable) && 0 === strpos($callable, 'static::')) {
$callable = substr_replace($callable, get_class($this), 0, 6);
}
call_user_func($callable, $command, $this->prefix);
}
}
+9 -2
View File
@@ -71,7 +71,7 @@ class ProcessorChain implements \ArrayAccess, ProcessorInterface
/**
* Returns an iterator over the list of command processor in the chain.
*
* @return \ArrayIterator
* @return \Traversable<int, ProcessorInterface>
*/
public function getIterator()
{
@@ -89,8 +89,9 @@ class ProcessorChain implements \ArrayAccess, ProcessorInterface
}
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($index)
{
return isset($this->processors[$index]);
@@ -98,7 +99,9 @@ class ProcessorChain implements \ArrayAccess, ProcessorInterface
/**
* {@inheritdoc}
* @return ProcessorInterface|null
*/
#[\ReturnTypeWillChange]
public function offsetGet($index)
{
return $this->processors[$index];
@@ -106,7 +109,9 @@ class ProcessorChain implements \ArrayAccess, ProcessorInterface
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($index, $processor)
{
if (!$processor instanceof ProcessorInterface) {
@@ -121,7 +126,9 @@ class ProcessorChain implements \ArrayAccess, ProcessorInterface
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($index)
{
unset($this->processors[$index]);
+4 -1
View File
@@ -31,7 +31,10 @@ class ServerSentinel extends Command
*/
public function parseResponse($data)
{
switch (strtolower($this->getArgument(0))) {
$argument = $this->getArgument(0);
$argument = is_null($argument) ? null : strtolower($argument);
switch ($argument) {
case 'masters':
case 'slaves':
return self::processMastersOrSlaves($data);
+6 -1
View File
@@ -34,7 +34,12 @@ abstract class CommunicationException extends PredisException
$code = null,
\Exception $innerException = null
) {
parent::__construct($message, $code, $innerException);
parent::__construct(
is_null($message) ? '' : $message,
is_null($code) ? 0 : $code,
$innerException
);
$this->connection = $connection;
}
+13 -7
View File
@@ -11,16 +11,22 @@
namespace Predis\Configuration;
use Predis\Command\Processor\ProcessorInterface;
use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Connection\FactoryInterface;
use Predis\Profile\ProfileInterface;
/**
* Interface defining a container for client options.
*
* @property-read mixed aggregate Custom connection aggregator.
* @property-read mixed cluster Aggregate connection for clustering.
* @property-read mixed connections Connection factory.
* @property-read mixed exceptions Toggles exceptions in client for -ERR responses.
* @property-read mixed prefix Key prefixing strategy using the given prefix.
* @property-read mixed profile Server profile.
* @property-read mixed replication Aggregate connection for replication.
* @property-read callable $aggregate Custom connection aggregator.
* @property-read ClusterInterface $cluster Aggregate connection for clustering.
* @property-read FactoryInterface $connections Connection factory.
* @property-read bool $exceptions Toggles exceptions in client for -ERR responses.
* @property-read ProcessorInterface $prefix Key prefixing strategy using the given prefix.
* @property-read ProfileInterface $profile Server profile.
* @property-read ReplicationInterface $replication Aggregate connection for replication.
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
+7 -5
View File
@@ -36,10 +36,6 @@ class ReplicationOption implements OptionInterface
return $value;
}
if (is_bool($value) || $value === null) {
return $value ? $this->getDefault($options) : null;
}
if ($value === 'sentinel') {
return function ($sentinels, $options) {
return new SentinelReplication($options->service, $sentinels, $options->connections);
@@ -50,7 +46,13 @@ class ReplicationOption implements OptionInterface
!is_object($value) &&
null !== $asbool = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
) {
return $asbool ? $this->getDefault($options) : null;
if (true === $asbool) {
return $this->getDefault($options);
} else {
throw new \InvalidArgumentException(
"Values evaluating to FALSE are not accepted for `replication`"
);
}
}
throw new \InvalidArgumentException(
+4 -2
View File
@@ -176,16 +176,18 @@ class PredisCluster implements ClusterInterface, \IteratorAggregate, \Countable
}
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return count($this->pool);
}
/**
* {@inheritdoc}
* @return \Traversable<string|int, NodeConnectionInterface>
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new \ArrayIterator($this->pool);
+4 -2
View File
@@ -600,16 +600,18 @@ class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
}
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return count($this->pool);
}
/**
* {@inheritdoc}
* @return \Traversable<int, NodeConnectionInterface>
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
if ($this->useClusterSlots) {
@@ -20,6 +20,7 @@ use Predis\Connection\NodeConnectionInterface;
use Predis\Connection\Parameters;
use Predis\Replication\ReplicationStrategy;
use Predis\Replication\RoleException;
use Predis\Response\Error;
use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;
@@ -146,14 +147,14 @@ class SentinelReplication implements ReplicationInterface
}
/**
* Sets the time to wait (in seconds) before fetching a new configuration
* Sets the time to wait (in milliseconds) before fetching a new configuration
* from one of the sentinels.
*
* @param float $seconds Time to wait before the next attempt.
* @param float $milliseconds Time to wait before the next attempt.
*/
public function setRetryWait($seconds)
public function setRetryWait($milliseconds)
{
$this->retryWait = (float) $seconds;
$this->retryWait = (float) $milliseconds;
}
/**
@@ -239,9 +240,14 @@ class SentinelReplication implements ReplicationInterface
}
if (is_array($parameters)) {
// We explicitly set "database" and "password" to null,
// so that no AUTH and SELECT command is send to the sentinels.
// NOTE: sentinels do not accept AUTH and SELECT commands so we must
// explicitly set them to NULL to avoid problems when using default
// parameters set via client options. Actually AUTH is supported for
// sentinels starting with Redis 5 but we have to differentiate from
// sentinels passwords and nodes passwords, this will be implemented
// in a later release.
$parameters['database'] = null;
$parameters['username'] = null;
$parameters['password'] = null;
if (!isset($parameters['timeout'])) {
@@ -515,14 +521,20 @@ class SentinelReplication implements ReplicationInterface
/**
* Asserts that the specified connection matches an expected role.
*
* @param NodeConnectionInterface $sentinel Connection to a redis server.
* @param string $role Expected role of the server ("master", "slave" or "sentinel").
* @param NodeConnectionInterface $connection Connection to a redis server.
* @param string $role Expected role of the server ("master", "slave" or "sentinel").
*
* @throws RoleException|ConnectionException
*/
protected function assertConnectionRole(NodeConnectionInterface $connection, $role)
{
$role = strtolower($role);
$actualRole = $connection->executeCommand(RawCommand::create('ROLE'));
if ($actualRole instanceof Error) {
throw new ConnectionException($connection, $actualRole->getMessage());
}
if ($role !== $actualRole[0]) {
throw new RoleException($connection, "Expected $role but got $actualRole[0] [$connection]");
}
+7 -3
View File
@@ -173,13 +173,17 @@ class Factory implements FactoryInterface
{
$parameters = $connection->getParameters();
if (isset($parameters->password)) {
if (isset($parameters->password) && strlen($parameters->password)) {
$cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
? array('AUTH', $parameters->username, $parameters->password)
: array('AUTH', $parameters->password);
$connection->addConnectCommand(
new RawCommand(array('AUTH', $parameters->password))
new RawCommand($cmdAuthArgs)
);
}
if (isset($parameters->database)) {
if (isset($parameters->database) && strlen($parameters->database)) {
$connection->addConnectCommand(
new RawCommand(array('SELECT', $parameters->database))
);
+10 -1
View File
@@ -109,8 +109,17 @@ class Parameters implements ParametersInterface
}
if (stripos($uri, 'redis') === 0) {
if (isset($parsed['user'])) {
if (strlen($parsed['user'])) {
$parsed['username'] = $parsed['user'];
}
unset($parsed['user']);
}
if (isset($parsed['pass'])) {
$parsed['password'] = $parsed['pass'];
if (strlen($parsed['pass'])) {
$parsed['password'] = $parsed['pass'];
}
unset($parsed['pass']);
}
+5 -5
View File
@@ -66,9 +66,9 @@ class PhpiredisSocketConnection extends AbstractConnection
*/
public function __destruct()
{
phpiredis_reader_destroy($this->reader);
parent::__destruct();
phpiredis_reader_destroy($this->reader);
}
/**
@@ -227,9 +227,7 @@ class PhpiredisSocketConnection extends AbstractConnection
$protocol = SOL_TCP;
}
$socket = @socket_create($domain, SOCK_STREAM, $protocol);
if (!is_resource($socket)) {
if (false === $socket = @socket_create($domain, SOCK_STREAM, $protocol)) {
$this->emitSocketError();
}
@@ -344,7 +342,9 @@ class PhpiredisSocketConnection extends AbstractConnection
public function disconnect()
{
if ($this->isConnected()) {
phpiredis_reader_reset($this->reader);
socket_close($this->getResource());
parent::disconnect();
}
}
+30 -5
View File
@@ -67,9 +67,19 @@ class PhpiredisStreamConnection extends StreamConnection
*/
public function __destruct()
{
phpiredis_reader_destroy($this->reader);
parent::__destruct();
phpiredis_reader_destroy($this->reader);
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
phpiredis_reader_reset($this->reader);
parent::disconnect();
}
/**
@@ -87,9 +97,23 @@ class PhpiredisStreamConnection extends StreamConnection
/**
* {@inheritdoc}
*/
protected function assertSslSupport(ParametersInterface $parameters)
protected function assertParameters(ParametersInterface $parameters)
{
throw new \InvalidArgumentException('SSL encryption is not supported by this connection backend.');
switch ($parameters->scheme) {
case 'tcp':
case 'redis':
case 'unix':
break;
case 'tls':
case 'rediss':
throw new \InvalidArgumentException('SSL encryption is not supported by this connection backend.');
default:
throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
}
return $parameters;
}
/**
@@ -99,8 +123,9 @@ class PhpiredisStreamConnection extends StreamConnection
{
$socket = null;
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
$context = stream_context_create();
$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags);
$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context);
if (!$resource) {
$this->onConnectionError(trim($errstr), $errno);
+5 -4
View File
@@ -123,8 +123,9 @@ class StreamConnection extends AbstractConnection
protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
{
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
$context = stream_context_create();
if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags)) {
if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context)) {
$this->onConnectionError(trim($errstr), $errno);
}
@@ -288,7 +289,7 @@ class StreamConnection extends AbstractConnection
$socket = $this->getResource();
while (($length = strlen($buffer)) > 0) {
$written = @fwrite($socket, $buffer);
$written = is_resource($socket) ? @fwrite($socket, $buffer) : false;
if ($length === $written) {
return;
@@ -332,7 +333,7 @@ class StreamConnection extends AbstractConnection
$bytesLeft = ($size += 2);
do {
$chunk = fread($socket, min($bytesLeft, 4096));
$chunk = is_resource($socket) ? fread($socket, min($bytesLeft, 4096)) : false;
if ($chunk === false || $chunk === '') {
$this->onConnectionError('Error while reading bytes from the server.');
@@ -387,7 +388,7 @@ class StreamConnection extends AbstractConnection
$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";
foreach ($arguments as $argument) {
$arglen = strlen($argument);
$arglen = strlen(strval($argument));
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
}
+1 -1
View File
@@ -119,7 +119,7 @@ class WebdisConnection implements NodeConnectionInterface
$parameters = $this->getParameters();
$timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0) * 1000;
if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP)) {
if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$host = "[$host]";
}
+9 -1
View File
@@ -24,7 +24,7 @@ class Consumer implements \Iterator
{
private $client;
private $valid;
private $position;
private $position = 0;
/**
* @param ClientInterface $client Client instance used by the consumer.
@@ -90,7 +90,9 @@ class Consumer implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
{
// NOOP
@@ -101,6 +103,7 @@ class Consumer implements \Iterator
*
* @return object
*/
#[\ReturnTypeWillChange]
public function current()
{
return $this->getValue();
@@ -108,7 +111,9 @@ class Consumer implements \Iterator
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
{
return $this->position;
@@ -116,7 +121,9 @@ class Consumer implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function next()
{
++$this->position;
@@ -127,6 +134,7 @@ class Consumer implements \Iterator
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function valid()
{
return $this->valid;
+13
View File
@@ -225,6 +225,19 @@ class Pipeline implements ClientContextInterface
return $this->responses;
}
/**
* Clear the buffer holding all of the commands and responses.
*
* @return $this
*/
public function clear()
{
$this->responses = array();
$this->pipeline = new \SplQueue();
return $this;
}
/**
* Returns if the pipeline should throw exceptions on server errors.
*
+10 -3
View File
@@ -30,7 +30,7 @@ abstract class AbstractConsumer implements \Iterator
const STATUS_SUBSCRIBED = 2; // 0b0010
const STATUS_PSUBSCRIBED = 4; // 0b0100
private $position = null;
private $position = 0;
private $statusFlags = self::STATUS_VALID;
/**
@@ -150,7 +150,9 @@ abstract class AbstractConsumer implements \Iterator
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
{
// NOOP
@@ -160,8 +162,9 @@ abstract class AbstractConsumer implements \Iterator
* Returns the last message payload retrieved from the server and generated
* by one of the active subscriptions.
*
* @return array
* @return \stdClass
*/
#[\ReturnTypeWillChange]
public function current()
{
return $this->getValue();
@@ -169,7 +172,9 @@ abstract class AbstractConsumer implements \Iterator
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
{
return $this->position;
@@ -178,6 +183,7 @@ abstract class AbstractConsumer implements \Iterator
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function next()
{
if ($this->valid()) {
@@ -192,6 +198,7 @@ abstract class AbstractConsumer implements \Iterator
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function valid()
{
$isValid = $this->isFlagSet(self::STATUS_VALID);
@@ -213,7 +220,7 @@ abstract class AbstractConsumer implements \Iterator
* Waits for a new message from the server generated by one of the active
* subscriptions and returns it when available.
*
* @return array
* @return \stdClass
*/
abstract protected function getValue();
}
+6
View File
@@ -16,6 +16,8 @@ use Predis\ClientInterface;
use Predis\Command\Command;
use Predis\Connection\AggregateConnectionInterface;
use Predis\NotSupportedException;
use Predis\Response\ServerException;
use Predis\Response\Error;
/**
* PUB/SUB consumer abstraction.
@@ -116,6 +118,10 @@ class Consumer extends AbstractConsumer
{
$response = $this->client->getConnection()->read();
if ($response instanceof Error) {
throw new ServerException($response->getMessage());
}
switch ($response[0]) {
case self::SUBSCRIBE:
case self::UNSUBSCRIBE:
+2 -27
View File
@@ -62,7 +62,8 @@ class ReplicationStrategy
}
if (($eval = $id === 'EVAL') || $id === 'EVALSHA') {
$sha1 = $eval ? sha1($command->getArgument(0)) : $command->getArgument(0);
$argument = $command->getArgument(0);
$sha1 = $eval ? sha1(strval($argument)) : $argument;
if (isset($this->readonlySHA1[$sha1])) {
if (true === $readonly = $this->readonlySHA1[$sha1]) {
@@ -89,31 +90,6 @@ class ReplicationStrategy
return isset($this->disallowed[$command->getId()]);
}
/**
* Checks if a SORT command is a readable operation by parsing the arguments
* array of the specified commad instance.
*
* @param CommandInterface $command Command instance.
*
* @return bool
*/
protected function isSortReadOnly(CommandInterface $command)
{
$arguments = $command->getArguments();
$argc = count($arguments);
if ($argc > 1) {
for ($i = 1; $i < $argc; ++$i) {
$argument = strtoupper($arguments[$i]);
if ($argument === 'STORE') {
return false;
}
}
}
return true;
}
/**
* Checks if BITFIELD performs a read-only operation by looking for certain
* SET and INCRYBY modifiers in the arguments array of the command.
@@ -292,7 +268,6 @@ class ReplicationStrategy
'BITPOS' => true,
'TIME' => true,
'PFCOUNT' => true,
'SORT' => array($this, 'isSortReadOnly'),
'BITFIELD' => array($this, 'isBitfieldReadOnly'),
'GEOHASH' => true,
'GEOPOS' => true,
@@ -33,7 +33,9 @@ abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInter
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function rewind()
{
// NOOP
@@ -41,7 +43,9 @@ abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInter
/**
* {@inheritdoc}
* @return mixed
*/
#[\ReturnTypeWillChange]
public function current()
{
return $this->current;
@@ -49,7 +53,9 @@ abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInter
/**
* {@inheritdoc}
* @return int
*/
#[\ReturnTypeWillChange]
public function key()
{
return $this->position;
@@ -57,7 +63,9 @@ abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInter
/**
* {@inheritdoc}
* @return void
*/
#[\ReturnTypeWillChange]
public function next()
{
if (++$this->position < $this->size) {
@@ -67,7 +75,9 @@ abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInter
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function valid()
{
return $this->position < $this->size;
@@ -82,6 +92,7 @@ abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInter
*
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return $this->size;
+2
View File
@@ -60,7 +60,9 @@ class MultiBulkTuple extends MultiBulk implements \OuterIterator
/**
* {@inheritdoc}
* @return \Iterator
*/
#[\ReturnTypeWillChange]
public function getInnerIterator()
{
return $this->iterator;
+12
View File
@@ -64,7 +64,9 @@ class Handler implements \SessionHandlerInterface
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function open($save_path, $session_id)
{
// NOOP
@@ -73,7 +75,9 @@ class Handler implements \SessionHandlerInterface
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function close()
{
// NOOP
@@ -82,7 +86,9 @@ class Handler implements \SessionHandlerInterface
/**
* {@inheritdoc}
* @return int|bool
*/
#[\ReturnTypeWillChange]
public function gc($maxlifetime)
{
// NOOP
@@ -91,7 +97,9 @@ class Handler implements \SessionHandlerInterface
/**
* {@inheritdoc}
* @return string
*/
#[\ReturnTypeWillChange]
public function read($session_id)
{
if ($data = $this->client->get($session_id)) {
@@ -102,7 +110,9 @@ class Handler implements \SessionHandlerInterface
}
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function write($session_id, $session_data)
{
$this->client->setex($session_id, $this->ttl, $session_data);
@@ -112,7 +122,9 @@ class Handler implements \SessionHandlerInterface
/**
* {@inheritdoc}
* @return bool
*/
#[\ReturnTypeWillChange]
public function destroy($session_id)
{
$this->client->del($session_id);
@@ -29,7 +29,7 @@ class AbortedMultiExecException extends PredisException
*/
public function __construct(MultiExec $transaction, $message, $code = null)
{
parent::__construct($message, $code);
parent::__construct($message, is_null($code) ? 0 : $code);
$this->transaction = $transaction;
}
+12
View File
@@ -337,4 +337,16 @@ abstract class PredisTestCase extends \PHPUnit_Framework_TestCase
$this->checkRequiredRedisServerVersion();
}
/**
* Marks current test skipped when test suite is running on CI environments.
*
* @param string $message
*/
protected function markTestSkippedOnCIEnvironment($message = 'Test skipped on CI environment')
{
if (getenv('GITHUB_ACTIONS') || getenv('TRAVIS')) {
$this->markTestSkipped($message);
}
}
}
+7 -5
View File
@@ -853,15 +853,17 @@ class ClientTest extends PredisTestCase
/**
* @group disconnected
* @expectedException \Predis\ClientException
* @expectedExceptionMessage The underlying connection is not traversable
*/
public function testGetIteratorWithNonTraversableConnectionThrowsException()
public function testGetIteratorWithNonTraversableConnectionNoException()
{
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection = $this->getMockConnection('tcp://127.0.0.1:6381');
$client = new Client($connection);
$client->getIterator();
$iterator = $client->getIterator();
$this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
$this->assertSame($connection, $nodeClient->getConnection());
$this->assertSame('127.0.0.1:6381', $iterator->key());
}
// ******************************************************************** //
+11
View File
@@ -36,4 +36,15 @@ class CRC16Test extends PredisTestCase
$this->assertSame(25343, $crc16->hash('key:008'));
$this->assertSame(29406, $crc16->hash('key:009'));
}
/**
* @group disconnected
*/
public function testHashGenerationWithIntegerValues()
{
$crc16 = new CRC16();
$this->assertSame(13907, $crc16->hash(0));
$this->assertSame(55177, $crc16->hash(1234));
}
}
@@ -57,8 +57,8 @@ class HashKeyTest extends PredisTestCase
}
/**
* @link https://github.com/nrk/predis/pull/330
* @link https://github.com/nrk/predis/issues/331
* @see https://github.com/predis/predis/pull/330
* @see https://github.com/predis/predis/issues/331
* @group disconnected
*/
public function testIterationWithIntegerFields()
@@ -57,7 +57,7 @@ class SortedSetKeyTest extends PredisTestCase
}
/**
* @link https://github.com/nrk/predis/issues/216
* @see https://github.com/predis/predis/issues/216
* @group disconnected
*/
public function testIterationWithIntegerMembers()
+14 -2
View File
@@ -71,12 +71,24 @@ class ConnectionSelectTest extends PredisCommandTestCase
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessage ERR invalid DB index
* @expectedExceptionMessageRegExp /ERR.*DB index/
*/
public function testThrowsExceptionOnUnexpectedDatabase()
public function testThrowsExceptionOnUnexpectedDatabaseRange()
{
$redis = $this->getClient();
$redis->select(100000000);
}
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessageRegExp /ERR (invalid DB index|value is not)/
*/
public function testThrowsExceptionOnUnexpectedDatabaseName()
{
$redis = $this->getClient();
$redis->select('x');
}
}
+1 -1
View File
@@ -82,7 +82,7 @@ class KeyMoveTest extends PredisCommandTestCase
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessage ERR index out of range
* @expectedExceptionMessageRegEx /ERR.*out of range/
*/
public function testThrowsExceptionOnInvalidDatabases()
{
@@ -145,7 +145,7 @@ class PubSubSubscribeByPatternTest extends PredisCommandTestCase
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessageRegExp /ERR only .* allowed in this context/
* @expectedExceptionMessageRegExp /ERR.*only .* allowed in this context/
*/
public function testCannotSendOtherCommandsAfterPsubscribe()
{
+1 -1
View File
@@ -145,7 +145,7 @@ class PubSubSubscribeTest extends PredisCommandTestCase
/**
* @group connected
* @expectedException \Predis\Response\ServerException
* @expectedExceptionMessageRegExp /ERR only .* allowed in this context/
* @expectedExceptionMessageRegExp /ERR.*only .* allowed in this context/
*/
public function testCannotSendOtherCommandsAfterSubscribe()
{
+20 -1
View File
@@ -74,10 +74,29 @@ class RawCommandTest extends PredisTestCase
* argument is missing, PHP emits an E_WARNING.
*
* @group disconnected
* @expectedException \PHPUnit_Framework_Error_Warning
*/
public function testPHPWarningOnMissingCommandIDWithStaticCreate()
{
if (version_compare(PHP_VERSION, "7.1", '>')) {
$this->markTestSkipped('only for PHP < 7.1');
}
$this->setExpectedException('PHPUnit_Framework_Error_Warning');
RawCommand::create();
}
/**
* The signature of RawCommand::create() requires one argument which is the
* ID of the command (other arguments are fetched dinamically). If the first
* argument is missing, PHP 7.1 throw an exception
*
* @group disconnected
*/
public function testPHPWarningOnMissingCommandIDWithStaticCreate71()
{
if (version_compare(PHP_VERSION, "7.1", '<')) {
$this->markTestSkipped('only for PHP > 7.1');
}
$this->setExpectedException('ArgumentCountError');
RawCommand::create();
}
+13 -2
View File
@@ -102,13 +102,24 @@ class ServerCommandTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
// NOTE: starting with Redis 6.0 and the introduction of Access Control
// Lists, COMMAND INFO returns an additional array for each specified
// command in yhe request with a list of the ACL categories associated
// to a command. We simply append this additional array in the expected
// response if the test suite is executed against Redis >= 6.0.
if ($this->isRedisServerVersion('>=', '6.0')) {
$expected[0][] = array('@read', '@string', '@fast');
}
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
// NOTE: we use assertEquals instead of assertSame because Redis returns
// flags as +STATUS responses, represented by Predis with instances of
// Predis\Response\Status instead of plain strings. This class responds
// to __toString() so the string conversion is implicit, but assertSame
// checks for strict equality while assertEquals is loose.
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
$this->assertEquals($expected, $response);
}
@@ -76,7 +76,7 @@ class StringIncrementByFloatTest extends PredisCommandTestCase
$redis->set('foo', 2);
// We use round() to avoid errors on some platforms, see the following
// issue https://github.com/nrk/predis/issues/220 for reference.
// issue https://github.com/predis/predis/issues/220 for reference.
$this->assertEquals(22.123, $redis->incrbyfloat('foo', 20.123));
$this->assertEquals(10, round($redis->incrbyfloat('foo', -12.123), 5));
$this->assertEquals(-100.01, round($redis->incrbyfloat('foo', -110.01), 5));
@@ -31,26 +31,49 @@ class ReplicationOptionTest extends PredisTestCase
}
/**
* @group disconnected
* @return array
*/
public function testAcceptsValuesThatCanBeInterpretedAsBooleans()
public function provideValuesEvaluatingTrue()
{
return array(array(true), array(1), array('true'), array('on'));
}
/**
* @group disconnected
* @dataProvider provideValuesEvaluatingTrue
*/
public function testAcceptsValuesThatCanBeInterpretedAsBooleanTrue($value)
{
$option = new ReplicationOption();
$options = $this->getMock('Predis\Configuration\OptionsInterface');
$this->assertNull($option->filter($options, null));
$this->assertInstanceOf('Predis\Connection\Aggregate\MasterSlaveReplication', $option->filter($options, $value));
}
$this->assertInstanceOf('Predis\Connection\Aggregate\ReplicationInterface', $option->filter($options, true));
$this->assertNull($option->filter($options, false));
/**
* @return array
*/
public function provideValuesEvaluatingFalse()
{
return array(array(false), array(0), array('false'), array('off'));
}
$this->assertInstanceOf('Predis\Connection\Aggregate\ReplicationInterface', $option->filter($options, 1));
$this->assertNull($option->filter($options, 0));
/**
* @group disconnected
* @dataProvider provideValuesEvaluatingFalse
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Values evaluating to FALSE are not accepted for `replication`
*/
public function testDoesNotAcceptValuesThatCanBeInterpretedAsBooleanFalse($value)
{
if (version_compare(PHP_VERSION, '5.4', '<')) {
$this->markTestSkipped('Skip test, because.');
}
$this->assertInstanceOf('Predis\Connection\Aggregate\ReplicationInterface', $option->filter($options, 'true'));
$this->assertNull($option->filter($options, 'false'));
$option = new ReplicationOption();
$options = $this->getMock('Predis\Configuration\OptionsInterface');
$this->assertInstanceOf('Predis\Connection\Aggregate\ReplicationInterface', $option->filter($options, 'on'));
$this->assertNull($option->filter($options, 'off'));
$option->filter($options, $value);
}
/**
@@ -541,29 +541,6 @@ class MasterSlaveReplicationTest extends PredisTestCase
$replication->executeCommand($cmdEval);
}
/**
* @group disconnected
*/
public function testSortTriggersSwitchToMasterConnectionOnStoreModifier()
{
$profile = Profile\Factory::get('dev');
$cmdSortNormal = $profile->createCommand('sort', array('key'));
$cmdSortStore = $profile->createCommand('sort', array('key', array('store' => 'key:store')));
$master = $this->getMockConnection('tcp://host1?alias=master');
$master->expects($this->once())->method('executeCommand')->with($cmdSortStore);
$slave1 = $this->getMockConnection('tcp://host2?alias=slave1');
$slave1->expects($this->once())->method('executeCommand')->with($cmdSortNormal);
$replication = new MasterSlaveReplication();
$replication->add($master);
$replication->add($slave1);
$replication->executeCommand($cmdSortNormal);
$replication->executeCommand($cmdSortStore);
}
/**
* @group disconnected
*/
@@ -245,8 +245,8 @@ class RedisClusterTest extends PredisTestCase
public function testGetIteratorReturnsConnectionsMappedInSlotsMapWhenUseClusterSlotsIsDisabled()
{
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=0-5460');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10921');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10922-16383');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10922');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10923-16383');
$connection4 = $this->getMockConnection('tcp://127.0.0.1:6384');
$cluster = new RedisCluster(new Connection\Factory());
@@ -274,8 +274,8 @@ class RedisClusterTest extends PredisTestCase
{
$slotsmap = array(
array(0, 5460, array('127.0.0.1', 6381), array()),
array(5461, 10921, array('127.0.0.1', 6383), array()),
array(10922, 16383, array('127.0.0.1', 6384), array()),
array(5461, 10922, array('127.0.0.1', 6383), array()),
array(10923, 16383, array('127.0.0.1', 6384), array()),
);
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=0-5460');
@@ -286,7 +286,7 @@ class RedisClusterTest extends PredisTestCase
))
->will($this->returnValue($slotsmap));
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10921');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10922');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383');
$connection4 = $this->getMockConnection('tcp://127.0.0.1:6384');
@@ -398,8 +398,8 @@ class RedisClusterTest extends PredisTestCase
public function testCanAssignConnectionsToRangeOfSlotsFromParameters()
{
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-5460');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=5461-10921');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=10922-16383');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=5461-10922');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=10923-16383');
$cluster = new RedisCluster(new Connection\Factory());
$cluster->add($connection1);
@@ -410,8 +410,8 @@ class RedisClusterTest extends PredisTestCase
$expectedMap = array_merge(
array_fill(0, 5461, '127.0.0.1:6379'),
array_fill(5460, 5461, '127.0.0.1:6380'),
array_fill(10921, 5462, '127.0.0.1:6381')
array_fill(5460, 5462, '127.0.0.1:6380'),
array_fill(10923, 5461, '127.0.0.1:6381')
);
$actualMap = $cluster->getSlotsMap();
@@ -426,8 +426,8 @@ class RedisClusterTest extends PredisTestCase
public function testCanAssignConnectionsToSingleSlotOrRangesOfSlotsFromParameters()
{
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-5460,5500-5600,11000');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=5461-5499,5600-10921');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=10922-10999,11001-16383');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=5461-5499,5600-10922');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=10923-10999,11001-16383');
$cluster = new RedisCluster(new Connection\Factory());
$cluster->add($connection1);
@@ -440,8 +440,8 @@ class RedisClusterTest extends PredisTestCase
array_fill(0, 5461, '127.0.0.1:6379'),
array_fill(5460, 39, '127.0.0.1:6380'),
array_fill(5499, 101, '127.0.0.1:6379'),
array_fill(5599, 5321, '127.0.0.1:6380'),
array_fill(10921, 78, '127.0.0.1:6381'),
array_fill(5599, 5322, '127.0.0.1:6380'),
array_fill(10923, 77, '127.0.0.1:6381'),
array_fill(11000, 1, '127.0.0.1:6379'),
array_fill(11000, 5383, '127.0.0.1:6381')
);
@@ -555,8 +555,8 @@ class RedisClusterTest extends PredisTestCase
{
$slotsmap = array(
array(0, 5460, array('127.0.0.1', 9381), array()),
array(5461, 10921, array('127.0.0.1', 6382), array()),
array(10922, 16383, array('127.0.0.1', 6383), array()),
array(5461, 10922, array('127.0.0.1', 6382), array()),
array(10923, 16383, array('127.0.0.1', 6383), array()),
);
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=0-5460');
@@ -569,7 +569,7 @@ class RedisClusterTest extends PredisTestCase
new Connection\ConnectionException($connection1, 'Unknown connection error [127.0.0.1:6381]')
));
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10921');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10922');
$connection2->expects($this->any())
->method('executeCommand')
->with($this->isRedisCommand(
@@ -577,7 +577,7 @@ class RedisClusterTest extends PredisTestCase
))
->will($this->returnValue($slotsmap));
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10922-16383');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10923-16383');
$connection3->expects($this->any())
->method('executeCommand')
->with($this->isRedisCommand(
@@ -720,8 +720,8 @@ class RedisClusterTest extends PredisTestCase
{
$slotsmap = array(
array(0, 5460, array('127.0.0.1', 9381), array()),
array(5461, 10921, array('127.0.0.1', 6382), array()),
array(10922, 16383, array('127.0.0.1', 6383), array()),
array(5461, 10922, array('127.0.0.1', 6382), array()),
array(10923, 16383, array('127.0.0.1', 6383), array()),
);
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=0-5460');
@@ -734,7 +734,7 @@ class RedisClusterTest extends PredisTestCase
new Connection\ConnectionException($connection1, 'Unknown connection error [127.0.0.1:6381]')
));
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10921');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10922');
$connection2->expects($this->once())
->method('executeCommand')
->with($this->isRedisCommand(
@@ -744,7 +744,7 @@ class RedisClusterTest extends PredisTestCase
new Connection\ConnectionException($connection2, 'Unknown connection error [127.0.0.1:6383]')
));
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10922-16383');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10923-16383');
$connection3->expects($this->once())
->method('executeCommand')
->with($this->isRedisCommand(
@@ -777,8 +777,8 @@ class RedisClusterTest extends PredisTestCase
{
$slotsmap = array(
array(0, 5460, array('127.0.0.1', 9381), array()),
array(5461, 10921, array('127.0.0.1', 6382), array()),
array(10922, 16383, array('127.0.0.1', 6383), array()),
array(5461, 10922, array('127.0.0.1', 6382), array()),
array(10923, 16383, array('127.0.0.1', 6383), array()),
);
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=0-5460');
@@ -791,7 +791,7 @@ class RedisClusterTest extends PredisTestCase
new Connection\ConnectionException($connection1, 'Unknown connection error [127.0.0.1:6381]')
));
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10921');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6382?slots=5461-10922');
$connection2->expects($this->any())
->method('executeCommand')
->with($this->isRedisCommand(
@@ -801,7 +801,7 @@ class RedisClusterTest extends PredisTestCase
new Connection\ConnectionException($connection2, 'Unknown connection error [127.0.0.1:6382]')
));
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10922-16383');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6383?slots=10923-16383');
$connection3->expects($this->never())
->method('executeCommand');
@@ -1142,9 +1142,9 @@ class RedisClusterTest extends PredisTestCase
*/
public function testCanBeSerialized()
{
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-1364');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=1365-2729');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=2730-4095');
$connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-5460');
$connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=5461-10922');
$connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=10923-16383');
$cluster = new RedisCluster(new Connection\Factory());
$cluster->add($connection1);
@@ -36,15 +36,19 @@ class SentinelReplicationTest extends PredisTestCase
/**
* @group disconnected
*/
public function testParametersForSentinelConnectionShouldNotUseDatabaseAndPassword()
public function testParametersForSentinelConnectionShouldNotUseDatabaseAndUsernameAndPassword()
{
$replication = $this->getReplicationConnection('svc', array(
'tcp://127.0.0.1:5381?alias=sentinel1&database=1&password=secret',
'tcp://127.0.0.1:5381?alias=sentinel1&database=1&username=myusername&password=secret',
));
$parameters = $replication->getSentinelConnection()->getParameters()->toArray();
$this->assertArraySubset(array('database' => null, 'password' => null), $parameters);
$this->assertArraySubset(array(
'database' => null,
'username' => null,
'password' => null
), $parameters);
}
/**
+129 -2
View File
@@ -280,8 +280,6 @@ class FactoryTest extends PredisTestCase
/**
* @group disconnected
*
* @todo This test smells but there's no other way around it right now.
*/
public function testCreateConnectionWithInitializationCommands()
{
@@ -303,6 +301,111 @@ class FactoryTest extends PredisTestCase
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
*/
public function testCreateConnectionWithPasswordAndNoUsernameAddsInitializationCommandAuthWithOneArgument()
{
$parameters = new Parameters(array(
'password' => 'foobar',
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->once(1))
->method('addConnectCommand')
->with($this->isRedisCommand('AUTH', array('foobar')));
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
*/
public function testCreateConnectionWithPasswordAndUsernameAddsInitializationCommandAuthWithTwoArguments()
{
$parameters = new Parameters(array(
'username' => 'myusername',
'password' => 'foobar',
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->once(1))
->method('addConnectCommand')
->with($this->isRedisCommand('AUTH', array('myusername', 'foobar')));
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
*/
public function testCreateConnectionWithUsernameAndNoPasswordDoesNotAddInitializationCommands()
{
$parameters = new Parameters(array(
'username' => 'myusername',
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->never())
->method('addConnectCommand');
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
* @dataProvider provideEmptyParametersForInitializationCommands
*/
public function testCreateConnectionWithEmptyParametersDoesNotAddInitializationCommands($parameter, $value)
{
$parameters = new Parameters(array(
$parameter => $value,
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->never())
->method('addConnectCommand');
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
@@ -487,4 +590,28 @@ class FactoryTest extends PredisTestCase
return array($connection, get_class($connection));
}
/**
* Provides empty values for specific parameters.
*
* These parameters usually trigger the addition of initializatin commands
* to connection instances like `password` => AUTH and `database` => SELECT,
* but they should not be added when their values are NULL or empty strings.
*
* @return array
*/
public function provideEmptyParametersForInitializationCommands()
{
return array(
// AUTH
array('username', ''),
array('username', null),
array('password', ''),
array('password', null),
// SELECT
array('database', ''),
array('database', null),
);
}
}
+34 -17
View File
@@ -156,7 +156,7 @@ class ParametersTest extends PredisTestCase
*/
public function testParsingURIWithRedisScheme()
{
$uri = 'redis://:secret@10.10.10.10:6400/5?timeout=0.5&persistent=1';
$uri = 'redis://predis:secret@10.10.10.10:6400/5?timeout=0.5&persistent=1';
$expected = array(
'scheme' => 'redis',
@@ -164,20 +164,48 @@ class ParametersTest extends PredisTestCase
'port' => 6400,
'timeout' => '0.5',
'persistent' => '1',
'username' => 'predis',
'password' => 'secret',
'database' => '5',
);
$parameters = Parameters::parse($uri);
// TODO: parse_url() in PHP >= 5.6 returns an empty "user" entry in the
// dictionary when no username has been provided in the URI string. This
// actually makes sense, but let's keep the test ugly & simple for now.
unset($parameters['user']);
$this->assertSame($expected, $parameters);
}
/**
* @group disconnected
*/
public function testRedisSchemeOverridesUsernameAndPasswordInQueryString()
{
$parameters = Parameters::parse('redis://predis:secret@10.10.10.10/5?username=ignored&password=ignored');
$this->assertSame('predis', $parameters['username']);
$this->assertSame('secret', $parameters['password']);
}
/**
* @group disconnected
*/
public function testRedisSchemeDoesNotOverridesUsernameAndPasswordInQueryStringOnEmptyAuthFragment()
{
$parameters = Parameters::parse('redis://:@10.10.10.10/5?username=predis&password=secret');
$this->assertSame('predis', $parameters['username']);
$this->assertSame('secret', $parameters['password']);
}
/**
* @group disconnected
*/
public function testRedisSchemeOverridesDatabaseInQueryString()
{
$parameters = Parameters::parse('redis://10.10.10.10/5?database=10');
$this->assertSame('5', $parameters['database']);
}
/**
* @group disconnected
*/
@@ -197,17 +225,6 @@ class ParametersTest extends PredisTestCase
$this->assertSame($expected, $parameters);
}
/**
* @group disconnected
*/
public function testRedisSchemeOverridesPasswordAndDatabaseInQueryString()
{
$parameters = Parameters::parse('redis://:secret@10.10.10.10/5?password=ignored&database=4');
$this->assertSame('secret', $parameters['password']);
$this->assertSame('5', $parameters['database']);
}
/**
* @group disconnected
*/
@@ -76,6 +76,28 @@ class PhpiredisSocketConnectionTest extends PredisConnectionTestCase
// ---- INTEGRATION TESTS --------------------------------------------- //
// ******************************************************************** //
/**
* @group connected
*/
public function testClearsPendingResponsesInReaderBufferOnDisconnect()
{
$profile = $this->getCurrentProfile();
$connection = $this->createConnection();
$cmdECHOBefore = $profile->createCommand('echo', array('BEFORE DISCONNECT'));
$cmdECHOAfter = $profile->createCommand('echo', array('AFTER DISCONNECT'));
$connection->writeRequest($cmdECHOBefore);
$connection->writeRequest($cmdECHOBefore);
$connection->writeRequest($cmdECHOBefore);
$connection->readResponse($cmdECHOBefore);
$connection->disconnect();
$response = $connection->executeCommand($cmdECHOAfter);
$this->assertSame('AFTER DISCONNECT', $response);
}
/**
* @group connected
* @expectedException \Predis\Connection\ConnectionException
@@ -76,6 +76,28 @@ class PhpiredisStreamConnectionTest extends PredisConnectionTestCase
// ---- INTEGRATION TESTS --------------------------------------------- //
// ******************************************************************** //
/**
* @group connected
*/
public function testClearsPendingResponsesInReaderBufferOnDisconnect()
{
$profile = $this->getCurrentProfile();
$connection = $this->createConnection();
$cmdECHOBefore = $profile->createCommand('echo', array('BEFORE DISCONNECT'));
$cmdECHOAfter = $profile->createCommand('echo', array('AFTER DISCONNECT'));
$connection->writeRequest($cmdECHOBefore);
$connection->writeRequest($cmdECHOBefore);
$connection->writeRequest($cmdECHOBefore);
$connection->readResponse($cmdECHOBefore);
$connection->disconnect();
$response = $connection->executeCommand($cmdECHOAfter);
$this->assertSame('AFTER DISCONNECT', $response);
}
/**
* @group connected
* @group slow
+53
View File
@@ -234,6 +234,59 @@ class PipelineTest extends PredisTestCase
$this->assertSame(array('one', 'two', 'three', 'four'), $pipeline->execute());
}
/**
* @group disconnected
*/
public function testClearBuffer()
{
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->never())
->method('writeRequest');
$connection->expects($this->never())
->method('readResponse')
->will($this->returnCallback($this->getReadCallback()));
$pipeline = new Pipeline(new Client($connection));
$pipeline->echo('one');
$pipeline->echo('two');
$pipeline->clear();
$this->assertSame(array(), $pipeline->execute());
}
/**
* @group disconnected
*/
public function testClearResponses()
{
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->exactly(4))
->method('writeRequest');
$connection->expects($this->exactly(4))
->method('readResponse')
->will($this->returnCallback($this->getReadCallback()));
$pipeline = new Pipeline(new Client($connection));
$pipeline->echo('one');
$pipeline->echo('two');
$this->assertSame(array('one', 'two'), $pipeline->execute());
$pipeline->clear();
$pipeline->echo('three');
$pipeline->echo('four');
$this->assertSame(array('three', 'four'), $pipeline->execute());
$pipeline->clear();
$this->assertSame(array(), $pipeline->execute());
}
/**
* @group disconnected
*/
+46
View File
@@ -297,11 +297,25 @@ class ConsumerTest extends PredisTestCase
// ---- INTEGRATION TESTS --------------------------------------------- //
// ******************************************************************** //
// NOTE: the following 2 tests fail at random without any apparent reason
// when executed on our CI environments and these failures are not tied
// to a particular version of PHP or Redis. It is most likely some weird
// timing issue on busy systems as it is really rare to get it triggered
// locally. The chances it is a bug in the library are pretty low so for
// now we just mark this test skipped on our CI environments (but still
// enabled for local test runs) and "debug" this issue using a separate
// branch to avoid having spurious failures on main development branches
// which is utterly annoying.
/**
* @group connected
*/
public function testPubSubAgainstRedisServer()
{
$this->markTestSkippedOnCIEnvironment(
'Test temporarily skipped on CI environments, see note in the body of the test' // TODO
);
$parameters = array(
'host' => REDIS_SERVER_HOST,
'port' => REDIS_SERVER_PORT,
@@ -347,6 +361,10 @@ class ConsumerTest extends PredisTestCase
*/
public function testPubSubAgainstRedisServerBlocking()
{
$this->markTestSkippedOnCIEnvironment(
'Test temporarily skipped on CI environments, see note in the body of the test' // TODO
);
$parameters = array(
'host' => REDIS_SERVER_HOST,
'port' => REDIS_SERVER_PORT,
@@ -408,4 +426,32 @@ class ConsumerTest extends PredisTestCase
exit(0);
}
}
/**
* @group connected
* @expectedException \Predis\Response\ServerException
*/
public function testInvalidSubscriptionThrowsServerException()
{
$parameters = array(
'host' => REDIS_SERVER_HOST,
'port' => REDIS_SERVER_PORT,
'database' => REDIS_SERVER_DBNUM,
'read_write_timeout' => -1, // -1 to set blocking reads
);
$options = array('profile' => REDIS_SERVER_VERSION);
$consumer = new Client($parameters, $options);
$consumer->connect();
$pubsub = $consumer->pubSubLoop();
// calling psubscribe with invalid empty parameter list
$pubsub->psubscribe(array());
foreach ($pubsub as $message) {
// should trigger the ServerException
}
}
}
@@ -23,11 +23,25 @@ class DispatcherLoopTest extends PredisTestCase
// ---- INTEGRATION TESTS --------------------------------------------- //
// ******************************************************************** //
// NOTE: the following 2 tests fail at random without any apparent reason
// when executed on our CI environments and these failures are not tied
// to a particular version of PHP or Redis. It is most likely some weird
// timing issue on busy systems as it is really rare to get it triggered
// locally. The chances it is a bug in the library are pretty low so for
// now we just mark this test skipped on our CI environments (but still
// enabled for local test runs) and "debug" this issue using a separate
// branch to avoid having spurious failures on main development branches
// which is utterly annoying.
/**
* @group connected
*/
public function testDispatcherLoopAgainstRedisServer()
{
$this->markTestSkippedOnCIEnvironment(
'Test temporarily skipped on CI environments, see note in the body of the test' // TODO
);
$parameters = array(
'host' => REDIS_SERVER_HOST,
'port' => REDIS_SERVER_PORT,
@@ -87,6 +101,10 @@ class DispatcherLoopTest extends PredisTestCase
*/
public function testDispatcherLoopAgainstRedisServerWithPrefix()
{
$this->markTestSkippedOnCIEnvironment(
'Test temporarily skipped on CI environments, see note in the body of the test' // TODO
);
$parameters = array(
'host' => REDIS_SERVER_HOST,
'port' => REDIS_SERVER_PORT,
@@ -81,15 +81,15 @@ class ReplicationStrategyTest extends PredisTestCase
$profile = Profile\Factory::getDevelopment();
$strategy = new ReplicationStrategy();
$cmdReadSort = $profile->createCommand('SORT', array('key:list'));
$this->assertTrue(
$strategy->isReadOperation($cmdReadSort),
'SORT is expected to be a read operation.'
$cmdReturnSort = $profile->createCommand('SORT', array('key:list'));
$this->assertFalse(
$strategy->isReadOperation($cmdReturnSort),
'SORT is expected to be a write operation.'
);
$cmdWriteSort = $profile->createCommand('SORT', array('key:list', array('store' => 'key:stored')));
$cmdStoreSort = $profile->createCommand('SORT', array('key:list', array('store' => 'key:stored')));
$this->assertFalse(
$strategy->isReadOperation($cmdWriteSort),
$strategy->isReadOperation($cmdStoreSort),
'SORT with STORE is expected to be a write operation.'
);
}
+1 -1
View File
@@ -69,7 +69,7 @@ $ phpunit --exclude-group slow
### Testing Redis commands ###
We also provide an helper script in the `bin` directory that can be used to automatically generate a
file with the scheleton of a test case to test a Redis command by specifying the name of the class
file with the skeleton of a test case to test a Redis command by specifying the name of the class
in the `Predis\Command` namespace (only classes in this namespace are considered valid). For example
to generate a test case for `SET` (represented by the `Predis\Command\StringSet` class):
+16
View File
@@ -0,0 +1,16 @@
<?php
/**
* Apply patches to support newer PHP versions.
*/
$patches = array(
'phpunit_mock_objects.patch' => 'phpunit/phpunit-mock-objects',
'phpunit_php7.patch' => 'phpunit/phpunit',
'phpunit_php8.patch' => 'phpunit/phpunit',
'phpunit_php81.patch' => 'phpunit/phpunit',
);
foreach ($patches as $patch => $package) {
chdir(__DIR__.'/../vendor/'.$package);
passthru(sprintf('patch -p1 -f < ../../../tests/%s', $patch));
}
+38
View File
@@ -0,0 +1,38 @@
diff --git a/src/Framework/MockObject/Generator.php b/src/Framework/MockObject/Generator.php
index 3df3abb..fc76d5d 100644
--- a/src/Framework/MockObject/Generator.php
+++ b/src/Framework/MockObject/Generator.php
@@ -1031,16 +1031,29 @@ protected function getMethodParameters(ReflectionMethod $method, $forCall = fals
$typeDeclaration = '';
if (!$forCall) {
+ if (PHP_VERSION_ID >= 80000) {
+ $isArray = $parameter->getType() && $parameter->getType()->getName() === 'array';
+ $isCallable = $parameter->getType() && $parameter->getType()->getName() === 'callable';
+ } else {
+ $isArray = $parameter->isArray();
+ $isCallable = version_compare(PHP_VERSION, '5.4.0', '>=') ? $parameter->isCallable() : false;
+ }
+
if ($this->hasType($parameter)) {
- $typeDeclaration = (string) $parameter->getType() . ' ';
- } elseif ($parameter->isArray()) {
+ $type = $parameter->getType();
+ $typeDeclaration = (PHP_VERSION_ID >= 70100 ? $type->getName() : (string) $type) . ' ';
+ } elseif ($isArray) {
$typeDeclaration = 'array ';
} elseif ((defined('HHVM_VERSION') || version_compare(PHP_VERSION, '5.4.0', '>='))
- && $parameter->isCallable()) {
+ && $isCallable) {
$typeDeclaration = 'callable ';
} else {
try {
- $class = $parameter->getClass();
+ if (PHP_VERSION_ID >= 80000) {
+ $class = $parameter->getType();
+ } else {
+ $class = $parameter->getClass();
+ }
} catch (ReflectionException $e) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
sprintf(
+60
View File
@@ -0,0 +1,60 @@
diff --git a/src/Util/Getopt.php b/src/Util/Getopt.php
index ba21be3..96931a3 100644
--- a/src/Util/Getopt.php
+++ b/src/Util/Getopt.php
@@ -35,7 +35,15 @@ class PHPUnit_Util_Getopt
reset($args);
array_map('trim', $args);
- while (list($i, $arg) = each($args)) {
+ while (true) {
+ $arg = current($args);
+ $i = key($args);
+ next($args);
+
+ if ($arg === false) {
+ break;
+ }
+
if ($arg == '') {
continue;
}
@@ -94,11 +102,14 @@ class PHPUnit_Util_Getopt
if ($i + 1 < $argLen) {
$opts[] = array($opt, substr($arg, $i + 1));
break;
- } elseif (list(, $opt_arg) = each($args)) {
} else {
- throw new PHPUnit_Framework_Exception(
- "option requires an argument -- $opt"
- );
+ $opt_arg = current($args);
+ next($args);
+ if ($opt_arg === false) {
+ throw new PHPUnit_Framework_Exception(
+ "option requires an argument -- $opt"
+ );
+ }
}
}
}
@@ -139,11 +150,14 @@ class PHPUnit_Util_Getopt
if (substr($long_opt, -1) == '=') {
if (substr($long_opt, -2) != '==') {
- if (!strlen($opt_arg) &&
- !(list(, $opt_arg) = each($args))) {
- throw new PHPUnit_Framework_Exception(
- "option --$opt requires an argument"
- );
+ if (!strlen($opt_arg)) {
+ $opt_arg = current($args);
+ next($args);
+ if ($opt_arg === false) {
+ throw new PHPUnit_Framework_Exception(
+ "option --$opt requires an argument"
+ );
+ }
}
}
} elseif ($opt_arg) {
+39
View File
@@ -0,0 +1,39 @@
diff --git a/src/Framework/TestCase.php b/src/Framework/TestCase.php
index 638f42513..b4c7d3a5e 100644
--- a/src/Framework/TestCase.php
+++ b/src/Framework/TestCase.php
@@ -905,7 +905,7 @@ protected function runTest()
try {
$testResult = $method->invokeArgs(
$this,
- array_merge($this->data, $this->dependencyInput)
+ array_values(array_merge($this->data, $this->dependencyInput))
);
} catch (Throwable $_e) {
$e = $_e;
diff --git a/src/Util/Configuration.php b/src/Util/Configuration.php
index 5c1041608..b2f7a7bd0 100644
--- a/src/Util/Configuration.php
+++ b/src/Util/Configuration.php
@@ -162,7 +162,7 @@ protected function __construct($filename)
/**
* @since Method available since Release 3.4.0
*/
- final private function __clone()
+ private function __clone()
{
}
diff --git a/src/Util/PHP/Template/TestCaseMethod.tpl.dist b/src/Util/PHP/Template/TestCaseMethod.tpl.dist
index b48f354cd..d59cdeea7 100644
--- a/src/Util/PHP/Template/TestCaseMethod.tpl.dist
+++ b/src/Util/PHP/Template/TestCaseMethod.tpl.dist
@@ -78,7 +78,7 @@ if ('' !== $configurationFilePath) {
unset($configuration);
}
-function __phpunit_error_handler($errno, $errstr, $errfile, $errline, $errcontext)
+function __phpunit_error_handler($errno, $errstr, $errfile, $errline, $errcontext = null)
{
return true;
}
+50
View File
@@ -0,0 +1,50 @@
diff --git a/src/Util/Configuration.php b/src/Util/Configuration.php
index b2f7a7bd0c6..1a1a444d378 100644
--- a/src/Util/Configuration.php
+++ b/src/Util/Configuration.php
@@ -514,22 +514,17 @@ public function handlePHPConfiguration()
foreach (array('var', 'post', 'get', 'cookie', 'server', 'files', 'request') as $array) {
// See https://github.com/sebastianbergmann/phpunit/issues/277
- switch ($array) {
- case 'var':
- $target = &$GLOBALS;
- break;
-
- case 'server':
- $target = &$_SERVER;
- break;
-
- default:
- $target = &$GLOBALS['_' . strtoupper($array)];
- break;
- }
-
foreach ($configuration[$array] as $name => $value) {
- $target[$name] = $value;
+ switch ($array) {
+ case 'var':
+ $GLOBALS[$name] = $value;
+ break;
+ case 'server':
+ $_SERVER[$name] = $value;
+ break;
+ default:
+ $GLOBALS['_' . strtoupper($array)][$name] = $value;
+ }
}
}
diff --git a/src/Util/Getopt.php b/src/Util/Getopt.php
index 370e97d73f8..5bd8553970b 100644
--- a/src/Util/Getopt.php
+++ b/src/Util/Getopt.php
@@ -144,7 +144,7 @@ protected static function parseLongOption($arg, $long_options, &$opts, &$args)
if (substr($long_opt, -1) == '=') {
if (substr($long_opt, -2) != '==') {
- if (!strlen($opt_arg)) {
+ if (null === $opt_arg || strlen($opt_arg) < 1) {
$opt_arg = current($args);
next($args);
if (!($opt_arg)) {