mirror of
https://github.com/predis/predis.git
synced 2026-08-21 14:20:56 +00:00
Compare commits
640 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4be306d0a | |||
| 25d0008b2f | |||
| 30274aa242 | |||
| f5ba47ad74 | |||
| fbb0236840 | |||
| ba5e501346 | |||
| ab9cbe712f | |||
| 16f2d8a768 | |||
| 7c9e4ab595 | |||
| b6389e4a03 | |||
| dedc1ba0a9 | |||
| df653a7c00 | |||
| 5c02e4e47b | |||
| c2b24bd873 | |||
| 45e351be79 | |||
| b5cdab35c7 | |||
| dbfc1a74ba | |||
| 4e1186f845 | |||
| aa5c893d5a | |||
| fff303a03b | |||
| 78ec22563a | |||
| 30254a2594 | |||
| f372029cfc | |||
| 87aba18002 | |||
| dc33d62b77 | |||
| b230e243f5 | |||
| 44c9232b13 | |||
| 776f5831a6 | |||
| 31e2516156 | |||
| b379d4f1b3 | |||
| 60a863f5fc | |||
| f7d8088bba | |||
| 38710cd69b | |||
| 7fa17b2ebc | |||
| dcb57ea08d | |||
| 872d953b50 | |||
| f630ff809f | |||
| 19bad41582 | |||
| be6b7fe5f0 | |||
| 647c51a5b3 | |||
| dd1b63ae3b | |||
| 7146b69707 | |||
| 0bd7684d14 | |||
| 558e10963c | |||
| 14a4303a54 | |||
| 7d78600506 | |||
| 784c555b67 | |||
| a67d35b799 | |||
| 0ee5233f4f | |||
| 9a05d43737 | |||
| 6fe56985fc | |||
| 57363f6d11 | |||
| fdf5894022 | |||
| 6147f34478 | |||
| 2ff8c37104 | |||
| 69bef7fd35 | |||
| 346986099d | |||
| 9213f02da8 | |||
| 4ab2bcea64 | |||
| 217bd69b7f | |||
| bd00b8cfe2 | |||
| a32eaf627b | |||
| e89f5cbc39 | |||
| 4188dc51bf | |||
| 7b41029fd7 | |||
| eb8de52269 | |||
| 202c558103 | |||
| 89e662dc89 | |||
| 356f22a062 | |||
| 823f615699 | |||
| 7e58ded8dc | |||
| 2969982a4f | |||
| 88da187344 | |||
| a33781e58c | |||
| a074cdb79b | |||
| 63992a0a6e | |||
| ca4ec79575 | |||
| 2e0c55ac57 | |||
| 9edc11dc8e | |||
| 50334ed3f4 | |||
| 1319574b4e | |||
| 029822fe22 | |||
| d226923484 | |||
| 959734cf8c | |||
| dd29068845 | |||
| 36a04e84d7 | |||
| 5b4a7970bb | |||
| 235427950f | |||
| 45da0fca55 | |||
| 2d53db7b9b | |||
| f05cb1b46d | |||
| 4db00173f3 | |||
| a2265b12b3 | |||
| 0cd56406fe | |||
| e575c32cb4 | |||
| 42f237e306 | |||
| 940326e5bd | |||
| ea32f74512 | |||
| 8dbac3dd73 | |||
| 5a474c5a32 | |||
| 0148743a76 | |||
| 5c935d97bd | |||
| 1fd113c570 | |||
| abd284c972 | |||
| ff2e0823ec | |||
| a6c6951bf8 | |||
| 87417f4d7e | |||
| 2aa0b071fc | |||
| f784dfad84 | |||
| 10c2f321ff | |||
| 7da3da776f | |||
| 90cb71ac4a | |||
| 2d4383c891 | |||
| 8ea76f79c7 | |||
| 5c5dd40527 | |||
| 4638e05865 | |||
| 4784291640 | |||
| a51ff2d6e5 | |||
| 451d28ee66 | |||
| e23fd9bea8 | |||
| 8fbe658ca8 | |||
| d89027d2da | |||
| 26289f47ec | |||
| ba0dc12d5b | |||
| 42a9489f11 | |||
| 51febb32a9 | |||
| 0a5363dddf | |||
| b852eeed9f | |||
| 10dcac8f05 | |||
| ae61a0fd2b | |||
| dc6c298960 | |||
| e04c7d51b8 | |||
| da8a203a75 | |||
| bf32f4b87c | |||
| 46671b9095 | |||
| 9a38d2caec | |||
| cfa456fdd1 | |||
| 6a577a0eb5 | |||
| 8357af177e | |||
| 7ebb8a8b42 | |||
| 728d9dceb5 | |||
| a092f6d4da | |||
| 3befbb3ac2 | |||
| 8d8a618d0e | |||
| 5e1ea94f4a | |||
| b9b899eaf0 | |||
| 5065541cc6 | |||
| f5a7d8ece8 | |||
| 25cd43033f | |||
| 90d8c684f0 | |||
| 09f9133df7 | |||
| bff7906f68 | |||
| b73606de68 | |||
| c127d02e92 | |||
| 6693980b14 | |||
| 7ba465048f | |||
| 5f81bfcde3 | |||
| 2aa97e3e61 | |||
| 131a5a4ef9 | |||
| d1ec791ae9 | |||
| 8916f9a9ee | |||
| 3ac4141bcb | |||
| 587bf0b1e5 | |||
| 7cf9cfc496 | |||
| f7fea2e430 | |||
| c51485b318 | |||
| e1fb9ed1d4 | |||
| 913bcb3b20 | |||
| 2d23edc691 | |||
| af2548581e | |||
| fdf63bc03d | |||
| 2a6409590c | |||
| 02e43143d3 | |||
| 5529e33047 | |||
| 1125dc1bdd | |||
| feb69fb5f2 | |||
| 1d31a47cf4 | |||
| 35b2c99186 | |||
| 0f34f41ccf | |||
| 43f278fb71 | |||
| b7a7b6838b | |||
| 714f9ddc64 | |||
| d465de7b42 | |||
| 405ae4af65 | |||
| 7e89719ceb | |||
| aa9aafe926 | |||
| 0779c1c24a | |||
| e66c33a444 | |||
| 001a7c0827 | |||
| 58c5029574 | |||
| 6ceebbfbec | |||
| c40ad5dd47 | |||
| 2a7607f128 | |||
| 278f89924c | |||
| cbf015164c | |||
| fded76bca3 | |||
| e7f2d28f23 | |||
| 1c05c878f4 | |||
| 5eb975ef69 | |||
| 3fbc012c03 | |||
| cebdf889a4 | |||
| 863718bd2b | |||
| b01ac201d6 | |||
| d5bd28958a | |||
| 95b9f63cab | |||
| 59b5658cf5 | |||
| 8744285cb3 | |||
| 14fda643f7 | |||
| 57e778e098 | |||
| f9fd4525b5 | |||
| ac34983635 | |||
| 978e7ac551 | |||
| ca11c522d6 | |||
| 6eed3d7647 | |||
| 73cb6bbf2a | |||
| 5acdab9176 | |||
| 35023dd83f | |||
| 70df7ca64d | |||
| f0549b5dad | |||
| b7ac7595c2 | |||
| 1f66f4e8f7 | |||
| 73eb09378e | |||
| 427309db69 | |||
| ee45de4f0e | |||
| 6ece8c40a0 | |||
| 373d30b070 | |||
| ac8d0c1f42 | |||
| cf70d2f20e | |||
| ccf8822b4b | |||
| d27d3b0acb | |||
| 5b7504b069 | |||
| 6ef8e99822 | |||
| 4bf0ee4c6a | |||
| 59b9319bb8 | |||
| bcf92a7548 | |||
| d2c001812f | |||
| 3ae3414a0d | |||
| a00ffbf53f | |||
| 583b924085 | |||
| 3c77d3b0c1 | |||
| e049db124c | |||
| b2e0dc62fe | |||
| f7ff65e0fa | |||
| b253bdc41e | |||
| 5d7f297110 | |||
| 7f690cb62e | |||
| cb3cd050ab | |||
| c4e0d9df92 | |||
| 41ea336175 | |||
| 5d40b85f10 | |||
| b7ac108d43 | |||
| cf581a3b49 | |||
| bb4b8c3c35 | |||
| 09895f27bf | |||
| 980edf2f7b | |||
| c8e20e428a | |||
| 7a56856d46 | |||
| fc4e279b9a | |||
| 09b0750cb7 | |||
| d52daacba9 | |||
| 00247abc50 | |||
| 862da9a3b2 | |||
| d6173bb33b | |||
| d0b431016d | |||
| 5856bde198 | |||
| 4840736503 | |||
| 2d39408c0f | |||
| 374101cfc3 | |||
| cec7c24236 | |||
| 2a5483df90 | |||
| 0a60a156f0 | |||
| 1e0ef2a64d | |||
| 30e74e36aa | |||
| 1125809de9 | |||
| 712e6420e9 | |||
| 84e0f5af7a | |||
| c047c4992a | |||
| ce706a375c | |||
| 66f22899a1 | |||
| 620adb2fe6 | |||
| 1b5e2d0d0d | |||
| 3d499e82a3 | |||
| 8068c87e47 | |||
| c6f51e82bf | |||
| 944da8c9b8 | |||
| f01ef33735 | |||
| aaac082324 | |||
| aa210aeb03 | |||
| e6f1788e27 | |||
| c26b6763f9 | |||
| 9d2cb975eb | |||
| 2e6a76d83e | |||
| 046715a455 | |||
| c3a58dffdf | |||
| 7d60e995f8 | |||
| f18d7103f5 | |||
| e42c72c043 | |||
| 621c3d7fd3 | |||
| b71c798f9b | |||
| 1022be6010 | |||
| e41db42b01 | |||
| ecd4c6281c | |||
| 35ce43d526 | |||
| 7f9d06bb83 | |||
| a8edc02eb6 | |||
| 205ffbbd73 | |||
| b0f955b437 | |||
| 8d15e5ec08 | |||
| 6fbc421b96 | |||
| 298e7a14fa | |||
| 22c2230d00 | |||
| a1c7889584 | |||
| 5e90e615b1 | |||
| 321d2624ab | |||
| acd29ec076 | |||
| 3c6389f4dd | |||
| 1d53f8a988 | |||
| dd679661dd | |||
| f36138c0b7 | |||
| 31e08f0d5d | |||
| cdb91284f1 | |||
| 38c7697881 | |||
| b45ba55f46 | |||
| b50b90aa66 | |||
| 0128ecc623 | |||
| bf991a24f3 | |||
| bab0cd999c | |||
| 30d81c942a | |||
| f066356858 | |||
| 7649533141 | |||
| a4d0abc734 | |||
| b38f640ac9 | |||
| d431ea6dba | |||
| 715b1badcb | |||
| d79aadc38f | |||
| 9136033eea | |||
| 16d17af577 | |||
| 1a7b604c1b | |||
| 70a84e1d5a | |||
| fb2d8a37c1 | |||
| 7c5aba08cd | |||
| 1a769e3cc3 | |||
| 9a72b98c4a | |||
| 089b972def | |||
| b1ebc8df2f | |||
| 153758019c | |||
| 62f8730f1a | |||
| 9b8b362747 | |||
| ee9e09aa07 | |||
| 66f98186f0 | |||
| 463f2d655c | |||
| b2db97d983 | |||
| 9da1648145 | |||
| 5ad00774e1 | |||
| ff004aeaaa | |||
| df2c9eb7ff | |||
| 4d8348158f | |||
| 0ab0aa14fb | |||
| 85c978fdad | |||
| b7f411a252 | |||
| 9866500ad6 | |||
| 73ee5aabad | |||
| e88938cdfd | |||
| 93ae376618 | |||
| 7028082b7f | |||
| d09d8edc7d | |||
| 70e42f8fca | |||
| 695b6dd7b3 | |||
| 6ce09a2a8b | |||
| bb03602326 | |||
| 5c9adbacd7 | |||
| 8533dbdb0b | |||
| d78e1b6ab7 | |||
| d5aec78086 | |||
| 0faae20737 | |||
| 4eb4960b63 | |||
| 75c64b7f2f | |||
| d78780382a | |||
| 98aacd8d9a | |||
| 4824af1563 | |||
| cb18d67b6a | |||
| 4576dc029f | |||
| aa458a1922 | |||
| 2d2930d24f | |||
| 7e0ec1a265 | |||
| 04e597ebba | |||
| d681bff4ab | |||
| 3dea41aa66 | |||
| 69c66e157f | |||
| dd50cfe47e | |||
| 8451146d38 | |||
| d45ce35923 | |||
| 6cd124cc59 | |||
| d6fa4a3292 | |||
| 5b771704d3 | |||
| 68d972a1b1 | |||
| 4bf035918d | |||
| 94c4e2ffee | |||
| 6e2fd181f1 | |||
| 1c21fcc5b3 | |||
| 531261b0fc | |||
| 7434a9bd0e | |||
| c4123ce7ce | |||
| 536992e277 | |||
| 5a735aa670 | |||
| 15f2776d77 | |||
| dc1103582e | |||
| 8c0498a893 | |||
| aba24d0f6f | |||
| a1df4f20da | |||
| 116eaba75e | |||
| de4bae3f9b | |||
| b50a5975ac | |||
| 1c1b4096f6 | |||
| f8e4ba152f | |||
| 6b6b73f5f4 | |||
| 729e40d6c0 | |||
| fbcfdc343e | |||
| 8cbcb09c4c | |||
| 2781bd780f | |||
| 9675626aac | |||
| f8829985f7 | |||
| e2e809c9d4 | |||
| ef0067e1a4 | |||
| da343046e5 | |||
| 76d6681f68 | |||
| 8d01be388d | |||
| c38376dcc4 | |||
| c354d02105 | |||
| d6685a424a | |||
| 05ef62ff97 | |||
| b76e876b73 | |||
| ebd895a67d | |||
| 923e7ed5fd | |||
| 9e0fe7bdc7 | |||
| 5d774dc581 | |||
| dffbb8b042 | |||
| 06d5475129 | |||
| 1536455fea | |||
| aa1b070f9b | |||
| 3e125c964c | |||
| e9fdc47d3f | |||
| d3930ea298 | |||
| 0efcbb7992 | |||
| f2af247c63 | |||
| a5cf6d72cd | |||
| 7173f0c80c | |||
| 495e3c6f8a | |||
| 3465bc7c1f | |||
| 8bf896f81f | |||
| 0085bc08ae | |||
| f7232b9ddc | |||
| 95cc528904 | |||
| 4a16cb9417 | |||
| 94758d5f58 | |||
| acc0f04bdb | |||
| 09de7be7cb | |||
| 70b279bbdc | |||
| f8cbbc5b8f | |||
| 83720075f3 | |||
| 9901233fa1 | |||
| dcb4093046 | |||
| 1e8af648cb | |||
| ff5e3515c3 | |||
| 59813cd74e | |||
| bfd96b15dc | |||
| 51b466267d | |||
| 78f3596566 | |||
| ac01c1a17f | |||
| 46920c9c77 | |||
| b26d6103a6 | |||
| a4760d65cd | |||
| 49aa6f0aca | |||
| 292f9939b2 | |||
| daa36a980d | |||
| 0b09d2c359 | |||
| 0a622aee31 | |||
| 040dfebd9c | |||
| 0e4604a9bb | |||
| deb64c295a | |||
| aac06a4cd8 | |||
| dfb5cf2c1b | |||
| a1024bba53 | |||
| f357cafb14 | |||
| 2b4cf80d90 | |||
| 6cd1f03834 | |||
| 732d7f96d1 | |||
| b4e1ab106c | |||
| 5a2c61c02b | |||
| 1b9e10bdd8 | |||
| 37e2b546b0 | |||
| f163e1221b | |||
| 1bb2ab95ef | |||
| ea18afc820 | |||
| baa91da35b | |||
| 6d85a81da4 | |||
| f913e81b9f | |||
| 003b3d180d | |||
| a6e1ac11d0 | |||
| be46ab813c | |||
| 6918de6e4b | |||
| cfa97dd9f5 | |||
| 1e8f790ee4 | |||
| c655affe5f | |||
| 457fd6076d | |||
| 282287765b | |||
| 00d6160549 | |||
| 576163724c | |||
| 9df9dbdedc | |||
| 8d7f5099c4 | |||
| e8daf45269 | |||
| 8567b05459 | |||
| 6e76ea6c7e | |||
| e774a301c4 | |||
| 2b85824d74 | |||
| 81422b9992 | |||
| c230b6e831 | |||
| 69d4c013f7 | |||
| 1ac9cc9c71 | |||
| b2f59a0c63 | |||
| 93971bcb45 | |||
| e54bc31212 | |||
| b9eddae96f | |||
| 7683f97ff2 | |||
| f4f9d02551 | |||
| bacdb7ff62 | |||
| e0c6ad58be | |||
| febd99421f | |||
| 8559c2cb30 | |||
| 2ba54a0e1c | |||
| 024a31d571 | |||
| d0572b0efc | |||
| 0f80cb55bb | |||
| 55a3fd65a2 | |||
| 6c732c737b | |||
| 559853bdd5 | |||
| 28e1e7ad25 | |||
| 98112fdb39 | |||
| 0e8d978348 | |||
| 469f3cc68b | |||
| 36f8210864 | |||
| 81be513eaa | |||
| 4b73afc316 | |||
| fd6a14d80b | |||
| f2d92f1e29 | |||
| c3cafaa9a6 | |||
| 89d6c0e9b6 | |||
| 9f51263136 | |||
| a75e52cf5a | |||
| b865cee1f8 | |||
| 1f0be85a3d | |||
| 2578e154d4 | |||
| 81da6d2553 | |||
| 188eaf035b | |||
| 6638776d85 | |||
| 511fe0bbab | |||
| 56a3e327fc | |||
| 63cf5048a7 | |||
| 177d7e1c6a | |||
| 8a84f8b6cf | |||
| 09f15a9cb9 | |||
| 2b4885abc3 | |||
| 649e71c0ab | |||
| 14ac381aad | |||
| 78360ea27b | |||
| 214b7d2dc9 | |||
| 2d0b30dac5 | |||
| 75afe831b0 | |||
| c36e6fd900 | |||
| 743ccc39ae | |||
| 41c29bed4e | |||
| 90f37f8698 | |||
| dc889be2a2 | |||
| ca7bd8149f | |||
| 9426d78b90 | |||
| 6b6c91cd15 | |||
| b511911ddb | |||
| eb450ae0b4 | |||
| ca033d15a9 | |||
| 9443da1948 | |||
| 298dc87613 | |||
| 92697aa075 | |||
| 7c393cbc09 | |||
| 5b6e4dc3dd | |||
| b37d072b68 | |||
| 608c48146f | |||
| bcba9e1009 | |||
| 64a84d9020 | |||
| a3b4c2244a | |||
| 4805a048ed | |||
| c394458b80 | |||
| 51d0b58cd3 | |||
| 890ace8565 | |||
| 8ba432e8f7 | |||
| d61bb3af07 | |||
| da381fffa9 | |||
| 7b01bc0644 | |||
| 7893fd1faa | |||
| 785670dcf7 | |||
| ec723fd4a9 | |||
| b67af29eb6 | |||
| dc14c29676 | |||
| ce625ca902 | |||
| 46d293a716 | |||
| fcd41a4787 | |||
| 8dc9450f39 | |||
| 6ad522f492 | |||
| 317fb6c398 | |||
| 93163bdfb3 | |||
| 626520b836 | |||
| aaea628c55 | |||
| 135fd5004b | |||
| c25a815317 | |||
| 39a9fc2ddd | |||
| f5bca54bba | |||
| 364aa180f9 | |||
| 4da506cd9e | |||
| ef5034dc72 | |||
| 994f045a4a | |||
| 8cd8d4e580 | |||
| 22f1aafae8 | |||
| c47b009b69 | |||
| 2cff6f0886 | |||
| 63cb150fc2 | |||
| 466c666547 | |||
| 8d5c794efe | |||
| e3fba5d4b7 | |||
| a8400f2ed8 | |||
| 44629a33db | |||
| d38f164d3f | |||
| 9bc5685959 | |||
| 565690a5b1 | |||
| bdbbe18e6c | |||
| 78027f0498 | |||
| 104cd1eae7 | |||
| 5148ce16c6 | |||
| 4b9ab0bcce | |||
| 39ed8e3e8f | |||
| 6f4347010d | |||
| c43278eceb |
@@ -0,0 +1,8 @@
|
||||
* text=auto
|
||||
|
||||
/tests export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/phpunit.xml.travisci export-ignore
|
||||
@@ -1,2 +1,7 @@
|
||||
*.tgz
|
||||
*.phar
|
||||
phpunit.xml
|
||||
package.xml
|
||||
composer.lock
|
||||
experiments/
|
||||
vendor/
|
||||
|
||||
+18
-4
@@ -2,8 +2,22 @@ language: php
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- v0.7
|
||||
script: phpunit -c phpunit.xml.travisci
|
||||
except:
|
||||
- v0.5
|
||||
- v0.6
|
||||
- php5.2_backport
|
||||
- documentation
|
||||
services: redis-server
|
||||
before_script:
|
||||
- composer self-update
|
||||
- composer install --no-interaction --prefer-source --dev
|
||||
script:
|
||||
- vendor/bin/phpunit -c phpunit.xml.travisci
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
fast_finish: true
|
||||
|
||||
+481
-15
@@ -1,5 +1,471 @@
|
||||
v1.0.0 (2014-08-01)
|
||||
================================================================================
|
||||
|
||||
- Switched to PSR-4 for autoloading.
|
||||
|
||||
- The default server profile for Redis is `3.0`.
|
||||
|
||||
- Removed server profile for Redis 1.2.
|
||||
|
||||
- Added `SENTINEL` to the profile for Redis 2.6 and `PUBSUB` to the profile for
|
||||
Redis 2.8.
|
||||
|
||||
- `Predis\Client` can now send raw commands using `Predis\Client::executeRaw()`.
|
||||
|
||||
- Status responses are returned as instances of `Predis\Response\Status`, for
|
||||
example +OK is not returned as boolean TRUE anymore which is a breaking change
|
||||
for those using strict comparisons. Status responses can be casted to string
|
||||
values carrying the original payload, so one can do `$response == 'OK'` which
|
||||
is also more akin to how Redis replies to clients.
|
||||
|
||||
- Commands `ZRANGE`, `ZRANGEBYSCORE`, `ZREVRANGE` and `ZREVRANGEBYSCORE` using
|
||||
`WITHSCORE` return a named array of member => score instead of using an array
|
||||
of [member, score] elements. Insertion order is preserved anyway due to how
|
||||
PHP works internally.
|
||||
|
||||
- The command `ZSCAN` returns a named array of member => score instead of using
|
||||
an array of [member, score] elements. Insertion order is preserved anyway due
|
||||
to how PHP works internally.
|
||||
|
||||
- The rules for redis-cluster are now leveraged for empty key tags when using
|
||||
client-side sharding, which means that when one or the first occurrence of {}
|
||||
is found in a key it will most likely produce a different hash than previous
|
||||
versions of Predis thus leading to a different partitioning in these cases.
|
||||
|
||||
- Invoking `Predis\Client::connect()` when the underlying connection has been
|
||||
already established does not throw any exception anymore, now the connection
|
||||
simply does not attempt to perform any operation.
|
||||
|
||||
- Added the `aggregate` client option, useful to fully customize how the client
|
||||
should aggregate multiple connections when an array of connection parameters
|
||||
is passed to `Predis\Client::__construct()`.
|
||||
|
||||
- Dropped support for streamable multibulk responses. Actually we still ship the
|
||||
iterator response classes just in case anyone would want to build custom stuff
|
||||
at a level lower than the client abstraction (our standard and composable text
|
||||
protocol processors still handle them and can be used as an example).
|
||||
|
||||
- Simplified the implementation of connection parameters by removing method used
|
||||
to cast to int / bool / float certain parameters supplied by users. Casting
|
||||
values, if deemed necessary, should be done by the consumer or you can just
|
||||
subclass `Predis\Connection\Parameters` and override the `filter()` method.
|
||||
|
||||
- Changed a couple of options for our transaction abstraction:
|
||||
|
||||
- `exceptions`: overrides the value of the client option with the same name.
|
||||
Please note that it does not affect all the transaction control commands
|
||||
such as `MULTI`, `EXEC`, `DISCARD`, `WATCH` and `UNWATCH`.
|
||||
- `on_retry`: this option has been removed.
|
||||
|
||||
- Removed pipeline executors, now command pipelines can be easily customized by
|
||||
extending the standard `Predis\Pipeline\Pipeline` class. Accepted options when
|
||||
creating a pipeline using `Predis\Client::pipeline()` are:
|
||||
|
||||
- `atomic`: returns a pipeline wrapped in a MULTI / EXEC transaction
|
||||
(class: `Predis\Pipeline\Atomic`).
|
||||
- `fire-and-forget`: returns a pipeline that does not read back responses
|
||||
(class: `Predis\Pipeline\FireAndForget`).
|
||||
|
||||
- Renamed the two base abstract command classes:
|
||||
|
||||
- `Predis\Command\AbstractCommand` is now `Predis\Command\Command`
|
||||
- `Predis\Command\ScriptedCommand` is now `Predis\Command\ScriptCommand`
|
||||
|
||||
- Dropped `Predis\Command\Command::__toString()` (see issue #151).
|
||||
|
||||
- The key prefixing logic has been moved from command classes to the key prefix
|
||||
processor. Developers can define or override handlers used to prefix keys, but
|
||||
they can also define the needed logic in their command classes by implementing
|
||||
`Predis\Command\PrefixableCommandInterface` just like before.
|
||||
|
||||
- `Predis\PubSub\DispatcherLoop` now takes a `Predis\PubSub\Consumer` instance
|
||||
as the sole argument of its constructor instead of `Predis\ClientInterface`.
|
||||
|
||||
- All of the interfaces and classes related to translated Redis response types
|
||||
have been moved in the new `Predis\Response` namespace and most of them have
|
||||
been renamed to make their fully-qualified name less redundant. Now the base
|
||||
response interface is `Predis\Response\ResponseInterface`.
|
||||
|
||||
- Renamed interface `Predis\Command\Processor\CommandProcessorInterface` to a
|
||||
shorter `Predis\Command\Processor\ProcessorInterface`. Also removed interface
|
||||
for chain processors since it is basically useless.
|
||||
|
||||
- Renamed `Predis\ExecutableContextInterface` to `Predis\ClientContextInterface`
|
||||
and augmented it with a couple of required methods since this interface is no
|
||||
more comparable to a basic client as it could be misleading.
|
||||
|
||||
- The `Predis\Option` namespace is now known as `Predis\Configuration` and have
|
||||
a fully-reworked `Options` class with the ability to lazily initialize values
|
||||
using objects that responds to `__invoke()` (not all the kinds of callables)
|
||||
even for custom options defined by the user.
|
||||
|
||||
- Renamed `Predis\Connection\ConnectionInterface::writeCommand()` into
|
||||
`writeRequest()` for consistency with its counterpart, `readResponse()`.
|
||||
|
||||
- Renamed `Predis\Connection\SingleConnectionInterface::pushInitCommand()` into
|
||||
`addConnectCommand()` which is more obvious.
|
||||
|
||||
- Renamed the connection class based on both ext-phpiredis and ext-socket into
|
||||
`Predis\Connection\PhpiredisSocketConnection`. The one based on PHP's streams
|
||||
is still named `Predis\Connection\PhpiredisStreamConnection`.
|
||||
|
||||
- Renamed the connection factory class to `Predis\Connection\Factory`. Now its
|
||||
constructor does not require anymore a profile instance to create `AUTH` and
|
||||
`SELECT` commands when parameters contain both `password` and `database`. Raw
|
||||
commands will be used instead.
|
||||
|
||||
- Renamed the connection parameters class to `Predis\Connection\Parameters`. Now
|
||||
its constructor accepts only named arrays, but instances can still be created
|
||||
using both URIs or arrays using the static method `Parameters::create()`.
|
||||
|
||||
- The profile factory code has been extracted from the abstract Redis profile
|
||||
class and now lives in `Predis\Profile\Factory`.
|
||||
|
||||
- The `Predis\Connection` namespace has been completely reorganized by renaming
|
||||
a few classes and interfaces and adding some sub-namespaces.
|
||||
|
||||
- Most classes and interfaces in the `Predis\Protocol` namespace have been moved
|
||||
or renamed while rationalizing the whole API for external protocol processors.
|
||||
|
||||
|
||||
v0.8.7 (2014-08-01)
|
||||
================================================================================
|
||||
|
||||
- Added `3.0` in the server profiles aliases list for Redis 3.0. `2.8` is still
|
||||
the default server profile and `dev` still targets Redis 3.0.
|
||||
|
||||
- Added `COMMAND` to the server profile for Redis 2.8.
|
||||
|
||||
- Switched internally to the `CLUSTER SLOTS` command instead of `CLUSTER NODES`
|
||||
to fetch the updated slots map from redis-cluster. This change requires users
|
||||
to upgrade Redis nodes to >= 3.0.0b7.
|
||||
|
||||
- The updated slots map is now fetched automatically from redis-cluster upon the
|
||||
first `-MOVED` response by default. This change makes it possible to feed the
|
||||
client constructor with only a few nodes of the actual cluster composition,
|
||||
without needing a more complex configuration.
|
||||
|
||||
- Implemented support for `PING` in PUB/SUB loop for Redis >= 3.0.0b8.
|
||||
|
||||
- The default client-side sharding strategy and the one for redis-cluster now
|
||||
share the same implementations as they follow the same rules. One difference,
|
||||
aside from the different hashing function used to calculate distribution, is
|
||||
in how empty hash tags like {} are treated by redis-cluster.
|
||||
|
||||
- __FIX__: the patch applied to fix #180 introduced a regression affecting read/
|
||||
write timeouts in `Predis\Connection\PhpiredisStreamConnection`. Unfortunately
|
||||
the only possible solution requires PHP 5.4+. On PHP 5.3, read/write timeouts
|
||||
will be ignored from now on.
|
||||
|
||||
|
||||
v0.8.6 (2014-07-15)
|
||||
================================================================================
|
||||
|
||||
- Redis 2.8 is now the default server profile as there are no changes that would
|
||||
break compatibility with previous releases.
|
||||
|
||||
- Added `PFADD`, `PFCOUNT`, `PFMERGE` to the server profile for Redis 2.8 for
|
||||
handling the HyperLogLog data structure introduced in Redis 2.8.9.
|
||||
|
||||
- Added `ZLEXCOUNT`, `ZRANGEBYLEX`, `ZREMRANGEBYLEX` to the server profile for
|
||||
Redis 2.8 for handling lexicographic operations on members of sorted sets.
|
||||
|
||||
- Added support for key hash tags when using redis-cluster (Redis 3.0.0b1).
|
||||
|
||||
- __FIX__: minor tweaks to make Predis compatible with HHVM >= 2.4.0.
|
||||
|
||||
- __FIX__: responses to `INFO` are now properly parsed and will not break when
|
||||
redis sentinel is being used (ISSUE #154).
|
||||
|
||||
- __FIX__: added missing support for `INCRBYFLOAT` in cluster and replication
|
||||
configurations (ISSUE #159).
|
||||
|
||||
- __FIX__: fix parsing of the output of `CLUSTER NODES` to fetch the slots map
|
||||
from a node when redis-cluster has slaves in its configuration (ISSUE #165).
|
||||
|
||||
- __FIX__: prevent a stack overflow when iterating over large Redis collections
|
||||
using our abstraction for cursor-based iterators (ISSUE #182).
|
||||
|
||||
- __FIX__: properly discards transactions when the server immediately returns an
|
||||
error response (e.g. -OOM or -ERR on invalid arguments for a command) instead
|
||||
of a +QUEUED response (ISSUE #187).
|
||||
|
||||
- Upgraded to PHPUnit 4.* for the test suite.
|
||||
|
||||
|
||||
v0.8.5 (2014-01-16)
|
||||
================================================================================
|
||||
|
||||
- Added `2.8` in the server profiles aliases list for Redis 2.8. `2.6` is still
|
||||
the default server profile and `dev` now targets Redis 3.0.
|
||||
|
||||
- Added `SCAN`, `SSCAN`, `ZSCAN`, `HSCAN` to the server profile for Redis 2.8.
|
||||
|
||||
- Implemented PHP iterators for incremental iterations over Redis collections:
|
||||
|
||||
- keyspace (cursor-based iterator using `SCAN`)
|
||||
- sets (cursor-based iterator using `SSCAN`)
|
||||
- sorted sets (cursor-based iterator using `ZSCAN`)
|
||||
- hashes (cursor-based iterator using `HSCAN`)
|
||||
- lists (plain iterator using `LRANGE`)
|
||||
|
||||
- It is now possible to execute "raw commands" using `Predis\Command\RawCommand`
|
||||
and a variable list of command arguments. Input arguments are not filtered and
|
||||
responses are not parsed, which means arguments must follow the signature of
|
||||
the command as defined by Redis and complex responses are left untouched.
|
||||
|
||||
- URI parsing for connection parameters has been improved and has slightly less
|
||||
overhead when the number of fields in the querystring grows. New features are:
|
||||
|
||||
- Parsing does not break when value of a field contains one or more "=".
|
||||
- Repeated fieldnames using [] produce an array of values.
|
||||
- Empty or incomplete "key=value" pairs result in an empty string for "key".
|
||||
|
||||
- Various improvements and fixes to the redis-cluster connection backend:
|
||||
|
||||
- __FIX__: the `ASKING` command is sent upon -ASK redirections.
|
||||
- An updated slots-map can be fetched from nodes using the `CLUSTER NODES`
|
||||
command. By default this is a manual operation but can be enabled to get
|
||||
automatically done upon -MOVED redirections.
|
||||
- It is possible to specify a common set of connection parameters that are
|
||||
applied to connections created on the fly upon redirections to nodes not
|
||||
part of the initial pool.
|
||||
|
||||
- List of deprecated methods:
|
||||
|
||||
- `Predis\Client::multiExec()`: superseded by `Predis\Client::transaction()`
|
||||
and to be removed in the next major release.
|
||||
- `Predis\Client::pubSub()`: superseded by `Predis\Client::pubSubLoop()` and
|
||||
to be removed in the next major release. This change was needed due to the
|
||||
recently introduced `PUBSUB` command in Redis 2.8.
|
||||
|
||||
|
||||
v0.8.4 (2013-07-27)
|
||||
================================================================================
|
||||
|
||||
- Added `DUMP` and `RESTORE` to the server profile for Redis 2.6.
|
||||
|
||||
- Connection exceptions now report basic host details in their messages.
|
||||
|
||||
- Allow `Predis\Connection\PhpiredisConnection` to use a random IP when a host
|
||||
actually has several IPs (ISSUE #116).
|
||||
|
||||
- __FIX__: allow `HMSET` when using a cluster of Redis nodes with client-side
|
||||
sharding or redis-cluster (ISSUE #106).
|
||||
|
||||
- __FIX__: set `WITHSCORES` modifer for `ZRANGE`, `ZREVRANGE`, `ZRANGEBYSCORE`
|
||||
and `ZREVRANGEBYSCORE` only when the options array passed to these commands
|
||||
has `WITHSCORES` set to `true` (ISSUE #107).
|
||||
|
||||
- __FIX__: scripted commands falling back from `EVALSHA` to `EVAL` resulted in
|
||||
PHP errors when using a prefixed client (ISSUE #109).
|
||||
|
||||
- __FIX__: `Predis\PubSub\DispatcherLoop` now works properly when using key
|
||||
prefixing (ISSUE #114).
|
||||
|
||||
|
||||
v0.8.3 (2013-02-18)
|
||||
================================================================================
|
||||
|
||||
- Added `CLIENT SETNAME` and `CLIENT GETNAME` (ISSUE #102).
|
||||
|
||||
- Implemented the `Predis\Connection\PhpiredisStreamConnection` class using the
|
||||
`phpiredis` extension like `Predis\Connection\PhpiredisStreamConnection`, but
|
||||
without requiring the `socket` extension since it relies on PHP's streams.
|
||||
|
||||
- Added support for the TCP_NODELAY flag via the `tcp_nodelay` parameter for
|
||||
stream-based connections, namely `Predis\Connection\StreamConnection` and
|
||||
`Predis\Connection\PhpiredisStreamConnection` (requires PHP >= 5.4.0).
|
||||
|
||||
- Updated the aggregated connection class for redis-cluster to work with 16384
|
||||
hash slots instead of 4096 to reflect the recent change from redis unstable
|
||||
([see this commit](https://github.com/antirez/redis/commit/ebd666d)).
|
||||
|
||||
- The constructor of `Predis\Client` now accepts a callable as first argument
|
||||
returning `Predis\Connection\ConnectionInterface`. Users can create their
|
||||
own self-contained strategies to create and set up the underlying connection.
|
||||
|
||||
- Users should return `0` from `Predis\Command\ScriptedCommand::getKeysCount()`
|
||||
instead of `FALSE` to indicate that all of the arguments of a Lua script must
|
||||
be used to populate `ARGV[]`. This does not represent a breaking change.
|
||||
|
||||
- The `Predis\Helpers` class has been deprecated and it will be removed in
|
||||
future releases.
|
||||
|
||||
|
||||
v0.8.2 (2013-02-03)
|
||||
================================================================================
|
||||
|
||||
- Added `Predis\Session\SessionHandler` to make it easy to store PHP sessions
|
||||
on Redis using Predis. Please note that this class needs either PHP >= 5.4.0
|
||||
or a polyfill for PHP's `SessionHandlerInterface`.
|
||||
|
||||
- Added the ability to get the default value of a client option directly from
|
||||
`Predis\Option\ClientOption` using the `getDefault()` method by passing the
|
||||
option name or its instance.
|
||||
|
||||
- __FIX__: the standard pipeline executor was not using the response parser
|
||||
methods associated to commands to process raw responses (ISSUE #101).
|
||||
|
||||
|
||||
v0.8.1 (2013-01-19)
|
||||
================================================================================
|
||||
|
||||
- The `connections` client option can now accept a callable object returning
|
||||
an instance of `Predis\Connection\ConnectionFactoryInterface`.
|
||||
|
||||
- Client options accepting callable objects as factories now pass their actual
|
||||
instance to the callable as the second argument.
|
||||
|
||||
- `Predis\Command\Processor\KeyPrefixProcessor` can now be directly casted to
|
||||
string to obtain the current prefix, useful with string interpolation.
|
||||
|
||||
- Added an optional callable argument to `Predis\Cluster\Distribution\HashRing`
|
||||
and `Predis\Cluster\Distribution\KetamaPureRing` constructor that can be used
|
||||
to customize how the distributor should extract the connection hash when
|
||||
initializing the nodes distribution (ISSUE #36).
|
||||
|
||||
- Correctly handle `TTL` and `PTTL` returning -2 on non existing keys starting
|
||||
with Redis 2.8.
|
||||
|
||||
- __FIX__: a missing use directive in `Predis\Transaction\MultiExecContext`
|
||||
caused PHP errors when Redis did not return `+QUEUED` replies to commands
|
||||
when inside a MULTI / EXEC context.
|
||||
|
||||
- __FIX__: the `parseResponse()` method implemented for a scripted command was
|
||||
ignored when retrying to execute a Lua script by falling back to `EVAL` after
|
||||
a `-NOSCRIPT` error (ISSUE #94).
|
||||
|
||||
- __FIX__: when subclassing `Predis\Client` the `getClientFor()` method returns
|
||||
a new instance of the subclass instead of a new instance of `Predis\Client`.
|
||||
|
||||
|
||||
v0.8.0 (2012-10-23)
|
||||
================================================================================
|
||||
|
||||
- The default server profile for Redis is now `2.6`.
|
||||
|
||||
- Certain connection parameters have been renamed:
|
||||
|
||||
- `connection_async` is now `async_connect`
|
||||
- `connection_timeout` is now `timeout`
|
||||
- `connection_persistent` is now `persistent`
|
||||
|
||||
- The `throw_errors` connection parameter has been removed and replaced by the
|
||||
new `exceptions` client option since exceptions on `-ERR` replies returned by
|
||||
Redis are not generated by connection classes anymore but instead are thrown
|
||||
by the client class and other abstractions such as pipeline contexts.
|
||||
|
||||
- Added smart support for redis-cluster (Redis v3.0) in addition to the usual
|
||||
cluster implementation that uses client-side sharding.
|
||||
|
||||
- Various namespaces and classes have been renamed to follow rules inspired by
|
||||
the Symfony2 naming conventions.
|
||||
|
||||
- The second argument of the constructor of `Predis\Client` does not accept
|
||||
strings or instances of `Predis\Profile\ServerProfileInterface` anymore.
|
||||
To specify a server profile you must explicitly set `profile` in the array
|
||||
of client options.
|
||||
|
||||
- `Predis\Command\ScriptedCommand` internally relies on `EVALSHA` instead of
|
||||
`EVAL` thus avoiding to send Lua scripts bodies on each request. The client
|
||||
automatically resends the command falling back to `EVAL` when Redis returns a
|
||||
`-NOSCRIPT` error. Automatic fallback to `EVAL` does not work with pipelines,
|
||||
inside a `MULTI / EXEC` context or with plain `EVALSHA` commands.
|
||||
|
||||
- Complex responses are no more parsed by connection classes as they must be
|
||||
processed by consumer classes using the handler associated to the issued
|
||||
command. This means that executing commands directly on connections only
|
||||
returns simple Redis types, but nothing changes when using `Predis\Client`
|
||||
or the provided abstractions for pipelines and transactions.
|
||||
|
||||
- Iterators for multi-bulk replies now skip the response parsing method of the
|
||||
command that generated the response and are passed directly to user code.
|
||||
Pipeline and transaction objects still consume automatically iterators.
|
||||
|
||||
- Cluster and replication connections now extend a new common interface,
|
||||
`Predis\Connection\AggregatedConnectionInterface`.
|
||||
|
||||
- `Predis\Connection\MasterSlaveReplication` now uses an external strategy
|
||||
class to handle the logic for checking readable / writable commands and Lua
|
||||
scripts.
|
||||
|
||||
- Command pipelines have been optimized for both speed and code cleanness, but
|
||||
at the cost of bringing a breaking change in the signature of the interface
|
||||
for pipeline executors.
|
||||
|
||||
- Added a new pipeline executor that sends commands wrapped in a MULTI / EXEC
|
||||
context to make the execution atomic: if a pipeline fails at a certain point
|
||||
then the whole pipeline is discarded.
|
||||
|
||||
- The key-hashing mechanism for commands is now handled externally and is no
|
||||
more a competence of each command class. This change is neeeded to support
|
||||
both client-side sharding and Redis cluster.
|
||||
|
||||
- `Predis\Options\Option` is now abstract, see `Predis\Option\AbstractOption`.
|
||||
|
||||
|
||||
v0.7.3 (2012-06-01)
|
||||
================================================================================
|
||||
|
||||
- New commands available in the Redis v2.6 profile (dev): `BITOP`, `BITCOUNT`.
|
||||
|
||||
- When the number of keys `Predis\Commands\ScriptedCommand` is negative, Predis
|
||||
will count from the end of the arguments list to calculate the actual number
|
||||
of keys that will be interpreted as elements for `KEYS` by the underlying
|
||||
`EVAL` command.
|
||||
|
||||
- __FIX__: `examples\CustomDistributionStrategy.php` had a mistyped constructor
|
||||
call and produced a bad distribution due to an error as pointed in ISSUE #63.
|
||||
This bug is limited to the above mentioned example and does not affect the
|
||||
classes implemented in the `Predis\Distribution` namespace.
|
||||
|
||||
- __FIX__: `Predis\Commands\ServerEvalSHA::getScriptHash()` was calculating the
|
||||
hash while it just needs to return the first argument of the command.
|
||||
|
||||
- __FIX__: `Predis\Autoloader` has been modified to allow cascading autoloaders
|
||||
for the `Predis` namespace.
|
||||
|
||||
|
||||
v0.7.2 (2012-04-01)
|
||||
================================================================================
|
||||
|
||||
- Added `2.6` in the server profiles aliases list for the upcoming Redis 2.6.
|
||||
`2.4` is still the default server profile. `dev` now targets Redis 2.8.
|
||||
|
||||
- Connection instances can be serialized and unserialized using `serialize()`
|
||||
and `unserialize()`. This is handy in certain scenarios such as client-side
|
||||
clustering or replication to lower the overhead of initializing a connection
|
||||
object with many sub-connections since unserializing them can be up to 5x
|
||||
times faster.
|
||||
|
||||
- Reworked the default autoloader to make it faster. It is also possible to
|
||||
prepend it in PHP's autoload stack.
|
||||
|
||||
- __FIX__: fixed parsing of the payload returned by `MONITOR` with Redis 2.6.
|
||||
|
||||
|
||||
v0.7.1 (2011-12-27)
|
||||
================================================================================
|
||||
|
||||
- The PEAR channel on PearHub has been deprecated in favour of `pear.nrk.io`.
|
||||
|
||||
- Miscellaneous minor fixes.
|
||||
|
||||
- Added transparent support for master / slave replication configurations where
|
||||
write operations are performed on the master server and read operations are
|
||||
routed to one of the slaves. Please refer to ISSUE #21 for a bit of history
|
||||
and more details about replication support in Predis.
|
||||
|
||||
- The `profile` client option now accepts a callable object used to initialize
|
||||
a new instance of `Predis\Profiles\IServerProfile`.
|
||||
|
||||
- Exposed a method for MULTI / EXEC contexts that adds the ability to execute
|
||||
instances of Redis commands against transaction objects.
|
||||
|
||||
|
||||
v0.7.0 (2011-12-11)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Predis now adheres to the PSR-0 standard which means that there is no more a
|
||||
single file holding all the classes of the library, but multiple files (one
|
||||
@@ -66,19 +532,19 @@ v0.7.0 (2011-12-11)
|
||||
thus removed. Serialization of commands is now a competence of connections.
|
||||
|
||||
- The `Predis\IConnection` interface has been splitted into two new interfaces:
|
||||
`Predis\Network\IConnectionSingle and `Predis\Network\IConnectionCluster`.
|
||||
`Predis\Network\IConnectionSingle` and `Predis\Network\IConnectionCluster`.
|
||||
|
||||
- The constructor of `Predis\Client` now accepts more type of arguments such as
|
||||
instances of `Predis\IConnectionParameters` and `Predis\Network\IConnection`.
|
||||
|
||||
|
||||
v0.6.6 (2011-04-01)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Switched to Redis 2.2 as the default server profile (there are no changes
|
||||
that would break compatibility with previous releases). Long command names
|
||||
are no more supported by default but if you need them you can still require
|
||||
Predis_Compatibility.php to avoid breaking compatibility.
|
||||
`Predis_Compatibility.php` to avoid breaking compatibility.
|
||||
|
||||
- Added a `VERSION` constant to `Predis\Client`.
|
||||
|
||||
@@ -88,7 +554,7 @@ v0.6.6 (2011-04-01)
|
||||
|
||||
- Predis now uses by default a new protocol reader, more lightweight and
|
||||
faster than the default handler-based one. Users can revert to the old
|
||||
protocol reader with the 'reader' client option set to `composable`.
|
||||
protocol reader with the `reader` client option set to `composable`.
|
||||
This client option can also accept custom reader classes implementing the
|
||||
new `Predis\IResponseReader` interface.
|
||||
|
||||
@@ -112,7 +578,7 @@ v0.6.6 (2011-04-01)
|
||||
|
||||
|
||||
v0.6.5 (2011-02-12)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- __FIX__: due to an untested internal change introduced in v0.6.4, a wrong
|
||||
handling of bulk reads of zero-length values was producing protocol
|
||||
@@ -120,7 +586,7 @@ v0.6.5 (2011-02-12)
|
||||
|
||||
|
||||
v0.6.4 (2011-02-12)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Various performance improvements (15% ~ 25%) especially when dealing with
|
||||
long multibulk replies or when using clustered connections.
|
||||
@@ -134,7 +600,7 @@ v0.6.4 (2011-02-12)
|
||||
|
||||
|
||||
v0.6.3 (2011-01-01)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- New commands available in the Redis v2.2 profile (dev):
|
||||
- Strings: `SETRANGE`, `GETRANGE`, `SETBIT`, `GETBIT`
|
||||
@@ -148,7 +614,7 @@ v0.6.3 (2011-01-01)
|
||||
|
||||
|
||||
v0.6.2 (2010-11-28)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Minor internal improvements and clean ups.
|
||||
|
||||
@@ -173,7 +639,7 @@ v0.6.2 (2010-11-28)
|
||||
|
||||
|
||||
v0.6.1 (2010-07-11)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Minor internal improvements and clean ups.
|
||||
|
||||
@@ -215,7 +681,7 @@ v0.6.1 (2010-07-11)
|
||||
|
||||
|
||||
v0.6.0 (2010-05-24)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Switched to the new multi-bulk request protocol for all of the commands
|
||||
in the Redis 1.2 and Redis 2.0 profiles. Inline and bulk requests are now
|
||||
@@ -227,7 +693,7 @@ v0.6.0 (2010-05-24)
|
||||
to instances of Redis 1.2.x).
|
||||
|
||||
- Support for Redis 1.0 is now optional and it is provided by requiring
|
||||
'Predis_Compatibility.php' before creating an instance of Predis\Client.
|
||||
'Predis_Compatibility.php' before creating an instance of `Predis\Client`.
|
||||
|
||||
- New commands added to the Redis 2.0 profile since Predis 0.5.1:
|
||||
- Strings: `SETEX`, `APPEND`, `SUBSTR`
|
||||
@@ -240,7 +706,7 @@ v0.6.0 (2010-05-24)
|
||||
|
||||
- Introduced client-level options with the new `Predis\ClientOptions` class.
|
||||
Options can be passed to the constructor of `Predis\Client` in its second
|
||||
argument as an array or an instance of Predis\ClientOptions. For brevity's
|
||||
argument as an array or an instance of `Predis\ClientOptions`. For brevity's
|
||||
sake and compatibility with older versions, the constructor still accepts
|
||||
an instance of `Predis\RedisServerProfile` in its second argument. The
|
||||
currently supported client options are:
|
||||
@@ -330,7 +796,7 @@ v0.6.0 (2010-05-24)
|
||||
|
||||
|
||||
v0.5.1 (2010-01-23)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
* `RPOPLPUSH` has been changed from bulk command to inline command in Redis
|
||||
1.2.1, so `ListPopLastPushHead` now extends `InlineCommand`. The old behavior
|
||||
@@ -345,5 +811,5 @@ v0.5.1 (2010-01-23)
|
||||
|
||||
|
||||
v0.5.0 (2010-01-09)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
* First versioned release of Predis
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
## Filing bug reports ##
|
||||
|
||||
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/nrk/predis/issues)
|
||||
section of the project.
|
||||
|
||||
When reporting bugs, in addition to the obvious description of your issue you __must__ always provide
|
||||
some essential information about your environment such as:
|
||||
|
||||
1. version of Predis (check the `VERSION` file or the `Predis\Client::VERSION` constant).
|
||||
2. version of Redis (check `redis_version` returned by [`INFO`](http://redis.io/commands/info)).
|
||||
3. version of PHP.
|
||||
4. name and version of the operating system.
|
||||
5. when possible, a small snippet of code that reproduces the issue.
|
||||
|
||||
__Think about it__: we do not have a crystal ball and cannot predict things or peer into the unknown
|
||||
so please provide as much details as possible to help us isolating issues and fix them.
|
||||
|
||||
__Never__ use GitHub issues to post generic questions about Predis! When you have questions about
|
||||
how Predis works or how it can be used, please just hop me an email and I will get back to you as
|
||||
soon as possible.
|
||||
|
||||
|
||||
## Contributing code ##
|
||||
|
||||
If you want to work on Predis, it is highly recommended that you first run the test suite in order
|
||||
to check that everything is OK and report strange behaviours or bugs. When modifying Predis please
|
||||
make sure that no warnings or notices are emitted by PHP running the interpreter in your development
|
||||
environment with the `error_reporting` variable set to `E_ALL | E_STRICT`.
|
||||
|
||||
The recommended way to contribute to Predis is to fork the project on GitHub, create topic branches
|
||||
on your newly created repository to fix bugs or add new features (possibly with tests covering your
|
||||
modifications) and then open a pull request with a description of the applied changes. Obviously you
|
||||
can use any other Git hosting provider of your preference.
|
||||
|
||||
We always aim for consistency in our code base so you should follow basic coding rules as defined by
|
||||
[PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
|
||||
and [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
|
||||
and stick with the conventions used in Predis to name classes and interfaces. Indentation should be
|
||||
done with 4 spaces and code should be wrapped at 100 columns (please try to stay within this limit
|
||||
even if the above mentioned official coding guidelines set the soft limit to 120 columns).
|
||||
|
||||
Please follow these [commit guidelines](http://git-scm.com/book/ch5-2.html#Commit-Guidelines) when
|
||||
committing your code to Git and always write a meaningful (not necessarily extended) description of
|
||||
your changes before opening pull requests.
|
||||
@@ -1,79 +0,0 @@
|
||||
# Some frequently asked questions about the performances of Predis #
|
||||
____________________________________________
|
||||
|
||||
|
||||
### Predis is a pure-PHP implementation: it can not be fast enough! ###
|
||||
|
||||
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you
|
||||
a couple of easy numbers using a single Predis client with PHP 5.3.5 (custom build) and Redis 2.2
|
||||
(localhost) under Ubuntu 11.04 (running on a Intel Q6600):
|
||||
|
||||
19600 SET/sec using 12 bytes for both key and value
|
||||
18900 GET/sec while retrieving the very same values
|
||||
0.200 seconds to fetch 30000 keys using _KEYS *_.
|
||||
|
||||
How does it compare with a nice C-based extension such as [__phpredis__](http://github.com/nicolasff/phpredis)?
|
||||
|
||||
30500 SET/sec using 12 bytes for both key and value
|
||||
31000 GET/sec while retrieving the very same values
|
||||
0.030 seconds to fetch 30000 keys using "KEYS *"".
|
||||
|
||||
Wow, __phpredis__ looks so much faster! Well we are comparing a C extension with a pure-PHP library so
|
||||
lower numbers are quite expected, but there is a fundamental flaw in them: is this really how you are
|
||||
going to use Redis in your application? Are you really going to send thousands of commands in a for-loop
|
||||
for each page request using a single client instance? If so, well I guess you are probably doing something
|
||||
wrong. Also, if you need to SET or GET multiple keys you should definitely use commands such as MSET and
|
||||
MGET. You can also use pipelining to get more performances when this technique can be used.
|
||||
|
||||
There is one more thing. We have tested the overhead of Predis by connecting on a localhost instance of
|
||||
Redis, but how these numbers change when we hit the network by connecting to instances of Redis that
|
||||
reside on other servers?
|
||||
|
||||
Using Predis:
|
||||
3600 SET/sec using 12 bytes for both key and value
|
||||
3600 GET/sec while retrieving the very same values
|
||||
0.210 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
Using phpredis:
|
||||
4000 SET/sec using 12 bytes for both key and value
|
||||
4000 GET/sec while retrieving the very same values
|
||||
0.051 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
There you go, you get almost the same average numbers and the reason is quite simple: network latency
|
||||
is a real performance killer and you cannot do (almost) anything about that. As a disclaimer, please
|
||||
remember that we are measuring the overhead of client libraries implementations and the effects of the
|
||||
network round-trip time, we are not really measuring how fast Redis is. Redis shines the best with
|
||||
thousands of concurrent clients doing requests! Also, actual performances should be measured according
|
||||
to how your application will use Redis.
|
||||
|
||||
|
||||
### I am convinced, but performances for multi-bulk replies (e.g. _KEYS *_) are still worse ###
|
||||
|
||||
Fair enough, but there is actually an option for you if you need even more speed and it consists on
|
||||
installing __[phpiredis](http://github.com/seppo0010/phpiredis)__ (note the additional _i_ in the
|
||||
name) and let Predis using it. __phpiredis__ is a C-based extension that wraps __hiredis__ (the
|
||||
official Redis C client library) with a thin layer that exposes its features to PHP. You will now
|
||||
get the benefits of a faster protocol parser just by adding a single line of code in your application:
|
||||
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array('tcp' => 'Predis\Network\PhpiredisConnection')
|
||||
));
|
||||
|
||||
As simple as it is, nothing will really change in the way you use the library in your application. So,
|
||||
how fast is it now? There are not much improvements for inline or short bulk replies (e.g. _SET_ or
|
||||
_GET_), but the speed for parsing multi-bulk replies is now on par with phpredis:
|
||||
|
||||
Using Predis with a phpiredis-based connection to fetch 30000 keys using _KEYS *_:
|
||||
|
||||
0.031 seconds from a local Redis instance
|
||||
0.058 seconds from a remote Redis instance
|
||||
|
||||
|
||||
### If I need to install a C extension to get better performances, why not using phpredis? ###
|
||||
|
||||
Good question. Generically speaking, if you need absolute uber-speed using localhost instances of Redis
|
||||
and you do not care about abstractions built around some Redis features such as MULTI / EXEC, or if you
|
||||
do not need any kind of extensibility or guaranteed backwards compatibility with different versions of
|
||||
Redis (Predis currently supports from 1.2 up to 2.2, and even the current development version), then
|
||||
using __phpredis__ can make sense for you. Otherwise, Predis is for you. Using __phpiredis__ gives you
|
||||
a nice speed bump, but it is not mandatory.
|
||||
@@ -1,58 +1,169 @@
|
||||
# Some frequently asked questions about Predis #
|
||||
____________________________________________
|
||||
|
||||
________________________________________________
|
||||
|
||||
### What is the point of Predis? ###
|
||||
|
||||
The main point of Predis is about offering a highly customizable client for Redis that can be easily
|
||||
extended by developers while still being reasonabily fast. With Predis you can swap almost any class
|
||||
used internally with your own custom implementation: you can build connection classes, or new
|
||||
distribution strategies for client-side sharding, or class handlers to replace existing commands or
|
||||
add new ones. All of this can be achieved without messing with the source code of the library and
|
||||
directly in your own application. Given the fast pace at which Redis is developed and adds new
|
||||
features, this can be a great asset that allows you to add new and still missing features or commands,
|
||||
or change the behaviour of the library without the need to break your dependencies in production code
|
||||
(well, at least to some degree).
|
||||
|
||||
|
||||
### How about performances? ###
|
||||
|
||||
Please refer to the dedicated __FAQ.PERFORMANCES__ file.
|
||||
|
||||
|
||||
### Why PHP 5.3? ###
|
||||
|
||||
Seriously, are you still using PHP 5.2 to build new applications? I assume that if you are throwing Redis
|
||||
in the mix, then you are probably coding something new after all. PHP 5.3 is faster, less memory hungry
|
||||
and has a few nice features such as namespaces and closures (kind of). More importantly, PHP 5.2 is not
|
||||
even officially supported anymore (aside from security patches). PHP 5.3 is not the future of PHP, but
|
||||
its current present. Furthermore, most of the existing frameworks out there are also making the switch
|
||||
with their respective new major versions. If you still insist on using PHP 5.2, you can get any recent
|
||||
backported release of Predis 0.6.x, or just use a different library.
|
||||
|
||||
|
||||
### Why so many files for just one library? ###
|
||||
|
||||
Before v0.7, Predis used the one-big-file approach to distribute the library. As much as you prefer having
|
||||
just one file for everything, this kind of solution is actually not that good. Predis now complies with the
|
||||
[PSR-0](http://groups.google.com/group/php-standards/web/psr-0-final-proposal) standard to play nice with
|
||||
the major recent frameworks and libraries, so it needs an autoloader function to be defined. If you still
|
||||
want to have just one file grouping all the classes for whatever reason, then the __bin/create-single-file.php__
|
||||
script in the repository can generate it for you. There is also the __bin/create-phar.php__ script that
|
||||
generates a single [Phar archive](http://www.php.net/manual/en/intro.phar.php) of the whole library.
|
||||
|
||||
The main point of Predis is about offering a highly customizable and extensible client for Redis,
|
||||
that can be easily extended by developers while still being reasonabily fast. With Predis you can
|
||||
swap almost any class with your own custom implementation: you can have custom connection classes,
|
||||
new distribution strategies for client-side sharding, or handlers to replace or add Redis commands.
|
||||
All of this can be achieved without messing with the source code of the library and directly in your
|
||||
own application. Given the fast pace at which Redis is developed and adds new features, this can be
|
||||
a great asset since it allows developers to add new and still missing features or commands or change
|
||||
the standard behaviour of the library without the need to break dependencies in production code (at
|
||||
least to some degree).
|
||||
|
||||
### Does Predis support UNIX domain sockets and persistent connections? ###
|
||||
|
||||
Yes. Obviously, persistent connections actually work when using PHP configured as a persistent process that
|
||||
gets recycled between requests (see [PHP-FPM](http://php-fpm.org/)).
|
||||
|
||||
Yes. Obviously persistent connections actually work only when using PHP configured as a persistent
|
||||
process reused by the web server (see [PHP-FPM](http://php-fpm.org)).
|
||||
|
||||
### Does Predis support transparent (de)serialization of values? ###
|
||||
|
||||
No, and it will not ever do that for you by default. The reason behind this decision is that serialization
|
||||
is usually something that developers prefer to customize depending on their needs and can not be easily
|
||||
generalized when using Redis because of the many possible access patterns for the data. This does not
|
||||
mean that it is impossible to have such a feature, you can leverage Predis' extensibility to define your
|
||||
own serialization-aware commands. See [here](http://github.com/nrk/predis/issues/29#issuecomment-1202624)
|
||||
for more details on how to implement such a feature with a practical example.
|
||||
No and it will not ever do that by default. The reason behind this decision is that serialization is
|
||||
usually something that developers prefer to customize depending on their needs and can not be easily
|
||||
generalized when using Redis because of the many possible access patterns for your data. This does
|
||||
not mean that it is impossible to have such a feature since you can leverage the extensibility of
|
||||
this library to define your own serialization-aware commands. You can find more details about how to
|
||||
do that [on this issue](http://github.com/nrk/predis/issues/29#issuecomment-1202624).
|
||||
|
||||
### How can I force Predis to connect to Redis before sending any command? ###
|
||||
|
||||
Explicitly connecting to Redis is usually not needed since the client initializes connections lazily
|
||||
only when they are needed. Admittedly, this behavior can be inconvenient in certain scenarios when
|
||||
you absolutely need to perform an upfront check to determine if the server is up and running and
|
||||
eventually catch exceptions on failures. Forcing the client to open the underlying connection can be
|
||||
done by invoking `Predis\Client::connect()`:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client();
|
||||
|
||||
try {
|
||||
$client->connect();
|
||||
} catch (Predis\Connection\ConnectionException $exception) {
|
||||
// We could not connect to Redis! Your handling code goes here.
|
||||
}
|
||||
|
||||
$client->info();
|
||||
```
|
||||
|
||||
### How Predis abstracts Redis commands? ###
|
||||
|
||||
The approach used to implement Redis commands is quite simple: by default each command follows the
|
||||
same signature as defined on the [Redis documentation](http://redis.io/commands) which makes things
|
||||
pretty easy if you already know how Redis works or you need to look up how to use certain commands.
|
||||
Alternatively, variadic commands can accept an array for keys or values (depending on the command)
|
||||
instead of a list of arguments. Commands such as [`RPUSH`](http://redis.io/commands/rpush) and
|
||||
[`HMSET`](http://redis.io/commands/hmset) are great examples:
|
||||
|
||||
```php
|
||||
$client->rpush('my:list', 'value1', 'value2', 'value3'); // plain method arguments
|
||||
$client->rpush('my:list', ['value1', 'value2', 'value3']); // single argument array
|
||||
|
||||
$client->hmset('my:hash', 'field1', 'value1', 'field2', 'value2'); // plain method arguments
|
||||
$client->hmset('my:hash', ['field1'=>'value1', 'field2'=>'value2']); // single named array
|
||||
```
|
||||
|
||||
An exception to this rule is [`SORT`](http://redis.io/commands/sort) for which modifiers are passed
|
||||
[using a named array](tests/Predis/Command/KeySortTest.php#L54-L75).
|
||||
|
||||
|
||||
# Speaking about performances... #
|
||||
_________________________________________________
|
||||
|
||||
|
||||
### Predis is a pure-PHP implementation: it can not be fast enough! ###
|
||||
|
||||
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you a
|
||||
couple of easy numbers with a simple test that uses a single client and is executed by PHP 5.5.6
|
||||
against a local instance of Redis 2.8 that runs under Ubuntu 13.10 on a Intel Q6600:
|
||||
|
||||
```
|
||||
21000 SET/sec using 12 bytes for both key and value.
|
||||
21000 GET/sec while retrieving the very same values.
|
||||
0.130 seconds to fetch 30000 keys using _KEYS *_.
|
||||
```
|
||||
|
||||
How does it compare with [__phpredis__](http://github.com/nicolasff/phpredis), a nice C extension
|
||||
providing an efficient client for Redis?
|
||||
|
||||
```
|
||||
30100 SET/sec using 12 bytes for both key and value
|
||||
29400 GET/sec while retrieving the very same values
|
||||
0.035 seconds to fetch 30000 keys using "KEYS *"".
|
||||
```
|
||||
|
||||
Wow __phpredis__ seems much faster! Well, we are comparing a C extension with a pure-PHP library so
|
||||
lower numbers are quite expected but there is a fundamental flaw in them: is this really how you are
|
||||
going to use Redis in your application? Are you really going to send thousands of commands using a
|
||||
for-loop on each page request using a single client instance? If so... well I guess you are probably
|
||||
doing something wrong. Also, if you need to `SET` or `GET` multiple keys you should definitely use
|
||||
commands such as `MSET` and `MGET`. You can also use pipelining to get more performances when this
|
||||
technique can be used.
|
||||
|
||||
There is one more thing: we have tested the overhead of Predis by connecting on a localhost instance
|
||||
of Redis but how these numbers change when we hit the physical network by connecting to remote Redis
|
||||
instances?
|
||||
|
||||
```
|
||||
Using Predis:
|
||||
3200 SET/sec using 12 bytes for both key and value
|
||||
3200 GET/sec while retrieving the very same values
|
||||
0.132 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
Using phpredis:
|
||||
3500 SET/sec using 12 bytes for both key and value
|
||||
3500 GET/sec while retrieving the very same values
|
||||
0.045 seconds to fetch 30000 keys using "KEYS *".
|
||||
```
|
||||
|
||||
There you go, you get almost the same average numbers and the reason is simple: network latency is a
|
||||
real performance killer and you cannot do (almost) anything about that. As a disclaimer, remember
|
||||
that we are measuring the overhead of client libraries implementations and the effects of network
|
||||
round-trip times, so we are not really measuring how fast Redis is. Redis shines best with thousands
|
||||
of concurrent clients doing requests! Also, actual performances should be measured according to how
|
||||
your application will use Redis.
|
||||
|
||||
### I am convinced, but performances for multi-bulk responses are still worse ###
|
||||
|
||||
Fair enough, but there is an option available if you need even more speed and consists on installing
|
||||
__[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name) and let the
|
||||
client use it. __phpiredis__ is another C extension that wraps __hiredis__ (the official C client
|
||||
library for Redis) with a thin layer exposing its features to PHP. You can then choose between two
|
||||
different connection classes:
|
||||
|
||||
- `Predis\Connection\PhpiredisStreamConnection` (using native PHP streams).
|
||||
- `Predis\Connection\PhpiredisSocketConnection` (requires `ext-socket`).
|
||||
|
||||
You will now get the benefits of a faster protocol serializer and parser just by adding a couple of
|
||||
lines of code:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisStreamConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisSocketConnection',
|
||||
),
|
||||
));
|
||||
```
|
||||
|
||||
Dead simple. Nothing changes in the way you use the library in your application. So how fast is it
|
||||
our basic benchmark script now? There are not much improvements for inline or short bulk responses
|
||||
like the ones returned by `SET` and `GET`, but the speed for parsing multi-bulk responses is now on
|
||||
par with phpredis:
|
||||
|
||||
```
|
||||
Fatching 30000 keys with _KEYS *_ using Predis paired with phpiredis::
|
||||
|
||||
0.035 seconds from a local Redis instance
|
||||
0.047 seconds from a remote Redis instance
|
||||
```
|
||||
|
||||
### If I need an extension to get better performances, why not using phpredis? ###
|
||||
|
||||
Good question. Generically speaking if you need absolute uber-speed using Redis on the localhost and
|
||||
you do not care about abstractions built around some Redis features such as MULTI / EXEC, or if you
|
||||
do not need any kind of extensibility or guaranteed backwards compatibility with different versions
|
||||
of Redis (Predis currently supports from 1.2 up to 2.8 and the current development version), then
|
||||
using __phpredis__ makes absolutely sense. Otherwise, Predis is perfect for the job and by adding
|
||||
__phpiredis__ you can get a nice speed bump almost for free.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2011 Daniele Alessandri
|
||||
Copyright (c) 2009-2014 Daniele Alessandri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
||||
@@ -1,147 +1,251 @@
|
||||
# Predis #
|
||||
|
||||
Predis is a flexible and feature-complete PHP (>= 5.3) client library for the Redis key-value store.
|
||||
[](https://packagist.org/packages/predis/predis)
|
||||
[](https://packagist.org/packages/predis/predis)
|
||||
|
||||
For a list of frequently asked questions about Predis, see the __FAQ__ file in the root of the repository.
|
||||
For a version compatible with PHP 5.2 you must use the backported version from the latest release in the
|
||||
0.6.x series. More details are available on the [official wiki](http://wiki.github.com/nrk/predis) of the
|
||||
project,
|
||||
Predis is a flexible and feature-complete [Redis](http://redis.io) client library for PHP >= 5.3.
|
||||
|
||||
By default Predis does not require any additional C extension, but it can be optionally paired with
|
||||
[phpiredis](https://github.com/nrk/phpiredis) to lower the overhead of serializing and parsing the
|
||||
Redis protocol. An asynchronous implementation of the client, albeit experimental, is also available
|
||||
through [Predis\Async](https://github.com/nrk/predis-async).
|
||||
|
||||
Predis can be used with [HHVM](http://www.hhvm.com) >= 2.3.0, but there are no guarantees you will
|
||||
not run into unexpected issues (especially when the JIT compiler is enabled via `Eval.Jit = true`)
|
||||
due to HHVM being still under heavy development, thus unstable and not yet 100% compatible with PHP.
|
||||
|
||||
More details about the project can be found in our [frequently asked questions](FAQ.md) section or
|
||||
on the online [wiki](https://github.com/nrk/predis/wiki).
|
||||
|
||||
|
||||
## Main features ##
|
||||
|
||||
- Complete support for Redis from __1.2__ to __2.4__ and the current development versions using different
|
||||
server profiles.
|
||||
- Client-side sharding with support for consistent hashing or custom distribution strategies.
|
||||
- Command pipelining on single and aggregated connections.
|
||||
- Transparent key prefixing strategy capable of handling any command known that has keys in its arguments.
|
||||
- Abstraction for Redis transactions (Redis >= 2.0) with support for CAS operations (Redis >= 2.2).
|
||||
- Connections to Redis instances are automatically and lazily estabilished upon the first call to a command.
|
||||
- Ability to connect to Redis using TCP/IP or UNIX domain sockets with support for persistent connections.
|
||||
- Ability to use alternative connection classes to use different types of network or protocol backends.
|
||||
- Flexible system to define and register your own set of commands or server profiles to client instances.
|
||||
- Wide range of Redis versions supported (from __2.0__ to __3.0__ and __unstable__) using profiles.
|
||||
- Cluster of nodes via client-side sharding using consistent hashing or custom distributors.
|
||||
- Smart support for [redis-cluster](http://redis.io/topics/cluster-tutorial) (Redis >= 3.0).
|
||||
- Support for master-slave replication configurations (write on master, read from slaves).
|
||||
- Transparent key prefixing for all known Redis commands using a customizable prefixing strategy.
|
||||
- Command pipelining (works on both single nodes and aggregate connections).
|
||||
- Abstraction for Redis transactions (Redis >= 2.0) supporting CAS operations (Redis >= 2.2).
|
||||
- Abstraction for Lua scripting (Redis >= 2.6) with automatic switching between `EVALSHA` or `EVAL`.
|
||||
- Abstraction for `SCAN`, `SSCAN`, `ZSCAN` and `HSCAN` (Redis >= 2.8) based on PHP iterators.
|
||||
- Connections to Redis are established lazily by the client upon the first command.
|
||||
- Support for both TCP/IP and UNIX domain sockets and persistent connections.
|
||||
- Support for [Webdis](http://webd.is) (both `ext-curl` and `ext-phpiredis` are needed).
|
||||
- Support for custom connection classes for providing different network or protocol backends.
|
||||
- Flexible system for defining and registering custom sets of supported commands or profiles.
|
||||
|
||||
|
||||
## How to use Predis ##
|
||||
|
||||
Predis is available on [Packagist](http://packagist.org/packages/predis/predis) for an easy installation
|
||||
using [Composer](http://packagist.org/about-composer). Composer helps you manage dependencies for your
|
||||
projects and libraries without much hassle which makes it the preferred way to get up and running with
|
||||
new applications. Alternatively, the library is available on [PearHub](http://pearhub.org/projects/predis)'s
|
||||
channel for a more traditional installation via PEAR. Zip and tar.gz archives are also downloadable from
|
||||
GitHub by browsing the list of [tagged releases](http://github.com/nrk/predis/tags).
|
||||
Predis is available on [Packagist](http://packagist.org/packages/predis/predis) which allows a quick
|
||||
installation using [Composer](http://packagist.org/about-composer). Alternatively, the library can
|
||||
be found on our [own PEAR channel](http://pear.nrk.io) for a more traditional installation via PEAR.
|
||||
Ultimately, archives of each release are [available on GitHub](https://github.com/nrk/predis/tags).
|
||||
|
||||
|
||||
### Loading the library ###
|
||||
|
||||
To automatically load all of its files, Predis relies on the autoloading features of PHP and complies
|
||||
with the [PSR-0 standard](http://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) for
|
||||
interoperability with most of the major frameworks and libraries. Everything is transparently handled
|
||||
for you when installing the library using Composer, but you can also leverage its own autoloader class
|
||||
if you are going to use it in a project or script without any PSR-0 compliant autoloading facility:
|
||||
Predis relies on the autoloading features of PHP to load its files when needed and complies with the
|
||||
[PSR-4 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md).
|
||||
Autoloading is handled automatically when dependencies are managed through Composer, but it is also
|
||||
possible to leverage its own autoloader in projects or scripts not having any autoload facility:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
require PREDIS_BASE_PATH . '/Autoloader.php';
|
||||
```php
|
||||
// Prepend a base path if Predis is not available in your "include_path".
|
||||
require 'Predis/Autoloader.php';
|
||||
|
||||
Predis\Autoloader::register();
|
||||
```
|
||||
|
||||
You can create a single [Phar](http://www.php.net/manual/en/intro.phar.php) archive from the repository
|
||||
just by launching the `bin/create-phar.php` executable script. The generated Phar archive ships with a
|
||||
stub defining an autoloader function for Predis, so you just need to require the Phar to be able to use
|
||||
the library.
|
||||
|
||||
Alternatively you can generate a single PHP file that holds every class, just like older versions of
|
||||
Predis, using the `bin/create-single-file.php` executable sript. In this way you can load Predis in your
|
||||
scripts simply by using functions such as `require` and `include`, but this practice is not encouraged.
|
||||
It is possible to easily create a [phar](http://www.php.net/manual/en/intro.phar.php) archive from
|
||||
the repository just by launching `bin/create-phar`. The generated phar contains a stub defining an
|
||||
autoloader function for Predis, so you just need to require the phar to start using the library.
|
||||
Alternatively it is possible to generate one single PHP file holding every class like older versions
|
||||
of Predis by launching `bin/create-single-file`, but this practice __is not__ encouraged.
|
||||
|
||||
|
||||
### Connecting to a local instance of Redis ###
|
||||
### Connecting to Redis ###
|
||||
|
||||
When connecting to local instance of Redis (`127.0.0.1` on port `6379`), you do not have to specify any
|
||||
additional parameter to create a new client instance:
|
||||
When not specifying any connection parameter to create a new client, Predis assumes `127.0.0.1` and
|
||||
`6379` as the default host and port with a connection timeout of 5 seconds:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$redis = new Predis\Client();
|
||||
$redis->set('foo', 'bar');
|
||||
$value = $redis->get('foo');
|
||||
```php
|
||||
$client = new Predis\Client();
|
||||
$client->set('foo', 'bar');
|
||||
$value = $client->get('foo');
|
||||
```
|
||||
|
||||
However you can use an URI string or a named array to specify the needed connection parameters:
|
||||
Connection parameters can be supplied either in the form of URI strings or named arrays. While the
|
||||
latter is the preferred way to supply parameters, URI strings can be useful for quick configurations
|
||||
or when parameters are read from a non-structured source:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$redis = new Predis\Client('tcp://10.0.0.1:6379');
|
||||
|
||||
// is equivalent to:
|
||||
|
||||
$redis = new Predis\Client(array(
|
||||
```php
|
||||
// Named array of connection parameters:
|
||||
$client = new Predis\Client([
|
||||
'scheme' => 'tcp',
|
||||
'host' => '10.0.0.1',
|
||||
'port' => 6379,
|
||||
));
|
||||
]);
|
||||
|
||||
// Same set of parameters, but using an URI string:
|
||||
$client = new Predis\Client('tcp://10.0.0.1:6379');
|
||||
```
|
||||
|
||||
When an array of connection parameters is provided, Predis automatically works in cluster mode using
|
||||
client-side sharding. Both named arrays and URI strings can be mixed when providing configurations
|
||||
for each node:
|
||||
|
||||
### Pipelining multiple commands to multiple instances of Redis with client-side sharding ###
|
||||
```php
|
||||
$client = new Predis\Client([
|
||||
'tcp://10.0.0.1?alias=first-node',
|
||||
['host' => '10.0.0.2', 'alias' => 'second-node'],
|
||||
]);
|
||||
```
|
||||
|
||||
Pipelining helps with performances when there is the need to send many commands to a server in one go.
|
||||
Furthermore, pipelining works transparently even on aggregated connections. To achieve this, Predis
|
||||
supports client-side sharding using consistent-hashing on keys while clustered connections are supported
|
||||
natively by the client class.
|
||||
The actual list of supported connection parameters can vary depending on each connection backend so
|
||||
it is recommended to refer to their specific documentation or implementation for details.
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$redis = new Predis\Client(array(
|
||||
array('host' => '10.0.0.1', 'port' => 6379),
|
||||
array('host' => '10.0.0.2', 'port' => 6379)
|
||||
));
|
||||
|
||||
$replies = $redis->pipeline(function($pipe) {
|
||||
### Client configuration ###
|
||||
|
||||
Various aspects of the client can be configured simply by passing options to the second argument of
|
||||
`Predis\Client::__construct()`. Options are managed using a mini DI-alike container and their values
|
||||
are usually lazily initialized only when needed. Predis by default supports the following options:
|
||||
|
||||
- `profile`: which profile to use in order to match a specific version of Redis.
|
||||
- `prefix`: a prefix string that is automatically applied to keys found in commands.
|
||||
- `exceptions`: whether the client should throw or return responses upon Redis errors.
|
||||
- `connections`: connection backends or a connection factory to be used by the client.
|
||||
- `cluster`: which backend to use for clustering (`predis`, `redis` or custom configuration).
|
||||
- `replication`: which backend to use for replication (predis or custom configuration).
|
||||
- `aggregate`: custom connections aggregator (overrides both `cluster` and `replication`).
|
||||
|
||||
Users can provide custom options with their values or lazy callable initializers that are stored in
|
||||
the options container for later use through the library.
|
||||
|
||||
|
||||
### Aggregate connections ###
|
||||
|
||||
Predis is able to aggregate multiple connections which is the base for cluster and replication. By
|
||||
default the client implements a cluster of nodes using either client-side sharding (default) or a
|
||||
Redis-backed solution using [redis-cluster](http://redis.io/topics/cluster-tutorial).
|
||||
As for replication, Predis can handle a single-master and multiple-slaves setup by executing read
|
||||
operations on slaves and switching to the master for write operations. The replication behavior is
|
||||
fully configurable.
|
||||
|
||||
#### Replication ####
|
||||
|
||||
The client can be configured to work in a master / slave replication setup by executing read-only
|
||||
commands on slave nodes and automatically switch to the master node as soon as a command performing
|
||||
a write operation is executed. This is the basic configuration needed to work with replication:
|
||||
|
||||
```php
|
||||
// Parameters require one master node specifically marked with `alias=master`.
|
||||
$parameters = ['tcp://10.0.0.1?alias=master', 'tcp://10.0.0.2?alias=slave-01'];
|
||||
$options = ['replication' => true];
|
||||
|
||||
$client = new Predis\Client($parameters, $options);
|
||||
```
|
||||
|
||||
While Predis is able to distinguish commands performing write and read-only operations, `EVAL` and
|
||||
`EVALSHA` represent a corner case in which the client switches to the master node because it is not
|
||||
able to tell when a Lua script is safe to be executed on slaves. While this is the default behavior,
|
||||
when certain Lua scripts do not perform write operations it is possible to provide an hint to tell
|
||||
the client to stick with slaves for their execution.
|
||||
|
||||
```php
|
||||
$parameters = ['tcp://10.0.0.1?alias=master', 'tcp://10.0.0.2?alias=slave-01'];
|
||||
$options = ['replication' => function () {
|
||||
// Set scripts that won't trigger a switch from a slave to the master node.
|
||||
$strategy = new Predis\Replication\ReplicationStrategy();
|
||||
$strategy->setScriptReadOnly($LUA_SCRIPT);
|
||||
|
||||
return new Predis\Connection\Aggregate\MasterSlaveReplication($strategy);
|
||||
}];
|
||||
|
||||
$client = new Predis\Client($parameters, $options);
|
||||
$client->eval($LUA_SCRIPT, 0); // Sticks to slave using `eval`...
|
||||
$client->evalsha(sha1($LUA_SCRIPT), 0); // ... and `evalsha`, too.
|
||||
```
|
||||
|
||||
The `examples` directory contains two complete scripts showing how replication can be configured for
|
||||
[simple](examples/replication_simple.php) or [complex](examples/replication_complex.php) scenarios.
|
||||
|
||||
|
||||
#### Cluster ####
|
||||
|
||||
Simply passing an array of connection parameters to the client constructor configures Predis to work
|
||||
in cluster mode using client-side sharding. If you, on the other hand, want to leverage Redis >= 3.0
|
||||
nodes coordinated by redis-cluster, then the client must be initialized like this:
|
||||
|
||||
```php
|
||||
$parameters = ['tcp://10.0.0.1', 'tcp://10.0.0.2'];
|
||||
$options = ['cluster' => 'redis'];
|
||||
|
||||
$client = new Predis\Client($parameters, $options);
|
||||
```
|
||||
|
||||
When using redis-cluster, it is not necessary to pass all of the nodes that compose your cluster but
|
||||
you can simply specify only a few nodes: Predis will automatically fetch the full and updated slots
|
||||
map directly from Redis by contacting one of the servers.
|
||||
|
||||
__NOTE__: our support for redis-cluster does not currently consider master / slave replication but
|
||||
this feature will be added in a future release of this library.
|
||||
|
||||
|
||||
### Command pipelines ###
|
||||
|
||||
Pipelining can help with performances when many commands need to be sent to a server by reducing the
|
||||
latency introduced by network round-trip timings. Pipelining also works with aggregate connections.
|
||||
The client can execute the pipeline inside a callable block or return a pipeline instance with the
|
||||
ability to chain commands thanks to its fluent interface:
|
||||
|
||||
```php
|
||||
// Executes a pipeline inside a given callable block:
|
||||
$responses = $client->pipeline(function ($pipe) {
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$pipe->set("key:$i", str_pad($i, 4, '0', 0));
|
||||
$pipe->get("key:$i");
|
||||
}
|
||||
});
|
||||
|
||||
// Returns a pipeline instance with fluent interface:
|
||||
$responses = $client->pipeline()->set('foo', 'bar')->get('foo')->execute();
|
||||
```
|
||||
|
||||
|
||||
### Overriding standard connection classes with custom ones ###
|
||||
### Transactions ###
|
||||
|
||||
Predis allows developers to create new connection classes to add support for new protocols or override
|
||||
the existing ones and provide a different implementation compared to the default classes. This can be
|
||||
obtained by subclassing the `Predis\Network\IConnectionSingle` interface.
|
||||
The client provides an abstraction for Redis transactions based on `MULTI` and `EXEC` with a similar
|
||||
interface to command pipelines:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
class MyConnectionClass implements Predis\Network\IConnectionSingle
|
||||
{
|
||||
// implementation goes here
|
||||
}
|
||||
```php
|
||||
// Executes a transaction inside a given callable block:
|
||||
$responses = $client->transaction(function ($tx) {
|
||||
$tx->set('foo', 'bar');
|
||||
$tx->get('foo');
|
||||
});
|
||||
|
||||
// Let Predis automatically use your own class to handle connections identified by the tcp scheme.
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array('tcp' => 'MyConnectionClass')
|
||||
));
|
||||
// Returns a transaction instance with fluent interface:
|
||||
$responses = $client->transaction()->set('foo', 'bar')->get('foo')->execute();
|
||||
```
|
||||
|
||||
The classes contained in the `Predis\Network` namespace give you a better insight with actual code on
|
||||
how to create new connection classes.
|
||||
This abstraction can perform check-and-set operations thanks to `WATCH` and `UNWATCH` and provides
|
||||
automatic retries of transactions aborted by Redis when `WATCH`ed keys are touched. For an example
|
||||
of a transaction using CAS you can see [the following example](examples/transaction_using_cas.php).
|
||||
|
||||
|
||||
### Defining and registering new commands on the client at runtime ###
|
||||
### Adding new commands ###
|
||||
|
||||
Let's suppose Redis just added the support for a brand new feature associated with a new command. If
|
||||
you want to start using the above mentioned new feature right away without messing with Predis source
|
||||
code or waiting for it to find its way into a stable Predis release, then you can start off by creating
|
||||
a new class that matches the command type and its behaviour and then bind it to a client instance at
|
||||
runtime. Actually, it is easier done than said:
|
||||
While we try to update Predis to stay up to date with all the commands available in Redis, you might
|
||||
prefer to stick with an older version of the library or provide a different way to filter arguments
|
||||
or parse responses for specific commands. To achieve that, Predis provides the ability to implement
|
||||
new command classes to define or override commands in the server profiles used by the client:
|
||||
|
||||
``` php
|
||||
<?php
|
||||
class BrandNewRedisCommand extends Predis\Commands\Command
|
||||
```php
|
||||
// Define a new command by extending Predis\Command\Command:
|
||||
class BrandNewRedisCommand extends Predis\Command\Command
|
||||
{
|
||||
public function getId()
|
||||
{
|
||||
@@ -149,72 +253,143 @@ class BrandNewRedisCommand extends Predis\Commands\Command
|
||||
}
|
||||
}
|
||||
|
||||
$redis = new Predis\Client();
|
||||
$redis->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
|
||||
$redis->newcmd();
|
||||
// Inject your command in the current profile:
|
||||
$client = new Predis\Client();
|
||||
$client->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
|
||||
|
||||
$response = $client->newcmd();
|
||||
```
|
||||
|
||||
There is also a method to send raw commands without filtering their arguments or parsing responses.
|
||||
Users must provide the arguments list as an array, following the command signatures as defined by
|
||||
the [Redis documentation for commands](http://redis.io/commands):
|
||||
|
||||
```php
|
||||
$response = $client->executeRaw(['SET', 'foo', 'bar']);
|
||||
```
|
||||
|
||||
|
||||
## Test suite ##
|
||||
### Script commands ###
|
||||
|
||||
__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running in
|
||||
production environments or containing data you are interested in!
|
||||
While it is possible to leverage [Lua scripting](http://redis.io/commands/eval) on Redis 2.6+ using
|
||||
[`EVAL`](http://redis.io/commands/eval) and [`EVALSHA`](http://redis.io/commands/evalsha), Predis
|
||||
offers script commands as an higher level abstraction aiming to make things simple. Script commands
|
||||
can be registered in the server profile used by the client and are accessible as if they were plain
|
||||
Redis commands, but they define Lua scripts that get transmitted to the server for remote execution.
|
||||
Internally they use [`EVALSHA`](http://redis.io/commands/evalsha) by default and identify a script
|
||||
by its SHA1 hash to save bandwidth, but [`EVAL`](http://redis.io/commands/eval) is used as a fall
|
||||
back when needed:
|
||||
|
||||
Predis has a comprehensive test suite covering every aspect of the library. The suite performs integration
|
||||
tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct behaviour of the
|
||||
implementation of each command and automatically skips commands not defined in the selected version of
|
||||
Redis. If you do not have Redis up and running, integration tests can be disabled. By default, the test
|
||||
suite is configured to execute integration tests using the server profile for Redis v2.4 (which is the
|
||||
current stable version of Redis). You can optionally run the suite against a Redis instance built from
|
||||
the `unstable` branch with the development profile by changing the `REDIS_SERVER_VERSION` to `dev` in
|
||||
the `phpunit.xml` file. More details about testing Predis are available in `tests/README.md`.
|
||||
```php
|
||||
// Define a new scriptable command by extending Predis\Command\ScriptCommand:
|
||||
class ListPushRandomValue extends Predis\Command\ScriptCommand
|
||||
{
|
||||
public function getKeysCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Predis uses Travis CI for continuous integration. You can find the results of the test suite and the build
|
||||
history [on its project page](http://travis-ci.org/nrk/predis).
|
||||
public function getScript()
|
||||
{
|
||||
return <<<LUA
|
||||
math.randomseed(ARGV[1])
|
||||
local rnd = tostring(math.random())
|
||||
redis.call('lpush', KEYS[1], rnd)
|
||||
return rnd
|
||||
LUA;
|
||||
}
|
||||
}
|
||||
|
||||
// Inject your script command in the current profile:
|
||||
$client = new Predis\Client();
|
||||
$client->getProfile()->defineCommand('lpushrand', 'ListPushRandomValue');
|
||||
|
||||
$response = $client->lpushrand('random_values', $seed = mt_rand());
|
||||
```
|
||||
|
||||
|
||||
## Contributing ##
|
||||
### Customizable connection backends ###
|
||||
|
||||
If you want to work on Predis, it is highly recommended that you first run the test suite in order to
|
||||
check that everything is OK, and report strange behaviours or bugs. When modifying Predis please make
|
||||
sure that no warnings or notices are emitted by PHP by running the interpreter in your development
|
||||
environment with the `error_reporting` variable set to `E_ALL | E_STRICT`.
|
||||
Predis can use different connection backends to connect to Redis. Two of them leverage a third party
|
||||
extension such as [phpiredis](https://github.com/nrk/phpiredis) resulting in major performance gains
|
||||
especially when dealing with big multibulk responses. While one is based on PHP streams, the other
|
||||
is based on socket resources provided by `ext-socket`. Both support TCP/IP or UNIX domain sockets:
|
||||
|
||||
The recommended way to contribute to Predis is to fork the project on GitHub, create new topic branches
|
||||
on your newly created repository to fix or add features (possibly with tests covering your modifications)
|
||||
and then open a new pull request with a description of the applied changes. Obviously you can use any
|
||||
other Git hosting provider of your preference.
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', [
|
||||
'connections' => [
|
||||
'tcp' => 'Predis\Connection\PhpiredisStreamConnection', // PHP streams
|
||||
'unix' => 'Predis\Connection\PhpiredisSocketConnection', // ext-socket
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
Developers can create their own connection classes to support whole new network backends, extend
|
||||
existing ones or provide completely different implementations. Connection classes must implement
|
||||
`Predis\Connection\NodeConnectionInterface` or extend `Predis\Connection\AbstractConnection`:
|
||||
|
||||
```php
|
||||
class MyConnectionClass implements Predis\Connection\NodeConnectionInterface
|
||||
{
|
||||
// Implementation goes here...
|
||||
}
|
||||
|
||||
// Use MyConnectionClass to handle connections for the `tcp` scheme:
|
||||
$client = new Predis\Client('tcp://127.0.0.1', [
|
||||
'connections' => ['tcp' => 'MyConnectionClass'],
|
||||
]);
|
||||
```
|
||||
|
||||
For a more in-depth insight on how to create new connection backends you can refer to the actual
|
||||
implementation of the standard connection classes available in the `Predis\Connection` namespace.
|
||||
|
||||
|
||||
## Dependencies ##
|
||||
## Development ##
|
||||
|
||||
- PHP >= 5.3.2
|
||||
- PHPUnit >= 3.5.0 (needed to run the test suite)
|
||||
|
||||
## Links ##
|
||||
### Reporting bugs and contributing code ###
|
||||
|
||||
### Project ###
|
||||
- [Source code](http://github.com/nrk/predis/)
|
||||
- [Wiki](http://wiki.github.com/nrk/predis/)
|
||||
- [Issue tracker](http://github.com/nrk/predis/issues)
|
||||
Contributions to Predis are highly appreciated either in the form of pull requests for new features,
|
||||
bug fixes, or just bug reports. We only ask you to adhere to a [basic set of rules](CONTRIBUTING.md)
|
||||
before submitting your changes or filing bugs on the issue tracker to make it easier for everyone to
|
||||
stay consistent while working on the project.
|
||||
|
||||
### Related ###
|
||||
- [Redis](http://redis.io/)
|
||||
- [PHP](http://php.net/)
|
||||
- [PHPUnit](http://www.phpunit.de/)
|
||||
- [Git](http://git-scm.com/)
|
||||
|
||||
## Author ##
|
||||
### Test suite ###
|
||||
|
||||
__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running
|
||||
in production environments or containing data you are interested in!
|
||||
|
||||
Predis has a comprehensive test suite covering every aspect of the library. This test suite performs
|
||||
integration tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct
|
||||
behavior of the implementation of each command and automatically skips commands not defined in the
|
||||
specified Redis profile. If you do not have Redis up and running, integration tests can be disabled.
|
||||
By default the test suite is configured to execute integration tests using the profile for Redis 2.8
|
||||
(which is the current stable version of Redis) but can optionally target a Redis instance built from
|
||||
the `unstable` branch by modifying `phpunit.xml` and setting `REDIS_SERVER_VERSION` to `dev` so that
|
||||
the development server profile will be used. You can refer to [the tests README](tests/README.md)
|
||||
for more detailed information about testing Predis.
|
||||
|
||||
Predis uses 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).
|
||||
|
||||
|
||||
## Other ##
|
||||
|
||||
|
||||
### 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)
|
||||
- [PEAR channel](http://pear.nrk.io)
|
||||
|
||||
|
||||
### Author ###
|
||||
|
||||
- [Daniele Alessandri](mailto:suppakilla@gmail.com) ([twitter](http://twitter.com/JoL1hAHN))
|
||||
|
||||
## Contributors ##
|
||||
|
||||
- [Lorenzo Castelli](http://github.com/lcastelli)
|
||||
- [Jordi Boggiano](http://github.com/Seldaek) ([twitter](http://twitter.com/seldaek))
|
||||
- [Sebastian Waisbrot](http://github.com/seppo0010) ([twitter](http://twitter.com/seppo0010))
|
||||
for his work on extending [phpiredis](http://github.com/seppo0010/phpiredis) for Predis
|
||||
### License ###
|
||||
|
||||
## License ##
|
||||
|
||||
The code for Predis is distributed under the terms of the MIT license (see LICENSE).
|
||||
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
* Documentation! The README is obviously not enought to show how to use Predis
|
||||
as it does not cover all of its features.
|
||||
|
||||
* [v0.8] Implement smart and transparent support for redis-cluster.
|
||||
+1
-1
@@ -9,6 +9,6 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/lib/Predis/Autoloader.php';
|
||||
require __DIR__.'/src/Autoloader.php';
|
||||
|
||||
Predis\Autoloader::register();
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
// -------------------------------------------------------------------------- //
|
||||
// This script 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
|
||||
// in the Predis\Commands namespace (only classes in this namespace are valid).
|
||||
// in the Predis\Command namespace (only classes in this namespace are valid).
|
||||
// For example, to generate a test case for SET (which is represented by the
|
||||
// Predis\Commands\StringSet class):
|
||||
// Predis\Command\StringSet class):
|
||||
//
|
||||
// $ ./bin/generate-command-test.php --class=StringSet
|
||||
// $ ./bin/generate-command-test --class=StringSet
|
||||
//
|
||||
// Here is a list of optional arguments:
|
||||
//
|
||||
@@ -33,14 +33,14 @@
|
||||
// is explicitly specified.
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Commands\IPrefixable;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\PrefixableCommandInterface;
|
||||
|
||||
class CommandTestCaseGenerator
|
||||
{
|
||||
private $options;
|
||||
|
||||
public function __construct(Array $options)
|
||||
public function __construct(array $options)
|
||||
{
|
||||
if (!isset($options['class'])) {
|
||||
throw new RuntimeException("Missing 'class' option.");
|
||||
@@ -61,7 +61,7 @@ class CommandTestCaseGenerator
|
||||
|
||||
$options = array(
|
||||
'overwrite' => false,
|
||||
'tests' => __DIR__.'/../tests',
|
||||
'tests' => __DIR__.'/../tests/Predis',
|
||||
);
|
||||
|
||||
foreach ($getops as $option => $value) {
|
||||
@@ -92,10 +92,10 @@ class CommandTestCaseGenerator
|
||||
throw new RuntimeException("Missing 'class' option.");
|
||||
}
|
||||
|
||||
$options['fqn'] = "Predis\\Commands\\{$options['class']}";
|
||||
$options['path'] = "Predis/Commands/{$options['class']}.php";
|
||||
$options['fqn'] = "Predis\\Command\\{$options['class']}";
|
||||
$options['path'] = "Command/{$options['class']}.php";
|
||||
|
||||
$source = __DIR__.'/../lib/'.$options['path'];
|
||||
$source = __DIR__.'/../src/'.$options['path'];
|
||||
if (!file_exists($source)) {
|
||||
throw new RuntimeException("Cannot find class file for {$options['fqn']} in $source.");
|
||||
}
|
||||
@@ -116,7 +116,8 @@ class CommandTestCaseGenerator
|
||||
return $this->options['realm'];
|
||||
}
|
||||
|
||||
$class = array_pop(explode('\\', $this->options['fqn']));
|
||||
$fqnParts = explode('\\', $this->options['fqn']);
|
||||
$class = array_pop($fqnParts);
|
||||
list($realm,) = preg_split('/([[:upper:]][[:lower:]]+)/', $class, 2, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
return strtolower($realm);
|
||||
@@ -129,11 +130,15 @@ class CommandTestCaseGenerator
|
||||
if (!$reflection->isInstantiable()) {
|
||||
throw new RuntimeException("Class $class must be instantiable, abstract classes or interfaces are not allowed.");
|
||||
}
|
||||
if (!$reflection->implementsInterface('Predis\Commands\ICommand')) {
|
||||
throw new RuntimeException("Class $class must implement the Predis\Commands\ICommand interface.");
|
||||
if (!$reflection->implementsInterface('Predis\Command\CommandInterface')) {
|
||||
throw new RuntimeException("Class $class must implement Predis\Command\CommandInterface.");
|
||||
}
|
||||
|
||||
/*
|
||||
* @var CommandInterface
|
||||
*/
|
||||
$instance = $reflection->newInstance();
|
||||
|
||||
$buffer = $this->getTestCaseBuffer($instance);
|
||||
|
||||
return $buffer;
|
||||
@@ -148,11 +153,12 @@ class CommandTestCaseGenerator
|
||||
file_put_contents($options['output'], $this->generate());
|
||||
}
|
||||
|
||||
protected function getTestCaseBuffer(ICommand $instance)
|
||||
protected function getTestCaseBuffer(CommandInterface $instance)
|
||||
{
|
||||
$id = $instance->getId();
|
||||
$fqn = get_class($instance);
|
||||
$class = array_pop(explode('\\', $fqn)) . "Test";
|
||||
$fqnParts = explode('\\', $fqn);
|
||||
$class = array_pop($fqnParts) . "Test";
|
||||
$realm = $this->getTestRealm();
|
||||
|
||||
$buffer =<<<PHP
|
||||
@@ -167,15 +173,13 @@ class CommandTestCaseGenerator
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-$realm
|
||||
*/
|
||||
class $class extends CommandTestCase
|
||||
class $class extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -226,7 +230,7 @@ class $class extends CommandTestCase
|
||||
|
||||
PHP;
|
||||
|
||||
if ($instance instanceof IPrefixable) {
|
||||
if ($instance instanceof PrefixableCommandInterface) {
|
||||
$buffer .=<<<PHP
|
||||
|
||||
/**
|
||||
@@ -245,6 +249,17 @@ PHP;
|
||||
\$this->assertSame(\$expected, \$command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysIgnoredOnEmptyArguments()
|
||||
{
|
||||
\$command = \$this->getCommand();
|
||||
\$command->prefixKeys('prefix:');
|
||||
|
||||
\$this->assertSame(array(), \$command->getArguments());
|
||||
}
|
||||
|
||||
PHP;
|
||||
}
|
||||
|
||||
Executable
+233
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
// In order to be able to execute this script to create a PEAR package of Predis
|
||||
// the `pear` binary must be available and executable in your $PATH.
|
||||
// The parts used to parse author and version strings are taken from Onion (used
|
||||
// by this library in the past) just to keep on relying on the package.ini file
|
||||
// to simplify things. We might consider to switch to using the PEAR classes
|
||||
// directly in the future.
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
function executeWithBackup($file, $callback)
|
||||
{
|
||||
$exception = null;
|
||||
$backup = "$file.backup";
|
||||
|
||||
copy($file, $backup);
|
||||
|
||||
try {
|
||||
call_user_func($callback, $file);
|
||||
} catch (Exception $exception) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
unlink($file);
|
||||
rename($backup, $file);
|
||||
|
||||
if ($exception) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
function parseAuthor($string)
|
||||
{
|
||||
$author = array();
|
||||
|
||||
if (preg_match('/^\s*(.+?)\s*(?:"(\S+)"\s*)?<(\S+)>\s*$/x', $string , $regs)) {
|
||||
if (count($regs) == 4) {
|
||||
list($_,$name,$user,$email) = $regs;
|
||||
$author['name'] = $name;
|
||||
$author['user'] = $user;
|
||||
$author['email'] = $email;
|
||||
} elseif (count($regs) == 3) {
|
||||
list($_,$name,$email) = $regs;
|
||||
$author['name'] = $name;
|
||||
$author['email'] = $email;
|
||||
}
|
||||
} else {
|
||||
$author['name'] = $string;
|
||||
}
|
||||
|
||||
return $author;
|
||||
}
|
||||
|
||||
function parseVersion($string)
|
||||
{
|
||||
$version_pattern = '([0-9.]+)';
|
||||
|
||||
if (preg_match("/^\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array('min' => $regs[1] ?: '0.0.0');
|
||||
} elseif (preg_match("/^\s*[>=]+\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array('min' => $regs[1] ?: '0.0.0');
|
||||
} elseif (preg_match("/^\s*[<=]+\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array('max' => $regs[1]);
|
||||
} elseif (preg_match("/^\s*$version_pattern\s*<=>\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array(
|
||||
'min' => $regs[1] ?: '0.0.0',
|
||||
'max' => $regs[2],
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function addRolePath($pkg, $path, $role)
|
||||
{
|
||||
if (is_dir($path)) {
|
||||
$dirRoot = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$dirTree = new RecursiveIteratorIterator($dirRoot, RecursiveIteratorIterator::CHILD_FIRST);
|
||||
|
||||
foreach ($dirTree as $fileinfo) {
|
||||
if ($fileinfo->isFile()) {
|
||||
addPackageFile($pkg, $fileinfo, $role, $path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach (glob($path) as $filename) {
|
||||
addPackageFile($pkg, new SplFileInfo($filename), $role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
|
||||
{
|
||||
$fileNode = $pkg->contents->dir->addChild('file');
|
||||
$fileNode->addAttribute('name', $filepath = $fileinfo->getPathname());
|
||||
$fileNode->addAttribute('role', $role);
|
||||
$fileNode->addAttribute('md5sum', md5_file($filepath));
|
||||
|
||||
$installNode = $pkg->phprelease->filelist->addChild('install');
|
||||
$installNode->addAttribute('name', $filepath);
|
||||
$installNode->addAttribute('as', !$baseDir ? basename($filepath) : substr($filepath, strlen($baseDir) + 1));
|
||||
}
|
||||
|
||||
function generatePackageXml($packageINI)
|
||||
{
|
||||
$XML = <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<package packagerversion="1.4.10" version="2.0"
|
||||
xmlns="http://pear.php.net/dtd/package-2.0"
|
||||
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
|
||||
http://pear.php.net/dtd/tasks-1.0.xsd
|
||||
http://pear.php.net/dtd/package-2.0
|
||||
http://pear.php.net/dtd/package-2.0.xsd" />
|
||||
XML;
|
||||
|
||||
$cfg = parse_ini_file($packageINI, true);
|
||||
$pkg = new SimpleXMLElement($XML);
|
||||
|
||||
$pkg->name = $cfg['package']['name'];
|
||||
$pkg->channel = $cfg['package']['channel'];
|
||||
$pkg->summary = $cfg['package']['desc'];
|
||||
$pkg->description = $cfg['package']['desc'];
|
||||
|
||||
$author = parseAuthor($cfg['package']['author']);
|
||||
$pkg->addChild('lead');
|
||||
$pkg->lead->name = $author['name'];
|
||||
$pkg->lead->user = $author['user'];
|
||||
$pkg->lead->email = $author['email'];
|
||||
$pkg->lead->active = 'yes';
|
||||
|
||||
$datetime = new DateTime('now');
|
||||
$pkg->date = $datetime->format('Y-m-d');
|
||||
$pkg->time = $datetime->format('H:i:s');
|
||||
|
||||
$pkg->addChild('version');
|
||||
$pkg->version->release = $cfg['package']['version'];
|
||||
$pkg->version->api = $cfg['package']['version'];
|
||||
|
||||
$pkg->addChild('stability');
|
||||
$pkg->stability->release = $cfg['package']['stability'];
|
||||
$pkg->stability->api = $cfg['package']['stability'];
|
||||
|
||||
$pkg->license = $cfg['package']['license'];
|
||||
$pkg->notes = '-';
|
||||
|
||||
$pkg->addChild('contents')->addChild('dir')->addAttribute('name', '/');
|
||||
|
||||
$pkg->addChild('dependencies')->addChild('required');
|
||||
foreach ($cfg['require'] as $required => $version) {
|
||||
$version = parseVersion($version);
|
||||
$pkg->dependencies->required->addChild($required);
|
||||
|
||||
if (isset($version['min'])) {
|
||||
$pkg->dependencies->required->$required->min = $version['min'];
|
||||
}
|
||||
if (isset($version['max'])) {
|
||||
$pkg->dependencies->required->$required->min = $version['max'];
|
||||
}
|
||||
}
|
||||
|
||||
$pkg->addChild('phprelease')->addChild('filelist');
|
||||
|
||||
$pathToRole = array(
|
||||
'doc' => 'doc', 'docs' => 'doc', 'examples' => 'doc',
|
||||
'lib' => 'php', 'src' => 'php',
|
||||
'test' => 'test', 'tests' => 'test',
|
||||
);
|
||||
|
||||
foreach (array_merge($pathToRole, $cfg['roles'] ?: array()) as $path => $role) {
|
||||
addRolePath($pkg, $path, $role);
|
||||
}
|
||||
|
||||
return $pkg;
|
||||
}
|
||||
|
||||
function rewritePackageInstallAs($pkg)
|
||||
{
|
||||
foreach ($pkg->phprelease->filelist->install as $file) {
|
||||
if (preg_match('/^src\//', $file['name'])) {
|
||||
$file['as'] = "Predis/{$file['as']}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function savePackageXml($xml)
|
||||
{
|
||||
$dom = new DOMDocument("1.0");
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
$dom->loadXML($xml->asXML());
|
||||
|
||||
file_put_contents('package.xml', $dom->saveXML());
|
||||
}
|
||||
|
||||
function buildPackage()
|
||||
{
|
||||
passthru('pear -q package && rm package.xml');
|
||||
}
|
||||
|
||||
function modifyPhpunitXml($file)
|
||||
{
|
||||
$cfg = new SimpleXMLElement($file, null, true);
|
||||
|
||||
$cfg[0]['bootstrap'] = str_replace('tests/', '', $cfg[0]['bootstrap']);
|
||||
$cfg->testsuites->testsuite->directory = str_replace('tests/', '', $cfg->testsuites->testsuite->directory);
|
||||
|
||||
$cfg->saveXml($file);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
executeWithBackup(__DIR__.'/../phpunit.xml.dist', function ($file) {
|
||||
modifyPhpunitXml($file);
|
||||
|
||||
$pkg = generatePackageXml('package.ini');
|
||||
rewritePackageInstallAs($pkg);
|
||||
savePackageXml($pkg);
|
||||
|
||||
buildPackage();
|
||||
});
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
$options = array(
|
||||
'name' => 'predis',
|
||||
'project_path' => __DIR__ . '/../lib/',
|
||||
'project_path' => __DIR__ . '/../src',
|
||||
'compression' => Phar::NONE,
|
||||
'append_version' => true,
|
||||
);
|
||||
@@ -50,9 +50,9 @@ function getPharStub($options)
|
||||
return <<<EOSTUB
|
||||
<?php
|
||||
Phar::mapPhar('predis.phar');
|
||||
spl_autoload_register(function(\$class) {
|
||||
spl_autoload_register(function (\$class) {
|
||||
if (strpos(\$class, 'Predis\\\\') === 0) {
|
||||
\$file = 'phar://predis.phar/'.strtr(\$class, '\\\', '/').'.php';
|
||||
\$file = 'phar://predis.phar/'.strtr(substr(\$class, 7), '\\\', '/').'.php';
|
||||
if (file_exists(\$file)) {
|
||||
require \$file;
|
||||
return true;
|
||||
@@ -36,7 +36,7 @@ class CommandLine
|
||||
$getops = getopt(implode(array_keys($parameters)), $parameters);
|
||||
|
||||
$options = array(
|
||||
'source' => __DIR__ . "/../lib/",
|
||||
'source' => __DIR__ . "/../src",
|
||||
'output' => PredisFile::NS_ROOT . '.php',
|
||||
'exclude' => array(),
|
||||
);
|
||||
@@ -80,11 +80,10 @@ class PredisFile
|
||||
$this->namespaces = array();
|
||||
}
|
||||
|
||||
public static function from($libraryPath, Array $exclude = array())
|
||||
public static function from($libraryPath, array $exclude = array())
|
||||
{
|
||||
$nsroot = self::NS_ROOT;
|
||||
$predisFile = new PredisFile();
|
||||
$libIterator = new RecursiveDirectoryIterator("$libraryPath$nsroot");
|
||||
$libIterator = new RecursiveDirectoryIterator($libraryPath);
|
||||
|
||||
foreach (new RecursiveIteratorIterator($libIterator) as $classFile)
|
||||
{
|
||||
@@ -92,7 +91,7 @@ class PredisFile
|
||||
continue;
|
||||
}
|
||||
|
||||
$namespace = strtr(str_replace($libraryPath, '', $classFile->getPath()), '/', '\\');
|
||||
$namespace = self::NS_ROOT.strtr(str_replace($libraryPath, '', $classFile->getPath()), '/', '\\');
|
||||
|
||||
if (in_array(sprintf('%s\\%s', $namespace, $classFile->getBasename('.php')), $exclude)) {
|
||||
continue;
|
||||
@@ -184,7 +183,7 @@ class PredisFile
|
||||
{
|
||||
$namespaces = array_fill_keys(array_unique(
|
||||
array_map(
|
||||
function($fqn) { return PhpNamespace::extractName($fqn); },
|
||||
function ($fqn) { return PhpNamespace::extractName($fqn); },
|
||||
array_keys($dependencyScores)
|
||||
)
|
||||
), 0);
|
||||
@@ -200,7 +199,7 @@ class PredisFile
|
||||
|
||||
private function getOrderedClasses(PhpNamespace $phpNamespace, $classes)
|
||||
{
|
||||
$nsClassesFQNs = array_map(function($cl) { return $cl->getFQN(); }, $phpNamespace->getClasses());
|
||||
$nsClassesFQNs = array_map(function ($cl) { return $cl->getFQN(); }, $phpNamespace->getClasses());
|
||||
$nsOrderedClasses = array();
|
||||
|
||||
foreach ($nsClassesFQNs as $nsClassFQN) {
|
||||
@@ -321,13 +320,15 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
{
|
||||
private $use;
|
||||
private $aliases;
|
||||
private $reverseAliases;
|
||||
private $namespace;
|
||||
|
||||
public function __construct(PhpNamespace $namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->use = array();
|
||||
$this->aliases = array();
|
||||
$this->namespace = $namespace;
|
||||
$this->reverseAliases = array();
|
||||
}
|
||||
|
||||
public function add($use, $as = null)
|
||||
@@ -336,8 +337,35 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
return;
|
||||
}
|
||||
|
||||
$rename = null;
|
||||
$this->use[] = $use;
|
||||
$this->aliases[$as ?: PhpClass::extractName($use)] = $use;
|
||||
$aliasedClassName = $as ?: PhpClass::extractName($use);
|
||||
|
||||
if (isset($this->aliases[$aliasedClassName])) {
|
||||
$parentNs = $this->getParentNamespace();
|
||||
|
||||
if ($parentNs && false !== $pos = strrpos($parentNs, '\\')) {
|
||||
$parentNs = substr($parentNs, $pos);
|
||||
}
|
||||
|
||||
$newAlias = "{$parentNs}_{$aliasedClassName}";
|
||||
$rename = (object) array(
|
||||
'namespace' => $this->namespace,
|
||||
'from' => $aliasedClassName,
|
||||
'to' => $newAlias,
|
||||
);
|
||||
|
||||
$this->aliases[$newAlias] = $use;
|
||||
$as = $newAlias;
|
||||
} else {
|
||||
$this->aliases[$aliasedClassName] = $use;
|
||||
}
|
||||
|
||||
if ($as !== null) {
|
||||
$this->reverseAliases[$use] = $as;
|
||||
}
|
||||
|
||||
return $rename;
|
||||
}
|
||||
|
||||
public function getList()
|
||||
@@ -352,7 +380,15 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
|
||||
public function getPhpCode()
|
||||
{
|
||||
$reducer = function($str, $use) { return $str .= "use $use;\n"; };
|
||||
$reverseAliases = $this->reverseAliases;
|
||||
|
||||
$reducer = function ($str, $use) use ($reverseAliases) {
|
||||
if (isset($reverseAliases[$use])) {
|
||||
return $str .= "use $use as {$reverseAliases[$use]};\n";
|
||||
} else {
|
||||
return $str .= "use $use;\n";
|
||||
}
|
||||
};
|
||||
|
||||
return array_reduce($this->getList(), $reducer, '');
|
||||
}
|
||||
@@ -362,6 +398,15 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
public function getParentNamespace()
|
||||
{
|
||||
if (false !== $pos = strrpos($this->namespace, '\\')) {
|
||||
return substr($this->namespace, 0, $pos);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getFQN($className)
|
||||
{
|
||||
if (($nsSepFirst = strpos($className, '\\')) === false) {
|
||||
@@ -428,10 +473,19 @@ LICENSE;
|
||||
|
||||
private function extractData()
|
||||
{
|
||||
$renames = array();
|
||||
$useDirectives = $this->getNamespace()->getUseDirectives();
|
||||
|
||||
$useExtractor = function($m) use($useDirectives) {
|
||||
$useDirectives->add(($namespacedPath = $m[1]));
|
||||
$useExtractor = function ($m) use ($useDirectives, &$renames) {
|
||||
array_shift($m);
|
||||
|
||||
if (isset($m[1])) {
|
||||
$m[1] = str_replace(" as ", '', $m[1]);
|
||||
}
|
||||
|
||||
if ($rename = call_user_func_array(array($useDirectives, 'add'), $m)) {
|
||||
$renames[] = $rename;
|
||||
}
|
||||
};
|
||||
|
||||
$classBuffer = stream_get_contents(fopen($this->getFile()->getPathname(), 'r'));
|
||||
@@ -443,6 +497,10 @@ LICENSE;
|
||||
$classBuffer = preg_replace('/namespace\s+[\w\d_\\\\]+;\s?/', '', $classBuffer);
|
||||
$classBuffer = preg_replace_callback('/use\s+([\w\d_\\\\]+)(\s+as\s+.*)?;\s?\n?/', $useExtractor, $classBuffer);
|
||||
|
||||
foreach ($renames as $rename) {
|
||||
$classBuffer = str_replace($rename->from, $rename->to, $classBuffer);
|
||||
}
|
||||
|
||||
$this->body = trim($classBuffer);
|
||||
|
||||
$this->extractHierarchy();
|
||||
@@ -453,7 +511,7 @@ LICENSE;
|
||||
$implements = array();
|
||||
$extends = array();
|
||||
|
||||
$extractor = function($iterator, $callback) {
|
||||
$extractor = function ($iterator, $callback) {
|
||||
$className = '';
|
||||
$iterator->seek($iterator->key() + 1);
|
||||
|
||||
@@ -464,8 +522,7 @@ LICENSE;
|
||||
if (preg_match('/\s?,\s?/', $token)) {
|
||||
$callback(trim($className));
|
||||
$className = '';
|
||||
}
|
||||
else if ($token == '{') {
|
||||
} else if ($token == '{') {
|
||||
$callback(trim($className));
|
||||
return;
|
||||
}
|
||||
@@ -510,13 +567,13 @@ LICENSE;
|
||||
break;
|
||||
|
||||
case T_IMPLEMENTS:
|
||||
$extractor($iterator, function($fqn) use (&$implements) {
|
||||
$extractor($iterator, function ($fqn) use (&$implements) {
|
||||
$implements[] = $fqn;
|
||||
});
|
||||
break;
|
||||
|
||||
case T_EXTENDS:
|
||||
$extractor($iterator, function($fqn) use (&$extends) {
|
||||
$extractor($iterator, function ($fqn) use (&$extends) {
|
||||
$extends[] = $fqn;
|
||||
});
|
||||
break;
|
||||
+17
-2
@@ -5,6 +5,9 @@
|
||||
"keywords": ["nosql", "redis", "predis"],
|
||||
"homepage": "http://github.com/nrk/predis",
|
||||
"license": "MIT",
|
||||
"support": {
|
||||
"issues": "https://github.com/nrk/predis/issues"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Daniele Alessandri",
|
||||
@@ -13,9 +16,21 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol",
|
||||
"ext-curl": "Allows access to Webdis when paired with phpiredis"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {"Predis": "lib/"}
|
||||
"psr-4": {"Predis\\": "src/"}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
|
||||
// Developers can customize the distribution strategy used by the client
|
||||
// to distribute keys among a cluster of servers simply by creating a class
|
||||
// that implements the Predis\Distribution\IDistributionStrategy interface.
|
||||
|
||||
use Predis\Distribution\IDistributionStrategy;
|
||||
use Predis\Network\PredisCluster;
|
||||
|
||||
class NaiveDistributionStrategy implements IDistributionStrategy
|
||||
{
|
||||
private $nodes;
|
||||
private $nodesCount;
|
||||
|
||||
public function __constructor()
|
||||
{
|
||||
$this->nodes = array();
|
||||
$this->nodesCount = 0;
|
||||
}
|
||||
|
||||
public function add($node, $weight = null)
|
||||
{
|
||||
$this->nodes[] = $node;
|
||||
$this->nodesCount++;
|
||||
}
|
||||
|
||||
public function remove($node)
|
||||
{
|
||||
$this->nodes = array_filter($this->nodes, function($n) use($node) {
|
||||
return $n !== $node;
|
||||
});
|
||||
|
||||
$this->nodesCount = count($this->nodes);
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
$count = $this->nodesCount;
|
||||
if ($count === 0) {
|
||||
throw new RuntimeException('No connections');
|
||||
}
|
||||
|
||||
return $this->nodes[$count > 1 ? abs(crc32($key) % $count) : 0];
|
||||
}
|
||||
|
||||
public function generateKey($value)
|
||||
{
|
||||
return crc32($value);
|
||||
}
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'cluster' => function() {
|
||||
$distributor = new NaiveDistributionStrategy();
|
||||
return new PredisCluster($distributor);
|
||||
},
|
||||
);
|
||||
|
||||
$client = new Predis\Client($multiple_servers, $options);
|
||||
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$client->set("key:$i", str_pad($i, 4, '0', 0));
|
||||
$client->get("key:$i");
|
||||
}
|
||||
|
||||
$server1 = $client->getClientFor('first')->info();
|
||||
$server2 = $client->getClientFor('second')->info();
|
||||
|
||||
printf("Server '%s' has %d keys while server '%s' has %d keys.\n",
|
||||
'first', $server1['db15']['keys'], 'second', $server2['db15']['keys']
|
||||
);
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
|
||||
// Predis ships with a KeyPrefixProcessor class that is used to transparently
|
||||
// prefix each key before sending commands to Redis, even for complex commands
|
||||
// such as SORT, ZUNIONSTORE and ZINTERSTORE. Key prefixes are useful to create
|
||||
// user-level namespaces for you keyspace, thus eliminating the need for separate
|
||||
// logical databases.
|
||||
|
||||
$client = new Predis\Client($single_server, array('prefix' => 'nrk:'));
|
||||
|
||||
$client->mset(array('foo' => 'bar', 'lol' => 'wut'));
|
||||
var_dump($client->mget('foo', 'lol'));
|
||||
/*
|
||||
array(2) {
|
||||
[0]=> string(3) "bar"
|
||||
[1]=> string(3) "wut"
|
||||
}
|
||||
*/
|
||||
|
||||
var_dump($client->keys('*'));
|
||||
/*
|
||||
array(2) {
|
||||
[0]=> string(7) "nrk:foo"
|
||||
[1]=> string(7) "nrk:lol"
|
||||
}
|
||||
*/
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
|
||||
// redis can set keys and their relative values in one go
|
||||
// using MSET, then the same values can be retrieved with
|
||||
// a single command using MGET.
|
||||
|
||||
$mkv = array(
|
||||
'usr:0001' => 'First user',
|
||||
'usr:0002' => 'Second user',
|
||||
'usr:0003' => 'Third user'
|
||||
);
|
||||
|
||||
$client = new Predis\Client($single_server);
|
||||
|
||||
$client->mset($mkv);
|
||||
$retval = $client->mget(array_keys($mkv));
|
||||
|
||||
print_r($retval);
|
||||
|
||||
/* OUTPUT:
|
||||
Array
|
||||
(
|
||||
[0] => First user
|
||||
[1] => Second user
|
||||
[2] => Third user
|
||||
)
|
||||
*/
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
|
||||
// This example will not work with versions of Redis < 2.6.
|
||||
//
|
||||
// Additionally to the EVAL command defined in the current development profile, the new
|
||||
// Predis\Commands\ScriptedCommand base class can be used to build an higher abstraction
|
||||
// for our "scripted" commands so that they will appear just like any other command on
|
||||
// the client-side. This is a quick example used to implement INCREX.
|
||||
|
||||
use Predis\Commands\ScriptedCommand;
|
||||
|
||||
class IncrementExistingKey extends ScriptedCommand
|
||||
{
|
||||
public function getKeysCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getScript()
|
||||
{
|
||||
return
|
||||
<<<LUA
|
||||
local cmd = redis.call
|
||||
if cmd('exists', KEYS[1]) == 1 then
|
||||
return cmd('incr', KEYS[1])
|
||||
end
|
||||
LUA;
|
||||
}
|
||||
}
|
||||
|
||||
$client = new Predis\Client($single_server, 'dev');
|
||||
|
||||
$client->getProfile()->defineCommand('increx', 'IncrementExistingKey');
|
||||
|
||||
$client->set('foo', 10);
|
||||
|
||||
var_dump($client->increx('foo')); // int(11)
|
||||
var_dump($client->increx('bar')); // NULL
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
|
||||
// simple set and get scenario
|
||||
|
||||
$client = new Predis\Client($single_server);
|
||||
|
||||
$client->set('library', 'predis');
|
||||
$retval = $client->get('library');
|
||||
|
||||
var_dump($retval);
|
||||
|
||||
/* OUTPUT
|
||||
string(6) "predis"
|
||||
*/
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// Developers can implement Predis\Distribution\DistributorInterface to create
|
||||
// their own distributors used by the client to distribute keys among a cluster
|
||||
// of servers.
|
||||
|
||||
use Predis\Cluster\PredisStrategy;
|
||||
use Predis\Cluster\Distributor\DistributorInterface;
|
||||
use Predis\Cluster\Hash\HashGeneratorInterface;
|
||||
use Predis\Connection\Aggregate\PredisCluster;
|
||||
|
||||
class NaiveDistributor implements DistributorInterface, HashGeneratorInterface
|
||||
{
|
||||
private $nodes;
|
||||
private $nodesCount;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->nodes = array();
|
||||
$this->nodesCount = 0;
|
||||
}
|
||||
|
||||
public function add($node, $weight = null)
|
||||
{
|
||||
$this->nodes[] = $node;
|
||||
$this->nodesCount++;
|
||||
}
|
||||
|
||||
public function remove($node)
|
||||
{
|
||||
$this->nodes = array_filter($this->nodes, function ($n) use ($node) {
|
||||
return $n !== $node;
|
||||
});
|
||||
|
||||
$this->nodesCount = count($this->nodes);
|
||||
}
|
||||
|
||||
public function getSlot($hash)
|
||||
{
|
||||
return $this->nodesCount > 1 ? abs($hash % $this->nodesCount) : 0;
|
||||
}
|
||||
|
||||
public function getBySlot($slot)
|
||||
{
|
||||
return isset($this->nodes[$slot]) ? $this->nodes[$slot] : null;
|
||||
}
|
||||
|
||||
public function getByHash($hash)
|
||||
{
|
||||
if (!$this->nodesCount) {
|
||||
throw new RuntimeException('No connections.');
|
||||
}
|
||||
|
||||
$slot = $this->getSlot($hash);
|
||||
$node = $this->getBySlot($slot);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function get($value)
|
||||
{
|
||||
$hash = $this->hash($value);
|
||||
$node = $this->getByHash($hash);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function hash($value)
|
||||
{
|
||||
return crc32($value);
|
||||
}
|
||||
|
||||
public function getHashGenerator()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'cluster' => function () {
|
||||
$distributor = new NaiveDistributor();
|
||||
$strategy = new PredisStrategy($distributor);
|
||||
$cluster = new PredisCluster($strategy);
|
||||
|
||||
return $cluster;
|
||||
},
|
||||
);
|
||||
|
||||
$client = new Predis\Client($multiple_servers, $options);
|
||||
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$client->set("key:$i", str_pad($i, 4, '0', 0));
|
||||
$client->get("key:$i");
|
||||
}
|
||||
|
||||
$server1 = $client->getClientFor('first')->info();
|
||||
$server2 = $client->getClientFor('second')->info();
|
||||
|
||||
if (isset($server1['Keyspace'], $server2['Keyspace'])) {
|
||||
$server1 = $server1['Keyspace'];
|
||||
$server2 = $server2['Keyspace'];
|
||||
}
|
||||
|
||||
printf("Server '%s' has %d keys while server '%s' has %d keys.\n",
|
||||
'first', $server1['db15']['keys'], 'second', $server2['db15']['keys']
|
||||
);
|
||||
@@ -9,11 +9,15 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
use Predis\ConnectionParameters;
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Network\StreamConnection;
|
||||
// This is an example of how you can easily extend an existing connection class
|
||||
// and trace the execution of commands for debugging purposes. This can be quite
|
||||
// useful as a starting poing to understand how your application interacts with
|
||||
// Redis.
|
||||
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Connection\StreamConnection;
|
||||
|
||||
class SimpleDebuggableConnection extends StreamConnection
|
||||
{
|
||||
@@ -27,9 +31,9 @@ class SimpleDebuggableConnection extends StreamConnection
|
||||
parent::connect();
|
||||
}
|
||||
|
||||
private function storeDebug(ICommand $command, $direction)
|
||||
private function storeDebug(CommandInterface $command, $direction)
|
||||
{
|
||||
$firtsArg = $command->getArgument(0);
|
||||
$firtsArg = $command->getArgument(0);
|
||||
$timestamp = round(microtime(true) - $this->tstart, 4);
|
||||
|
||||
$debug = $command->getId();
|
||||
@@ -40,19 +44,19 @@ class SimpleDebuggableConnection extends StreamConnection
|
||||
$this->debugBuffer[] = $debug;
|
||||
}
|
||||
|
||||
public function writeCommand(ICommand $command)
|
||||
public function writeRequest(CommandInterface $command)
|
||||
{
|
||||
parent::writeCommand($command);
|
||||
parent::writeRequest($command);
|
||||
|
||||
$this->storeDebug($command, '->');
|
||||
}
|
||||
|
||||
public function readResponse(ICommand $command)
|
||||
public function readResponse(CommandInterface $command)
|
||||
{
|
||||
$reply = parent::readResponse($command);
|
||||
$response = parent::readResponse($command);
|
||||
$this->storeDebug($command, '<-');
|
||||
|
||||
return $reply;
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getDebugBuffer()
|
||||
@@ -72,18 +76,17 @@ $client->set('foo', 'bar');
|
||||
$client->get('foo');
|
||||
$client->info();
|
||||
|
||||
print_r($client->getConnection()->getDebugBuffer());
|
||||
var_export($client->getConnection()->getDebugBuffer());
|
||||
|
||||
/* OUTPUT:
|
||||
Array
|
||||
(
|
||||
[0] => SELECT 15 -> 127.0.0.1:6379 [0.0008s]
|
||||
[1] => SELECT 15 <- 127.0.0.1:6379 [0.0012s]
|
||||
[2] => SET foo -> 127.0.0.1:6379 [0.0014s]
|
||||
[3] => SET foo <- 127.0.0.1:6379 [0.0014s]
|
||||
[4] => GET foo -> 127.0.0.1:6379 [0.0016s]
|
||||
[5] => GET foo <- 127.0.0.1:6379 [0.0018s]
|
||||
[6] => INFO -> 127.0.0.1:6379 [0.002s]
|
||||
[7] => INFO <- 127.0.0.1:6379 [0.0025s]
|
||||
array (
|
||||
0 => 'SELECT 15 -> 127.0.0.1:6379 [0.0008s]',
|
||||
1 => 'SELECT 15 <- 127.0.0.1:6379 [0.001s]',
|
||||
2 => 'SET foo -> 127.0.0.1:6379 [0.001s]',
|
||||
3 => 'SET foo <- 127.0.0.1:6379 [0.0011s]',
|
||||
4 => 'GET foo -> 127.0.0.1:6379 [0.0013s]',
|
||||
5 => 'GET foo <- 127.0.0.1:6379 [0.0015s]',
|
||||
6 => 'INFO -> 127.0.0.1:6379 [0.0019s]',
|
||||
7 => 'INFO <- 127.0.0.1:6379 [0.0022s]',
|
||||
)
|
||||
*/
|
||||
@@ -9,28 +9,29 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
/*
|
||||
This is a basic example on how to use the Predis\DispatcherLoop class.
|
||||
// This is a basic example on how to use the Predis\DispatcherLoop class.
|
||||
//
|
||||
// To see this example in action you can just use redis-cli and publish some
|
||||
// messages to the 'events' and 'control' channel, e.g.:
|
||||
|
||||
To see this example in action you can just use redis-cli and publish some
|
||||
messages to the 'events' and 'control' channel, e.g.:
|
||||
|
||||
./redis-cli
|
||||
PUBLISH events first
|
||||
PUBLISH events second
|
||||
PUBLISH events third
|
||||
PUBLISH control terminate_dispatcher
|
||||
*/
|
||||
// ./redis-cli
|
||||
// PUBLISH events first
|
||||
// PUBLISH events second
|
||||
// PUBLISH events third
|
||||
// PUBLISH control terminate_dispatcher
|
||||
|
||||
// Create a client and disable r/w timeout on the socket
|
||||
$client = new Predis\Client($single_server + array('read_write_timeout' => 0));
|
||||
|
||||
// Create a Predis\DispatcherLoop instance and attach a bunch of callbacks.
|
||||
$dispatcher = new Predis\PubSub\DispatcherLoop($client);
|
||||
// Return an initialized PubSub consumer instance from the client.
|
||||
$pubsub = $client->pubSubLoop();
|
||||
|
||||
// Demonstrate how to use a callable class as a callback for Predis\DispatcherLoop.
|
||||
// Create a dispatcher loop instance and attach a bunch of callbacks.
|
||||
$dispatcher = new Predis\PubSub\DispatcherLoop($pubsub);
|
||||
|
||||
// Demonstrate how to use a callable class as a callback for the dispatcher loop.
|
||||
class EventsListener implements Countable
|
||||
{
|
||||
private $events;
|
||||
@@ -60,7 +61,7 @@ class EventsListener implements Countable
|
||||
$dispatcher->attachCallback('events', ($events = new EventsListener()));
|
||||
|
||||
// Attach a function to control the dispatcher loop termination with a message.
|
||||
$dispatcher->attachCallback('control', function($payload) use ($dispatcher) {
|
||||
$dispatcher->attachCallback('control', function ($payload) use ($dispatcher) {
|
||||
if ($payload === 'terminate_dispatcher') {
|
||||
$dispatcher->stop();
|
||||
}
|
||||
@@ -71,8 +72,8 @@ $dispatcher->attachCallback('control', function($payload) use ($dispatcher) {
|
||||
$dispatcher->run();
|
||||
|
||||
// Display our achievements!
|
||||
echo "We received {$events->count()} messages!\n";
|
||||
echo "We received {$events->count()} messages!", PHP_EOL;
|
||||
|
||||
// Say goodbye :-)
|
||||
$info = $client->info();
|
||||
print_r("Goodbye from Redis v{$info['redis_version']}!\n");
|
||||
$version = redis_version($client->info());
|
||||
echo "Goodbye from Redis $version!", PHP_EOL;
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
$client = new Predis\Client($single_server);
|
||||
|
||||
// Plain old SET and GET example...
|
||||
$client->set('library', 'predis');
|
||||
$response = $client->get('library');
|
||||
|
||||
var_export($response); echo PHP_EOL;
|
||||
/* OUTPUT: 'predis' */
|
||||
|
||||
// Redis has the MSET and MGET commands to set or get multiple keys in one go,
|
||||
// cases like this Predis accepts arguments for variadic commands both as a list
|
||||
// of arguments or an array containing all of the keys and/or values.
|
||||
$mkv = array(
|
||||
'uid:0001' => '1st user',
|
||||
'uid:0002' => '2nd user',
|
||||
'uid:0003' => '3rd user'
|
||||
);
|
||||
|
||||
$client->mset($mkv);
|
||||
$response = $client->mget(array_keys($mkv));
|
||||
|
||||
var_export($response); echo PHP_EOL;
|
||||
/* OUTPUT:
|
||||
array (
|
||||
0 => '1st user',
|
||||
1 => '2nd user',
|
||||
2 => '3rd user',
|
||||
) */
|
||||
|
||||
// Predis can also send "raw" commands to Redis. The difference between sending
|
||||
// commands to Redis the usual way and the "raw" way is that in the latter case
|
||||
// their arguments are not filtered nor responses coming from Redis are parsed.
|
||||
|
||||
$response = $client->executeRaw(array(
|
||||
'MGET', 'uid:0001', 'uid:0002', 'uid:0003'
|
||||
));
|
||||
|
||||
var_export($response); echo PHP_EOL;
|
||||
/* OUTPUT:
|
||||
array (
|
||||
0 => '1st user',
|
||||
1 => '2nd user',
|
||||
2 => '3rd user',
|
||||
) */
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// Predis can prefix keys found in commands arguments before sending commands to
|
||||
// Redis, even for complex commands such as SORT, ZUNIONSTORE and ZINTERSTORE.
|
||||
// Prefixing keys can be useful to create user-level namespaces for you keyspace
|
||||
// thus reducing the need for separate logical databases in certain scenarios.
|
||||
|
||||
$client = new Predis\Client($single_server, array('prefix' => 'nrk:'));
|
||||
|
||||
$client->mset(array('foo' => 'bar', 'lol' => 'wut'));
|
||||
var_export($client->mget('foo', 'lol'));
|
||||
/*
|
||||
array (
|
||||
0 => 'bar',
|
||||
1 => 'wut',
|
||||
)
|
||||
*/
|
||||
|
||||
var_export($client->keys('*'));
|
||||
/*
|
||||
array (
|
||||
0 => 'nrk:foo',
|
||||
1 => 'nrk:lol',
|
||||
)
|
||||
*/
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// This example will not work with versions of Redis < 2.6.
|
||||
//
|
||||
// Additionally to the EVAL command defined in the current development profile,
|
||||
// the Predis\Command\ScriptCommand class can be used to build an higher level
|
||||
// abstraction for "scriptable" commands so that they will appear just like any
|
||||
// other command on the client-side. This is a quick example used to implement
|
||||
// INCREX.
|
||||
|
||||
use Predis\Command\ScriptCommand;
|
||||
|
||||
class IncrementExistingKeysBy extends ScriptCommand
|
||||
{
|
||||
public function getKeysCount()
|
||||
{
|
||||
// Tell Predis to use all the arguments but the last one as arguments
|
||||
// for KEYS. The last one will be used to populate ARGV.
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function getScript()
|
||||
{
|
||||
return <<<LUA
|
||||
local cmd, insert = redis.call, table.insert
|
||||
local increment, results = ARGV[1], { }
|
||||
|
||||
for idx, key in ipairs(KEYS) do
|
||||
if cmd('exists', key) == 1 then
|
||||
insert(results, idx, cmd('incrby', key, increment))
|
||||
else
|
||||
insert(results, idx, false)
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
LUA;
|
||||
}
|
||||
}
|
||||
|
||||
$client = new Predis\Client($single_server, array(
|
||||
'profile' => function ($options) {
|
||||
$profile = $options->getDefault('profile');
|
||||
$profile->defineCommand('increxby', 'IncrementExistingKeysBy');
|
||||
|
||||
return $profile;
|
||||
}
|
||||
));
|
||||
|
||||
$client->mset('foo', 10, 'foobar', 100);
|
||||
|
||||
var_export($client->increxby('foo', 'foofoo', 'foobar', 50));
|
||||
|
||||
/*
|
||||
array (
|
||||
0 => 60,
|
||||
1 => NULL,
|
||||
2 => 150,
|
||||
)
|
||||
*/
|
||||
@@ -9,10 +9,10 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// This is a basic example on how to use the Predis\MonitorContext class.
|
||||
// You can use redis-cli to send commands to the same Redis instance your client is
|
||||
// This is a basic example on how to use the Predis\Monitor\Consumer class. You
|
||||
// can use redis-cli to send commands to the same Redis instance your client is
|
||||
// connected to, and then type "ECHO QUIT_MONITOR" in redis-cli when you want to
|
||||
// exit the monitor loop and terminate this script in a graceful way.
|
||||
|
||||
@@ -25,20 +25,20 @@ $timestamp = new DateTime();
|
||||
foreach (($monitor = $client->monitor()) as $event) {
|
||||
$timestamp->setTimestamp((int) $event->timestamp);
|
||||
|
||||
// If we notice a ECHO command with the message QUIT_MONITOR, we close the
|
||||
// monitor context and then break the loop.
|
||||
// If we notice a ECHO command with the message QUIT_MONITOR, we stop the
|
||||
// monitor consumer and then break the loop.
|
||||
if ($event->command === 'ECHO' && $event->arguments === '"QUIT_MONITOR"') {
|
||||
echo "Exiting the monitor loop...\n";
|
||||
$monitor->closeContext();
|
||||
echo "Exiting the monitor loop...", PHP_EOL;
|
||||
$monitor->stop();
|
||||
break;
|
||||
}
|
||||
|
||||
echo "* Received {$event->command} on DB {$event->database} at {$timestamp->format(DateTime::W3C)}\n";
|
||||
echo "* Received {$event->command} on DB {$event->database} at {$timestamp->format(DateTime::W3C)}", PHP_EOL;
|
||||
if (isset($event->arguments)) {
|
||||
echo " Arguments: {$event->arguments}\n";
|
||||
echo " Arguments: {$event->arguments}", PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
// Say goodbye :-)
|
||||
$info = $client->info();
|
||||
print_r("Goodbye from Redis v{$info['redis_version']}!\n");
|
||||
$version = redis_version($client->info());
|
||||
echo "Goodbye from Redis $version!", PHP_EOL;
|
||||
@@ -9,15 +9,15 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// When you have a whole set of consecutive commands to send to
|
||||
// a redis server, you can use a pipeline to improve performances.
|
||||
// When you have a whole set of consecutive commands to send to a redis server,
|
||||
// you can use a pipeline to dramatically improve performances. Pipelines can
|
||||
// greatly reduce the effects of network round-trips.
|
||||
|
||||
$client = new Predis\Client($single_server);
|
||||
|
||||
$replies = $client->pipeline(function($pipe) {
|
||||
$pipe->ping();
|
||||
$responses = $client->pipeline(function ($pipe) {
|
||||
$pipe->flushdb();
|
||||
$pipe->incrby('counter', 10);
|
||||
$pipe->incrby('counter', 30);
|
||||
@@ -26,22 +26,20 @@ $replies = $client->pipeline(function($pipe) {
|
||||
$pipe->mget('does_not_exist', 'counter');
|
||||
});
|
||||
|
||||
print_r($replies);
|
||||
var_export($responses);
|
||||
|
||||
/* OUTPUT:
|
||||
Array
|
||||
(
|
||||
[0] => 1
|
||||
[1] => 1
|
||||
[2] => 10
|
||||
[3] => 40
|
||||
[4] => 1
|
||||
[5] => 40
|
||||
[6] => Array
|
||||
(
|
||||
[0] =>
|
||||
[1] => 40
|
||||
)
|
||||
|
||||
array (
|
||||
0 => Predis\Response\Status::__set_state(array(
|
||||
'payload' => 'OK',
|
||||
)),
|
||||
1 => 10,
|
||||
2 => 40,
|
||||
3 => true,
|
||||
4 => '40',
|
||||
5 => array (
|
||||
0 => NULL,
|
||||
1 => '40',
|
||||
),
|
||||
)
|
||||
*/
|
||||
@@ -9,16 +9,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// Redis 2.0 features new commands that allow clients to subscribe for
|
||||
// events published on certain channels (PUBSUB).
|
||||
// Starting from Redis 2.0 clients can subscribe and listen for events published
|
||||
// on certain channels using a Publish/Subscribe (PUB/SUB) approach.
|
||||
|
||||
// Create a client and disable r/w timeout on the socket
|
||||
$client = new Predis\Client($single_server + array('read_write_timeout' => 0));
|
||||
|
||||
// Initialize a new pubsub context
|
||||
$pubsub = $client->pubSub();
|
||||
// Initialize a new pubsub consumer.
|
||||
$pubsub = $client->pubSubLoop();
|
||||
|
||||
// Subscribe to your channels
|
||||
$pubsub->subscribe('control_channel', 'notifications');
|
||||
@@ -30,32 +30,30 @@ $pubsub->subscribe('control_channel', 'notifications');
|
||||
foreach ($pubsub as $message) {
|
||||
switch ($message->kind) {
|
||||
case 'subscribe':
|
||||
echo "Subscribed to {$message->channel}\n";
|
||||
echo "Subscribed to {$message->channel}", PHP_EOL;
|
||||
break;
|
||||
|
||||
case 'message':
|
||||
if ($message->channel == 'control_channel') {
|
||||
if ($message->payload == 'quit_loop') {
|
||||
echo "Aborting pubsub loop...\n";
|
||||
echo "Aborting pubsub loop...", PHP_EOL;
|
||||
$pubsub->unsubscribe();
|
||||
} else {
|
||||
echo "Received an unrecognized command: {$message->payload}.", PHP_EOL;
|
||||
}
|
||||
else {
|
||||
echo "Received an unrecognized command: {$message->payload}.\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo "Received the following message from {$message->channel}:\n",
|
||||
" {$message->payload}\n\n";
|
||||
} else {
|
||||
echo "Received the following message from {$message->channel}:",
|
||||
PHP_EOL, " {$message->payload}", PHP_EOL, PHP_EOL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Always unset the pubsub context instance when you are done! The
|
||||
// Always unset the pubsub consumer instance when you are done! The
|
||||
// class destructor will take care of cleanups and prevent protocol
|
||||
// desynchronizations between the client and the server.
|
||||
unset($pubsub);
|
||||
|
||||
// Say goodbye :-)
|
||||
$info = $client->info();
|
||||
print_r("Goodbye from Redis v{$info['redis_version']}!\n");
|
||||
$version = redis_version($client->info());
|
||||
echo "Goodbye from Redis $version!", PHP_EOL;
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
use Predis\Collection\Iterator;
|
||||
|
||||
// Starting from Redis 2.8, clients can iterate incrementally over collections
|
||||
// without blocking the server like it happens when a command such as KEYS is
|
||||
// executed on a Redis instance storing millions of keys. These commands are:
|
||||
//
|
||||
// - SCAN (iterates over the keyspace)
|
||||
// - SSCAN (iterates over members of a set)
|
||||
// - ZSCAN (iterates over members and ranks of a sorted set)
|
||||
// - HSCAN (iterates over fields and values of an hash).
|
||||
|
||||
// Predis provides a specialized abstraction for each command based on standard
|
||||
// SPL iterators making it possible to easily consume SCAN-based iterations in
|
||||
// your PHP code.
|
||||
//
|
||||
// See http://redis.io/commands/scan for more details.
|
||||
//
|
||||
|
||||
// Create a client using `2.8` as a server profile (needs Redis 2.8!)
|
||||
$client = new Predis\Client($single_server, array('profile' => '2.8'));
|
||||
|
||||
// Prepare some keys for our example
|
||||
$client->del('predis:set', 'predis:zset', 'predis:hash');
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$client->sadd('predis:set', "member:$i");
|
||||
$client->zadd('predis:zset', -$i, "member:$i");
|
||||
$client->hset('predis:hash', "field:$i", "value:$i");
|
||||
}
|
||||
|
||||
// === Keyspace iterator based on SCAN ===
|
||||
echo 'Scan the keyspace matching only our prefixed keys:', PHP_EOL;
|
||||
foreach (new Iterator\Keyspace($client, 'predis:*') as $key) {
|
||||
echo " - $key", PHP_EOL;
|
||||
}
|
||||
|
||||
/* OUTPUT
|
||||
Scan the keyspace matching only our prefixed keys:
|
||||
- predis:zset
|
||||
- predis:set
|
||||
- predis:hash
|
||||
*/
|
||||
|
||||
// === Set iterator based on SSCAN ===
|
||||
echo 'Scan members of `predis:set`:', PHP_EOL;
|
||||
foreach (new Iterator\SetKey($client, 'predis:set') as $member) {
|
||||
echo " - $member", PHP_EOL;
|
||||
}
|
||||
|
||||
/* OUTPUT
|
||||
Scan members of `predis:set`:
|
||||
- member:1
|
||||
- member:4
|
||||
- member:0
|
||||
- member:3
|
||||
- member:2
|
||||
*/
|
||||
|
||||
// === Sorted set iterator based on ZSCAN ===
|
||||
echo 'Scan members and ranks of `predis:zset`:', PHP_EOL;
|
||||
foreach (new Iterator\SortedSetKey($client, 'predis:zset') as $member => $rank) {
|
||||
echo " - $member [rank: $rank]", PHP_EOL;
|
||||
}
|
||||
|
||||
/* OUTPUT
|
||||
Scan members and ranks of `predis:zset`:
|
||||
- member:4 [rank: -4]
|
||||
- member:3 [rank: -3]
|
||||
- member:2 [rank: -2]
|
||||
- member:1 [rank: -1]
|
||||
- member:0 [rank: 0]
|
||||
*/
|
||||
|
||||
// === Hash iterator based on HSCAN ===
|
||||
echo 'Scan fields and values of `predis:hash`:', PHP_EOL;
|
||||
foreach (new Iterator\HashKey($client, 'predis:hash') as $field => $value) {
|
||||
echo " - $field => $value", PHP_EOL;
|
||||
}
|
||||
|
||||
/* OUTPUT
|
||||
Scan fields and values of `predis:hash`:
|
||||
- field:0 => value:0
|
||||
- field:1 => value:1
|
||||
- field:2 => value:2
|
||||
- field:3 => value:3
|
||||
- field:4 => value:4
|
||||
*/
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// Predis allows to set Lua scripts as read-only operations for replication.
|
||||
// This works for both EVAL and EVALSHA and also for the client-side abstraction
|
||||
// built upon them (Predis\Command\ScriptCommand). This example shows a slightly
|
||||
// more complex configuration that injects a new script command in the server
|
||||
// profile used by the new client instance and marks it marks it as a read-only
|
||||
// operation for replication so that it will be executed on slaves.
|
||||
|
||||
use Predis\Command\ScriptCommand;
|
||||
use Predis\Connection\Aggregate\MasterSlaveReplication;
|
||||
use Predis\Replication\ReplicationStrategy;
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
// Define a new script command that returns all the fields of a variable number
|
||||
// of hashes with a single roundtrip.
|
||||
|
||||
class HashMultipleGetAll extends ScriptCommand
|
||||
{
|
||||
const BODY = <<<LUA
|
||||
local hashes = {}
|
||||
for _, key in pairs(KEYS) do
|
||||
table.insert(hashes, key)
|
||||
table.insert(hashes, redis.call('hgetall', key))
|
||||
end
|
||||
return hashes
|
||||
LUA;
|
||||
|
||||
public function getScript()
|
||||
{
|
||||
return self::BODY;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
$parameters = array(
|
||||
'tcp://127.0.0.1:6379/?alias=master',
|
||||
'tcp://127.0.0.1:6380/?alias=slave',
|
||||
);
|
||||
|
||||
$options = array(
|
||||
'profile' => function ($options, $option) {
|
||||
$profile = $options->getDefault($option);
|
||||
$profile->defineCommand('hmgetall', 'HashMultipleGetAll');
|
||||
|
||||
return $profile;
|
||||
},
|
||||
'replication' => function () {
|
||||
$strategy = new ReplicationStrategy();
|
||||
$strategy->setScriptReadOnly(HashMultipleGetAll::BODY);
|
||||
|
||||
$replication = new MasterSlaveReplication($strategy);
|
||||
|
||||
return $replication;
|
||||
},
|
||||
);
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
$client = new Predis\Client($parameters, $options);
|
||||
|
||||
// Execute the following commands on the master server using redis-cli:
|
||||
// $ ./redis-cli HMSET metavars foo bar hoge piyo
|
||||
// $ ./redis-cli HMSET servers master host1 slave host2
|
||||
|
||||
$hashes = $client->hmgetall('metavars', 'servers');
|
||||
|
||||
$replication = $client->getConnection();
|
||||
$stillOnSlave = $replication->getCurrent() === $replication->getConnectionById('slave');
|
||||
|
||||
echo "Is still on slave? ", $stillOnSlave ? 'YES!' : 'NO!', PHP_EOL;
|
||||
var_export($hashes);
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// Predis supports master / slave replication scenarios where write operations
|
||||
// are performed on the master server and read operations are executed against
|
||||
// one of the slaves. The behavior of commands or EVAL scripts can be customized
|
||||
// at will. As soon as a write operation is performed the client switches to the
|
||||
// master server for all the subsequent requests (either reads and writes).
|
||||
//
|
||||
// This example must be executed using the second Redis server configured as the
|
||||
// slave of the first one (see the "SLAVEOF" command).
|
||||
//
|
||||
|
||||
$parameters = array(
|
||||
'tcp://127.0.0.1:6379?database=15&alias=master',
|
||||
'tcp://127.0.0.1:6380?database=15&alias=slave',
|
||||
);
|
||||
|
||||
$options = array('replication' => true);
|
||||
|
||||
$client = new Predis\Client($parameters, $options);
|
||||
|
||||
// Read operation.
|
||||
$exists = $client->exists('foo') ? 'yes' : 'no';
|
||||
$current = $client->getConnection()->getCurrent()->getParameters();
|
||||
echo "Does 'foo' exist on {$current->alias}? $exists.", PHP_EOL;
|
||||
|
||||
// Write operation.
|
||||
$client->set('foo', 'bar');
|
||||
$current = $client->getConnection()->getCurrent()->getParameters();
|
||||
echo "Now 'foo' has been set to 'bar' on {$current->alias}!", PHP_EOL;
|
||||
|
||||
// Read operation.
|
||||
$bar = $client->get('foo');
|
||||
$current = $client->getConnection()->getCurrent()->getParameters();
|
||||
echo "We fetched 'foo' from {$current->alias} and its value is '$bar'.", PHP_EOL;
|
||||
|
||||
/* OUTPUT:
|
||||
Does 'foo' exist on slave? yes.
|
||||
Now 'foo' has been set to 'bar' on master!
|
||||
We fetched 'foo' from master and its value is 'bar'.
|
||||
*/
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// This example demonstrates how to use Predis to save PHP sessions on Redis.
|
||||
//
|
||||
// The value of `session.gc_maxlifetime` in `php.ini` will be used by default as
|
||||
// the TTL for keys holding session data but this value can be overridden when
|
||||
// creating the session handler instance using the `gc_maxlifetime` option.
|
||||
//
|
||||
// NOTE: this class requires PHP >= 5.4 but can be used on PHP 5.3 if a polyfill
|
||||
// for SessionHandlerInterface is provided either by you or an external package
|
||||
// like `symfony/http-foundation`.
|
||||
//
|
||||
// See http://www.php.net/class.sessionhandlerinterface.php for more details.
|
||||
//
|
||||
|
||||
if (!interface_exists('SessionHandlerInterface')) {
|
||||
die("ATTENTION: the session handler implemented by Predis requires PHP >= 5.4.0 ".
|
||||
"or a polyfill for SessionHandlerInterface provided by an external package.\n");
|
||||
}
|
||||
|
||||
// Instantiate a new client just like you would normally do. Using a prefix for
|
||||
// keys will effectively prefix all session keys with the specified string.
|
||||
$client = new Predis\Client($single_server, array('prefix' => 'sessions:'));
|
||||
|
||||
// Set `gc_maxlifetime` to specify a time-to-live of 5 seconds for session keys.
|
||||
$handler = new Predis\Session\Handler($client, array('gc_maxlifetime' => 5));
|
||||
|
||||
// Register the session handler.
|
||||
$handler->register();
|
||||
|
||||
// We just set a fixed session ID only for the sake of our example.
|
||||
session_id('example_session_id');
|
||||
|
||||
session_start();
|
||||
|
||||
if (isset($_SESSION['foo'])) {
|
||||
echo "Session has `foo` set to {$_SESSION['foo']}", PHP_EOL;
|
||||
} else {
|
||||
$_SESSION['foo'] = $value = mt_rand();
|
||||
echo "Empty session, `foo` has been set with $value", PHP_EOL;
|
||||
}
|
||||
@@ -11,6 +11,17 @@
|
||||
|
||||
require __DIR__.'/../autoload.php';
|
||||
|
||||
function redis_version($info)
|
||||
{
|
||||
if (isset($info['Server']['redis_version'])) {
|
||||
return $info['Server']['redis_version'];
|
||||
} elseif (isset($info['redis_version'])) {
|
||||
return $info['redis_version'];
|
||||
} else {
|
||||
return 'unknown version';
|
||||
}
|
||||
}
|
||||
|
||||
$single_server = array(
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
@@ -9,7 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
require 'SharedConfigurations.php';
|
||||
require __DIR__.'/shared.php';
|
||||
|
||||
// This is an implementation of an atomic client-side ZPOP using the support for
|
||||
// check-and-set (CAS) operations with MULTI/EXEC transactions, as described in
|
||||
@@ -19,9 +19,10 @@ require 'SharedConfigurations.php';
|
||||
//
|
||||
// ./redis-cli
|
||||
// SELECT 15
|
||||
// ZADD zset 1 a
|
||||
// ZADD zset 2 b
|
||||
// ZADD zset 3 c
|
||||
// ZADD zset 1 a 2 b 3 c
|
||||
//
|
||||
// Then execute this script four times and see its output.
|
||||
//
|
||||
|
||||
function zpop($client, $key)
|
||||
{
|
||||
@@ -33,7 +34,7 @@ function zpop($client, $key)
|
||||
// which the client bails out with an exception.
|
||||
);
|
||||
|
||||
$client->multiExec($options, function($tx) use ($key, &$element) {
|
||||
$client->transaction($options, function ($tx) use ($key, &$element) {
|
||||
@list($element) = $tx->zrange($key, 0, 0);
|
||||
|
||||
if (isset($element)) {
|
||||
@@ -48,4 +49,4 @@ function zpop($client, $key)
|
||||
$client = new Predis\Client($single_server);
|
||||
$zpopped = zpop($client, 'zset');
|
||||
|
||||
echo isset($zpopped) ? "ZPOPed $zpopped" : "Nothing to ZPOP!", "\n";
|
||||
echo isset($zpopped) ? "ZPOPed $zpopped" : "Nothing to ZPOP!", PHP_EOL;
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
/**
|
||||
* Implements a lightweight PSR-0 compliant autoloader.
|
||||
*
|
||||
* @author Eric Naeseth <eric@thumbtack.com>
|
||||
*/
|
||||
class Autoloader
|
||||
{
|
||||
private $baseDir;
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* @param string $baseDirectory Base directory where the source files are located.
|
||||
*/
|
||||
public function __construct($baseDirectory = null)
|
||||
{
|
||||
$this->baseDir = $baseDirectory ?: dirname(__FILE__);
|
||||
$this->prefix = __NAMESPACE__ . '\\';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the autoloader class with the PHP SPL autoloader.
|
||||
*/
|
||||
public static function register()
|
||||
{
|
||||
spl_autoload_register(array(new self, 'autoload'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a class from a file using its fully qualified name.
|
||||
*
|
||||
* @param string $className Fully qualified name of a class.
|
||||
*/
|
||||
public function autoload($className)
|
||||
{
|
||||
if (0 !== strpos($className, $this->prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$relativeClassName = substr($className, strlen($this->prefix));
|
||||
$classNameParts = explode('\\', $relativeClassName);
|
||||
|
||||
require_once $this->baseDir.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $classNameParts).'.php';
|
||||
}
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Options\IClientOptions;
|
||||
use Predis\Network\IConnection;
|
||||
use Predis\Network\IConnectionSingle;
|
||||
use Predis\Profiles\IServerProfile;
|
||||
use Predis\Options\ClientOptions;
|
||||
use Predis\Profiles\ServerProfile;
|
||||
use Predis\PubSub\PubSubContext;
|
||||
use Predis\Pipeline\PipelineContext;
|
||||
use Predis\Transaction\MultiExecContext;
|
||||
|
||||
/**
|
||||
* Main class that exposes the most high-level interface to interact with Redis.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
const VERSION = '0.7.0';
|
||||
|
||||
private $options;
|
||||
private $profile;
|
||||
private $connection;
|
||||
private $connections;
|
||||
|
||||
/**
|
||||
* Initializes a new client with optional connection parameters and client options.
|
||||
*
|
||||
* @param mixed $parameters Connection parameters for one or multiple servers.
|
||||
* @param mixed $options Options that specify certain behaviours for the client.
|
||||
*/
|
||||
public function __construct($parameters = null, $options = null)
|
||||
{
|
||||
$options = $this->filterOptions($options);
|
||||
$this->options = $options;
|
||||
$this->profile = $options->profile;
|
||||
$this->connections = $options->connections;
|
||||
$this->connection = $this->initializeConnection($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Predis\Options\ClientOptions from various types of
|
||||
* arguments (string, array, Predis\Profiles\ServerProfile) or returns the
|
||||
* passed object if it is an instance of Predis\Options\ClientOptions.
|
||||
*
|
||||
* @param mixed $options Client options.
|
||||
* @return ClientOptions
|
||||
*/
|
||||
protected function filterOptions($options)
|
||||
{
|
||||
if ($options === null) {
|
||||
return new ClientOptions();
|
||||
}
|
||||
if (is_array($options)) {
|
||||
return new ClientOptions($options);
|
||||
}
|
||||
if ($options instanceof IClientOptions) {
|
||||
return $options;
|
||||
}
|
||||
if ($options instanceof IServerProfile || is_string($options)) {
|
||||
return new ClientOptions(array('profile' => $options));
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Invalid type for client options");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes one or multiple connection (cluster) objects from various
|
||||
* types of arguments (string, array) or returns the passed object if it
|
||||
* implements the Predis\Network\IConnection interface.
|
||||
*
|
||||
* @param mixed $parameters Connection parameters or instance.
|
||||
* @return IConnection
|
||||
*/
|
||||
protected function initializeConnection($parameters)
|
||||
{
|
||||
if ($parameters instanceof IConnection) {
|
||||
return $parameters;
|
||||
}
|
||||
if (is_array($parameters) && isset($parameters[0])) {
|
||||
return $this->connections->createCluster($this->options->cluster, $parameters, $this->profile);
|
||||
}
|
||||
|
||||
return $this->connections->create($parameters, $this->profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server profile used by the client.
|
||||
*
|
||||
* @return IServerProfile
|
||||
*/
|
||||
public function getProfile()
|
||||
{
|
||||
return $this->profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client options specified upon initialization.
|
||||
*
|
||||
* @return ClientOptions
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection factory object used by the client.
|
||||
*
|
||||
* @return IConnectionFactory
|
||||
*/
|
||||
public function getConnectionFactory()
|
||||
{
|
||||
return $this->connections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of a client for the specified connection when the
|
||||
* client is connected to a cluster. The new instance will use the same
|
||||
* options of the original client.
|
||||
*
|
||||
* @return Client
|
||||
*/
|
||||
public function getClientFor($connectionAlias)
|
||||
{
|
||||
if (($connection = $this->getConnection($connectionAlias)) === null) {
|
||||
throw new \InvalidArgumentException("Invalid connection alias: '$connectionAlias'");
|
||||
}
|
||||
|
||||
return new Client($connection, $this->options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the connection to the server.
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
$this->connection->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->connection->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
*
|
||||
* This method is an alias of disconnect().
|
||||
*/
|
||||
public function quit()
|
||||
{
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the underlying connection is connected to Redis.
|
||||
*
|
||||
* @return Boolean True means that the connection is open.
|
||||
* False means that the connection is closed.
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return $this->connection->isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying connection instance or, when connected to a cluster,
|
||||
* one of the connection instances identified by its alias.
|
||||
*
|
||||
* @param string $id The alias of a connection when connected to a cluster.
|
||||
* @return IConnection
|
||||
*/
|
||||
public function getConnection($id = null)
|
||||
{
|
||||
if (isset($id)) {
|
||||
if (!Helpers::isCluster($this->connection)) {
|
||||
$message = 'Retrieving connections by alias is supported only with clustered connections';
|
||||
throw new NotSupportedException($message);
|
||||
}
|
||||
return $this->connection->getConnectionById($id);
|
||||
}
|
||||
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dinamically invokes a Redis command with the specified arguments.
|
||||
*
|
||||
* @param string $method The name of a Redis command.
|
||||
* @param array $arguments The arguments for the command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
$command = $this->profile->createCommand($method, $arguments);
|
||||
return $this->connection->executeCommand($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the specified Redis command.
|
||||
*
|
||||
* @param string $method The name of a Redis command.
|
||||
* @param array $arguments The arguments for the command.
|
||||
* @return ICommand
|
||||
*/
|
||||
public function createCommand($method, $arguments = array())
|
||||
{
|
||||
return $this->profile->createCommand($method, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the specified Redis command.
|
||||
*
|
||||
* @param ICommand $command A Redis command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function executeCommand(ICommand $command)
|
||||
{
|
||||
return $this->connection->executeCommand($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the specified Redis command on all the nodes of a cluster.
|
||||
*
|
||||
* @param ICommand $command A Redis command.
|
||||
* @return array
|
||||
*/
|
||||
public function executeCommandOnShards(ICommand $command)
|
||||
{
|
||||
if (Helpers::isCluster($this->connection)) {
|
||||
$replies = array();
|
||||
|
||||
foreach ($this->connection as $connection) {
|
||||
$replies[] = $connection->executeCommand($command);
|
||||
}
|
||||
|
||||
return $replies;
|
||||
}
|
||||
|
||||
return array($this->connection->executeCommand($command));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the specified initializer method on $this with 0, 1 or 2 arguments.
|
||||
*
|
||||
* TODO: Invert $argv and $initializer.
|
||||
*
|
||||
* @param array $argv Arguments for the initializer.
|
||||
* @param string $initializer The initializer method.
|
||||
* @return mixed
|
||||
*/
|
||||
private function sharedInitializer($argv, $initializer)
|
||||
{
|
||||
switch (count($argv)) {
|
||||
case 0:
|
||||
return $this->$initializer();
|
||||
|
||||
case 1:
|
||||
list($arg0) = $argv;
|
||||
return is_array($arg0) ? $this->$initializer($arg0) : $this->$initializer(null, $arg0);
|
||||
|
||||
case 2:
|
||||
list($arg0, $arg1) = $argv;
|
||||
return $this->$initializer($arg0, $arg1);
|
||||
|
||||
default:
|
||||
return $this->$initializer($this, $argv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new pipeline context and returns it, or returns the results of
|
||||
* a pipeline executed inside the optionally provided callable object.
|
||||
*
|
||||
* @param mixed $arg,... Options for the context, a callable object, or both.
|
||||
* @return PipelineContext|array
|
||||
*/
|
||||
public function pipeline(/* arguments */)
|
||||
{
|
||||
return $this->sharedInitializer(func_get_args(), 'initPipeline');
|
||||
}
|
||||
|
||||
/**
|
||||
* Pipeline context initializer.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return PipelineContext|array
|
||||
*/
|
||||
protected function initPipeline(Array $options = null, $callable = null)
|
||||
{
|
||||
$pipeline = new PipelineContext($this, $options);
|
||||
return $this->pipelineExecute($pipeline, $callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a pipeline context when a callable object is passed.
|
||||
*
|
||||
* @param array $options Options of the context initialization.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return PipelineContext|array
|
||||
*/
|
||||
private function pipelineExecute(PipelineContext $pipeline, $callable)
|
||||
{
|
||||
return isset($callable) ? $pipeline->execute($callable) : $pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transaction context and returns it, or returns the results of
|
||||
* a transaction executed inside the optionally provided callable object.
|
||||
*
|
||||
* @param mixed $arg,... Options for the context, a callable object, or both.
|
||||
* @return MultiExecContext|array
|
||||
*/
|
||||
public function multiExec(/* arguments */)
|
||||
{
|
||||
return $this->sharedInitializer(func_get_args(), 'initMultiExec');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction context initializer.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return MultiExecContext|array
|
||||
*/
|
||||
protected function initMultiExec(Array $options = null, $callable = null)
|
||||
{
|
||||
$transaction = new MultiExecContext($this, $options ?: array());
|
||||
return isset($callable) ? $transaction->execute($callable) : $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Publish / Subscribe context and returns it, or executes it
|
||||
* inside the optionally provided callable object.
|
||||
*
|
||||
* @param mixed $arg,... Options for the context, a callable object, or both.
|
||||
* @return MultiExecContext|array
|
||||
*/
|
||||
public function pubSub(/* arguments */)
|
||||
{
|
||||
return $this->sharedInitializer(func_get_args(), 'initPubSub');
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish / Subscribe context initializer.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return PubSubContext
|
||||
*/
|
||||
protected function initPubSub(Array $options = null, $callable = null)
|
||||
{
|
||||
$pubsub = new PubSubContext($this, $options);
|
||||
|
||||
if (!isset($callable)) {
|
||||
return $pubsub;
|
||||
}
|
||||
|
||||
foreach ($pubsub as $message) {
|
||||
if (call_user_func($callable, $pubsub, $message) === false) {
|
||||
$pubsub->closeContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new monitor context.
|
||||
*
|
||||
* @return MonitorContext
|
||||
*/
|
||||
public function monitor()
|
||||
{
|
||||
return new MonitorContext($this);
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use Predis\Helpers;
|
||||
use Predis\Distribution\INodeKeyGenerator;
|
||||
|
||||
/**
|
||||
* Base class for Redis commands.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
abstract class Command implements ICommand
|
||||
{
|
||||
private $hash;
|
||||
private $arguments = array();
|
||||
|
||||
/**
|
||||
* Returns a filtered array of the arguments.
|
||||
*
|
||||
* @param array $arguments List of arguments.
|
||||
* @return array
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(Array $arguments)
|
||||
{
|
||||
$this->arguments = $this->filterArguments($arguments);
|
||||
unset($this->hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arguments array without filtering.
|
||||
*
|
||||
* @param array $arguments List of arguments.
|
||||
*/
|
||||
public function setRawArguments(Array $arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
unset($this->hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument from the arguments list at the specified index.
|
||||
*
|
||||
* @param array $arguments Position of the argument.
|
||||
*/
|
||||
public function getArgument($index = 0)
|
||||
{
|
||||
if (isset($this->arguments[$index]) === true) {
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the command can return an hash for client-side sharding.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return isset($this->arguments[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified array of keys will generate the same hash.
|
||||
*
|
||||
* @param array $keys Array of keys.
|
||||
* @return Boolean
|
||||
*/
|
||||
protected function checkSameHashForKeys(Array $keys)
|
||||
{
|
||||
if (($count = count($keys)) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$currentKey = Helpers::extractKeyTag($keys[0]);
|
||||
|
||||
for ($i = 1; $i < $count; $i++) {
|
||||
$nextKey = Helpers::extractKeyTag($keys[$i]);
|
||||
if ($currentKey !== $nextKey) {
|
||||
return false;
|
||||
}
|
||||
$currentKey = $nextKey;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHash(INodeKeyGenerator $distributor)
|
||||
{
|
||||
if (isset($this->hash)) {
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
if ($this->canBeHashed()) {
|
||||
$key = Helpers::extractKeyTag($this->arguments[0]);
|
||||
$this->hash = $distributor->generateKey($key);
|
||||
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function used to reduce a list of arguments to a string.
|
||||
*
|
||||
* @param string $accumulator Temporary string.
|
||||
* @param string $argument Current argument.
|
||||
* @return string
|
||||
*/
|
||||
protected function toStringArgumentReducer($accumulator, $argument)
|
||||
{
|
||||
if (strlen($argument) > 32) {
|
||||
$argument = substr($argument, 0, 32) . '[...]';
|
||||
}
|
||||
$accumulator .= " $argument";
|
||||
|
||||
return $accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial string representation of the command with its arguments.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return array_reduce(
|
||||
$this->getArguments(),
|
||||
array($this, 'toStringArgumentReducer'),
|
||||
$this->getId()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/ping
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ConnectionPing extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'PING';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return $data === 'PONG' ? true : false;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use Predis\Distribution\INodeKeyGenerator;
|
||||
|
||||
/**
|
||||
* Defines an abstraction representing a Redis command.
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface ICommand
|
||||
{
|
||||
/**
|
||||
* Gets the ID of a Redis command.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId();
|
||||
|
||||
/**
|
||||
* Returns an hash of the command using the provided algorithm against the
|
||||
* key (used to calculate the distribution of keys with client-side sharding).
|
||||
*
|
||||
* @param INodeKeyGenerator $distributor Distribution algorithm.
|
||||
* @return int
|
||||
*/
|
||||
public function getHash(INodeKeyGenerator $distributor);
|
||||
|
||||
/**
|
||||
* Sets the arguments of the command.
|
||||
*
|
||||
* @param array $arguments List of arguments.
|
||||
*/
|
||||
public function setArguments(Array $arguments);
|
||||
|
||||
/**
|
||||
* Gets the arguments of the command.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getArguments();
|
||||
|
||||
/**
|
||||
* Parses a reply buffer and returns a PHP object.
|
||||
*
|
||||
* @param string $data Binary string containing the whole reply.
|
||||
* @return mixed
|
||||
*/
|
||||
public function parseResponse($data);
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/del
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class KeyDelete extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'DEL';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
$args = $this->getArguments();
|
||||
if (count($args) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->checkSameHashForKeys($args);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/rename
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class KeyRename extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'RENAME';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/rpoplpush
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ListPopLastPushHead extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'RPOPLPUSH';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return $this->checkSameHashForKeys($this->getArguments());
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/brpoplpush
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ListPopLastPushHeadBlocking extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'BRPOPLPUSH';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::skipLast($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return $this->checkSameHashForKeys(
|
||||
array_slice($args = $this->getArguments(), 0, count($args) - 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* Class that defines a few helpers method for prefixing keys.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PrefixHelpers
|
||||
{
|
||||
/**
|
||||
* Applies the specified prefix only the first argument.
|
||||
*
|
||||
* @param ICommand $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function first(ICommand $command, $prefix)
|
||||
{
|
||||
if ($arguments = $command->getArguments()) {
|
||||
$arguments[0] = "$prefix{$arguments[0]}";
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified prefix to all the arguments.
|
||||
*
|
||||
* @param ICommand $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function all(ICommand $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
|
||||
foreach ($arguments as &$key) {
|
||||
$key = "$prefix$key";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified prefix only to even arguments in the list.
|
||||
*
|
||||
* @param ICommand $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function interleaved(ICommand $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$length = count($arguments);
|
||||
|
||||
for ($i = 0; $i < $length; $i += 2) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified prefix to all the arguments but the last one.
|
||||
*
|
||||
* @param ICommand $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function skipLast(ICommand $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$length = count($arguments);
|
||||
|
||||
for ($i = 0; $i < $length - 1; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* Base class for Redis commands with prefixable keys.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
abstract class PrefixableCommand extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
if ($arguments = $this->getArguments()) {
|
||||
$arguments[0] = "$prefix{$arguments[0]}";
|
||||
$this->setRawArguments($arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands\Processors;
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
|
||||
/**
|
||||
* A command processor processes commands before they are sent to Redis.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface ICommandProcessor
|
||||
{
|
||||
/**
|
||||
* Processes a Redis command.
|
||||
*
|
||||
* @param ICommand $command Redis command.
|
||||
*/
|
||||
public function process(ICommand $command);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands\Processors;
|
||||
|
||||
/**
|
||||
* A command processor chain processes a command using multiple chained command
|
||||
* processor before it is sent to Redis.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface ICommandProcessorChain extends ICommandProcessor, \IteratorAggregate, \Countable
|
||||
{
|
||||
/**
|
||||
* Adds a command processor.
|
||||
*
|
||||
* @param ICommandProcessor $processor A command processor.
|
||||
*/
|
||||
public function add(ICommandProcessor $processor);
|
||||
|
||||
/**
|
||||
* Removes a command processor from the chain.
|
||||
*
|
||||
* @param ICommandProcessor $processor A command processor.
|
||||
*/
|
||||
public function remove(ICommandProcessor $processor);
|
||||
|
||||
/**
|
||||
* Returns an ordered list of the command processors in the chain.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProcessors();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands\Processors;
|
||||
|
||||
/**
|
||||
* Defines an object that can process commands using command processors.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IProcessingSupport
|
||||
{
|
||||
/**
|
||||
* Associates a command processor.
|
||||
*
|
||||
* @param ICommandProcessor $processor The command processor.
|
||||
*/
|
||||
public function setProcessor(ICommandProcessor $processor);
|
||||
|
||||
/**
|
||||
* Returns the associated command processor.
|
||||
*
|
||||
* @return ICommandProcessor
|
||||
*/
|
||||
public function getProcessor();
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands\Processors;
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Commands\IPrefixable;
|
||||
|
||||
/**
|
||||
* Command processor that is used to prefix the keys contained in the arguments
|
||||
* of a Redis command.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class KeyPrefixProcessor implements ICommandProcessor
|
||||
{
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* @param string $prefix Prefix for the keys.
|
||||
*/
|
||||
public function __construct($prefix)
|
||||
{
|
||||
$this->setPrefix($prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a prefix that is applied to all the keys.
|
||||
*
|
||||
* @param string $prefix Prefix for the keys.
|
||||
*/
|
||||
public function setPrefix($prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current prefix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPrefix()
|
||||
{
|
||||
return $this->prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ICommand $command)
|
||||
{
|
||||
if ($command instanceof IPrefixable) {
|
||||
$command->prefixKeys($this->prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/subscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PubSubSubscribe extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'SUBSCRIBE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/unsubscribe
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PubSubUnsubscribe extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'UNSUBSCRIBE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* Base class used to implement an higher level abstraction for "virtual"
|
||||
* commands based on EVAL.
|
||||
*
|
||||
* @link http://redis.io/commands/eval
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
abstract class ScriptedCommand extends ServerEval
|
||||
{
|
||||
/**
|
||||
* Gets the body of a Lua script.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public abstract function getScript();
|
||||
|
||||
/**
|
||||
* Gets the number of arguments that should be considered as keys.
|
||||
*
|
||||
* @todo Should we make a scripted command act by default as a variadic
|
||||
* command where the first argument is the key (KEYS[1]) and the
|
||||
* rest is the list of values (ARGV)?
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getKeysCount()
|
||||
{
|
||||
// The default behaviour for the base class is to use all the arguments
|
||||
// passed to a scripted command to populate the KEYS table in Lua.
|
||||
return count($this->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elements from the arguments that are identified as keys.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getKeys()
|
||||
{
|
||||
return array_slice($this->getArguments(), 2, $this->getKeysCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return array_merge(array($this->getScript(), $this->getKeysCount()), $arguments);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/eval
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerEval extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'EVAL';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
$arguments = $this->getArguments();
|
||||
|
||||
for ($i = 2; $i < $arguments[1] + 2; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$this->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the SHA1 hash of the body of the script.
|
||||
*
|
||||
* @return string SHA1 hash.
|
||||
*/
|
||||
public function getScriptHash()
|
||||
{
|
||||
return sha1($this->getArgument(0));
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/sinter
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class SetIntersection extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'SINTER';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return $this->checkSameHashForKeys($this->getArguments());
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/smove
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class SetMove extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'SMOVE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::skipLast($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
use Predis\Helpers;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/mget
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class StringGetMultiple extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'MGET';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
return Helpers::filterArrayArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return $this->checkSameHashForKeys($this->getArguments());
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/watch
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class TransactionWatch extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'WATCH';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
if (isset($arguments[0]) && is_array($arguments[0])) {
|
||||
return $arguments[0];
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Network\IConnectionSingle;
|
||||
|
||||
/**
|
||||
* Base exception class for network-related errors.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
abstract class CommunicationException extends PredisException
|
||||
{
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @param IConnectionSingle $connection Connection that generated the exception.
|
||||
* @param string $message Error message.
|
||||
* @param int $code Error code.
|
||||
* @param \Exception $innerException Inner exception for wrapping the original error.
|
||||
*/
|
||||
public function __construct(IConnectionSingle $connection,
|
||||
$message = null, $code = null, \Exception $innerException = null)
|
||||
{
|
||||
parent::__construct($message, $code, $innerException);
|
||||
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connection that generated the exception.
|
||||
*
|
||||
* @return IConnectionSingle
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the receiver should reset the underlying connection.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function shouldResetConnection()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Profiles\IServerProfile;
|
||||
use Predis\Network\IConnectionSingle;
|
||||
use Predis\Network\IConnectionCluster;
|
||||
use Predis\Profiles\ServerProfile;
|
||||
|
||||
/**
|
||||
* Provides a default factory for Redis connections that maps URI schemes
|
||||
* to connection classes implementing the Predis\Network\IConnectionSingle
|
||||
* interface.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ConnectionFactory implements IConnectionFactory
|
||||
{
|
||||
private $schemes;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the default connection factory class used by Predis.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->schemes = $this->getDefaultSchemes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a named array that maps URI schemes to connection classes.
|
||||
*
|
||||
* @return array Map of URI schemes and connection classes.
|
||||
*/
|
||||
protected function getDefaultSchemes()
|
||||
{
|
||||
return array(
|
||||
'tcp' => 'Predis\Network\StreamConnection',
|
||||
'unix' => 'Predis\Network\StreamConnection',
|
||||
'http' => 'Predis\Network\WebdisConnection',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided argument represents a valid connection class
|
||||
* implementing the Predis\Network\IConnectionSingle interface. Optionally,
|
||||
* callable objects are used for lazy initialization of connection objects.
|
||||
*
|
||||
* @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function checkInitializer($initializer)
|
||||
{
|
||||
if (is_callable($initializer)) {
|
||||
return $initializer;
|
||||
}
|
||||
|
||||
$initializerReflection = new \ReflectionClass($initializer);
|
||||
|
||||
if (!$initializerReflection->isSubclassOf('Predis\Network\IConnectionSingle')) {
|
||||
throw new \InvalidArgumentException(
|
||||
'A connection initializer must be a valid connection class or a callable object'
|
||||
);
|
||||
}
|
||||
|
||||
return $initializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function define($scheme, $initializer)
|
||||
{
|
||||
$this->schemes[$scheme] = $this->checkInitializer($initializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function undefine($scheme)
|
||||
{
|
||||
unset($this->schemes[$scheme]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create($parameters, IServerProfile $profile = null)
|
||||
{
|
||||
if (!$parameters instanceof IConnectionParameters) {
|
||||
$parameters = new ConnectionParameters($parameters ?: array());
|
||||
}
|
||||
|
||||
$scheme = $parameters->scheme;
|
||||
if (!isset($this->schemes[$scheme])) {
|
||||
throw new \InvalidArgumentException("Unknown connection scheme: $scheme");
|
||||
}
|
||||
|
||||
$initializer = $this->schemes[$scheme];
|
||||
if (!is_callable($initializer)) {
|
||||
$connection = new $initializer($parameters);
|
||||
$this->prepareConnection($connection, $profile ?: ServerProfile::getDefault());
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
$connection = call_user_func($initializer, $parameters, $profile);
|
||||
if (!$connection instanceof IConnectionSingle) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Objects returned by connection initializers must implement ' .
|
||||
'the Predis\Network\IConnectionSingle interface'
|
||||
);
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createCluster(IConnectionCluster $cluster, $parameters, IServerProfile $profile = null)
|
||||
{
|
||||
foreach ($parameters as $node) {
|
||||
$cluster->add($node instanceof IConnectionSingle ? $node : $this->create($node, $profile));
|
||||
}
|
||||
|
||||
return $cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a connection object after its initialization.
|
||||
*
|
||||
* @param IConnectionSingle $connection Instance of a connection object.
|
||||
* @param IServerProfile $profile $connection Instance of a connection object.
|
||||
*/
|
||||
protected function prepareConnection(IConnectionSingle $connection, IServerProfile $profile)
|
||||
{
|
||||
$parameters = $connection->getParameters();
|
||||
|
||||
if (isset($parameters->password)) {
|
||||
$command = $profile->createCommand('auth', array($parameters->password));
|
||||
$connection->pushInitCommand($command);
|
||||
}
|
||||
|
||||
if (isset($parameters->database)) {
|
||||
$command = $profile->createCommand('select', array($parameters->database));
|
||||
$connection->pushInitCommand($command);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\IConnectionParameters;
|
||||
use Predis\Options\IOption;
|
||||
|
||||
/**
|
||||
* Handles parsing and validation of connection parameters.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ConnectionParameters implements IConnectionParameters
|
||||
{
|
||||
private static $defaultParameters;
|
||||
private static $validators;
|
||||
|
||||
private $parameters;
|
||||
private $userDefined;
|
||||
|
||||
/**
|
||||
* @param string|array Connection parameters in the form of an URI string or a named array.
|
||||
*/
|
||||
public function __construct($parameters = array())
|
||||
{
|
||||
self::ensureDefaults();
|
||||
|
||||
if (!is_array($parameters)) {
|
||||
$parameters = $this->parseURI($parameters);
|
||||
}
|
||||
|
||||
$this->userDefined = array_keys($parameters);
|
||||
$this->parameters = $this->filter($parameters) + self::$defaultParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the default values and validators are initialized.
|
||||
*/
|
||||
private static function ensureDefaults()
|
||||
{
|
||||
if (!isset(self::$defaultParameters)) {
|
||||
self::$defaultParameters = array(
|
||||
'scheme' => 'tcp',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'database' => null,
|
||||
'password' => null,
|
||||
'connection_async' => false,
|
||||
'connection_persistent' => false,
|
||||
'connection_timeout' => 5.0,
|
||||
'read_write_timeout' => null,
|
||||
'alias' => null,
|
||||
'weight' => null,
|
||||
'path' => null,
|
||||
'iterable_multibulk' => false,
|
||||
'throw_errors' => true,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isset(self::$validators)) {
|
||||
$bool = function($value) { return (bool) $value; };
|
||||
$float = function($value) { return (float) $value; };
|
||||
$int = function($value) { return (int) $value; };
|
||||
|
||||
self::$validators = array(
|
||||
'port' => $int,
|
||||
'connection_async' => $bool,
|
||||
'connection_persistent' => $bool,
|
||||
'connection_timeout' => $float,
|
||||
'read_write_timeout' => $float,
|
||||
'iterable_multibulk' => $bool,
|
||||
'throw_errors' => $bool,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a default value and a validator for the specified parameter.
|
||||
*
|
||||
* @param string $parameter Name of the parameter.
|
||||
* @param mixed $default Default value or an instance of IOption.
|
||||
* @param mixed $callable A validator callback.
|
||||
*/
|
||||
public static function define($parameter, $default, $callable = null)
|
||||
{
|
||||
self::ensureDefaults();
|
||||
self::$defaultParameters[$parameter] = $default;
|
||||
|
||||
if ($default instanceof IOption) {
|
||||
self::$validators[$parameter] = $default;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($callable)) {
|
||||
unset(self::$validators[$parameter]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_callable($callable)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The validator for $parameter must be a callable object"
|
||||
);
|
||||
}
|
||||
|
||||
self::$validators[$parameter] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undefines the default value and validator for the specified parameter.
|
||||
*
|
||||
* @param string $parameter Name of the parameter.
|
||||
*/
|
||||
public static function undefine($parameter)
|
||||
{
|
||||
self::ensureDefaults();
|
||||
unset(self::$defaultParameters[$parameter], self::$validators[$parameter]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an URI string and returns an array of connection parameters.
|
||||
*
|
||||
* @param string $uri Connection string.
|
||||
* @return array
|
||||
*/
|
||||
private function parseURI($uri)
|
||||
{
|
||||
if (stripos($uri, 'unix') === 0) {
|
||||
// Hack to support URIs for UNIX sockets with minimal effort.
|
||||
$uri = str_ireplace('unix:///', 'unix://localhost/', $uri);
|
||||
}
|
||||
|
||||
if (($parsed = @parse_url($uri)) === false || !isset($parsed['host'])) {
|
||||
throw new ClientException("Invalid URI: $uri");
|
||||
}
|
||||
|
||||
if (isset($parsed['query'])) {
|
||||
foreach (explode('&', $parsed['query']) as $kv) {
|
||||
@list($k, $v) = explode('=', $kv);
|
||||
$parsed[$k] = $v;
|
||||
}
|
||||
unset($parsed['query']);
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and converts each value of the connection parameters array.
|
||||
*
|
||||
* @param array $parameters Connection parameters.
|
||||
* @return array
|
||||
*/
|
||||
private function filter(Array $parameters)
|
||||
{
|
||||
if (count($parameters) > 0) {
|
||||
$validators = array_intersect_key(self::$validators, $parameters);
|
||||
foreach ($validators as $parameter => $validator) {
|
||||
$parameters[$parameter] = $validator($parameters[$parameter]);
|
||||
}
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __get($parameter)
|
||||
{
|
||||
$value = $this->parameters[$parameter];
|
||||
|
||||
if ($value instanceof IOption) {
|
||||
$this->parameters[$parameter] = ($value = $value->getDefault());
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __isset($parameter)
|
||||
{
|
||||
return isset($this->parameters[$parameter]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified parameter has been set by the user.
|
||||
*
|
||||
* @param string $parameter Name of the parameter.
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isSetByUser($parameter)
|
||||
{
|
||||
return in_array($parameter, $this->userDefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getBaseURI()
|
||||
{
|
||||
if ($this->scheme === 'unix') {
|
||||
return "{$this->scheme}://{$this->path}";
|
||||
}
|
||||
|
||||
return "{$this->scheme}://{$this->host}:{$this->port}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI parts that must be omitted when calling __toString().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDisallowedURIParts()
|
||||
{
|
||||
return array('scheme', 'host', 'port', 'password', 'path');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$query = array();
|
||||
$parameters = $this->toArray();
|
||||
$reject = $this->getDisallowedURIParts();
|
||||
|
||||
foreach ($this->userDefined as $param) {
|
||||
if (in_array($param, $reject) || !isset($parameters[$param])) {
|
||||
continue;
|
||||
}
|
||||
$value = $parameters[$param];
|
||||
$query[] = "$param=" . ($value === false ? '0' : $value);
|
||||
}
|
||||
|
||||
if (count($query) === 0) {
|
||||
return $this->getBaseURI();
|
||||
}
|
||||
|
||||
return $this->getBaseURI() . '/?' . implode('&', $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
return array('parameters', 'userDefined');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
self::ensureDefaults();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Distribution;
|
||||
|
||||
/**
|
||||
* A distributor implements the logic to automatically distribute
|
||||
* keys among several nodes for client-side sharding.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IDistributionStrategy extends INodeKeyGenerator
|
||||
{
|
||||
/**
|
||||
* Adds a node to the distributor with an optional weight.
|
||||
*
|
||||
* @param mixed $node Node object.
|
||||
* @param int $weight Weight for the node.
|
||||
*/
|
||||
public function add($node, $weight = null);
|
||||
|
||||
/**
|
||||
* Removes a node from the distributor.
|
||||
*
|
||||
* @param mixed $node Node object.
|
||||
*/
|
||||
public function remove($node);
|
||||
|
||||
/**
|
||||
* Gets a node from the distributor using the computed hash of a key.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Distribution;
|
||||
|
||||
/**
|
||||
* A generator of node keys implements the logic used to calculate the hash of
|
||||
* a key to distribute the respective operations among nodes.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface INodeKeyGenerator
|
||||
{
|
||||
/**
|
||||
* Generates an hash that is used by the distributor algorithm
|
||||
*
|
||||
* @param string $value Value used to generate the hash.
|
||||
* @return int
|
||||
*/
|
||||
public function generateKey($value);
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Network\IConnection;
|
||||
use Predis\Network\IConnectionCluster;
|
||||
|
||||
/**
|
||||
* Defines a few helper methods.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class Helpers
|
||||
{
|
||||
/**
|
||||
* Checks if the specified connection represents a cluster.
|
||||
*
|
||||
* @param IConnection $connection Connection object.
|
||||
* @return Boolean
|
||||
*/
|
||||
public static function isCluster(IConnection $connection)
|
||||
{
|
||||
return $connection instanceof IConnectionCluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offers a generic and reusable method to handle exceptions generated by
|
||||
* a connection object.
|
||||
*
|
||||
* @param CommunicationException $exception Exception.
|
||||
*/
|
||||
public static function onCommunicationException(CommunicationException $exception)
|
||||
{
|
||||
if ($exception->shouldResetConnection()) {
|
||||
$connection = $exception->getConnection();
|
||||
if ($connection->isConnected()) {
|
||||
$connection->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the arguments array passed to a Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function filterArrayArguments(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 1 && is_array($arguments[0])) {
|
||||
return $arguments[0];
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the arguments array passed to a variadic Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function filterVariadicValues(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 2 && is_array($arguments[1])) {
|
||||
return array_merge(array($arguments[0]), $arguments[1]);
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only the hashable part of a key (delimited by "{...}"), or the
|
||||
* whole key if a key tag is not found in the string.
|
||||
*
|
||||
* @param string $key A key.
|
||||
* @return string
|
||||
*/
|
||||
public static function extractKeyTag($key)
|
||||
{
|
||||
$start = strpos($key, '{');
|
||||
if ($start !== false) {
|
||||
$end = strpos($key, '}', $start);
|
||||
if ($end !== false) {
|
||||
$key = substr($key, ++$start, $end - $start);
|
||||
}
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
use Predis\Profiles\IServerProfile;
|
||||
use Predis\Network\IConnectionCluster;
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by classes that provide their own mechanism
|
||||
* to create and initialize new instances of Predis\Network\IConnectionSingle.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IConnectionFactory
|
||||
{
|
||||
/**
|
||||
* Defines or overrides the connection class identified by a scheme prefix.
|
||||
*
|
||||
* @param string $scheme URI scheme identifying the connection class.
|
||||
* @param mixed $initializer FQN of a connection class or a callable object for lazy initialization.
|
||||
*/
|
||||
public function define($scheme, $initializer);
|
||||
|
||||
/**
|
||||
* Undefines the connection identified by a scheme prefix.
|
||||
*
|
||||
* @param string $scheme Parameters for the connection.
|
||||
*/
|
||||
public function undefine($scheme);
|
||||
|
||||
/**
|
||||
* Creates a new connection object.
|
||||
*
|
||||
* @param mixed $parameters Parameters for the connection.
|
||||
* @return Predis\Network\IConnectionSingle
|
||||
*/
|
||||
public function create($parameters, IServerProfile $profile = null);
|
||||
|
||||
/**
|
||||
* Prepares a cluster of connection objects.
|
||||
*
|
||||
* @param IConnectionCluster Instance of a connection cluster class.
|
||||
* @param array $parameters List of parameters for each connection object.
|
||||
* @return Predis\Network\IConnectionCluster
|
||||
*/
|
||||
public function createCluster(IConnectionCluster $cluster, $parameters, IServerProfile $profile = null);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by classes that provide their own mechanism
|
||||
* to parse and handle connection parameters.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IConnectionParameters
|
||||
{
|
||||
/**
|
||||
* Checks if the specified parameters is set.
|
||||
*
|
||||
* @param string $property Name of the property.
|
||||
* @return Boolean
|
||||
*/
|
||||
public function __isset($parameter);
|
||||
|
||||
/**
|
||||
* Returns the value of the specified parameter.
|
||||
*
|
||||
* @param string $parameter Name of the parameter.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($parameter);
|
||||
|
||||
/**
|
||||
* Returns an array representation of the connection parameters.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Iterators;
|
||||
|
||||
/**
|
||||
* Iterator that abstracts the access to multibulk replies and allows
|
||||
* them to be consumed by user's code in a streaming fashion.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
abstract class MultiBulkResponse implements \Iterator, \Countable
|
||||
{
|
||||
protected $position;
|
||||
protected $current;
|
||||
protected $replySize;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
if (++$this->position < $this->replySize) {
|
||||
$this->current = $this->getValue();
|
||||
}
|
||||
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->position < $this->replySize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items of the whole multibulk reply.
|
||||
*
|
||||
* This method should be used to get the size of the current multibulk
|
||||
* reply without using iterator_count, which actually consumes the
|
||||
* iterator to calculate the size (rewinding is not supported).
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return $this->replySize;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected abstract function getValue();
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Iterators;
|
||||
|
||||
use Predis\Network\IConnection;
|
||||
use Predis\Network\IConnectionSingle;
|
||||
|
||||
/**
|
||||
* Streams a multibulk reply.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class MultiBulkResponseSimple extends MultiBulkResponse
|
||||
{
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @param IConnectionSingle $connection Connection to Redis.
|
||||
* @param int $size Number of elements of the multibulk reply.
|
||||
*/
|
||||
public function __construct(IConnectionSingle $connection, $size)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->position = 0;
|
||||
$this->current = $size > 0 ? $this->getValue() : null;
|
||||
$this->replySize = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the synchronization of the client with the Redis protocol
|
||||
* then PHP's garbage collector kicks in (e.g. then the iterator goes
|
||||
* out of the scope of a foreach).
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->sync(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes the client with the queued elements that have not been
|
||||
* read from the connection by consuming the rest of the multibulk reply,
|
||||
* or simply by dropping the connection.
|
||||
*
|
||||
* @param Boolean $drop True to synchronize the client by dropping the connection.
|
||||
* False to synchronize the client by consuming the multibulk reply.
|
||||
*/
|
||||
public function sync($drop = false)
|
||||
{
|
||||
if ($drop == true) {
|
||||
if ($this->valid()) {
|
||||
$this->position = $this->replySize;
|
||||
$this->connection->disconnect();
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ($this->valid()) {
|
||||
$this->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next item of the multibulk reply from the server.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getValue()
|
||||
{
|
||||
return $this->connection->read();
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Iterators;
|
||||
|
||||
/**
|
||||
* Abstracts the access to a streamable list of tuples represented
|
||||
* as a multibulk reply that alternates keys and values.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class MultiBulkResponseTuple extends MultiBulkResponse implements \OuterIterator
|
||||
{
|
||||
private $iterator;
|
||||
|
||||
/**
|
||||
* @param MultiBulkResponseSimple $iterator Multibulk reply iterator.
|
||||
*/
|
||||
public function __construct(MultiBulkResponseSimple $iterator)
|
||||
{
|
||||
$virtualSize = count($iterator) / 2;
|
||||
$this->iterator = $iterator;
|
||||
$this->position = 0;
|
||||
$this->current = $virtualSize > 0 ? $this->getValue() : null;
|
||||
$this->replySize = $virtualSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInnerIterator()
|
||||
{
|
||||
return $this->iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->iterator->sync(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getValue()
|
||||
{
|
||||
$k = $this->iterator->current();
|
||||
$this->iterator->next();
|
||||
|
||||
$v = $this->iterator->current();
|
||||
$this->iterator->next();
|
||||
|
||||
return array($k, $v);
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis;
|
||||
|
||||
/**
|
||||
* Client-side abstraction of a Redis MONITOR context.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class MonitorContext implements \Iterator
|
||||
{
|
||||
private $client;
|
||||
private $isValid;
|
||||
private $position;
|
||||
|
||||
/**
|
||||
* @param Client Client instance used by the context.
|
||||
*/
|
||||
public function __construct(Client $client)
|
||||
{
|
||||
$this->checkCapabilities($client);
|
||||
$this->client = $client;
|
||||
$this->openContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically closes the context when PHP's garbage collector kicks in.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->closeContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the passed client instance satisfies the required conditions
|
||||
* needed to initialize a monitor context.
|
||||
*
|
||||
* @param Client Client instance used by the context.
|
||||
*/
|
||||
private function checkCapabilities(Client $client)
|
||||
{
|
||||
if (Helpers::isCluster($client->getConnection())) {
|
||||
throw new NotSupportedException('Cannot initialize a monitor context over a cluster of connections');
|
||||
}
|
||||
|
||||
if ($client->getProfile()->supportsCommand('monitor') === false) {
|
||||
throw new NotSupportedException('The current profile does not support the MONITOR command');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the context and sends the MONITOR command to the server.
|
||||
*
|
||||
* @param Client Client instance used by the context.
|
||||
*/
|
||||
protected function openContext()
|
||||
{
|
||||
$this->isValid = true;
|
||||
$monitor = $this->client->createCommand('monitor');
|
||||
$this->client->executeCommand($monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the context. Internally this is done by disconnecting from server
|
||||
* since there is no way to terminate the stream initialized by MONITOR.
|
||||
*/
|
||||
public function closeContext()
|
||||
{
|
||||
$this->client->disconnect();
|
||||
$this->isValid = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
// NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last message payload retrieved from the server.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->position++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the the context is still in a valid state to continue.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a new message from the server generated by MONITOR and
|
||||
* returns it when available.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
private function getValue()
|
||||
{
|
||||
$database = 0;
|
||||
$event = $this->client->getConnection()->read();
|
||||
|
||||
$callback = function($matches) use (&$database) {
|
||||
if (isset($matches[1])) {
|
||||
$database = (int) $matches[1];
|
||||
}
|
||||
return ' ';
|
||||
};
|
||||
|
||||
$event = preg_replace_callback('/ \(db (\d+)\) /', $callback, $event, 1);
|
||||
@list($timestamp, $command, $arguments) = split(' ', $event, 3);
|
||||
|
||||
return (object) array(
|
||||
'timestamp' => (float) $timestamp,
|
||||
'database' => $database,
|
||||
'command' => substr($command, 1, -1),
|
||||
'arguments' => $arguments,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Network;
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
|
||||
/**
|
||||
* Defines a connection object used to communicate with one or multiple
|
||||
* Redis servers.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IConnection
|
||||
{
|
||||
/**
|
||||
* Opens the connection.
|
||||
*/
|
||||
public function connect();
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
*/
|
||||
public function disconnect();
|
||||
|
||||
/**
|
||||
* Returns if the connection is open.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isConnected();
|
||||
|
||||
/**
|
||||
* Write a Redis command on the connection.
|
||||
*
|
||||
* @param ICommand $command Instance of a Redis command.
|
||||
*/
|
||||
public function writeCommand(ICommand $command);
|
||||
|
||||
/**
|
||||
* Reads the reply for a Redis command from the connection.
|
||||
*
|
||||
* @param ICommand $command Instance of a Redis command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function readResponse(ICommand $command);
|
||||
|
||||
/**
|
||||
* Writes a Redis command to the connection and reads back the reply.
|
||||
*
|
||||
* @param ICommand $command Instance of a Redis command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function executeCommand(ICommand $command);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Network;
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
|
||||
/**
|
||||
* Defines a cluster of Redis servers formed by aggregating multiple
|
||||
* connection objects.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IConnectionCluster extends IConnection
|
||||
{
|
||||
/**
|
||||
* Adds a connection instance to the cluster.
|
||||
*
|
||||
* @param IConnectionSingle $connection Instance of a connection.
|
||||
*/
|
||||
public function add(IConnectionSingle $connection);
|
||||
|
||||
/**
|
||||
* Removes the specified connection instance from the cluster.
|
||||
*
|
||||
* @param IConnectionSingle $connection Instance of a connection.
|
||||
* @return Boolean Returns true if the connection was in the pool.
|
||||
*/
|
||||
public function remove(IConnectionSingle $connection);
|
||||
|
||||
/**
|
||||
* Gets the actual connection instance in charge of the specified command.
|
||||
*
|
||||
* @param ICommand $command Instance of a Redis command.
|
||||
* @return IConnectionSingle
|
||||
*/
|
||||
public function getConnection(ICommand $command);
|
||||
|
||||
/**
|
||||
* Retrieves a connection instance from the cluster using an alias.
|
||||
*
|
||||
* @param string $connectionId Alias of a connection
|
||||
* @return IConnectionSingle
|
||||
*/
|
||||
public function getConnectionById($connectionId);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Network;
|
||||
|
||||
use Predis\Protocol\IProtocolProcessor;
|
||||
|
||||
/**
|
||||
* Defines a connection object used to communicate with a single Redis server
|
||||
* that leverages an external protocol processor to handle pluggable protocol
|
||||
* handlers.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IConnectionComposable extends IConnectionSingle
|
||||
{
|
||||
/**
|
||||
* Sets the protocol processor used by the connection.
|
||||
*
|
||||
* @param IProtocolProcessor $protocol Protocol processor.
|
||||
*/
|
||||
public function setProtocol(IProtocolProcessor $protocol);
|
||||
|
||||
/**
|
||||
* Gets the protocol processor used by the connection.
|
||||
*/
|
||||
public function getProtocol();
|
||||
|
||||
/**
|
||||
* Writes a buffer that contains a serialized Redis command.
|
||||
*
|
||||
* @param string $buffer Serialized Redis command.
|
||||
*/
|
||||
public function writeBytes($buffer);
|
||||
|
||||
/**
|
||||
* Reads a specified number of bytes from the connection.
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public function readBytes($length);
|
||||
|
||||
/**
|
||||
* Reads a line from the connection.
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
public function readLine();
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
use Predis\Network\IConnectionCluster;
|
||||
use Predis\Network\PredisCluster;
|
||||
|
||||
/**
|
||||
* Option class that returns a connection cluster to be used by a client.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ClientCluster extends Option
|
||||
{
|
||||
/**
|
||||
* Checks if the specified value is a valid instance of IConnectionCluster.
|
||||
*
|
||||
* @param IConnectionCluster $cluster Instance of a connection cluster.
|
||||
* @return IConnectionCluster
|
||||
*/
|
||||
protected function checkInstance($cluster)
|
||||
{
|
||||
if (!$cluster instanceof IConnectionCluster) {
|
||||
throw new \InvalidArgumentException('Instance of Predis\Network\IConnectionCluster expected');
|
||||
}
|
||||
|
||||
return $cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter(IClientOptions $options, $value)
|
||||
{
|
||||
if (is_callable($value)) {
|
||||
return $this->checkInstance(call_user_func($value, $options));
|
||||
}
|
||||
$initializer = $this->getInitializer($options, $value);
|
||||
|
||||
return $this->checkInstance($initializer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an initializer for the specified FQN or type.
|
||||
*
|
||||
* @param string $fqnOrType Type of cluster or FQN of a class implementing IConnectionCluster.
|
||||
* @param IClientOptions $options Instance of the client options.
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getInitializer(IClientOptions $options, $fqnOrType)
|
||||
{
|
||||
switch ($fqnOrType) {
|
||||
case 'predis':
|
||||
return function() { return new PredisCluster(); };
|
||||
|
||||
default:
|
||||
// TODO: we should not even allow non-string values here.
|
||||
if (is_string($fqnOrType) && !class_exists($fqnOrType)) {
|
||||
throw new \InvalidArgumentException('Class $fqnOrType does not exist');
|
||||
}
|
||||
return function() use($fqnOrType) {
|
||||
return new $fqnOrType();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefault(IClientOptions $options)
|
||||
{
|
||||
return new PredisCluster();
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
use Predis\IConnectionFactory;
|
||||
use Predis\ConnectionFactory;
|
||||
|
||||
/**
|
||||
* Option class that returns a connection factory to be used by a client.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ClientConnectionFactory extends Option
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter(IClientOptions $options, $value)
|
||||
{
|
||||
if ($value instanceof IConnectionFactory) {
|
||||
return $value;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$factory = $this->getDefault($options);
|
||||
foreach ($value as $scheme => $initializer) {
|
||||
$factory->define($scheme, $initializer);
|
||||
}
|
||||
return $factory;
|
||||
}
|
||||
if (is_string($value) && class_exists($value)) {
|
||||
if (!($factory = new $value()) && !$factory instanceof IConnectionFactory) {
|
||||
throw new \InvalidArgumentException("Class $value must be an instance of Predis\IConnectionFactory");
|
||||
}
|
||||
return $factory;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Invalid value for the connections option');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefault(IClientOptions $options)
|
||||
{
|
||||
return new ConnectionFactory();
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
/**
|
||||
* Class that manages client options with filtering and conversion.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ClientOptions implements IClientOptions
|
||||
{
|
||||
private $handlers;
|
||||
private $defined;
|
||||
private $options = array();
|
||||
|
||||
/**
|
||||
* @param array $options Array of client options.
|
||||
*/
|
||||
public function __construct(Array $options = array())
|
||||
{
|
||||
$this->handlers = $this->initialize($options);
|
||||
$this->defined = array_fill_keys(array_keys($options), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the default options are initialized.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaultOptions()
|
||||
{
|
||||
return array(
|
||||
'profile' => new ClientProfile(),
|
||||
'connections' => new ClientConnectionFactory(),
|
||||
'cluster' => new ClientCluster(),
|
||||
'prefix' => new ClientPrefix(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes client options handlers.
|
||||
*
|
||||
* @param array $options List of client options values.
|
||||
* @return array
|
||||
*/
|
||||
protected function initialize(Array $options)
|
||||
{
|
||||
$handlers = $this->getDefaultOptions();
|
||||
|
||||
foreach ($options as $option => $value) {
|
||||
if (isset($handlers[$option])) {
|
||||
$handler = $handlers[$option];
|
||||
$handlers[$option] = function($options) use($handler, $value) {
|
||||
return $handler->filter($options, $value);
|
||||
};
|
||||
}
|
||||
else {
|
||||
$this->options[$option] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified option is set.
|
||||
*
|
||||
* @param string $option Name of the option.
|
||||
* @return Boolean
|
||||
*/
|
||||
public function __isset($option)
|
||||
{
|
||||
return isset($this->defined[$option]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the specified option.
|
||||
*
|
||||
* @param string $option Name of the option.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($option)
|
||||
{
|
||||
if (isset($this->options[$option])) {
|
||||
return $this->options[$option];
|
||||
}
|
||||
|
||||
if (isset($this->handlers[$option])) {
|
||||
$handler = $this->handlers[$option];
|
||||
$value = $handler instanceof IOption ? $handler->getDefault($this) : $handler($this);
|
||||
$this->options[$option] = $value;
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
use Predis\Commands\Processors\KeyPrefixProcessor;
|
||||
|
||||
/**
|
||||
* Option class that handles the prefixing of keys in commands.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ClientPrefix extends Option
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter(IClientOptions $options, $value)
|
||||
{
|
||||
return new KeyPrefixProcessor($value);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
use Predis\Profiles\ServerProfile;
|
||||
use Predis\Profiles\IServerProfile;
|
||||
|
||||
/**
|
||||
* Option class that handles server profiles to be used by a client.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ClientProfile extends Option
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter(IClientOptions $options, $value)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$value = ServerProfile::get($value);
|
||||
if (isset($options->prefix)) {
|
||||
$value->setProcessor($options->prefix);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$value instanceof IServerProfile) {
|
||||
throw new \InvalidArgumentException('Invalid value for the profile option');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefault(IClientOptions $options)
|
||||
{
|
||||
$profile = ServerProfile::getDefault();
|
||||
if (isset($options->prefix)) {
|
||||
$profile->setProcessor($options->prefix);
|
||||
}
|
||||
|
||||
return $profile;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
/**
|
||||
* Implements a generic class used to dinamically define a client option.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class CustomOption implements IOption
|
||||
{
|
||||
private $filter;
|
||||
private $default;
|
||||
|
||||
/**
|
||||
* @param array $options List of options
|
||||
*/
|
||||
public function __construct(Array $options = array())
|
||||
{
|
||||
$this->filter = $this->ensureCallable($options, 'filter');
|
||||
$this->default = $this->ensureCallable($options, 'default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified value in the options array is a callable object.
|
||||
*
|
||||
* @param array $options Array of options
|
||||
* @param string $key Target option.
|
||||
*/
|
||||
private function ensureCallable($options, $key)
|
||||
{
|
||||
if (!isset($options[$key])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$callable = $options[$key];
|
||||
if (is_callable($callable)) {
|
||||
return $callable;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("The parameter $key must be callable");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter(IClientOptions $options, $value)
|
||||
{
|
||||
if (isset($value)) {
|
||||
if ($this->filter === null) {
|
||||
return $value;
|
||||
}
|
||||
$validator = $this->filter;
|
||||
|
||||
return $validator($options, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefault(IClientOptions $options)
|
||||
{
|
||||
if (!isset($this->default)) {
|
||||
return;
|
||||
}
|
||||
$default = $this->default;
|
||||
|
||||
return $default($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __invoke(IClientOptions $options, $value)
|
||||
{
|
||||
if (isset($value)) {
|
||||
return $this->filter($options, $value);
|
||||
}
|
||||
|
||||
return $this->getDefault($options);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
/**
|
||||
* Interface that defines a client option.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IOption
|
||||
{
|
||||
/**
|
||||
* Filters (and optionally converts) the passed value.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function filter(IClientOptions $options, $value);
|
||||
|
||||
/**
|
||||
* Returns a default value for the option.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault(IClientOptions $options);
|
||||
|
||||
/**
|
||||
* Filters a value and, if no value is specified, returns
|
||||
* the default one defined by the option.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __invoke(IClientOptions $options, $value);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Options;
|
||||
|
||||
/**
|
||||
* Implements a client option.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class Option implements IOption
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filter(IClientOptions $options, $value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefault(IClientOptions $options)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __invoke(IClientOptions $options, $value)
|
||||
{
|
||||
if (isset($value)) {
|
||||
return $this->filter($options, $value);
|
||||
}
|
||||
|
||||
return $this->getDefault($options);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\Network\IConnection;
|
||||
|
||||
/**
|
||||
* Defines a strategy to write a list of commands to the network
|
||||
* and read back their replies.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* Writes a list of commands to the network and reads back their replies.
|
||||
*
|
||||
* @param IConnection $connection Connection to Redis.
|
||||
* @param array $commands List of commands.
|
||||
* @return array
|
||||
*/
|
||||
public function execute(IConnection $connection, &$commands);
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\Client;
|
||||
use Predis\Helpers;
|
||||
use Predis\ClientException;
|
||||
use Predis\Commands\ICommand;
|
||||
|
||||
/**
|
||||
* Abstraction of a pipeline context where write and read operations
|
||||
* of commands and their replies over the network are pipelined.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class PipelineContext
|
||||
{
|
||||
private $client;
|
||||
private $executor;
|
||||
|
||||
private $pipeline = array();
|
||||
private $replies = array();
|
||||
private $running = false;
|
||||
|
||||
/**
|
||||
* @param Client Client instance used by the context.
|
||||
* @param array Options for the context initialization.
|
||||
*/
|
||||
public function __construct(Client $client, Array $options = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->executor = $this->createExecutor($client, $options ?: array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pipeline executor depending on the kind of the underlying
|
||||
* connection and the passed options.
|
||||
*
|
||||
* @param Client Client instance used by the context.
|
||||
* @param array Options for the context initialization.
|
||||
* @return IPipelineExecutor
|
||||
*/
|
||||
protected function createExecutor(Client $client, Array $options)
|
||||
{
|
||||
if (!$options) {
|
||||
return new StandardExecutor();
|
||||
}
|
||||
|
||||
if (isset($options['executor'])) {
|
||||
$executor = $options['executor'];
|
||||
if (!$executor instanceof IPipelineExecutor) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The executor option accepts only instances ' .
|
||||
'of Predis\Pipeline\IPipelineExecutor'
|
||||
);
|
||||
}
|
||||
return $executor;
|
||||
}
|
||||
|
||||
if (isset($options['safe']) && $options['safe'] == true) {
|
||||
$isCluster = Helpers::isCluster($client->getConnection());
|
||||
return $isCluster ? new SafeClusterExecutor() : new SafeExecutor();
|
||||
}
|
||||
|
||||
return new StandardExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a command into the pipeline buffer.
|
||||
*
|
||||
* @param string $method Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @return PipelineContext
|
||||
*/
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
$command = $this->client->createCommand($method, $arguments);
|
||||
$this->recordCommand($command);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a command instance into the pipeline buffer.
|
||||
*
|
||||
* @param ICommand $command Command to queue in the buffer.
|
||||
*/
|
||||
protected function recordCommand(ICommand $command)
|
||||
{
|
||||
$this->pipeline[] = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a command instance into the pipeline buffer.
|
||||
*
|
||||
* @param ICommand $command Command to queue in the buffer.
|
||||
*/
|
||||
public function executeCommand(ICommand $command)
|
||||
{
|
||||
$this->recordCommand($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the buffer that holds the queued commands.
|
||||
*
|
||||
* @param Boolean $send Specifies if the commands in the buffer should be sent to Redis.
|
||||
* @return PipelineContext
|
||||
*/
|
||||
public function flushPipeline($send = true)
|
||||
{
|
||||
if (count($this->pipeline) > 0) {
|
||||
if ($send) {
|
||||
$connection = $this->client->getConnection();
|
||||
$replies = $this->executor->execute($connection, $this->pipeline);
|
||||
$this->replies = array_merge($this->replies, $replies);
|
||||
}
|
||||
$this->pipeline = array();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the running status of the pipeline.
|
||||
*
|
||||
* @param Boolean $bool True if the pipeline is running.
|
||||
* False if the pipeline is not running.
|
||||
*/
|
||||
private function setRunning($bool)
|
||||
{
|
||||
if ($bool === true && $this->running === true) {
|
||||
throw new ClientException("This pipeline is already opened");
|
||||
}
|
||||
$this->running = $bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the actual execution of the whole pipeline.
|
||||
*
|
||||
* @param mixed $callable Callback for execution.
|
||||
* @return array
|
||||
*/
|
||||
public function execute($callable = null)
|
||||
{
|
||||
if ($callable && !is_callable($callable)) {
|
||||
throw new \InvalidArgumentException('Argument passed must be a callable object');
|
||||
}
|
||||
|
||||
$this->setRunning(true);
|
||||
$pipelineBlockException = null;
|
||||
|
||||
try {
|
||||
if ($callable !== null) {
|
||||
call_user_func($callable, $this);
|
||||
}
|
||||
$this->flushPipeline();
|
||||
}
|
||||
catch (\Exception $exception) {
|
||||
$pipelineBlockException = $exception;
|
||||
}
|
||||
|
||||
$this->setRunning(false);
|
||||
|
||||
if ($pipelineBlockException !== null) {
|
||||
throw $pipelineBlockException;
|
||||
}
|
||||
|
||||
return $this->replies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying client instance used by the pipeline object.
|
||||
*
|
||||
* @return Client
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying pipeline executor used by the pipeline object.
|
||||
*
|
||||
* @return IPipelineExecutor
|
||||
*/
|
||||
public function getExecutor()
|
||||
{
|
||||
return $this->executor;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\ServerException;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Network\IConnection;
|
||||
|
||||
/**
|
||||
* Implements a pipeline executor strategy for connection clusters that does
|
||||
* not fail when an error is encountered, but adds the returned error in the
|
||||
* replies array.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class SafeClusterExecutor implements IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(IConnection $connection, &$commands)
|
||||
{
|
||||
$connectionExceptions = array();
|
||||
$sizeofPipe = count($commands);
|
||||
$values = array();
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$cmdConnection = $connection->getConnection($command);
|
||||
|
||||
if (isset($connectionExceptions[spl_object_hash($cmdConnection)])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$cmdConnection->writeCommand($command);
|
||||
}
|
||||
catch (CommunicationException $exception) {
|
||||
$connectionExceptions[spl_object_hash($cmdConnection)] = $exception;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $sizeofPipe; $i++) {
|
||||
$command = $commands[$i];
|
||||
unset($commands[$i]);
|
||||
|
||||
$cmdConnection = $connection->getConnection($command);
|
||||
$connectionObjectHash = spl_object_hash($cmdConnection);
|
||||
|
||||
if (isset($connectionExceptions[$connectionObjectHash])) {
|
||||
$values[] = $connectionExceptions[$connectionObjectHash];
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $cmdConnection->readResponse($command);
|
||||
$values[] = $response instanceof \Iterator ? iterator_to_array($response) : $response;
|
||||
}
|
||||
catch (ServerException $exception) {
|
||||
$values[] = $exception->toResponseError();
|
||||
}
|
||||
catch (CommunicationException $exception) {
|
||||
$values[] = $exception;
|
||||
$connectionExceptions[$connectionObjectHash] = $exception;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\ServerException;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Network\IConnection;
|
||||
|
||||
/**
|
||||
* Implements a pipeline executor strategy that does not fail when an error is
|
||||
* encountered, but adds the returned error in the replies array.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class SafeExecutor implements IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(IConnection $connection, &$commands)
|
||||
{
|
||||
$sizeofPipe = count($commands);
|
||||
$values = array();
|
||||
|
||||
foreach ($commands as $command) {
|
||||
try {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
catch (CommunicationException $exception) {
|
||||
return array_fill(0, $sizeofPipe, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $sizeofPipe; $i++) {
|
||||
$command = $commands[$i];
|
||||
unset($commands[$i]);
|
||||
|
||||
try {
|
||||
$response = $connection->readResponse($command);
|
||||
$values[] = $response instanceof \Iterator ? iterator_to_array($response) : $response;
|
||||
}
|
||||
catch (ServerException $exception) {
|
||||
$values[] = $exception->toResponseError();
|
||||
}
|
||||
catch (CommunicationException $exception) {
|
||||
$toAdd = count($commands) - count($values);
|
||||
$values = array_merge($values, array_fill(0, $toAdd, $exception));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\ServerException;
|
||||
use Predis\Network\IConnection;
|
||||
|
||||
/**
|
||||
* Implements the standard pipeline executor strategy used
|
||||
* to write a list of commands and read their replies over
|
||||
* a connection to Redis.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class StandardExecutor implements IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(IConnection $connection, &$commands)
|
||||
{
|
||||
$sizeofPipe = count($commands);
|
||||
$values = array();
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
|
||||
try {
|
||||
for ($i = 0; $i < $sizeofPipe; $i++) {
|
||||
$response = $connection->readResponse($commands[$i]);
|
||||
$values[] = $response instanceof \Iterator
|
||||
? iterator_to_array($response)
|
||||
: $response;
|
||||
unset($commands[$i]);
|
||||
}
|
||||
}
|
||||
catch (ServerException $exception) {
|
||||
// Force disconnection to prevent protocol desynchronization.
|
||||
$connection->disconnect();
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
|
||||
/**
|
||||
* A server profile defines features and commands supported by certain
|
||||
* versions of Redis. Instances of Predis\Client should use a server
|
||||
* profile matching the version of Redis in use.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IServerProfile
|
||||
{
|
||||
/**
|
||||
* Gets a profile version corresponding to a Redis version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion();
|
||||
|
||||
/**
|
||||
* Checks if the profile supports the specified command.
|
||||
*
|
||||
* @param string $command Command ID.
|
||||
* @return Boolean
|
||||
*/
|
||||
public function supportsCommand($command);
|
||||
|
||||
/**
|
||||
* Checks if the profile supports the specified list of commands.
|
||||
*
|
||||
* @param array $commands List of command IDs.
|
||||
* @return string
|
||||
*/
|
||||
public function supportsCommands(Array $commands);
|
||||
|
||||
/**
|
||||
* Creates a new command instance.
|
||||
*
|
||||
* @param string $method Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @return Predis\Commands\ICommand
|
||||
*/
|
||||
public function createCommand($method, $arguments = array());
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\Commands\Processors\ICommandProcessor;
|
||||
use Predis\Commands\Processors\IProcessingSupport;
|
||||
|
||||
/**
|
||||
* Base class that implements common functionalities of server profiles.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
abstract class ServerProfile implements IServerProfile, IProcessingSupport
|
||||
{
|
||||
private static $profiles;
|
||||
|
||||
private $commands;
|
||||
private $processor;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->commands = $this->getSupportedCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of all the commands supported by the profile and their
|
||||
* actual PHP classes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected abstract function getSupportedCommands();
|
||||
|
||||
/**
|
||||
* Returns the default server profile.
|
||||
*
|
||||
* @return IServerProfile
|
||||
*/
|
||||
public static function getDefault()
|
||||
{
|
||||
return self::get('default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the development server profile.
|
||||
*
|
||||
* @return IServerProfile
|
||||
*/
|
||||
public static function getDevelopment()
|
||||
{
|
||||
return self::get('dev');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of all the server profiles supported by default and their
|
||||
* actual PHP classes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function getDefaultProfiles()
|
||||
{
|
||||
return array(
|
||||
'1.2' => 'Predis\Profiles\ServerVersion12',
|
||||
'2.0' => 'Predis\Profiles\ServerVersion20',
|
||||
'2.2' => 'Predis\Profiles\ServerVersion22',
|
||||
'2.4' => 'Predis\Profiles\ServerVersion24',
|
||||
'default' => 'Predis\Profiles\ServerVersion24',
|
||||
'dev' => 'Predis\Profiles\ServerVersionNext',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new server profile.
|
||||
*
|
||||
* @param string $alias Profile version or alias.
|
||||
* @param string $profileClass FQN of a class implementing Predis\Profiles\IServerProfile.
|
||||
*/
|
||||
public static function define($alias, $profileClass)
|
||||
{
|
||||
if (!isset(self::$profiles)) {
|
||||
self::$profiles = self::getDefaultProfiles();
|
||||
}
|
||||
|
||||
$profileReflection = new \ReflectionClass($profileClass);
|
||||
|
||||
if (!$profileReflection->isSubclassOf('Predis\Profiles\IServerProfile')) {
|
||||
throw new \InvalidArgumentException("Cannot register '$profileClass' as it is not a valid profile class");
|
||||
}
|
||||
|
||||
self::$profiles[$alias] = $profileClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified server profile.
|
||||
*
|
||||
* @param string $version Profile version or alias.
|
||||
* @return IServerProfile
|
||||
*/
|
||||
public static function get($version)
|
||||
{
|
||||
if (!isset(self::$profiles)) {
|
||||
self::$profiles = self::getDefaultProfiles();
|
||||
}
|
||||
if (!isset(self::$profiles[$version])) {
|
||||
throw new ClientException("Unknown server profile: $version");
|
||||
}
|
||||
|
||||
$profile = self::$profiles[$version];
|
||||
|
||||
return new $profile();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsCommands(Array $commands)
|
||||
{
|
||||
foreach ($commands as $command) {
|
||||
if ($this->supportsCommand($command) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsCommand($command)
|
||||
{
|
||||
return isset($this->commands[strtolower($command)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FQN of the class that represent the specified command ID
|
||||
* registered in the current server profile.
|
||||
*
|
||||
* @param string $command Command ID.
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandClass($command)
|
||||
{
|
||||
if (isset($this->commands[$command = strtolower($command)])) {
|
||||
return $this->commands[$command];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createCommand($method, $arguments = array())
|
||||
{
|
||||
$method = strtolower($method);
|
||||
if (!isset($this->commands[$method])) {
|
||||
throw new ClientException("'$method' is not a registered Redis command");
|
||||
}
|
||||
|
||||
$commandClass = $this->commands[$method];
|
||||
$command = new $commandClass();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
if (isset($this->processor)) {
|
||||
$this->processor->process($command);
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines new commands in the server profile.
|
||||
*
|
||||
* @param array $commands Named list of command IDs and their classes.
|
||||
*/
|
||||
public function defineCommands(Array $commands)
|
||||
{
|
||||
foreach ($commands as $alias => $command) {
|
||||
$this->defineCommand($alias, $command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a new commands in the server profile.
|
||||
*
|
||||
* @param string $alias Command ID.
|
||||
* @param string $command FQN of a class implementing Predis\Commands\ICommand.
|
||||
*/
|
||||
public function defineCommand($alias, $command)
|
||||
{
|
||||
$commandReflection = new \ReflectionClass($command);
|
||||
if (!$commandReflection->isSubclassOf('Predis\Commands\ICommand')) {
|
||||
throw new \InvalidArgumentException("Cannot register '$command' as it is not a valid Redis command");
|
||||
}
|
||||
$this->commands[strtolower($alias)] = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setProcessor(ICommandProcessor $processor = null)
|
||||
{
|
||||
$this->processor = $processor;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getProcessor()
|
||||
{
|
||||
return $this->processor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of server profile as its string representation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getVersion();
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
* Server profile for Redis v1.2.x.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerVersion12 extends ServerProfile
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return '1.2';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSupportedCommands()
|
||||
{
|
||||
return array(
|
||||
/* ---------------- Redis 1.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'exists' => 'Predis\Commands\KeyExists',
|
||||
'del' => 'Predis\Commands\KeyDelete',
|
||||
'type' => 'Predis\Commands\KeyType',
|
||||
'keys' => 'Predis\Commands\KeyKeysV12x',
|
||||
'randomkey' => 'Predis\Commands\KeyRandom',
|
||||
'rename' => 'Predis\Commands\KeyRename',
|
||||
'renamenx' => 'Predis\Commands\KeyRenamePreserve',
|
||||
'expire' => 'Predis\Commands\KeyExpire',
|
||||
'expireat' => 'Predis\Commands\KeyExpireAt',
|
||||
'ttl' => 'Predis\Commands\KeyTimeToLive',
|
||||
'move' => 'Predis\Commands\KeyMove',
|
||||
'sort' => 'Predis\Commands\KeySort',
|
||||
|
||||
/* commands operating on string values */
|
||||
'set' => 'Predis\Commands\StringSet',
|
||||
'setnx' => 'Predis\Commands\StringSetPreserve',
|
||||
'mset' => 'Predis\Commands\StringSetMultiple',
|
||||
'msetnx' => 'Predis\Commands\StringSetMultiplePreserve',
|
||||
'get' => 'Predis\Commands\StringGet',
|
||||
'mget' => 'Predis\Commands\StringGetMultiple',
|
||||
'getset' => 'Predis\Commands\StringGetSet',
|
||||
'incr' => 'Predis\Commands\StringIncrement',
|
||||
'incrby' => 'Predis\Commands\StringIncrementBy',
|
||||
'decr' => 'Predis\Commands\StringDecrement',
|
||||
'decrby' => 'Predis\Commands\StringDecrementBy',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpush' => 'Predis\Commands\ListPushTail',
|
||||
'lpush' => 'Predis\Commands\ListPushHead',
|
||||
'llen' => 'Predis\Commands\ListLength',
|
||||
'lrange' => 'Predis\Commands\ListRange',
|
||||
'ltrim' => 'Predis\Commands\ListTrim',
|
||||
'lindex' => 'Predis\Commands\ListIndex',
|
||||
'lset' => 'Predis\Commands\ListSet',
|
||||
'lrem' => 'Predis\Commands\ListRemove',
|
||||
'lpop' => 'Predis\Commands\ListPopFirst',
|
||||
'rpop' => 'Predis\Commands\ListPopLast',
|
||||
'rpoplpush' => 'Predis\Commands\ListPopLastPushHead',
|
||||
|
||||
/* commands operating on sets */
|
||||
'sadd' => 'Predis\Commands\SetAdd',
|
||||
'srem' => 'Predis\Commands\SetRemove',
|
||||
'spop' => 'Predis\Commands\SetPop',
|
||||
'smove' => 'Predis\Commands\SetMove',
|
||||
'scard' => 'Predis\Commands\SetCardinality',
|
||||
'sismember' => 'Predis\Commands\SetIsMember',
|
||||
'sinter' => 'Predis\Commands\SetIntersection',
|
||||
'sinterstore' => 'Predis\Commands\SetIntersectionStore',
|
||||
'sunion' => 'Predis\Commands\SetUnion',
|
||||
'sunionstore' => 'Predis\Commands\SetUnionStore',
|
||||
'sdiff' => 'Predis\Commands\SetDifference',
|
||||
'sdiffstore' => 'Predis\Commands\SetDifferenceStore',
|
||||
'smembers' => 'Predis\Commands\SetMembers',
|
||||
'srandmember' => 'Predis\Commands\SetRandomMember',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zadd' => 'Predis\Commands\ZSetAdd',
|
||||
'zincrby' => 'Predis\Commands\ZSetIncrementBy',
|
||||
'zrem' => 'Predis\Commands\ZSetRemove',
|
||||
'zrange' => 'Predis\Commands\ZSetRange',
|
||||
'zrevrange' => 'Predis\Commands\ZSetReverseRange',
|
||||
'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore',
|
||||
'zcard' => 'Predis\Commands\ZSetCardinality',
|
||||
'zscore' => 'Predis\Commands\ZSetScore',
|
||||
'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore',
|
||||
|
||||
/* connection related commands */
|
||||
'ping' => 'Predis\Commands\ConnectionPing',
|
||||
'auth' => 'Predis\Commands\ConnectionAuth',
|
||||
'select' => 'Predis\Commands\ConnectionSelect',
|
||||
'echo' => 'Predis\Commands\ConnectionEcho',
|
||||
'quit' => 'Predis\Commands\ConnectionQuit',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfo',
|
||||
'slaveof' => 'Predis\Commands\ServerSlaveOf',
|
||||
'monitor' => 'Predis\Commands\ServerMonitor',
|
||||
'dbsize' => 'Predis\Commands\ServerDatabaseSize',
|
||||
'flushdb' => 'Predis\Commands\ServerFlushDatabase',
|
||||
'flushall' => 'Predis\Commands\ServerFlushAll',
|
||||
'save' => 'Predis\Commands\ServerSave',
|
||||
'bgsave' => 'Predis\Commands\ServerBackgroundSave',
|
||||
'lastsave' => 'Predis\Commands\ServerLastSave',
|
||||
'shutdown' => 'Predis\Commands\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
* Server profile for Redis v2.0.x.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerVersion20 extends ServerProfile
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return '2.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSupportedCommands()
|
||||
{
|
||||
return array(
|
||||
/* ---------------- Redis 1.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'exists' => 'Predis\Commands\KeyExists',
|
||||
'del' => 'Predis\Commands\KeyDelete',
|
||||
'type' => 'Predis\Commands\KeyType',
|
||||
'keys' => 'Predis\Commands\KeyKeys',
|
||||
'randomkey' => 'Predis\Commands\KeyRandom',
|
||||
'rename' => 'Predis\Commands\KeyRename',
|
||||
'renamenx' => 'Predis\Commands\KeyRenamePreserve',
|
||||
'expire' => 'Predis\Commands\KeyExpire',
|
||||
'expireat' => 'Predis\Commands\KeyExpireAt',
|
||||
'ttl' => 'Predis\Commands\KeyTimeToLive',
|
||||
'move' => 'Predis\Commands\KeyMove',
|
||||
'sort' => 'Predis\Commands\KeySort',
|
||||
|
||||
/* commands operating on string values */
|
||||
'set' => 'Predis\Commands\StringSet',
|
||||
'setnx' => 'Predis\Commands\StringSetPreserve',
|
||||
'mset' => 'Predis\Commands\StringSetMultiple',
|
||||
'msetnx' => 'Predis\Commands\StringSetMultiplePreserve',
|
||||
'get' => 'Predis\Commands\StringGet',
|
||||
'mget' => 'Predis\Commands\StringGetMultiple',
|
||||
'getset' => 'Predis\Commands\StringGetSet',
|
||||
'incr' => 'Predis\Commands\StringIncrement',
|
||||
'incrby' => 'Predis\Commands\StringIncrementBy',
|
||||
'decr' => 'Predis\Commands\StringDecrement',
|
||||
'decrby' => 'Predis\Commands\StringDecrementBy',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpush' => 'Predis\Commands\ListPushTail',
|
||||
'lpush' => 'Predis\Commands\ListPushHead',
|
||||
'llen' => 'Predis\Commands\ListLength',
|
||||
'lrange' => 'Predis\Commands\ListRange',
|
||||
'ltrim' => 'Predis\Commands\ListTrim',
|
||||
'lindex' => 'Predis\Commands\ListIndex',
|
||||
'lset' => 'Predis\Commands\ListSet',
|
||||
'lrem' => 'Predis\Commands\ListRemove',
|
||||
'lpop' => 'Predis\Commands\ListPopFirst',
|
||||
'rpop' => 'Predis\Commands\ListPopLast',
|
||||
'rpoplpush' => 'Predis\Commands\ListPopLastPushHead',
|
||||
|
||||
/* commands operating on sets */
|
||||
'sadd' => 'Predis\Commands\SetAdd',
|
||||
'srem' => 'Predis\Commands\SetRemove',
|
||||
'spop' => 'Predis\Commands\SetPop',
|
||||
'smove' => 'Predis\Commands\SetMove',
|
||||
'scard' => 'Predis\Commands\SetCardinality',
|
||||
'sismember' => 'Predis\Commands\SetIsMember',
|
||||
'sinter' => 'Predis\Commands\SetIntersection',
|
||||
'sinterstore' => 'Predis\Commands\SetIntersectionStore',
|
||||
'sunion' => 'Predis\Commands\SetUnion',
|
||||
'sunionstore' => 'Predis\Commands\SetUnionStore',
|
||||
'sdiff' => 'Predis\Commands\SetDifference',
|
||||
'sdiffstore' => 'Predis\Commands\SetDifferenceStore',
|
||||
'smembers' => 'Predis\Commands\SetMembers',
|
||||
'srandmember' => 'Predis\Commands\SetRandomMember',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zadd' => 'Predis\Commands\ZSetAdd',
|
||||
'zincrby' => 'Predis\Commands\ZSetIncrementBy',
|
||||
'zrem' => 'Predis\Commands\ZSetRemove',
|
||||
'zrange' => 'Predis\Commands\ZSetRange',
|
||||
'zrevrange' => 'Predis\Commands\ZSetReverseRange',
|
||||
'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore',
|
||||
'zcard' => 'Predis\Commands\ZSetCardinality',
|
||||
'zscore' => 'Predis\Commands\ZSetScore',
|
||||
'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore',
|
||||
|
||||
/* connection related commands */
|
||||
'ping' => 'Predis\Commands\ConnectionPing',
|
||||
'auth' => 'Predis\Commands\ConnectionAuth',
|
||||
'select' => 'Predis\Commands\ConnectionSelect',
|
||||
'echo' => 'Predis\Commands\ConnectionEcho',
|
||||
'quit' => 'Predis\Commands\ConnectionQuit',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfo',
|
||||
'slaveof' => 'Predis\Commands\ServerSlaveOf',
|
||||
'monitor' => 'Predis\Commands\ServerMonitor',
|
||||
'dbsize' => 'Predis\Commands\ServerDatabaseSize',
|
||||
'flushdb' => 'Predis\Commands\ServerFlushDatabase',
|
||||
'flushall' => 'Predis\Commands\ServerFlushAll',
|
||||
'save' => 'Predis\Commands\ServerSave',
|
||||
'bgsave' => 'Predis\Commands\ServerBackgroundSave',
|
||||
'lastsave' => 'Predis\Commands\ServerLastSave',
|
||||
'shutdown' => 'Predis\Commands\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
'setex' => 'Predis\Commands\StringSetExpire',
|
||||
'append' => 'Predis\Commands\StringAppend',
|
||||
'substr' => 'Predis\Commands\StringSubstr',
|
||||
|
||||
/* commands operating on lists */
|
||||
'blpop' => 'Predis\Commands\ListPopFirstBlocking',
|
||||
'brpop' => 'Predis\Commands\ListPopLastBlocking',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zunionstore' => 'Predis\Commands\ZSetUnionStore',
|
||||
'zinterstore' => 'Predis\Commands\ZSetIntersectionStore',
|
||||
'zcount' => 'Predis\Commands\ZSetCount',
|
||||
'zrank' => 'Predis\Commands\ZSetRank',
|
||||
'zrevrank' => 'Predis\Commands\ZSetReverseRank',
|
||||
'zremrangebyrank' => 'Predis\Commands\ZSetRemoveRangeByRank',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hset' => 'Predis\Commands\HashSet',
|
||||
'hsetnx' => 'Predis\Commands\HashSetPreserve',
|
||||
'hmset' => 'Predis\Commands\HashSetMultiple',
|
||||
'hincrby' => 'Predis\Commands\HashIncrementBy',
|
||||
'hget' => 'Predis\Commands\HashGet',
|
||||
'hmget' => 'Predis\Commands\HashGetMultiple',
|
||||
'hdel' => 'Predis\Commands\HashDelete',
|
||||
'hexists' => 'Predis\Commands\HashExists',
|
||||
'hlen' => 'Predis\Commands\HashLength',
|
||||
'hkeys' => 'Predis\Commands\HashKeys',
|
||||
'hvals' => 'Predis\Commands\HashValues',
|
||||
'hgetall' => 'Predis\Commands\HashGetAll',
|
||||
|
||||
/* transactions */
|
||||
'multi' => 'Predis\Commands\TransactionMulti',
|
||||
'exec' => 'Predis\Commands\TransactionExec',
|
||||
'discard' => 'Predis\Commands\TransactionDiscard',
|
||||
|
||||
/* publish - subscribe */
|
||||
'subscribe' => 'Predis\Commands\PubSubSubscribe',
|
||||
'unsubscribe' => 'Predis\Commands\PubSubUnsubscribe',
|
||||
'psubscribe' => 'Predis\Commands\PubSubSubscribeByPattern',
|
||||
'punsubscribe' => 'Predis\Commands\PubSubUnsubscribeByPattern',
|
||||
'publish' => 'Predis\Commands\PubSubPublish',
|
||||
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Commands\ServerConfig',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
* Server profile for Redis v2.2.x.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerVersion22 extends ServerProfile
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return '2.2';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSupportedCommands()
|
||||
{
|
||||
return array(
|
||||
/* ---------------- Redis 1.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'exists' => 'Predis\Commands\KeyExists',
|
||||
'del' => 'Predis\Commands\KeyDelete',
|
||||
'type' => 'Predis\Commands\KeyType',
|
||||
'keys' => 'Predis\Commands\KeyKeys',
|
||||
'randomkey' => 'Predis\Commands\KeyRandom',
|
||||
'rename' => 'Predis\Commands\KeyRename',
|
||||
'renamenx' => 'Predis\Commands\KeyRenamePreserve',
|
||||
'expire' => 'Predis\Commands\KeyExpire',
|
||||
'expireat' => 'Predis\Commands\KeyExpireAt',
|
||||
'ttl' => 'Predis\Commands\KeyTimeToLive',
|
||||
'move' => 'Predis\Commands\KeyMove',
|
||||
'sort' => 'Predis\Commands\KeySort',
|
||||
|
||||
/* commands operating on string values */
|
||||
'set' => 'Predis\Commands\StringSet',
|
||||
'setnx' => 'Predis\Commands\StringSetPreserve',
|
||||
'mset' => 'Predis\Commands\StringSetMultiple',
|
||||
'msetnx' => 'Predis\Commands\StringSetMultiplePreserve',
|
||||
'get' => 'Predis\Commands\StringGet',
|
||||
'mget' => 'Predis\Commands\StringGetMultiple',
|
||||
'getset' => 'Predis\Commands\StringGetSet',
|
||||
'incr' => 'Predis\Commands\StringIncrement',
|
||||
'incrby' => 'Predis\Commands\StringIncrementBy',
|
||||
'decr' => 'Predis\Commands\StringDecrement',
|
||||
'decrby' => 'Predis\Commands\StringDecrementBy',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpush' => 'Predis\Commands\ListPushTail',
|
||||
'lpush' => 'Predis\Commands\ListPushHead',
|
||||
'llen' => 'Predis\Commands\ListLength',
|
||||
'lrange' => 'Predis\Commands\ListRange',
|
||||
'ltrim' => 'Predis\Commands\ListTrim',
|
||||
'lindex' => 'Predis\Commands\ListIndex',
|
||||
'lset' => 'Predis\Commands\ListSet',
|
||||
'lrem' => 'Predis\Commands\ListRemove',
|
||||
'lpop' => 'Predis\Commands\ListPopFirst',
|
||||
'rpop' => 'Predis\Commands\ListPopLast',
|
||||
'rpoplpush' => 'Predis\Commands\ListPopLastPushHead',
|
||||
|
||||
/* commands operating on sets */
|
||||
'sadd' => 'Predis\Commands\SetAdd',
|
||||
'srem' => 'Predis\Commands\SetRemove',
|
||||
'spop' => 'Predis\Commands\SetPop',
|
||||
'smove' => 'Predis\Commands\SetMove',
|
||||
'scard' => 'Predis\Commands\SetCardinality',
|
||||
'sismember' => 'Predis\Commands\SetIsMember',
|
||||
'sinter' => 'Predis\Commands\SetIntersection',
|
||||
'sinterstore' => 'Predis\Commands\SetIntersectionStore',
|
||||
'sunion' => 'Predis\Commands\SetUnion',
|
||||
'sunionstore' => 'Predis\Commands\SetUnionStore',
|
||||
'sdiff' => 'Predis\Commands\SetDifference',
|
||||
'sdiffstore' => 'Predis\Commands\SetDifferenceStore',
|
||||
'smembers' => 'Predis\Commands\SetMembers',
|
||||
'srandmember' => 'Predis\Commands\SetRandomMember',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zadd' => 'Predis\Commands\ZSetAdd',
|
||||
'zincrby' => 'Predis\Commands\ZSetIncrementBy',
|
||||
'zrem' => 'Predis\Commands\ZSetRemove',
|
||||
'zrange' => 'Predis\Commands\ZSetRange',
|
||||
'zrevrange' => 'Predis\Commands\ZSetReverseRange',
|
||||
'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore',
|
||||
'zcard' => 'Predis\Commands\ZSetCardinality',
|
||||
'zscore' => 'Predis\Commands\ZSetScore',
|
||||
'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore',
|
||||
|
||||
/* connection related commands */
|
||||
'ping' => 'Predis\Commands\ConnectionPing',
|
||||
'auth' => 'Predis\Commands\ConnectionAuth',
|
||||
'select' => 'Predis\Commands\ConnectionSelect',
|
||||
'echo' => 'Predis\Commands\ConnectionEcho',
|
||||
'quit' => 'Predis\Commands\ConnectionQuit',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfo',
|
||||
'slaveof' => 'Predis\Commands\ServerSlaveOf',
|
||||
'monitor' => 'Predis\Commands\ServerMonitor',
|
||||
'dbsize' => 'Predis\Commands\ServerDatabaseSize',
|
||||
'flushdb' => 'Predis\Commands\ServerFlushDatabase',
|
||||
'flushall' => 'Predis\Commands\ServerFlushAll',
|
||||
'save' => 'Predis\Commands\ServerSave',
|
||||
'bgsave' => 'Predis\Commands\ServerBackgroundSave',
|
||||
'lastsave' => 'Predis\Commands\ServerLastSave',
|
||||
'shutdown' => 'Predis\Commands\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
'setex' => 'Predis\Commands\StringSetExpire',
|
||||
'append' => 'Predis\Commands\StringAppend',
|
||||
'substr' => 'Predis\Commands\StringSubstr',
|
||||
|
||||
/* commands operating on lists */
|
||||
'blpop' => 'Predis\Commands\ListPopFirstBlocking',
|
||||
'brpop' => 'Predis\Commands\ListPopLastBlocking',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zunionstore' => 'Predis\Commands\ZSetUnionStore',
|
||||
'zinterstore' => 'Predis\Commands\ZSetIntersectionStore',
|
||||
'zcount' => 'Predis\Commands\ZSetCount',
|
||||
'zrank' => 'Predis\Commands\ZSetRank',
|
||||
'zrevrank' => 'Predis\Commands\ZSetReverseRank',
|
||||
'zremrangebyrank' => 'Predis\Commands\ZSetRemoveRangeByRank',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hset' => 'Predis\Commands\HashSet',
|
||||
'hsetnx' => 'Predis\Commands\HashSetPreserve',
|
||||
'hmset' => 'Predis\Commands\HashSetMultiple',
|
||||
'hincrby' => 'Predis\Commands\HashIncrementBy',
|
||||
'hget' => 'Predis\Commands\HashGet',
|
||||
'hmget' => 'Predis\Commands\HashGetMultiple',
|
||||
'hdel' => 'Predis\Commands\HashDelete',
|
||||
'hexists' => 'Predis\Commands\HashExists',
|
||||
'hlen' => 'Predis\Commands\HashLength',
|
||||
'hkeys' => 'Predis\Commands\HashKeys',
|
||||
'hvals' => 'Predis\Commands\HashValues',
|
||||
'hgetall' => 'Predis\Commands\HashGetAll',
|
||||
|
||||
/* transactions */
|
||||
'multi' => 'Predis\Commands\TransactionMulti',
|
||||
'exec' => 'Predis\Commands\TransactionExec',
|
||||
'discard' => 'Predis\Commands\TransactionDiscard',
|
||||
|
||||
/* publish - subscribe */
|
||||
'subscribe' => 'Predis\Commands\PubSubSubscribe',
|
||||
'unsubscribe' => 'Predis\Commands\PubSubUnsubscribe',
|
||||
'psubscribe' => 'Predis\Commands\PubSubSubscribeByPattern',
|
||||
'punsubscribe' => 'Predis\Commands\PubSubUnsubscribeByPattern',
|
||||
'publish' => 'Predis\Commands\PubSubPublish',
|
||||
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Commands\ServerConfig',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'persist' => 'Predis\Commands\KeyPersist',
|
||||
|
||||
/* commands operating on string values */
|
||||
'strlen' => 'Predis\Commands\StringStrlen',
|
||||
'setrange' => 'Predis\Commands\StringSetRange',
|
||||
'getrange' => 'Predis\Commands\StringGetRange',
|
||||
'setbit' => 'Predis\Commands\StringSetBit',
|
||||
'getbit' => 'Predis\Commands\StringGetBit',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpushx' => 'Predis\Commands\ListPushTailX',
|
||||
'lpushx' => 'Predis\Commands\ListPushHeadX',
|
||||
'linsert' => 'Predis\Commands\ListInsert',
|
||||
'brpoplpush' => 'Predis\Commands\ListPopLastPushHeadBlocking',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zrevrangebyscore' => 'Predis\Commands\ZSetReverseRangeByScore',
|
||||
|
||||
/* transactions */
|
||||
'watch' => 'Predis\Commands\TransactionWatch',
|
||||
'unwatch' => 'Predis\Commands\TransactionUnwatch',
|
||||
|
||||
/* remote server control commands */
|
||||
'object' => 'Predis\Commands\ServerObject',
|
||||
'slowlog' => 'Predis\Commands\ServerSlowlog',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
* Server profile for Redis v2.4.x.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerVersion24 extends ServerProfile
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return '2.4';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSupportedCommands()
|
||||
{
|
||||
return array(
|
||||
/* ---------------- Redis 1.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'exists' => 'Predis\Commands\KeyExists',
|
||||
'del' => 'Predis\Commands\KeyDelete',
|
||||
'type' => 'Predis\Commands\KeyType',
|
||||
'keys' => 'Predis\Commands\KeyKeys',
|
||||
'randomkey' => 'Predis\Commands\KeyRandom',
|
||||
'rename' => 'Predis\Commands\KeyRename',
|
||||
'renamenx' => 'Predis\Commands\KeyRenamePreserve',
|
||||
'expire' => 'Predis\Commands\KeyExpire',
|
||||
'expireat' => 'Predis\Commands\KeyExpireAt',
|
||||
'ttl' => 'Predis\Commands\KeyTimeToLive',
|
||||
'move' => 'Predis\Commands\KeyMove',
|
||||
'sort' => 'Predis\Commands\KeySort',
|
||||
|
||||
/* commands operating on string values */
|
||||
'set' => 'Predis\Commands\StringSet',
|
||||
'setnx' => 'Predis\Commands\StringSetPreserve',
|
||||
'mset' => 'Predis\Commands\StringSetMultiple',
|
||||
'msetnx' => 'Predis\Commands\StringSetMultiplePreserve',
|
||||
'get' => 'Predis\Commands\StringGet',
|
||||
'mget' => 'Predis\Commands\StringGetMultiple',
|
||||
'getset' => 'Predis\Commands\StringGetSet',
|
||||
'incr' => 'Predis\Commands\StringIncrement',
|
||||
'incrby' => 'Predis\Commands\StringIncrementBy',
|
||||
'decr' => 'Predis\Commands\StringDecrement',
|
||||
'decrby' => 'Predis\Commands\StringDecrementBy',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpush' => 'Predis\Commands\ListPushTail',
|
||||
'lpush' => 'Predis\Commands\ListPushHead',
|
||||
'llen' => 'Predis\Commands\ListLength',
|
||||
'lrange' => 'Predis\Commands\ListRange',
|
||||
'ltrim' => 'Predis\Commands\ListTrim',
|
||||
'lindex' => 'Predis\Commands\ListIndex',
|
||||
'lset' => 'Predis\Commands\ListSet',
|
||||
'lrem' => 'Predis\Commands\ListRemove',
|
||||
'lpop' => 'Predis\Commands\ListPopFirst',
|
||||
'rpop' => 'Predis\Commands\ListPopLast',
|
||||
'rpoplpush' => 'Predis\Commands\ListPopLastPushHead',
|
||||
|
||||
/* commands operating on sets */
|
||||
'sadd' => 'Predis\Commands\SetAdd',
|
||||
'srem' => 'Predis\Commands\SetRemove',
|
||||
'spop' => 'Predis\Commands\SetPop',
|
||||
'smove' => 'Predis\Commands\SetMove',
|
||||
'scard' => 'Predis\Commands\SetCardinality',
|
||||
'sismember' => 'Predis\Commands\SetIsMember',
|
||||
'sinter' => 'Predis\Commands\SetIntersection',
|
||||
'sinterstore' => 'Predis\Commands\SetIntersectionStore',
|
||||
'sunion' => 'Predis\Commands\SetUnion',
|
||||
'sunionstore' => 'Predis\Commands\SetUnionStore',
|
||||
'sdiff' => 'Predis\Commands\SetDifference',
|
||||
'sdiffstore' => 'Predis\Commands\SetDifferenceStore',
|
||||
'smembers' => 'Predis\Commands\SetMembers',
|
||||
'srandmember' => 'Predis\Commands\SetRandomMember',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zadd' => 'Predis\Commands\ZSetAdd',
|
||||
'zincrby' => 'Predis\Commands\ZSetIncrementBy',
|
||||
'zrem' => 'Predis\Commands\ZSetRemove',
|
||||
'zrange' => 'Predis\Commands\ZSetRange',
|
||||
'zrevrange' => 'Predis\Commands\ZSetReverseRange',
|
||||
'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore',
|
||||
'zcard' => 'Predis\Commands\ZSetCardinality',
|
||||
'zscore' => 'Predis\Commands\ZSetScore',
|
||||
'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore',
|
||||
|
||||
/* connection related commands */
|
||||
'ping' => 'Predis\Commands\ConnectionPing',
|
||||
'auth' => 'Predis\Commands\ConnectionAuth',
|
||||
'select' => 'Predis\Commands\ConnectionSelect',
|
||||
'echo' => 'Predis\Commands\ConnectionEcho',
|
||||
'quit' => 'Predis\Commands\ConnectionQuit',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfo',
|
||||
'slaveof' => 'Predis\Commands\ServerSlaveOf',
|
||||
'monitor' => 'Predis\Commands\ServerMonitor',
|
||||
'dbsize' => 'Predis\Commands\ServerDatabaseSize',
|
||||
'flushdb' => 'Predis\Commands\ServerFlushDatabase',
|
||||
'flushall' => 'Predis\Commands\ServerFlushAll',
|
||||
'save' => 'Predis\Commands\ServerSave',
|
||||
'bgsave' => 'Predis\Commands\ServerBackgroundSave',
|
||||
'lastsave' => 'Predis\Commands\ServerLastSave',
|
||||
'shutdown' => 'Predis\Commands\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
'setex' => 'Predis\Commands\StringSetExpire',
|
||||
'append' => 'Predis\Commands\StringAppend',
|
||||
'substr' => 'Predis\Commands\StringSubstr',
|
||||
|
||||
/* commands operating on lists */
|
||||
'blpop' => 'Predis\Commands\ListPopFirstBlocking',
|
||||
'brpop' => 'Predis\Commands\ListPopLastBlocking',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zunionstore' => 'Predis\Commands\ZSetUnionStore',
|
||||
'zinterstore' => 'Predis\Commands\ZSetIntersectionStore',
|
||||
'zcount' => 'Predis\Commands\ZSetCount',
|
||||
'zrank' => 'Predis\Commands\ZSetRank',
|
||||
'zrevrank' => 'Predis\Commands\ZSetReverseRank',
|
||||
'zremrangebyrank' => 'Predis\Commands\ZSetRemoveRangeByRank',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hset' => 'Predis\Commands\HashSet',
|
||||
'hsetnx' => 'Predis\Commands\HashSetPreserve',
|
||||
'hmset' => 'Predis\Commands\HashSetMultiple',
|
||||
'hincrby' => 'Predis\Commands\HashIncrementBy',
|
||||
'hget' => 'Predis\Commands\HashGet',
|
||||
'hmget' => 'Predis\Commands\HashGetMultiple',
|
||||
'hdel' => 'Predis\Commands\HashDelete',
|
||||
'hexists' => 'Predis\Commands\HashExists',
|
||||
'hlen' => 'Predis\Commands\HashLength',
|
||||
'hkeys' => 'Predis\Commands\HashKeys',
|
||||
'hvals' => 'Predis\Commands\HashValues',
|
||||
'hgetall' => 'Predis\Commands\HashGetAll',
|
||||
|
||||
/* transactions */
|
||||
'multi' => 'Predis\Commands\TransactionMulti',
|
||||
'exec' => 'Predis\Commands\TransactionExec',
|
||||
'discard' => 'Predis\Commands\TransactionDiscard',
|
||||
|
||||
/* publish - subscribe */
|
||||
'subscribe' => 'Predis\Commands\PubSubSubscribe',
|
||||
'unsubscribe' => 'Predis\Commands\PubSubUnsubscribe',
|
||||
'psubscribe' => 'Predis\Commands\PubSubSubscribeByPattern',
|
||||
'punsubscribe' => 'Predis\Commands\PubSubUnsubscribeByPattern',
|
||||
'publish' => 'Predis\Commands\PubSubPublish',
|
||||
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Commands\ServerConfig',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
'persist' => 'Predis\Commands\KeyPersist',
|
||||
|
||||
/* commands operating on string values */
|
||||
'strlen' => 'Predis\Commands\StringStrlen',
|
||||
'setrange' => 'Predis\Commands\StringSetRange',
|
||||
'getrange' => 'Predis\Commands\StringGetRange',
|
||||
'setbit' => 'Predis\Commands\StringSetBit',
|
||||
'getbit' => 'Predis\Commands\StringGetBit',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpushx' => 'Predis\Commands\ListPushTailX',
|
||||
'lpushx' => 'Predis\Commands\ListPushHeadX',
|
||||
'linsert' => 'Predis\Commands\ListInsert',
|
||||
'brpoplpush' => 'Predis\Commands\ListPopLastPushHeadBlocking',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zrevrangebyscore' => 'Predis\Commands\ZSetReverseRangeByScore',
|
||||
|
||||
/* transactions */
|
||||
'watch' => 'Predis\Commands\TransactionWatch',
|
||||
'unwatch' => 'Predis\Commands\TransactionUnwatch',
|
||||
|
||||
/* remote server control commands */
|
||||
'object' => 'Predis\Commands\ServerObject',
|
||||
'slowlog' => 'Predis\Commands\ServerSlowlog',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.4 ---------------- */
|
||||
|
||||
/* remote server control commands */
|
||||
'client' => 'Predis\Commands\ServerClient',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Profiles;
|
||||
|
||||
/**
|
||||
* Server profile for the current development version of Redis.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerVersionNext extends ServerVersion24
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
return '2.6';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSupportedCommands()
|
||||
{
|
||||
return array_merge(parent::getSupportedCommands(), array(
|
||||
/* commands operating on the key space */
|
||||
'pttl' => 'Predis\Commands\KeyPreciseTimeToLive',
|
||||
'pexpire' => 'Predis\Commands\KeyPreciseExpire',
|
||||
'pexpireat' => 'Predis\Commands\KeyPreciseExpireAt',
|
||||
|
||||
/* commands operating on string values */
|
||||
'psetex' => 'Predis\Commands\StringPreciseSetExpire',
|
||||
'incrbyfloat' => 'Predis\Commands\StringIncrementByFloat',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hincrbyfloat' => 'Predis\Commands\HashIncrementByFloat',
|
||||
|
||||
/* scripting */
|
||||
'eval' => 'Predis\Commands\ServerEval',
|
||||
'evalsha' => 'Predis\Commands\ServerEvalSHA',
|
||||
'script' => 'Predis\Commands\ServerScript',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Commands\ServerInfoV26x',
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Protocol;
|
||||
|
||||
/**
|
||||
* Interface that defines a customizable protocol processor that serializes
|
||||
* Redis commands and parses replies returned by the server to PHP objects
|
||||
* using a pluggable set of classes defining the underlying wire protocol.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IComposableProtocolProcessor extends IProtocolProcessor
|
||||
{
|
||||
/**
|
||||
* Sets the command serializer to be used by the protocol processor.
|
||||
*
|
||||
* @param ICommandSerializer $serializer Command serializer.
|
||||
*/
|
||||
public function setSerializer(ICommandSerializer $serializer);
|
||||
|
||||
/**
|
||||
* Returns the command serializer used by the protocol processor.
|
||||
*
|
||||
* @return ICommandSerializer
|
||||
*/
|
||||
public function getSerializer();
|
||||
|
||||
/**
|
||||
* Sets the response reader to be used by the protocol processor.
|
||||
*
|
||||
* @param IResponseReader $reader Response reader.
|
||||
*/
|
||||
public function setReader(IResponseReader $reader);
|
||||
|
||||
/**
|
||||
* Returns the response reader used by the protocol processor.
|
||||
*
|
||||
* @return IResponseReader
|
||||
*/
|
||||
public function getReader();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Protocol;
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Network\IConnectionComposable;
|
||||
|
||||
/**
|
||||
* Interface that defines a protocol processor that serializes Redis commands
|
||||
* and parses replies returned by the server to PHP objects.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IProtocolProcessor extends IResponseReader
|
||||
{
|
||||
/**
|
||||
* Writes a Redis command on the specified connection.
|
||||
*
|
||||
* @param IConnectionComposable $connection Connection to Redis.
|
||||
* @param ICommand $command Redis command.
|
||||
*/
|
||||
public function write(IConnectionComposable $connection, ICommand $command);
|
||||
|
||||
/**
|
||||
* Sets the options for the protocol processor.
|
||||
*
|
||||
* @param string $option Name of the option.
|
||||
* @param mixed $value Value of the option.
|
||||
*/
|
||||
public function setOption($option, $value);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Protocol;
|
||||
|
||||
use Predis\Network\IConnectionComposable;
|
||||
|
||||
/**
|
||||
* Interface that defines an handler able to parse a reply.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IResponseHandler
|
||||
{
|
||||
/**
|
||||
* Parses a type of reply returned by Redis and reads more data from the
|
||||
* connection if needed.
|
||||
*
|
||||
* @param IConnectionComposable $connection Connection to Redis.
|
||||
* @param string $payload Initial payload of the reply.
|
||||
* @return mixed
|
||||
*/
|
||||
function handle(IConnectionComposable $connection, $payload);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Protocol;
|
||||
|
||||
use Predis\Network\IConnectionComposable;
|
||||
|
||||
/**
|
||||
* Interface that defines a response reader able to parse replies returned by
|
||||
* Redis and deserialize them to PHP objects.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
interface IResponseReader
|
||||
{
|
||||
/**
|
||||
* Reads replies from a connection to Redis and deserializes them.
|
||||
*
|
||||
* @param IConnectionComposable $connection Connection to Redis.
|
||||
* @return mixed
|
||||
*/
|
||||
public function read(IConnectionComposable $connection);
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Protocol\Text;
|
||||
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Protocol\IResponseReader;
|
||||
use Predis\Protocol\ICommandSerializer;
|
||||
use Predis\Protocol\IComposableProtocolProcessor;
|
||||
use Predis\Network\IConnectionComposable;
|
||||
|
||||
/**
|
||||
* Implements a customizable protocol processor that uses the standard Redis
|
||||
* wire protocol to serialize Redis commands and parse replies returned by
|
||||
* the server using a pluggable set of classes.
|
||||
*
|
||||
* @link http://redis.io/topics/protocol
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ComposableTextProtocol implements IComposableProtocolProcessor
|
||||
{
|
||||
private $serializer;
|
||||
private $reader;
|
||||
|
||||
/**
|
||||
* @param array $options Set of options used to initialize the protocol processor.
|
||||
*/
|
||||
public function __construct(Array $options = array())
|
||||
{
|
||||
$this->setSerializer(new TextCommandSerializer());
|
||||
$this->setReader(new TextResponseReader());
|
||||
|
||||
if (count($options) > 0) {
|
||||
$this->initializeOptions($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the protocol processor using a set of options.
|
||||
*
|
||||
* @param array $options Set of options.
|
||||
*/
|
||||
private function initializeOptions(Array $options)
|
||||
{
|
||||
foreach ($options as $k => $v) {
|
||||
$this->setOption($k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOption($option, $value)
|
||||
{
|
||||
switch ($option) {
|
||||
case 'iterable_multibulk':
|
||||
$handler = $value ? new ResponseMultiBulkStreamHandler() : new ResponseMultiBulkHandler();
|
||||
$this->reader->setHandler(TextProtocol::PREFIX_MULTI_BULK, $handler);
|
||||
break;
|
||||
|
||||
case 'throw_errors':
|
||||
$handler = $value ? new ResponseErrorHandler() : new ResponseErrorSilentHandler();
|
||||
$this->reader->setHandler(TextProtocol::PREFIX_ERROR, $handler);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("The option $option is not supported by the current protocol");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function serialize(ICommand $command)
|
||||
{
|
||||
return $this->serializer->serialize($command);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write(IConnectionComposable $connection, ICommand $command)
|
||||
{
|
||||
$connection->writeBytes($this->serializer->serialize($command));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read(IConnectionComposable $connection)
|
||||
{
|
||||
return $this->reader->read($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSerializer(ICommandSerializer $serializer)
|
||||
{
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSerializer()
|
||||
{
|
||||
return $this->serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setReader(IResponseReader $reader)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReader()
|
||||
{
|
||||
return $this->reader;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user