├── .composer-auth.json
├── .gitignore
├── .styleci.yml
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── appveyor.yml
├── composer.json
├── phpunit.xml.dist
├── src
    ├── AbstractRedisStore.php
    ├── Api
    │   ├── CountableStore.php
    │   ├── InvalidKeyException.php
    │   ├── KeyValueStore.php
    │   ├── NoSuchKeyException.php
    │   ├── ReadException.php
    │   ├── SerializationFailedException.php
    │   ├── SortableStore.php
    │   ├── UnserializationFailedException.php
    │   ├── UnsupportedValueException.php
    │   └── WriteException.php
    ├── ArrayStore.php
    ├── DbalStore.php
    ├── Decorator
    │   ├── AbstractDecorator.php
    │   ├── CachingDecorator.php
    │   ├── CountableDecorator.php
    │   └── SortableDecorator.php
    ├── JsonFileStore.php
    ├── MongoDbStore.php
    ├── NullStore.php
    ├── PhpRedisStore.php
    ├── PredisStore.php
    ├── RiakStore.php
    ├── SerializingArrayStore.php
    └── Util
    │   ├── KeyUtil.php
    │   └── Serializer.php
└── tests
    ├── AbstractCountableStoreTest.php
    ├── AbstractKeyValueStoreTest.php
    ├── AbstractMongoDbStoreTest.php
    ├── AbstractSortableCountableStoreTest.php
    ├── ArrayStoreTest.php
    ├── DbalStoreTest.php
    ├── Decorator
        ├── AbstractDecoratorTest.php
        ├── CachingDecoratorTest.php
        ├── CountableDecoratorTest.php
        └── SortableDecoratorTest.php
    ├── Fixtures
        ├── NotSerializable.php
        ├── PrivateProperties.php
        ├── TestClearableCache.php
        ├── TestClearableFlushableCache.php
        ├── TestException.php
        ├── TestFlushableCache.php
        └── file
    ├── JsonFileStoreTest.php
    ├── NonSerializingBinaryMongoDbStoreTest.php
    ├── NonSerializingMongoDbStoreTest.php
    ├── NullStoreTest.php
    ├── PhpRedisStoreTest.php
    ├── PredisStoreTest.php
    ├── RiakStoreTest.php
    ├── SerializingArrayStoreTest.php
    ├── SerializingBinaryMongoDbStoreTest.php
    ├── SerializingMongoDbStoreTest.php
    └── Util
        └── SerializerTest.php
/.composer-auth.json:
--------------------------------------------------------------------------------
1 | {
2 |     "github-oauth": {
3 |         "github.com": "PLEASE DO NOT USE THIS TOKEN IN YOUR OWN PROJECTS/FORKS",
4 |         "github.com": "This token is reserved for testing the webmozart/* repositories",
5 |         "github.com": "a9debbffdd953ee9b3b82dbc3b807cde2086bb86"
6 |     }
7 | }
8 | 
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | composer.lock
3 | 
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
 1 | preset: symfony
 2 | 
 3 | enabled:
 4 |     - ordered_use
 5 |     - strict
 6 | 
 7 | disabled:
 8 |     - empty_return
 9 |     - phpdoc_annotation_without_dot # This is still buggy: https://github.com/symfony/symfony/pull/19198
10 | 
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
 1 | language: php
 2 | 
 3 | services:
 4 |   - redis-server
 5 |   - riak
 6 |   - mongodb
 7 | 
 8 | branches:
 9 |   only:
10 |     - master
11 | 
12 | sudo: false
13 | 
14 | cache:
15 |   directories:
16 |     - $HOME/.composer/cache/files
17 | 
18 | matrix:
19 |   include:
20 |     - php: 5.3
21 |     - php: 5.4
22 |     - php: 5.5
23 |     - php: 5.6
24 |     - php: hhvm
25 |     - php: nightly
26 |     - php: 7.0
27 |       env: COVERAGE=yes
28 |     - php: 7.0
29 |       env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable'
30 |   allow_failures:
31 |     - php: hhvm
32 |     - php: nightly
33 |   fast_finish: true
34 | 
35 | 
36 | before_install:
37 |   - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi
38 |   - if [[ $TRAVIS_PHP_VERSION != hhvm && $TRAVIS_PHP_VERSION != 5.3 ]]; then pecl install -f mongodb; echo "extension=mongodb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi
39 |   - if [[ $TRAVIS_PHP_VERSION != hhvm && $COVERAGE != yes ]]; then phpenv config-rm xdebug.ini; fi;
40 |   - if [[ $TRAVIS_REPO_SLUG = webmozart/key-value-store ]]; then cp .composer-auth.json ~/.composer/auth.json; fi;
41 |   - composer self-update
42 | 
43 | install:
44 |   # mongodb/mongodb is not compatible with HHVM/5.3
45 |   - if [[ $TRAVIS_PHP_VERSION = hhvm || $TRAVIS_PHP_VERSION = 5.3 ]]; then composer remove --dev mongodb/mongodb; fi
46 |   - composer update $COMPOSER_FLAGS --prefer-dist --no-interaction
47 | 
48 | script: if [[ $COVERAGE = yes ]]; then vendor/bin/phpunit --verbose --coverage-clover=coverage.clover; else vendor/bin/phpunit --verbose; fi
49 | 
50 | after_script: if [[ $COVERAGE = yes ]]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
51 | 
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
 1 | Changelog
 2 | =========
 3 | 
 4 | * 1.0.0-beta8 (2016-08-09)
 5 | 
 6 |  * added `MongoDbStore`
 7 |  * added flag `ArrayStore::SERIALIZE`
 8 |  * deprecated `SerializingArrayStore`
 9 | 
10 | * 1.0.0-beta7 (2016-01-14)
11 | 
12 |  * added `JsonFileStore::NO_SERIALIZE_STRINGS` and `JsonFileStore::NO_SERIALIZE_ARRAYS`
13 |  * disabled serialization of `null` values in `JsonFileStore`
14 |  * removed code from `JsonFileStore` and relied on webmozart/json instead
15 |  * added `JsonFileStore::ESCAPE_GT_LT`
16 |  * added `JsonFileStore::ESCAPE_AMPERSAND`
17 |  * added `JsonFileStore::ESCAPE_SINGLE_QUOTE`
18 |  * added `JsonFileStore::ESCAPE_DOUBLE_QUOTE`
19 |  * added `JsonFileStore::NO_ESCAPE_SLASH`
20 |  * added `JsonFileStore::NO_ESCAPE_UNICODE`
21 |  * added `JsonFileStore::PRETTY_PRINT`
22 |  * added `JsonFileStore::TERMINATE_WITH_LINE_FEED`
23 | 
24 | * 1.0.0-beta6 (2015-10-02)
25 | 
26 |  * added `SerializingArrayStore`
27 |  * added `DbalStore`
28 | 
29 | * 1.0.0-beta5 (2015-08-11)
30 | 
31 |  * added `AbstractDecorator`
32 |  * added `AbstractRedisStore`
33 |  * added `CountableStore`
34 |  * added `SortableStore`
35 |  * renamed `CachedStore` to `CachingDecorator`
36 |  * added `CountableDecorator`
37 |  * added `SortableDecorator`
38 |  * implemented `CountableStore` and `SortableStore` in `ArrayStore`,
39 |   `JsonFileStore` and `NullStore`
40 |  * made `KeyUtil` final
41 |  * made `Serializer` final
42 | 
43 | * 1.0.0-beta4 (2015-05-28)
44 | 
45 |  * added `KeyValueStore::keys()`
46 |  * renamed `KeyValueStore::has()` to `exists()`
47 |  * added `KeyValueStore::getOrFail()`
48 |  * added `KeyValueStore::getMultiple()`
49 |  * added `KeyValueStore::getMultipleOrFail()`
50 | 
51 | * 1.0.0-beta3 (2015-04-13)
52 | 
53 |  * replaced `Assert` by webmozart/assert
54 |  
55 | * 1.0.0-beta2 (2015-01-21)
56 | 
57 |  * added `PhpRedisStore`
58 |  * added `CachedStore`
59 |  * removed optional argument `$cache` from `JsonFileStore::__construct()`
60 |  * removed implementations that don't make sense for a key-value store: 
61 |    * `MemcacheStore` (not persistent)
62 |    * `MemcachedStore` (not persistent)
63 |    * `SharedMemoryStore` (not persistent)
64 |  * added `Serializer` utility
65 |  * `KeyValueStore::get()` now throws an exception if the value cannot be unserialized
66 | 
67 | * 1.0.0-beta (2015-01-12)
68 | 
69 |  * first release
70 | 
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2014 Bernhard Schussek
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
 6 | this software and associated documentation files (the "Software"), to deal in
 7 | the Software without restriction, including without limitation the rights to
 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | Webmozart Key-Value-Store
  2 | =========================
  3 | 
  4 | [](https://travis-ci.org/webmozart/key-value-store)
  5 | [](https://ci.appveyor.com/project/webmozart/key-value-store/branch/master)
  6 | [](https://scrutinizer-ci.com/g/webmozart/key-value-store/?branch=master)
  7 | [](https://packagist.org/packages/webmozart/key-value-store)
  8 | [](https://packagist.org/packages/webmozart/key-value-store)
  9 | [](https://www.versioneye.com/php/webmozart:key-value-store/1.0.0)
 10 | 
 11 | Latest release: [1.0.0](https://packagist.org/packages/webmozart/key-value-store#1.0.0)
 12 | 
 13 | A key-value store API with implementations for different backends.
 14 | 
 15 | [API Documentation]
 16 | 
 17 | All contained key-value stores implement the interface [`KeyValueStore`]. The
 18 | following stores are currently supported:
 19 | 
 20 | * [`ArrayStore`]
 21 | * [`DbalStore`]
 22 | * [`JsonFileStore`]
 23 | * [`MongoDbStore`]
 24 | * [`NullStore`]
 25 | * [`PhpRedisStore`]
 26 | * [`PredisStore`]
 27 | * [`RiakStore`]
 28 | 
 29 | The interface [`CountableStore`] is supported by the following classes:
 30 | 
 31 | * [`ArrayStore`]
 32 | * [`JsonFileStore`]
 33 | * [`NullStore`]
 34 | * [`CountableDecorator`]
 35 | 
 36 | The interface [`SortableStore`] is supported by the following classes:
 37 | 
 38 | * [`ArrayStore`]
 39 | * [`JsonFileStore`]
 40 | * [`NullStore`]
 41 | * [`SortableDecorator`]
 42 | 
 43 | The decorator [`CachingDecorator`] exists for caching another store instance
 44 | in a Doctrine cache.
 45 | 
 46 | FAQ
 47 | ---
 48 | 
 49 | **Why not use [Doctrine Cache]?**
 50 | 
 51 | Caching is **not** key-value storage. When you use a cache, you accept that keys
 52 | may disappear for various reasons:
 53 | 
 54 | * Keys may expire.
 55 | * Keys may be overwritten when the cache is full.
 56 | * Keys may be lost after shutdowns.
 57 | * ...
 58 | 
 59 | In another word, caches are *volatile*. This is not a problem, since the cached
 60 | data is usually stored safely somewhere else. The point of a cache is to provide
 61 | high-performance access to frequently needed data.
 62 | 
 63 | Key-value stores, on the other hand, are *persistent*. When you write a key to a
 64 | key-value store, you expect it to be there until you delete it. It would be a
 65 | disaster if data would silently disappear from a key-value store (or any other
 66 | kind of database).
 67 | 
 68 | Hence the two libraries fulfill two very different purposes, even if their
 69 | interfaces and implementations are often similar.
 70 | 
 71 | The [`CachingDecorator`] actually uses a Doctrine Cache object to cache the data
 72 | of a persistent [`KeyValueStore`].
 73 | 
 74 | Authors
 75 | -------
 76 | 
 77 | * [Bernhard Schussek] a.k.a. [@webmozart]
 78 | * [The Community Contributors]
 79 | 
 80 | Installation
 81 | ------------
 82 | 
 83 | Use [Composer] to install the package:
 84 | 
 85 | ```
 86 | $ composer require webmozart/key-value-store
 87 | ```
 88 | 
 89 | Contribute
 90 | ----------
 91 | 
 92 | Contributions to the package are always welcome!
 93 | 
 94 | * Report any bugs or issues you find on the [issue tracker].
 95 | * You can grab the source code at the package's [Git repository].
 96 | 
 97 | Support
 98 | -------
 99 | 
100 | If you are having problems, send a mail to bschussek@gmail.com or shout out to
101 | [@webmozart] on Twitter.
102 | 
103 | License
104 | -------
105 | 
106 | All contents of this package are licensed under the [MIT license].
107 | 
108 | [Composer]: https://getcomposer.org
109 | [Bernhard Schussek]: http://webmozarts.com
110 | [The Community Contributors]: https://github.com/webmozart/key-value-store/graphs/contributors
111 | [issue tracker]: https://github.com/webmozart/key-value-store/issues
112 | [Git repository]: https://github.com/webmozart/key-value-store
113 | [@webmozart]: https://twitter.com/webmozart
114 | [MIT license]: LICENSE
115 | [Doctrine Cache]: https://github.com/doctrine/cache
116 | [API Documentation]: https://webmozart.github.io/key-value-store/api
117 | [`KeyValueStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.Api.KeyValueStore.html
118 | [`CountableStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.Api.CountableStore.html
119 | [`SortableStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.Api.SortableStore.html
120 | [`ArrayStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.ArrayStore.html
121 | [`DbalStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.DbalStore.html
122 | [`JsonFileStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.JsonFileStore.html
123 | [`MongoDbStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.MongoDbStore.html
124 | [`NullStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.NullStore.html
125 | [`PhpRedisStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.PhpRedisStore.html
126 | [`PredisStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.PredisStore.html
127 | [`RiakStore`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.RiakStore.html
128 | [`CachingDecorator`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.Decorator.CachingDecorator.html
129 | [`CountableDecorator`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.Decorator.CountableDecorator.html
130 | [`SortableDecorator`]: https://webmozart.github.io/key-value-store/api/latest/class-Webmozart.KeyValueStore.Decorator.SortableDecorator.html
131 | 
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
 1 | build: false
 2 | platform: x86
 3 | clone_folder: c:\projects\webmozart\key-value-store
 4 | 
 5 | services:
 6 |   - mongodb
 7 | 
 8 | branches:
 9 |   only:
10 |     - master
11 | 
12 | cache:
13 |   - c:\php -> appveyor.yml
14 | 
15 | init:
16 |   - SET PATH=c:\php;%PATH%
17 |   - SET COMPOSER_NO_INTERACTION=1
18 |   - SET PHP=1
19 | 
20 | install:
21 |   - IF EXIST c:\php (SET PHP=0) ELSE (mkdir c:\php)
22 |   - cd c:\php
23 |   - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-7.0.0-nts-Win32-VC14-x86.zip
24 |   - IF %PHP%==1 7z x php-7.0.0-nts-Win32-VC14-x86.zip -y >nul
25 |   - IF %PHP%==1 del /Q *.zip
26 |   - IF %PHP%==1 cd ext
27 |   - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/mongodb/1.1.8/php_mongodb-1.1.8-7.0-nts-vc14-x86.zip
28 |   - IF %PHP%==1 7z x php_mongodb-1.1.8-7.0-nts-vc14-x86.zip php_mongodb.dll -y >nul
29 |   - IF %PHP%==1 del /Q *.zip
30 |   - IF %PHP%==1 cd ..
31 |   - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat
32 |   - IF %PHP%==1 copy /Y php.ini-development php.ini
33 |   - IF %PHP%==1 echo max_execution_time=1200 >> php.ini
34 |   - IF %PHP%==1 echo date.timezone="UTC" >> php.ini
35 |   - IF %PHP%==1 echo extension_dir=ext >> php.ini
36 |   - IF %PHP%==1 echo extension=php_curl.dll >> php.ini
37 |   - IF %PHP%==1 echo extension=php_pdo_sqlite.dll >> php.ini
38 |   - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
39 |   - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini
40 |   - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini
41 |   - IF %PHP%==1 echo extension=php_mongodb.dll >> php.ini
42 |   - appveyor DownloadFile https://getcomposer.org/composer.phar
43 |   - cd c:\projects\webmozart\key-value-store
44 |   - mkdir %APPDATA%\Composer
45 |   - IF %APPVEYOR_REPO_NAME%==webmozart/key-value-store copy /Y .composer-auth.json %APPDATA%\Composer\auth.json
46 |   - composer update --prefer-dist --no-progress --ansi
47 | 
48 | test_script:
49 |   - cd c:\projects\webmozart\key-value-store
50 |   - vendor\bin\phpunit.bat --verbose
51 | 
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "name": "webmozart/key-value-store",
 3 |     "description": "A key-value store API with implementations for different backends.",
 4 |     "license": "MIT",
 5 |     "authors": [
 6 |         {
 7 |             "name": "Bernhard Schussek",
 8 |             "email": "bschussek@gmail.com"
 9 |         }
10 |     ],
11 |     "require": {
12 |         "php": "^5.3.3|^7.0",
13 |         "webmozart/assert": "^1.0"
14 |     },
15 |     "require-dev": {
16 |         "webmozart/json": "^1.1.1",
17 |         "symfony/filesystem": "^2.5",
18 |         "predis/predis": "^1.0",
19 |         "basho/riak": "^1.4",
20 |         "doctrine/cache": "^1.4",
21 |         "phpunit/phpunit": "^4.6",
22 |         "doctrine/dbal" : "^2.4",
23 |         "sebastian/version": "^1.0.1",
24 |         "mongodb/mongodb": "^1.0"
25 |     },
26 |     "suggest": {
27 |         "webmozart/json": "to enable the JsonFileStore",
28 |         "predis/predis": "to enable the PredisStore",
29 |         "basho/riak": "to enable the RiakStore",
30 |         "doctrine/cache": "to enable the CachedStore",
31 |         "doctrine/dbal": "to enable the DbalStore",
32 |         "mongodb/mongodb": "to enable the MongoDbStore"
33 |     },
34 |     "autoload": {
35 |         "psr-4": {
36 |             "Webmozart\\KeyValueStore\\": "src/"
37 |         }
38 |     },
39 |     "autoload-dev": {
40 |         "psr-4": {
41 |             "Webmozart\\KeyValueStore\\Tests\\": "tests/"
42 |         }
43 |     },
44 |     "extra": {
45 |         "branch-alias": {
46 |             "dev-master": "1.1-dev"
47 |         }
48 |     }
49 | }
50 | 
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 |     
 5 |         
 6 |             ./tests/
 7 |         
 8 |     
 9 | 
10 |     
11 |     
12 |         
13 |             ./src/
14 |         
15 |     
16 | 
17 | 
--------------------------------------------------------------------------------
/src/AbstractRedisStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Exception;
 15 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 16 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 17 | use Webmozart\KeyValueStore\Api\ReadException;
 18 | use Webmozart\KeyValueStore\Api\WriteException;
 19 | use Webmozart\KeyValueStore\Util\KeyUtil;
 20 | use Webmozart\KeyValueStore\Util\Serializer;
 21 | 
 22 | /**
 23 |  * An abstract Redis key-value store to support multiple Redis clients without code duplication.
 24 |  *
 25 |  * @since  1.0
 26 |  *
 27 |  * @author Bernhard Schussek 
 28 |  * @author Titouan Galopin 
 29 |  */
 30 | abstract class AbstractRedisStore implements KeyValueStore
 31 | {
 32 |     /**
 33 |      * Redis client.
 34 |      *
 35 |      * @var object
 36 |      */
 37 |     protected $client;
 38 | 
 39 |     /**
 40 |      * Return the value corresponding to "not found"
 41 |      * for the internal client.
 42 |      *
 43 |      * @return mixed
 44 |      */
 45 |     abstract protected function clientNotFoundValue();
 46 | 
 47 |     /**
 48 |      * Call the internal client method to fetch a key.
 49 |      * Don't have to catch the exceptions.
 50 |      *
 51 |      * @param string $key The key to fetch
 52 |      *
 53 |      * @return mixed The raw value
 54 |      */
 55 |     abstract protected function clientGet($key);
 56 | 
 57 |     /**
 58 |      * Call the internal client method to fetch multiple keys.
 59 |      * Don't have to catch the exceptions.
 60 |      *
 61 |      * @param array $keys The keys to fetch
 62 |      *
 63 |      * @return array The raw values
 64 |      */
 65 |     abstract protected function clientGetMultiple(array $keys);
 66 | 
 67 |     /**
 68 |      * Call the internal client method to set a value associated to a key.
 69 |      * Don't have to catch the exceptions.
 70 |      *
 71 |      * @param string $key
 72 |      * @param mixed  $value
 73 |      */
 74 |     abstract protected function clientSet($key, $value);
 75 | 
 76 |     /**
 77 |      * Call the internal client method to remove a key.
 78 |      * Don't have to catch the exceptions.
 79 |      *
 80 |      * @param string $key
 81 |      *
 82 |      * @return bool true if the removal worked, false otherwise
 83 |      */
 84 |     abstract protected function clientRemove($key);
 85 | 
 86 |     /**
 87 |      * Call the internal client method to check if a key exists.
 88 |      * Don't have to catch the exceptions.
 89 |      *
 90 |      * @param string $key
 91 |      *
 92 |      * @return bool
 93 |      */
 94 |     abstract protected function clientExists($key);
 95 | 
 96 |     /**
 97 |      * Call the internal client method to clear all the keys.
 98 |      * Don't have to catch the exceptions.
 99 |      */
100 |     abstract protected function clientClear();
101 | 
102 |     /**
103 |      * Call the internal client method to fetch all the keys.
104 |      * Don't have to catch the exceptions.
105 |      *
106 |      * @return array The keys
107 |      */
108 |     abstract protected function clientKeys();
109 | 
110 |     /**
111 |      * {@inheritdoc}
112 |      */
113 |     public function getMultiple(array $keys, $default = null)
114 |     {
115 |         KeyUtil::validateMultiple($keys);
116 | 
117 |         // Normalize indices of the array
118 |         $keys = array_values($keys);
119 |         $values = array();
120 | 
121 |         try {
122 |             $serializedValues = $this->clientGetMultiple($keys);
123 |         } catch (Exception $e) {
124 |             throw ReadException::forException($e);
125 |         }
126 | 
127 |         foreach ($serializedValues as $i => $serializedValue) {
128 |             $values[$keys[$i]] = $this->clientNotFoundValue() === $serializedValue
129 |                 ? $default
130 |                 : Serializer::unserialize($serializedValue);
131 |         }
132 | 
133 |         return $values;
134 |     }
135 | 
136 |     /**
137 |      * {@inheritdoc}
138 |      */
139 |     public function getMultipleOrFail(array $keys)
140 |     {
141 |         KeyUtil::validateMultiple($keys);
142 | 
143 |         // Normalize indices of the array
144 |         $keys = array_values($keys);
145 |         $values = array();
146 |         $notFoundKeys = array();
147 | 
148 |         try {
149 |             $serializedValues = $this->clientGetMultiple($keys);
150 |         } catch (Exception $e) {
151 |             throw ReadException::forException($e);
152 |         }
153 | 
154 |         foreach ($serializedValues as $i => $serializedValue) {
155 |             if ($this->clientNotFoundValue() === $serializedValue) {
156 |                 $notFoundKeys[] = $keys[$i];
157 |             } elseif (0 === count($notFoundKeys)) {
158 |                 $values[$keys[$i]] = Serializer::unserialize($serializedValue);
159 |             }
160 |         }
161 | 
162 |         if (0 !== count($notFoundKeys)) {
163 |             throw NoSuchKeyException::forKeys($notFoundKeys);
164 |         }
165 | 
166 |         return $values;
167 |     }
168 | 
169 |     /**
170 |      * {@inheritdoc}
171 |      */
172 |     public function get($key, $default = null)
173 |     {
174 |         KeyUtil::validate($key);
175 | 
176 |         try {
177 |             $serialized = $this->clientGet($key);
178 |         } catch (Exception $e) {
179 |             throw ReadException::forException($e);
180 |         }
181 | 
182 |         if ($this->clientNotFoundValue() === $serialized) {
183 |             return $default;
184 |         }
185 | 
186 |         return Serializer::unserialize($serialized);
187 |     }
188 | 
189 |     /**
190 |      * {@inheritdoc}
191 |      */
192 |     public function getOrFail($key)
193 |     {
194 |         KeyUtil::validate($key);
195 | 
196 |         try {
197 |             $serialized = $this->clientGet($key);
198 |         } catch (Exception $e) {
199 |             throw ReadException::forException($e);
200 |         }
201 | 
202 |         if ($this->clientNotFoundValue() === $serialized) {
203 |             throw NoSuchKeyException::forKey($key);
204 |         }
205 | 
206 |         return Serializer::unserialize($serialized);
207 |     }
208 | 
209 |     /**
210 |      * {@inheritdoc}
211 |      */
212 |     public function set($key, $value)
213 |     {
214 |         KeyUtil::validate($key);
215 | 
216 |         $serialized = Serializer::serialize($value);
217 | 
218 |         try {
219 |             $this->clientSet($key, $serialized);
220 |         } catch (Exception $e) {
221 |             throw WriteException::forException($e);
222 |         }
223 |     }
224 | 
225 |     /**
226 |      * {@inheritdoc}
227 |      */
228 |     public function remove($key)
229 |     {
230 |         KeyUtil::validate($key);
231 | 
232 |         try {
233 |             return (bool) $this->clientRemove($key);
234 |         } catch (Exception $e) {
235 |             throw WriteException::forException($e);
236 |         }
237 |     }
238 | 
239 |     /**
240 |      * {@inheritdoc}
241 |      */
242 |     public function exists($key)
243 |     {
244 |         KeyUtil::validate($key);
245 | 
246 |         try {
247 |             return $this->clientExists($key);
248 |         } catch (Exception $e) {
249 |             throw ReadException::forException($e);
250 |         }
251 |     }
252 | 
253 |     /**
254 |      * {@inheritdoc}
255 |      */
256 |     public function clear()
257 |     {
258 |         try {
259 |             $this->clientClear();
260 |         } catch (Exception $e) {
261 |             throw WriteException::forException($e);
262 |         }
263 |     }
264 | 
265 |     /**
266 |      * {@inheritdoc}
267 |      */
268 |     public function keys()
269 |     {
270 |         try {
271 |             return $this->clientKeys();
272 |         } catch (Exception $e) {
273 |             throw ReadException::forException($e);
274 |         }
275 |     }
276 | }
277 | 
--------------------------------------------------------------------------------
/src/Api/CountableStore.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | /**
15 |  * A countable key-value store.
16 |  *
17 |  * In addition of the properties of a classical store, a countable store
18 |  * has the ability to count its keys.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  * @author Titouan Galopin 
24 |  */
25 | interface CountableStore extends KeyValueStore
26 | {
27 |     /**
28 |      * Count the number of keys in the store.
29 |      *
30 |      * @throws ReadException If the store cannot be read.
31 |      */
32 |     public function count();
33 | }
34 | 
--------------------------------------------------------------------------------
/src/Api/InvalidKeyException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | use Exception;
15 | use RuntimeException;
16 | 
17 | /**
18 |  * Thrown when a key is invalid.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  */
24 | class InvalidKeyException extends RuntimeException
25 | {
26 |     /**
27 |      * Creates an exception for an invalid key.
28 |      *
29 |      * @param mixed          $key   The invalid key.
30 |      * @param Exception|null $cause The exception that caused this exception.
31 |      *
32 |      * @return static The created exception.
33 |      */
34 |     public static function forKey($key, Exception $cause = null)
35 |     {
36 |         return new static(sprintf(
37 |             'Expected a key of type integer or string. Got: %s',
38 |             is_object($key) ? get_class($key) : gettype($key)
39 |         ), 0, $cause);
40 |     }
41 | }
42 | 
--------------------------------------------------------------------------------
/src/Api/KeyValueStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Api;
 13 | 
 14 | /**
 15 |  * A key-value store.
 16 |  *
 17 |  * KeyUtil-value stores support storing values for integer or string keys chosen
 18 |  * by the user. Any serializable value can be stored, although an implementation
 19 |  * of this interface may further restrict the range of accepted values. See the
 20 |  * documentation of the implementation for more information.
 21 |  *
 22 |  * @since  1.0
 23 |  *
 24 |  * @author Bernhard Schussek 
 25 |  */
 26 | interface KeyValueStore
 27 | {
 28 |     /**
 29 |      * Sets the value for a key in the store.
 30 |      *
 31 |      * The key-value store accepts any serializable value. If a value is not
 32 |      * serializable, a {@link SerializationFailedException} is thrown.
 33 |      * Additionally, implementations may put further restrictions on their
 34 |      * accepted values. If an unsupported value is passed, an
 35 |      * {@link UnsupportedValueException} is thrown. Check the documentation of
 36 |      * the implementation to learn more about its supported values.
 37 |      *
 38 |      * Any integer or string value is accepted as key. If any other type is
 39 |      * passed for the key, an {@link InvalidKeyException} is thrown. You should
 40 |      * make sure that you only pass valid keys to the store.
 41 |      *
 42 |      * If the backend of the store cannot be written, a {@link WriteException}
 43 |      * is thrown. You should always handle this exception in your code:
 44 |      *
 45 |      * ```php
 46 |      * try {
 47 |      *     $store->set($key, $value);
 48 |      * } catch (WriteException $e) {
 49 |      *     // write failed
 50 |      * }
 51 |      * ```
 52 |      *
 53 |      * @param int|string $key   The key to set.
 54 |      * @param mixed      $value The value to set for the key.
 55 |      *
 56 |      * @throws WriteException               If the store cannot be written.
 57 |      * @throws InvalidKeyException          If the key is not a string or integer.
 58 |      * @throws SerializationFailedException If the value cannot be serialized.
 59 |      * @throws UnsupportedValueException    If the value is not supported by the
 60 |      *                                      implementation.
 61 |      */
 62 |     public function set($key, $value);
 63 | 
 64 |     /**
 65 |      * Returns the value of a key in the store.
 66 |      *
 67 |      * If a key does not exist in the store, the default value passed in the
 68 |      * second parameter is returned.
 69 |      *
 70 |      * Any integer or string value is accepted as key. If any other type is
 71 |      * passed for the key, an {@link InvalidKeyException} is thrown. You should
 72 |      * make sure that you only pass valid keys to the store.
 73 |      *
 74 |      * If the backend of the store cannot be read, a {@link ReadException}
 75 |      * is thrown. You should always handle this exception in your code:
 76 |      *
 77 |      * ```php
 78 |      * try {
 79 |      *     $value = $store->get($key);
 80 |      * } catch (ReadException $e) {
 81 |      *     // read failed
 82 |      * }
 83 |      * ```
 84 |      *
 85 |      * @param int|string $key     The key to get.
 86 |      * @param mixed      $default The default value to return if the key does
 87 |      *                            not exist.
 88 |      *
 89 |      * @return mixed The value of the key or the default value if the key does
 90 |      *               not exist.
 91 |      *
 92 |      * @throws ReadException                  If the store cannot be read.
 93 |      * @throws InvalidKeyException            If the key is not a string or integer.
 94 |      * @throws UnserializationFailedException If the stored value cannot be
 95 |      *                                        unserialized.
 96 |      */
 97 |     public function get($key, $default = null);
 98 | 
 99 |     /**
100 |      * Returns the value of a key in the store.
101 |      *
102 |      * If the key does not exist in the store, an exception is thrown.
103 |      *
104 |      * Any integer or string value is accepted as key. If any other type is
105 |      * passed for the key, an {@link InvalidKeyException} is thrown. You should
106 |      * make sure that you only pass valid keys to the store.
107 |      *
108 |      * If the backend of the store cannot be read, a {@link ReadException}
109 |      * is thrown. You should always handle this exception in your code:
110 |      *
111 |      * ```php
112 |      * try {
113 |      *     $value = $store->getOrFail($key);
114 |      * } catch (ReadException $e) {
115 |      *     // read failed
116 |      * }
117 |      * ```
118 |      *
119 |      * @param int|string $key The key to get.
120 |      *
121 |      * @return mixed The value of the key.
122 |      *
123 |      * @throws ReadException                  If the store cannot be read.
124 |      * @throws NoSuchKeyException             If the key was not found.
125 |      * @throws InvalidKeyException            If the key is not a string or integer.
126 |      * @throws UnserializationFailedException If the stored value cannot be
127 |      *                                        unserialized.
128 |      */
129 |     public function getOrFail($key);
130 | 
131 |     /**
132 |      * Returns the values of multiple keys in the store.
133 |      *
134 |      * The passed default value is returned for keys that don't exist.
135 |      *
136 |      * Any integer or string value is accepted as key. If any other type is
137 |      * passed for the key, an {@link InvalidKeyException} is thrown. You should
138 |      * make sure that you only pass valid keys to the store.
139 |      *
140 |      * If the backend of the store cannot be read, a {@link ReadException}
141 |      * is thrown. You should always handle this exception in your code:
142 |      *
143 |      * ```php
144 |      * try {
145 |      *     $value = $store->getMultiple(array($key1, $key2));
146 |      * } catch (ReadException $e) {
147 |      *     // read failed
148 |      * }
149 |      * ```
150 |      *
151 |      * @param array $keys    The keys to get. The keys must be strings or integers.
152 |      * @param mixed $default The default value to return for keys that are not
153 |      *                       found.
154 |      *
155 |      * @return array The values of the passed keys, indexed by the keys.
156 |      *
157 |      * @throws ReadException                  If the store cannot be read.
158 |      * @throws InvalidKeyException            If a key is not a string or integer.
159 |      * @throws UnserializationFailedException If a stored value cannot be
160 |      *                                        unserialized.
161 |      */
162 |     public function getMultiple(array $keys, $default = null);
163 | 
164 |     /**
165 |      * Returns the values of multiple keys in the store.
166 |      *
167 |      * If a key does not exist in the store, an exception is thrown.
168 |      *
169 |      * Any integer or string value is accepted as key. If any other type is
170 |      * passed for the key, an {@link InvalidKeyException} is thrown. You should
171 |      * make sure that you only pass valid keys to the store.
172 |      *
173 |      * If the backend of the store cannot be read, a {@link ReadException}
174 |      * is thrown. You should always handle this exception in your code:
175 |      *
176 |      * ```php
177 |      * try {
178 |      *     $value = $store->getMultipleOrFail(array($key1, $key2));
179 |      * } catch (ReadException $e) {
180 |      *     // read failed
181 |      * }
182 |      * ```
183 |      *
184 |      * @param array $keys The keys to get. The keys must be strings or integers.
185 |      *
186 |      * @return array The values of the passed keys, indexed by the keys.
187 |      *
188 |      * @throws ReadException                  If the store cannot be read.
189 |      * @throws NoSuchKeyException             If a key was not found.
190 |      * @throws InvalidKeyException            If a key is not a string or integer.
191 |      * @throws UnserializationFailedException If a stored value cannot be
192 |      *                                        unserialized.
193 |      */
194 |     public function getMultipleOrFail(array $keys);
195 | 
196 |     /**
197 |      * Removes a key from the store.
198 |      *
199 |      * If the store does not contain the key, this method returns `false`.
200 |      *
201 |      * Any integer or string value is accepted as key. If any other type is
202 |      * passed for the key, an {@link InvalidKeyException} is thrown. You should
203 |      * make sure that you only pass valid keys to the store.
204 |      *
205 |      * If the backend of the store cannot be written, a {@link WriteException}
206 |      * is thrown. You should always handle this exception in your code:
207 |      *
208 |      * ```php
209 |      * try {
210 |      *     $store->remove($key);
211 |      * } catch (WriteException $e) {
212 |      *     // write failed
213 |      * }
214 |      * ```
215 |      *
216 |      * @param int|string $key The key to remove.
217 |      *
218 |      * @return bool Returns `true` if a key was removed from the store.
219 |      *
220 |      * @throws WriteException      If the store cannot be written.
221 |      * @throws InvalidKeyException If the key is not a string or integer.
222 |      */
223 |     public function remove($key);
224 | 
225 |     /**
226 |      * Returns whether a key exists.
227 |      *
228 |      * Any integer or string value is accepted as key. If any other type is
229 |      * passed for the key, an {@link InvalidKeyException} is thrown. You should
230 |      * make sure that you only pass valid keys to the store.
231 |      *
232 |      * If the backend of the store cannot be read, a {@link ReadException}
233 |      * is thrown. You should always handle this exception in your code:
234 |      *
235 |      * ```php
236 |      * try {
237 |      *     if ($store->exists($key)) {
238 |      *         // ...
239 |      *     }
240 |      * } catch (ReadException $e) {
241 |      *     // read failed
242 |      * }
243 |      * ```
244 |      *
245 |      * @param int|string $key The key to test.
246 |      *
247 |      * @return bool Whether the key exists in the store.
248 |      *
249 |      * @throws ReadException       If the store cannot be read.
250 |      * @throws InvalidKeyException If the key is not a string or integer.
251 |      */
252 |     public function exists($key);
253 | 
254 |     /**
255 |      * Removes all keys from the store.
256 |      *
257 |      * If the backend of the store cannot be written, a {@link WriteException}
258 |      * is thrown. You should always handle this exception in your code:
259 |      *
260 |      * ```php
261 |      * try {
262 |      *     $store->clear();
263 |      * } catch (WriteException $e) {
264 |      *     // write failed
265 |      * }
266 |      * ```
267 |      *
268 |      * @throws WriteException If the store cannot be written.
269 |      */
270 |     public function clear();
271 | 
272 |     /**
273 |      * Returns all keys currently stored in the store.
274 |      *
275 |      * If the backend of the store cannot be read, a {@link ReadException}
276 |      * is thrown. You should always handle this exception in your code:
277 |      *
278 |      * ```php
279 |      * try {
280 |      *     foreach ($store->keys() as $key) {
281 |      *         // ...
282 |      *     }
283 |      * } catch (ReadException $e) {
284 |      *     // read failed
285 |      * }
286 |      * ```
287 |      *
288 |      * @return array The keys stored in the store. Each key is either a string
289 |      *               or an integer. The order of the keys is undefined.
290 |      *
291 |      * @throws ReadException If the store cannot be read.
292 |      */
293 |     public function keys();
294 | }
295 | 
--------------------------------------------------------------------------------
/src/Api/NoSuchKeyException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | use Exception;
15 | use RuntimeException;
16 | 
17 | /**
18 |  * Thrown when a key was not found in the store.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  */
24 | class NoSuchKeyException extends RuntimeException
25 | {
26 |     /**
27 |      * Creates an exception for a key that was not found.
28 |      *
29 |      * @param string|int     $key   The key that was not found.
30 |      * @param Exception|null $cause The exception that caused this exception.
31 |      *
32 |      * @return static The created exception.
33 |      */
34 |     public static function forKey($key, Exception $cause = null)
35 |     {
36 |         return new static(sprintf(
37 |             'The key "%s" does not exist.',
38 |             $key
39 |         ), 0, $cause);
40 |     }
41 | 
42 |     /**
43 |      * Creates an exception for multiple keys that were not found.
44 |      *
45 |      * @param array[]        $keys  The keys that were not found.
46 |      * @param Exception|null $cause The exception that caused this exception.
47 |      *
48 |      * @return static The created exception.
49 |      */
50 |     public static function forKeys(array $keys, Exception $cause = null)
51 |     {
52 |         return new static(sprintf(
53 |             'The keys "%s" does not exist.',
54 |             implode('", "', $keys)
55 |         ), 0, $cause);
56 |     }
57 | }
58 | 
--------------------------------------------------------------------------------
/src/Api/ReadException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | use Exception;
15 | use RuntimeException;
16 | 
17 | /**
18 |  * Thrown when a key-value store cannot be read.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  */
24 | class ReadException extends RuntimeException
25 | {
26 |     /**
27 |      * Creates a new exception..
28 |      *
29 |      * @param Exception $exception The exception that caused this exception.
30 |      *
31 |      * @return static The new exception.
32 |      */
33 |     public static function forException(Exception $exception)
34 |     {
35 |         return new static(sprintf(
36 |             'Could not read key-value store: %s',
37 |             $exception->getMessage()
38 |         ), $exception->getCode(), $exception);
39 |     }
40 | }
41 | 
--------------------------------------------------------------------------------
/src/Api/SerializationFailedException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | use Exception;
15 | use RuntimeException;
16 | 
17 | /**
18 |  * Thrown when a value cannot be serialized.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  */
24 | class SerializationFailedException extends RuntimeException
25 | {
26 |     /**
27 |      * Creates a new exception for the given value.
28 |      *
29 |      * @param mixed     $value  The value that could not be serialized.
30 |      * @param string    $reason The reason why the value could not be
31 |      *                          unserialized.
32 |      * @param int       $code   The exception code.
33 |      * @param Exception $cause  The exception that caused this exception.
34 |      *
35 |      * @return static The new exception.
36 |      */
37 |     public static function forValue($value, $reason = '', $code = 0, Exception $cause = null)
38 |     {
39 |         return self::forType(is_object($value) ? get_class($value) : gettype($value), $reason, $code, $cause);
40 |     }
41 | 
42 |     /**
43 |      * Creates a new exception for the given value type.
44 |      *
45 |      * @param string    $type   The type that could not be serialized.
46 |      * @param string    $reason The reason why the value could not be
47 |      *                          unserialized.
48 |      * @param int       $code   The exception code.
49 |      * @param Exception $cause  The exception that caused this exception.
50 |      *
51 |      * @return static The new exception.
52 |      */
53 |     public static function forType($type, $reason = '', $code = 0, Exception $cause = null)
54 |     {
55 |         return new static(sprintf(
56 |             'Could not serialize value of type %s%s',
57 |             $type,
58 |             $reason ? ': '.$reason : '.'
59 |         ), $code, $cause);
60 |     }
61 | }
62 | 
--------------------------------------------------------------------------------
/src/Api/SortableStore.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | /**
15 |  * A sortable key-value store.
16 |  *
17 |  * In addition of the properties of a classical store, a sortable store
18 |  * has the ability to sort its values by its keys.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  * @author Titouan Galopin 
24 |  */
25 | interface SortableStore extends KeyValueStore
26 | {
27 |     /**
28 |      * Sort the store by its keys.
29 |      *
30 |      * The store values will be arranged from lowest to highest when this
31 |      * function has completed.
32 |      *
33 |      * This method accepts an optional second parameter that may be used
34 |      * to modify the sorting behavior using the standard sort flags of PHP.
35 |      *
36 |      * @see http://php.net/manual/en/function.sort.php
37 |      *
38 |      * @param int $flags Sorting type flags (from the standard PHP sort flags).
39 |      *
40 |      * @throws ReadException  If the store cannot be read.
41 |      * @throws WriteException If the store cannot be written.
42 |      */
43 |     public function sort($flags = SORT_REGULAR);
44 | }
45 | 
--------------------------------------------------------------------------------
/src/Api/UnserializationFailedException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | use Exception;
15 | use RuntimeException;
16 | 
17 | /**
18 |  * Thrown when a value cannot be unserialized.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  */
24 | class UnserializationFailedException extends RuntimeException
25 | {
26 |     /**
27 |      * Creates a new exception for the given value.
28 |      *
29 |      * @param mixed     $value  The value that could not be unserialized.
30 |      * @param string    $reason The reason why the value could not be
31 |      *                          unserialized.
32 |      * @param int       $code   The exception code.
33 |      * @param Exception $cause  The exception that caused this exception.
34 |      *
35 |      * @return static The new exception.
36 |      */
37 |     public static function forValue($value, $reason = '', $code = 0, Exception $cause = null)
38 |     {
39 |         return self::forType(is_object($value) ? get_class($value) : gettype($value), $reason, $code, $cause);
40 |     }
41 | 
42 |     /**
43 |      * Creates a new exception for the given value type.
44 |      *
45 |      * @param string    $type   The type that could not be unserialized.
46 |      * @param string    $reason The reason why the value could not be
47 |      *                          unserialized.
48 |      * @param int       $code   The exception code.
49 |      * @param Exception $cause  The exception that caused this exception.
50 |      *
51 |      * @return static The new exception.
52 |      */
53 |     public static function forType($type, $reason = '', $code = 0, Exception $cause = null)
54 |     {
55 |         return new static(sprintf(
56 |             'Could not unserialize value of type %s%s',
57 |             $type,
58 |             $reason ? ': '.$reason : '.'
59 |         ), $code, $cause);
60 |     }
61 | }
62 | 
--------------------------------------------------------------------------------
/src/Api/UnsupportedValueException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | use Exception;
15 | use RuntimeException;
16 | 
17 | /**
18 |  * Thrown when an unsupported value is stored in a key-value store.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  */
24 | class UnsupportedValueException extends RuntimeException
25 | {
26 |     /**
27 |      * Creates a new exception for the given value type.
28 |      *
29 |      * @param string         $type  The name of the unsupported type.
30 |      * @param KeyValueStore  $store The store that does not support the type.
31 |      * @param int            $code  The exception code.
32 |      * @param Exception|null $cause The exception that caused this exception.
33 |      *
34 |      * @return static The new exception.
35 |      */
36 |     public static function forType($type, KeyValueStore $store, $code = 0, Exception $cause = null)
37 |     {
38 |         return new static(sprintf(
39 |             'Values of type %s are not supported by %s.',
40 |             $type,
41 |             get_class($store)
42 |         ), $code, $cause);
43 |     }
44 | 
45 |     /**
46 |      * Creates a new exception for the given value.
47 |      *
48 |      * @param string         $value The unsupported value.
49 |      * @param KeyValueStore  $store The store that does not support the type.
50 |      * @param int            $code  The exception code.
51 |      * @param Exception|null $cause The exception that caused this exception.
52 |      *
53 |      * @return static The new exception.
54 |      */
55 |     public static function forValue($value, KeyValueStore $store, $code = 0, Exception $cause = null)
56 |     {
57 |         return new static(sprintf(
58 |             'Values of type %s are not supported by %s.',
59 |             gettype($value),
60 |             get_class($store)
61 |         ), $code, $cause);
62 |     }
63 | }
64 | 
--------------------------------------------------------------------------------
/src/Api/WriteException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Api;
13 | 
14 | use Exception;
15 | use RuntimeException;
16 | 
17 | /**
18 |  * Thrown when a key-value store cannot be written.
19 |  *
20 |  * @since  1.0
21 |  *
22 |  * @author Bernhard Schussek 
23 |  */
24 | class WriteException extends RuntimeException
25 | {
26 |     /**
27 |      * Creates a new exception..
28 |      *
29 |      * @param Exception $exception The exception that caused this exception.
30 |      *
31 |      * @return static The new exception.
32 |      */
33 |     public static function forException(Exception $exception)
34 |     {
35 |         return new static(sprintf(
36 |             'Could not write key-value store: %s',
37 |             $exception->getMessage()
38 |         ), $exception->getCode(), $exception);
39 |     }
40 | }
41 | 
--------------------------------------------------------------------------------
/src/ArrayStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Webmozart\KeyValueStore\Api\CountableStore;
 15 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 16 | use Webmozart\KeyValueStore\Api\SortableStore;
 17 | use Webmozart\KeyValueStore\Util\KeyUtil;
 18 | 
 19 | /**
 20 |  * A key-value store backed by a PHP array.
 21 |  *
 22 |  * The contents of the store are lost when the store is released from memory.
 23 |  *
 24 |  * @since  1.0
 25 |  *
 26 |  * @author Bernhard Schussek 
 27 |  */
 28 | class ArrayStore implements SortableStore, CountableStore
 29 | {
 30 |     /**
 31 |      * Flag: Enable serialization.
 32 |      */
 33 |     const SERIALIZE = 1;
 34 | 
 35 |     /**
 36 |      * @var array
 37 |      */
 38 |     private $array = array();
 39 | 
 40 |     /**
 41 |      * @var callable
 42 |      */
 43 |     private $serialize;
 44 | 
 45 |     /**
 46 |      * @var callable
 47 |      */
 48 |     private $unserialize;
 49 | 
 50 |     /**
 51 |      * Creates a new store.
 52 |      *
 53 |      * @param array $array The values to set initially in the store.
 54 |      */
 55 |     public function __construct(array $array = array(), $flags = 0)
 56 |     {
 57 |         if ($flags & self::SERIALIZE) {
 58 |             $this->serialize = array(
 59 |                 'Webmozart\KeyValueStore\Util\Serializer',
 60 |                 'serialize',
 61 |             );
 62 |             $this->unserialize = array(
 63 |                 'Webmozart\KeyValueStore\Util\Serializer',
 64 |                 'unserialize',
 65 |             );
 66 |         } else {
 67 |             $this->serialize = function ($value) {
 68 |                 return $value;
 69 |             };
 70 |             $this->unserialize = function ($value) {
 71 |                 return $value;
 72 |             };
 73 |         }
 74 | 
 75 |         foreach ($array as $key => $value) {
 76 |             $this->set($key, $value);
 77 |         }
 78 |     }
 79 | 
 80 |     /**
 81 |      * {@inheritdoc}
 82 |      */
 83 |     public function set($key, $value)
 84 |     {
 85 |         KeyUtil::validate($key);
 86 | 
 87 |         $this->array[$key] = call_user_func($this->serialize, $value);
 88 |     }
 89 | 
 90 |     /**
 91 |      * {@inheritdoc}
 92 |      */
 93 |     public function get($key, $default = null)
 94 |     {
 95 |         KeyUtil::validate($key);
 96 | 
 97 |         if (!array_key_exists($key, $this->array)) {
 98 |             return $default;
 99 |         }
100 | 
101 |         return call_user_func($this->unserialize, $this->array[$key]);
102 |     }
103 | 
104 |     /**
105 |      * {@inheritdoc}
106 |      */
107 |     public function getOrFail($key)
108 |     {
109 |         KeyUtil::validate($key);
110 | 
111 |         if (!array_key_exists($key, $this->array)) {
112 |             throw NoSuchKeyException::forKey($key);
113 |         }
114 | 
115 |         return call_user_func($this->unserialize, $this->array[$key]);
116 |     }
117 | 
118 |     /**
119 |      * {@inheritdoc}
120 |      */
121 |     public function getMultiple(array $keys, $default = null)
122 |     {
123 |         KeyUtil::validateMultiple($keys);
124 | 
125 |         $values = array();
126 | 
127 |         foreach ($keys as $key) {
128 |             $values[$key] = array_key_exists($key, $this->array)
129 |                 ? call_user_func($this->unserialize, $this->array[$key])
130 |                 : $default;
131 |         }
132 | 
133 |         return $values;
134 |     }
135 | 
136 |     /**
137 |      * {@inheritdoc}
138 |      */
139 |     public function getMultipleOrFail(array $keys)
140 |     {
141 |         KeyUtil::validateMultiple($keys);
142 | 
143 |         $notFoundKeys = array_diff($keys, array_keys($this->array));
144 | 
145 |         if (count($notFoundKeys) > 0) {
146 |             throw NoSuchKeyException::forKeys($notFoundKeys);
147 |         }
148 | 
149 |         return $this->getMultiple($keys);
150 |     }
151 | 
152 |     /**
153 |      * {@inheritdoc}
154 |      */
155 |     public function remove($key)
156 |     {
157 |         KeyUtil::validate($key);
158 | 
159 |         $removed = array_key_exists($key, $this->array);
160 | 
161 |         unset($this->array[$key]);
162 | 
163 |         return $removed;
164 |     }
165 | 
166 |     /**
167 |      * {@inheritdoc}
168 |      */
169 |     public function exists($key)
170 |     {
171 |         KeyUtil::validate($key);
172 | 
173 |         return array_key_exists($key, $this->array);
174 |     }
175 | 
176 |     /**
177 |      * {@inheritdoc}
178 |      */
179 |     public function clear()
180 |     {
181 |         $this->array = array();
182 |     }
183 | 
184 |     /**
185 |      * {@inheritdoc}
186 |      */
187 |     public function keys()
188 |     {
189 |         return array_keys($this->array);
190 |     }
191 | 
192 |     /**
193 |      * Returns the contents of the store as array.
194 |      *
195 |      * @return array The keys and values in the store.
196 |      */
197 |     public function toArray()
198 |     {
199 |         return array_map($this->unserialize, $this->array);
200 |     }
201 | 
202 |     /**
203 |      * {@inheritdoc}
204 |      */
205 |     public function sort($flags = SORT_REGULAR)
206 |     {
207 |         ksort($this->array, $flags);
208 |     }
209 | 
210 |     /**
211 |      * {@inheritdoc}
212 |      */
213 |     public function count()
214 |     {
215 |         return count($this->array);
216 |     }
217 | }
218 | 
--------------------------------------------------------------------------------
/src/DbalStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Doctrine\DBAL\Connection;
 15 | use Doctrine\DBAL\Schema\Schema;
 16 | use Doctrine\DBAL\Schema\Table;
 17 | use Exception;
 18 | use PDO;
 19 | use Webmozart\Assert\Assert;
 20 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 21 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 22 | use Webmozart\KeyValueStore\Api\ReadException;
 23 | use Webmozart\KeyValueStore\Api\WriteException;
 24 | use Webmozart\KeyValueStore\Util\KeyUtil;
 25 | use Webmozart\KeyValueStore\Util\Serializer;
 26 | 
 27 | /**
 28 |  * A key-value store backed by Doctrine DBAL.
 29 |  *
 30 |  * @since  1.0
 31 |  *
 32 |  * @author Bernhard Schussek 
 33 |  * @author Michiel Boeckaert 
 34 |  */
 35 | class DbalStore implements KeyValueStore
 36 | {
 37 |     private $connection;
 38 |     private $tableName;
 39 | 
 40 |     /**
 41 |      * @param Connection $connection A doctrine connection instance
 42 |      * @param string     $tableName  The name of the database table
 43 |      */
 44 |     public function __construct(Connection $connection, $tableName = 'store')
 45 |     {
 46 |         Assert::stringNotEmpty($tableName, 'The table must be a string. Got: %s');
 47 | 
 48 |         $this->connection = $connection;
 49 |         $this->tableName = $tableName;
 50 |     }
 51 | 
 52 |     /**
 53 |      * {@inheritdoc}
 54 |      */
 55 |     public function set($key, $value)
 56 |     {
 57 |         KeyUtil::validate($key);
 58 | 
 59 |         try {
 60 |             $existing = $this->exists($key);
 61 |         } catch (Exception $e) {
 62 |             throw WriteException::forException($e);
 63 |         }
 64 | 
 65 |         if (false === $existing) {
 66 |             $this->doInsert($key, $value);
 67 |         } else {
 68 |             $this->doUpdate($key, $value);
 69 |         }
 70 |     }
 71 | 
 72 |     /**
 73 |      * {@inheritdoc}
 74 |      */
 75 |     public function get($key, $default = null)
 76 |     {
 77 |         KeyUtil::validate($key);
 78 | 
 79 |         $dbResult = $this->getDbRow($key);
 80 | 
 81 |         if (null === $dbResult) {
 82 |             return $default;
 83 |         }
 84 | 
 85 |         return Serializer::unserialize($dbResult['meta_value']);
 86 |     }
 87 | 
 88 |     /**
 89 |      * {@inheritdoc}
 90 |      */
 91 |     public function getOrFail($key)
 92 |     {
 93 |         KeyUtil::validate($key);
 94 | 
 95 |         $dbResult = $this->getDbRow($key);
 96 | 
 97 |         if (null === $dbResult) {
 98 |             throw NoSuchKeyException::forKey($key);
 99 |         }
100 | 
101 |         return Serializer::unserialize($dbResult['meta_value']);
102 |     }
103 | 
104 |     /**
105 |      * {@inheritdoc}
106 |      */
107 |     public function getMultiple(array $keys, $default = null)
108 |     {
109 |         KeyUtil::validateMultiple($keys);
110 | 
111 |         // Normalize indices of the array
112 |         $keys = array_values($keys);
113 |         $data = $this->doGetMultiple($keys);
114 | 
115 |         $results = array();
116 |         $resolved = array();
117 |         foreach ($data as $row) {
118 |             $results[$row['meta_key']] = Serializer::unserialize($row['meta_value']);
119 |             $resolved[$row['meta_key']] = $row['meta_key'];
120 |         }
121 | 
122 |         $notResolvedArr = array_diff($keys, $resolved);
123 |         foreach ($notResolvedArr as $notResolved) {
124 |             $results[$notResolved] = $default;
125 |         }
126 | 
127 |         return $results;
128 |     }
129 | 
130 |     /**
131 |      * {@inheritdoc}
132 |      */
133 |     public function getMultipleOrFail(array $keys)
134 |     {
135 |         KeyUtil::validateMultiple($keys);
136 | 
137 |         // Normalize indices of the array
138 |         $keys = array_values($keys);
139 | 
140 |         $data = $this->doGetMultiple($keys);
141 | 
142 |         $results = array();
143 |         $resolved = array();
144 |         foreach ($data as $row) {
145 |             $results[$row['meta_key']] = Serializer::unserialize($row['meta_value']);
146 |             $resolved[] = $row['meta_key'];
147 |         }
148 | 
149 |         $notResolvedArr = array_diff($keys, $resolved);
150 | 
151 |         if (!empty($notResolvedArr)) {
152 |             throw NoSuchKeyException::forKeys($notResolvedArr);
153 |         }
154 | 
155 |         return $results;
156 |     }
157 | 
158 |     /**
159 |      * {@inheritdoc}
160 |      */
161 |     public function remove($key)
162 |     {
163 |         KeyUtil::validate($key);
164 | 
165 |         try {
166 |             $result = $this->connection->delete($this->tableName, array('meta_key' => $key));
167 |         } catch (Exception $e) {
168 |             throw WriteException::forException($e);
169 |         }
170 | 
171 |         return $result === 1;
172 |     }
173 | 
174 |     /**
175 |      * {@inheritdoc}
176 |      */
177 |     public function exists($key)
178 |     {
179 |         KeyUtil::validate($key);
180 | 
181 |         try {
182 |             $result = $this->connection->fetchAssoc('SELECT * FROM '.$this->tableName.' WHERE meta_key = ?', array($key));
183 |         } catch (Exception $e) {
184 |             throw ReadException::forException($e);
185 |         }
186 | 
187 |         return $result ? true : false;
188 |     }
189 | 
190 |     /**
191 |      * {@inheritdoc}
192 |      */
193 |     public function clear()
194 |     {
195 |         try {
196 |             $stmt = $this->connection->query('DELETE FROM '.$this->tableName);
197 |             $stmt->execute();
198 |         } catch (Exception $e) {
199 |             throw WriteException::forException($e);
200 |         }
201 |     }
202 | 
203 |     /**
204 |      * {@inheritdoc}
205 |      */
206 |     public function keys()
207 |     {
208 |         try {
209 |             $stmt = $this->connection->query('SELECT meta_key FROM '.$this->tableName);
210 |             $result = $stmt->fetchAll(PDO::FETCH_COLUMN);
211 |         } catch (Exception $e) {
212 |             throw ReadException::forException($e);
213 |         }
214 | 
215 |         return $result;
216 |     }
217 | 
218 |     /**
219 |      * The name for our DBAL database table.
220 |      *
221 |      * @return string
222 |      */
223 |     public function getTableName()
224 |     {
225 |         return $this->tableName;
226 |     }
227 | 
228 |     /**
229 |      * Object Representation of the table used in this class.
230 |      *
231 |      * @return Table
232 |      */
233 |     public function getTableForCreate()
234 |     {
235 |         $schema = new Schema();
236 | 
237 |         $table = $schema->createTable($this->getTableName());
238 | 
239 |         $table->addColumn('id', 'integer', array('autoincrement' => true));
240 |         $table->addColumn('meta_key', 'string', array('length' => 255));
241 |         $table->addColumn('meta_value', 'object');
242 |         $table->setPrimaryKey(array('id'));
243 |         $table->addUniqueIndex(array('meta_key'));
244 | 
245 |         return $table;
246 |     }
247 | 
248 |     private function doInsert($key, $value)
249 |     {
250 |         $serialized = Serializer::serialize($value);
251 | 
252 |         try {
253 |             $this->connection->insert($this->tableName, array(
254 |                 'meta_key' => $key,
255 |                 'meta_value' => $serialized,
256 |             ));
257 |         } catch (Exception $e) {
258 |             throw WriteException::forException($e);
259 |         }
260 |     }
261 | 
262 |     private function doUpdate($key, $value)
263 |     {
264 |         $serialized = Serializer::serialize($value);
265 | 
266 |         try {
267 |             $this->connection->update($this->tableName, array(
268 |                 'meta_value' => $serialized,
269 |             ), array(
270 |                 'meta_key' => $key,
271 |             ));
272 |         } catch (Exception $e) {
273 |             throw WriteException::forException($e);
274 |         }
275 |     }
276 | 
277 |     private function doGetMultiple(array $keys)
278 |     {
279 |         try {
280 |             $stmt = $this->connection->executeQuery('SELECT * FROM '.$this->tableName.' WHERE meta_key IN (?)',
281 |                 array($keys),
282 |                 array(Connection::PARAM_STR_ARRAY)
283 |             );
284 |             $data = $stmt->fetchAll();
285 |         } catch (Exception $e) {
286 |             throw ReadException::forException($e);
287 |         }
288 | 
289 |         return is_array($data) ? $data : array();
290 |     }
291 | 
292 |     private function getDbRow($key)
293 |     {
294 |         try {
295 |             $dbResult = $this->connection->fetchAssoc('SELECT meta_value, meta_key FROM '.$this->tableName.' WHERE meta_key = ?', array($key));
296 |         } catch (Exception $e) {
297 |             throw ReadException::forException($e);
298 |         }
299 | 
300 |         if (empty($dbResult)) {
301 |             return null;
302 |         }
303 | 
304 |         return $dbResult;
305 |     }
306 | }
307 | 
--------------------------------------------------------------------------------
/src/Decorator/AbstractDecorator.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Decorator;
 13 | 
 14 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 15 | 
 16 | /**
 17 |  * A delegating decorator delegate each call of a KeyValueStore method
 18 |  * to the internal store.
 19 |  *
 20 |  * It is used by decorators that need to override only a few specific
 21 |  * methods (such as SortableDecorator or CountableDecorator).
 22 |  *
 23 |  * @since  1.0
 24 |  *
 25 |  * @author Bernhard Schussek 
 26 |  * @author Titouan Galopin 
 27 |  */
 28 | class AbstractDecorator implements KeyValueStore
 29 | {
 30 |     /**
 31 |      * @var KeyValueStore
 32 |      */
 33 |     protected $store;
 34 | 
 35 |     /**
 36 |      * Creates the store.
 37 |      *
 38 |      * @param KeyValueStore $store The store to sort.
 39 |      */
 40 |     public function __construct(KeyValueStore $store)
 41 |     {
 42 |         $this->store = $store;
 43 |     }
 44 | 
 45 |     /**
 46 |      * {@inheritdoc}
 47 |      */
 48 |     public function set($key, $value)
 49 |     {
 50 |         $this->store->set($key, $value);
 51 |     }
 52 | 
 53 |     /**
 54 |      * {@inheritdoc}
 55 |      */
 56 |     public function get($key, $default = null)
 57 |     {
 58 |         return $this->store->get($key, $default);
 59 |     }
 60 | 
 61 |     /**
 62 |      * {@inheritdoc}
 63 |      */
 64 |     public function getOrFail($key)
 65 |     {
 66 |         return $this->store->getOrFail($key);
 67 |     }
 68 | 
 69 |     /**
 70 |      * {@inheritdoc}
 71 |      */
 72 |     public function getMultiple(array $keys, $default = null)
 73 |     {
 74 |         return $this->store->getMultiple($keys, $default);
 75 |     }
 76 | 
 77 |     /**
 78 |      * {@inheritdoc}
 79 |      */
 80 |     public function getMultipleOrFail(array $keys)
 81 |     {
 82 |         return $this->store->getMultipleOrFail($keys);
 83 |     }
 84 | 
 85 |     /**
 86 |      * {@inheritdoc}
 87 |      */
 88 |     public function remove($key)
 89 |     {
 90 |         $this->store->remove($key);
 91 |     }
 92 | 
 93 |     /**
 94 |      * {@inheritdoc}
 95 |      */
 96 |     public function exists($key)
 97 |     {
 98 |         return $this->store->exists($key);
 99 |     }
100 | 
101 |     /**
102 |      * {@inheritdoc}
103 |      */
104 |     public function clear()
105 |     {
106 |         $this->store->clear();
107 |     }
108 | 
109 |     /**
110 |      * {@inheritdoc}
111 |      */
112 |     public function keys()
113 |     {
114 |         return $this->store->keys();
115 |     }
116 | }
117 | 
--------------------------------------------------------------------------------
/src/Decorator/CachingDecorator.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Decorator;
 13 | 
 14 | use Doctrine\Common\Cache\Cache;
 15 | use Doctrine\Common\Cache\ClearableCache;
 16 | use Doctrine\Common\Cache\FlushableCache;
 17 | use InvalidArgumentException;
 18 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 19 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 20 | 
 21 | /**
 22 |  * A caching decorator implementing a cache layer for any store.
 23 |  *
 24 |  * @since  1.0
 25 |  *
 26 |  * @author Bernhard Schussek 
 27 |  */
 28 | class CachingDecorator extends AbstractDecorator
 29 | {
 30 |     /**
 31 |      * @var Cache
 32 |      */
 33 |     private $cache;
 34 | 
 35 |     private $ttl;
 36 | 
 37 |     /**
 38 |      * Creates the store.
 39 |      *
 40 |      * @param KeyValueStore $store The cached store.
 41 |      * @param Cache         $cache The cache.
 42 |      * @param int           $ttl   The time-to-live for cache entries. If set to
 43 |      *                             0, cache entries never expire.
 44 |      *
 45 |      * @throws InvalidArgumentException If the provided cache is not supported
 46 |      */
 47 |     public function __construct(KeyValueStore $store, Cache $cache, $ttl = 0)
 48 |     {
 49 |         if (!$cache instanceof ClearableCache && !$cache instanceof FlushableCache) {
 50 |             throw new InvalidArgumentException(sprintf(
 51 |                 'The cache must either implement ClearableCache or '.
 52 |                 'FlushableCache. Got: %s',
 53 |                 get_class($cache)
 54 |             ));
 55 |         }
 56 | 
 57 |         parent::__construct($store);
 58 | 
 59 |         $this->cache = $cache;
 60 |         $this->ttl = $ttl;
 61 |     }
 62 | 
 63 |     /**
 64 |      * {@inheritdoc}
 65 |      */
 66 |     public function set($key, $value)
 67 |     {
 68 |         $this->store->set($key, $value);
 69 |         $this->cache->save($key, $value, $this->ttl);
 70 |     }
 71 | 
 72 |     /**
 73 |      * {@inheritdoc}
 74 |      */
 75 |     public function get($key, $default = null)
 76 |     {
 77 |         if ($this->cache->contains($key)) {
 78 |             return $this->cache->fetch($key);
 79 |         }
 80 | 
 81 |         try {
 82 |             $value = $this->store->getOrFail($key);
 83 |         } catch (NoSuchKeyException $e) {
 84 |             return $default;
 85 |         }
 86 | 
 87 |         $this->cache->save($key, $value, $this->ttl);
 88 | 
 89 |         return $value;
 90 |     }
 91 | 
 92 |     /**
 93 |      * {@inheritdoc}
 94 |      */
 95 |     public function getOrFail($key)
 96 |     {
 97 |         if ($this->cache->contains($key)) {
 98 |             return $this->cache->fetch($key);
 99 |         }
100 | 
101 |         $value = $this->store->getOrFail($key);
102 | 
103 |         $this->cache->save($key, $value, $this->ttl);
104 | 
105 |         return $value;
106 |     }
107 | 
108 |     /**
109 |      * {@inheritdoc}
110 |      */
111 |     public function getMultiple(array $keys, $default = null)
112 |     {
113 |         $values = array();
114 | 
115 |         // Read cached values from the cache
116 |         foreach ($keys as $i => $key) {
117 |             if ($this->cache->contains($key)) {
118 |                 $values[$key] = $this->cache->fetch($key);
119 |                 unset($keys[$i]);
120 |             }
121 |         }
122 | 
123 |         // Don't write cache, as we can't differentiate between existing and
124 |         // non-existing keys
125 |         return array_replace($values, $this->store->getMultiple($keys, $default));
126 |     }
127 | 
128 |     /**
129 |      * {@inheritdoc}
130 |      */
131 |     public function getMultipleOrFail(array $keys)
132 |     {
133 |         $values = array();
134 | 
135 |         // Read cached values from the cache
136 |         foreach ($keys as $i => $key) {
137 |             if ($this->cache->contains($key)) {
138 |                 $values[$key] = $this->cache->fetch($key);
139 |                 unset($keys[$i]);
140 |             }
141 |         }
142 | 
143 |         $values = array_replace($values, $this->store->getMultipleOrFail($keys));
144 | 
145 |         // Write newly fetched values to the cache
146 |         foreach ($keys as $key) {
147 |             $this->cache->save($key, $values[$key], $this->ttl);
148 |         }
149 | 
150 |         return $values;
151 |     }
152 | 
153 |     /**
154 |      * {@inheritdoc}
155 |      */
156 |     public function remove($key)
157 |     {
158 |         $this->store->remove($key);
159 |         $this->cache->delete($key);
160 |     }
161 | 
162 |     /**
163 |      * {@inheritdoc}
164 |      */
165 |     public function exists($key)
166 |     {
167 |         if ($this->cache->contains($key)) {
168 |             return true;
169 |         }
170 | 
171 |         return $this->store->exists($key);
172 |     }
173 | 
174 |     /**
175 |      * {@inheritdoc}
176 |      */
177 |     public function clear()
178 |     {
179 |         $this->store->clear();
180 | 
181 |         if ($this->cache instanceof ClearableCache) {
182 |             $this->cache->deleteAll();
183 |         } else {
184 |             $this->cache->flushAll();
185 |         }
186 |     }
187 | }
188 | 
--------------------------------------------------------------------------------
/src/Decorator/CountableDecorator.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Decorator;
13 | 
14 | use Webmozart\KeyValueStore\Api\CountableStore;
15 | 
16 | /**
17 |  * A countable decorator implementing a count system for any store.
18 |  *
19 |  * @since  1.0
20 |  *
21 |  * @author Bernhard Schussek 
22 |  * @author Titouan Galopin 
23 |  */
24 | class CountableDecorator extends AbstractDecorator implements CountableStore
25 | {
26 |     /**
27 |      * In-memory cache invalidated on store modification.
28 |      *
29 |      * @var int
30 |      */
31 |     private $cache;
32 | 
33 |     /**
34 |      * Is the cache fresh enough to be served?
35 |      *
36 |      * @var bool
37 |      */
38 |     private $cacheIsFresh = false;
39 | 
40 |     /**
41 |      * {@inheritdoc}
42 |      */
43 |     public function set($key, $value)
44 |     {
45 |         $this->cacheIsFresh = false;
46 |         $this->store->set($key, $value);
47 |     }
48 | 
49 |     /**
50 |      * {@inheritdoc}
51 |      */
52 |     public function remove($key)
53 |     {
54 |         $this->cacheIsFresh = false;
55 |         $this->store->remove($key);
56 |     }
57 | 
58 |     /**
59 |      * {@inheritdoc}
60 |      */
61 |     public function clear()
62 |     {
63 |         $this->cacheIsFresh = false;
64 |         $this->store->clear();
65 |     }
66 | 
67 |     /**
68 |      * {@inheritdoc}
69 |      */
70 |     public function count()
71 |     {
72 |         if (!$this->cacheIsFresh) {
73 |             $this->cache = count($this->store->keys());
74 |             $this->cacheIsFresh = true;
75 |         }
76 | 
77 |         return $this->cache;
78 |     }
79 | }
80 | 
--------------------------------------------------------------------------------
/src/Decorator/SortableDecorator.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Decorator;
13 | 
14 | use Webmozart\KeyValueStore\Api\SortableStore;
15 | 
16 | /**
17 |  * A sortable decorator implementing a sort system for any store.
18 |  *
19 |  * @since  1.0
20 |  *
21 |  * @author Bernhard Schussek 
22 |  * @author Titouan Galopin 
23 |  */
24 | class SortableDecorator extends AbstractDecorator implements SortableStore
25 | {
26 |     /**
27 |      * @var int
28 |      */
29 |     private $flags;
30 | 
31 |     /**
32 |      * {@inheritdoc}
33 |      */
34 |     public function sort($flags = SORT_REGULAR)
35 |     {
36 |         $this->flags = $flags;
37 |     }
38 | 
39 |     /**
40 |      * {@inheritdoc}
41 |      */
42 |     public function set($key, $value)
43 |     {
44 |         $this->flags = null;
45 |         $this->store->set($key, $value);
46 |     }
47 | 
48 |     /**
49 |      * {@inheritdoc}
50 |      */
51 |     public function keys()
52 |     {
53 |         $keys = $this->store->keys();
54 | 
55 |         if (null !== $this->flags) {
56 |             sort($keys, $this->flags);
57 |         }
58 | 
59 |         return $keys;
60 |     }
61 | }
62 | 
--------------------------------------------------------------------------------
/src/JsonFileStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use stdClass;
 15 | use Webmozart\Assert\Assert;
 16 | use Webmozart\Json\DecodingFailedException;
 17 | use Webmozart\Json\EncodingFailedException;
 18 | use Webmozart\Json\FileNotFoundException;
 19 | use Webmozart\Json\IOException;
 20 | use Webmozart\Json\JsonDecoder;
 21 | use Webmozart\Json\JsonEncoder;
 22 | use Webmozart\KeyValueStore\Api\CountableStore;
 23 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 24 | use Webmozart\KeyValueStore\Api\ReadException;
 25 | use Webmozart\KeyValueStore\Api\SortableStore;
 26 | use Webmozart\KeyValueStore\Api\UnsupportedValueException;
 27 | use Webmozart\KeyValueStore\Api\WriteException;
 28 | use Webmozart\KeyValueStore\Util\KeyUtil;
 29 | use Webmozart\KeyValueStore\Util\Serializer;
 30 | 
 31 | /**
 32 |  * A key-value store backed by a JSON file.
 33 |  *
 34 |  * @since  1.0
 35 |  *
 36 |  * @author Bernhard Schussek 
 37 |  */
 38 | class JsonFileStore implements SortableStore, CountableStore
 39 | {
 40 |     /**
 41 |      * Flag: Disable serialization of strings.
 42 |      */
 43 |     const NO_SERIALIZE_STRINGS = 1;
 44 | 
 45 |     /**
 46 |      * Flag: Disable serialization of arrays.
 47 |      */
 48 |     const NO_SERIALIZE_ARRAYS = 2;
 49 | 
 50 |     /**
 51 |      * Flag: Escape ">" and "<".
 52 |      */
 53 |     const ESCAPE_GT_LT = 4;
 54 | 
 55 |     /**
 56 |      * Flag: Escape "&".
 57 |      */
 58 |     const ESCAPE_AMPERSAND = 8;
 59 | 
 60 |     /**
 61 |      * Flag: Escape single quotes.
 62 |      */
 63 |     const ESCAPE_SINGLE_QUOTE = 16;
 64 | 
 65 |     /**
 66 |      * Flag: Escape double quotes.
 67 |      */
 68 |     const ESCAPE_DOUBLE_QUOTE = 32;
 69 | 
 70 |     /**
 71 |      * Flag: Don't escape forward slashes.
 72 |      */
 73 |     const NO_ESCAPE_SLASH = 64;
 74 | 
 75 |     /**
 76 |      * Flag: Don't escape Unicode characters.
 77 |      */
 78 |     const NO_ESCAPE_UNICODE = 128;
 79 | 
 80 |     /**
 81 |      * Flag: Format the JSON nicely.
 82 |      */
 83 |     const PRETTY_PRINT = 256;
 84 | 
 85 |     /**
 86 |      * Flag: Terminate the JSON with a line feed.
 87 |      */
 88 |     const TERMINATE_WITH_LINE_FEED = 512;
 89 | 
 90 |     /**
 91 |      * This seems to be the biggest float supported by json_encode()/json_decode().
 92 |      */
 93 |     const MAX_FLOAT = 1.0E+14;
 94 | 
 95 |     /**
 96 |      * @var string
 97 |      */
 98 |     private $path;
 99 | 
100 |     /**
101 |      * @var int
102 |      */
103 |     private $flags;
104 | 
105 |     /**
106 |      * @var JsonEncoder
107 |      */
108 |     private $encoder;
109 | 
110 |     /**
111 |      * @var JsonDecoder
112 |      */
113 |     private $decoder;
114 | 
115 |     public function __construct($path, $flags = 0)
116 |     {
117 |         Assert::string($path, 'The path must be a string. Got: %s');
118 |         Assert::notEmpty($path, 'The path must not be empty.');
119 |         Assert::integer($flags, 'The flags must be an integer. Got: %s');
120 | 
121 |         $this->path = $path;
122 |         $this->flags = $flags;
123 | 
124 |         $this->encoder = new JsonEncoder();
125 |         $this->encoder->setEscapeGtLt($this->flags & self::ESCAPE_GT_LT);
126 |         $this->encoder->setEscapeAmpersand($this->flags & self::ESCAPE_AMPERSAND);
127 |         $this->encoder->setEscapeSingleQuote($this->flags & self::ESCAPE_SINGLE_QUOTE);
128 |         $this->encoder->setEscapeDoubleQuote($this->flags & self::ESCAPE_DOUBLE_QUOTE);
129 |         $this->encoder->setEscapeSlash(!($this->flags & self::NO_ESCAPE_SLASH));
130 |         $this->encoder->setEscapeUnicode(!($this->flags & self::NO_ESCAPE_UNICODE));
131 |         $this->encoder->setPrettyPrinting($this->flags & self::PRETTY_PRINT);
132 |         $this->encoder->setTerminateWithLineFeed($this->flags & self::TERMINATE_WITH_LINE_FEED);
133 | 
134 |         $this->decoder = new JsonDecoder();
135 |         $this->decoder->setObjectDecoding(JsonDecoder::ASSOC_ARRAY);
136 |     }
137 | 
138 |     /**
139 |      * {@inheritdoc}
140 |      */
141 |     public function set($key, $value)
142 |     {
143 |         KeyUtil::validate($key);
144 | 
145 |         if (is_float($value) && $value > self::MAX_FLOAT) {
146 |             throw new UnsupportedValueException('The JSON file store cannot handle floats larger than 1.0E+14.');
147 |         }
148 | 
149 |         $data = $this->load();
150 |         $data[$key] = $this->serializeValue($value);
151 | 
152 |         $this->save($data);
153 |     }
154 | 
155 |     /**
156 |      * {@inheritdoc}
157 |      */
158 |     public function get($key, $default = null)
159 |     {
160 |         KeyUtil::validate($key);
161 | 
162 |         $data = $this->load();
163 | 
164 |         if (!array_key_exists($key, $data)) {
165 |             return $default;
166 |         }
167 | 
168 |         return $this->unserializeValue($data[$key]);
169 |     }
170 | 
171 |     /**
172 |      * {@inheritdoc}
173 |      */
174 |     public function getOrFail($key)
175 |     {
176 |         KeyUtil::validate($key);
177 | 
178 |         $data = $this->load();
179 | 
180 |         if (!array_key_exists($key, $data)) {
181 |             throw NoSuchKeyException::forKey($key);
182 |         }
183 | 
184 |         return $this->unserializeValue($data[$key]);
185 |     }
186 | 
187 |     /**
188 |      * {@inheritdoc}
189 |      */
190 |     public function getMultiple(array $keys, $default = null)
191 |     {
192 |         $values = array();
193 |         $data = $this->load();
194 | 
195 |         foreach ($keys as $key) {
196 |             KeyUtil::validate($key);
197 | 
198 |             if (array_key_exists($key, $data)) {
199 |                 $value = $this->unserializeValue($data[$key]);
200 |             } else {
201 |                 $value = $default;
202 |             }
203 | 
204 |             $values[$key] = $value;
205 |         }
206 | 
207 |         return $values;
208 |     }
209 | 
210 |     /**
211 |      * {@inheritdoc}
212 |      */
213 |     public function getMultipleOrFail(array $keys)
214 |     {
215 |         $values = array();
216 |         $data = $this->load();
217 | 
218 |         foreach ($keys as $key) {
219 |             KeyUtil::validate($key);
220 | 
221 |             if (!array_key_exists($key, $data)) {
222 |                 throw NoSuchKeyException::forKey($key);
223 |             }
224 | 
225 |             $values[$key] = $this->unserializeValue($data[$key]);
226 |         }
227 | 
228 |         return $values;
229 |     }
230 | 
231 |     /**
232 |      * {@inheritdoc}
233 |      */
234 |     public function remove($key)
235 |     {
236 |         KeyUtil::validate($key);
237 | 
238 |         $data = $this->load();
239 | 
240 |         if (!array_key_exists($key, $data)) {
241 |             return false;
242 |         }
243 | 
244 |         unset($data[$key]);
245 | 
246 |         $this->save($data);
247 | 
248 |         return true;
249 |     }
250 | 
251 |     /**
252 |      * {@inheritdoc}
253 |      */
254 |     public function exists($key)
255 |     {
256 |         KeyUtil::validate($key);
257 | 
258 |         $data = $this->load();
259 | 
260 |         return array_key_exists($key, $data);
261 |     }
262 | 
263 |     /**
264 |      * {@inheritdoc}
265 |      */
266 |     public function clear()
267 |     {
268 |         $this->save(new stdClass());
269 |     }
270 | 
271 |     /**
272 |      * {@inheritdoc}
273 |      */
274 |     public function keys()
275 |     {
276 |         return array_keys($this->load());
277 |     }
278 | 
279 |     /**
280 |      * {@inheritdoc}
281 |      */
282 |     public function sort($flags = SORT_REGULAR)
283 |     {
284 |         $data = $this->load();
285 | 
286 |         ksort($data, $flags);
287 | 
288 |         $this->save($data);
289 |     }
290 | 
291 |     /**
292 |      * {@inheritdoc}
293 |      */
294 |     public function count()
295 |     {
296 |         $data = $this->load();
297 | 
298 |         return count($data);
299 |     }
300 | 
301 |     private function load()
302 |     {
303 |         try {
304 |             return $this->decoder->decodeFile($this->path);
305 |         } catch (FileNotFoundException $e) {
306 |             return array();
307 |         } catch (DecodingFailedException $e) {
308 |             throw new ReadException($e->getMessage(), 0, $e);
309 |         } catch (IOException $e) {
310 |             throw new ReadException($e->getMessage(), 0, $e);
311 |         }
312 |     }
313 | 
314 |     private function save($data)
315 |     {
316 |         try {
317 |             $this->encoder->encodeFile($data, $this->path);
318 |         } catch (EncodingFailedException $e) {
319 |             if (JSON_ERROR_UTF8 === $e->getCode()) {
320 |                 throw UnsupportedValueException::forType('binary', $this);
321 |             }
322 | 
323 |             throw new WriteException($e->getMessage(), 0, $e);
324 |         } catch (IOException $e) {
325 |             throw new WriteException($e->getMessage(), 0, $e);
326 |         }
327 |     }
328 | 
329 |     private function serializeValue($value)
330 |     {
331 |         // Serialize if we have a string and string serialization is enabled...
332 |         $serializeValue = (is_string($value) && !($this->flags & self::NO_SERIALIZE_STRINGS))
333 |             // or we have an array and array serialization is enabled...
334 |             || (is_array($value) && !($this->flags & self::NO_SERIALIZE_ARRAYS))
335 |             // or we have any other non-scalar, non-null value
336 |             || (null !== $value && !is_scalar($value) && !is_array($value));
337 | 
338 |         if ($serializeValue) {
339 |             return Serializer::serialize($value);
340 |         }
341 | 
342 |         // If we have an array and array serialization is disabled, serialize
343 |         // its entries if necessary
344 |         if (is_array($value)) {
345 |             return array_map(array($this, 'serializeValue'), $value);
346 |         }
347 | 
348 |         return $value;
349 |     }
350 | 
351 |     private function unserializeValue($value)
352 |     {
353 |         // Unserialize value if it is a string...
354 |         $unserializeValue = is_string($value) && (
355 |             // and string serialization is enabled
356 |             !($this->flags & self::NO_SERIALIZE_STRINGS)
357 |             // or the string contains a serialized object
358 |             || 'O:' === ($prefix = substr($value, 0, 2))
359 |             // or the string contains a serialized array when array
360 |             // serialization is enabled
361 |             || ('a:' === $prefix && !($this->flags & self::NO_SERIALIZE_ARRAYS))
362 |         );
363 | 
364 |         if ($unserializeValue) {
365 |             return Serializer::unserialize($value);
366 |         }
367 | 
368 |         if (is_array($value)) {
369 |             return array_map(array($this, 'unserializeValue'), $value);
370 |         }
371 | 
372 |         return $value;
373 |     }
374 | }
375 | 
--------------------------------------------------------------------------------
/src/MongoDbStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Closure;
 15 | use Exception;
 16 | use MongoDB\BSON\Binary;
 17 | use MongoDB\Collection;
 18 | use MongoDB\Driver\Exception\UnexpectedValueException;
 19 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 20 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 21 | use Webmozart\KeyValueStore\Api\ReadException;
 22 | use Webmozart\KeyValueStore\Api\UnserializationFailedException;
 23 | use Webmozart\KeyValueStore\Api\UnsupportedValueException;
 24 | use Webmozart\KeyValueStore\Api\WriteException;
 25 | use Webmozart\KeyValueStore\Util\KeyUtil;
 26 | use Webmozart\KeyValueStore\Util\Serializer;
 27 | 
 28 | /**
 29 |  * A key-value-store backed by MongoDB.
 30 |  *
 31 |  * @since 1.0
 32 |  *
 33 |  * @author Bernhard Schussek 
 34 |  */
 35 | class MongoDbStore implements KeyValueStore
 36 | {
 37 |     /**
 38 |      * Flag: Disable serialization.
 39 |      */
 40 |     const NO_SERIALIZE = 1;
 41 | 
 42 |     /**
 43 |      * Flag: Support storage of binary data.
 44 |      */
 45 |     const SUPPORT_BINARY = 2;
 46 | 
 47 |     private static $typeMap = array(
 48 |         'root' => 'array',
 49 |         'document' => 'array',
 50 |         'array' => 'array',
 51 |     );
 52 | 
 53 |     /**
 54 |      * @var Collection
 55 |      */
 56 |     private $collection;
 57 | 
 58 |     /**
 59 |      * @var Closure
 60 |      */
 61 |     private $serialize;
 62 | 
 63 |     /**
 64 |      * @var Closure
 65 |      */
 66 |     private $unserialize;
 67 | 
 68 |     public function __construct(Collection $collection, $flags = 0)
 69 |     {
 70 |         $this->collection = $collection;
 71 | 
 72 |         if ($flags & self::NO_SERIALIZE) {
 73 |             if ($flags & self::SUPPORT_BINARY) {
 74 |                 $this->serialize = function ($unserialized) {
 75 |                     if (!is_string($unserialized)) {
 76 |                         throw UnsupportedValueException::forValue($unserialized, $this);
 77 |                     }
 78 | 
 79 |                     return new Binary($unserialized, Binary::TYPE_GENERIC);
 80 |                 };
 81 |                 $this->unserialize = function (Binary $serialized) {
 82 |                     return $serialized->getData();
 83 |                 };
 84 |             } else {
 85 |                 $this->serialize = function ($unserialized) {
 86 |                     if (!is_scalar($unserialized) && !is_array($unserialized) && null !== $unserialized) {
 87 |                         throw UnsupportedValueException::forValue($unserialized, $this);
 88 |                     }
 89 | 
 90 |                     return $unserialized;
 91 |                 };
 92 |                 $this->unserialize = function ($serialized) {
 93 |                     return $serialized;
 94 |                 };
 95 |             }
 96 |         } else {
 97 |             if ($flags & self::SUPPORT_BINARY) {
 98 |                 $this->serialize = function ($unserialized) {
 99 |                     return new Binary(
100 |                         Serializer::serialize($unserialized),
101 |                         Binary::TYPE_GENERIC
102 |                     );
103 |                 };
104 |                 $this->unserialize = function (Binary $serialized) {
105 |                     return Serializer::unserialize($serialized->getData());
106 |                 };
107 |             } else {
108 |                 $this->serialize = function ($unserialized) {
109 |                     return Serializer::serialize($unserialized);
110 |                 };
111 |                 $this->unserialize = function ($serialized) {
112 |                     return Serializer::unserialize($serialized);
113 |                 };
114 |             }
115 |         }
116 |     }
117 | 
118 |     /**
119 |      * {@inheritdoc}
120 |      */
121 |     public function set($key, $value)
122 |     {
123 |         KeyUtil::validate($key);
124 | 
125 |         $serialized = $this->serialize->__invoke($value);
126 | 
127 |         try {
128 |             $this->collection->replaceOne(
129 |                 array('_id' => $key),
130 |                 array('_id' => $key, 'value' => $serialized),
131 |                 array('upsert' => true)
132 |             );
133 |         } catch (UnexpectedValueException $e) {
134 |             throw UnsupportedValueException::forType('binary', $this, 0, $e);
135 |         } catch (Exception $e) {
136 |             throw WriteException::forException($e);
137 |         }
138 |     }
139 | 
140 |     /**
141 |      * {@inheritdoc}
142 |      */
143 |     public function get($key, $default = null)
144 |     {
145 |         KeyUtil::validate($key);
146 | 
147 |         try {
148 |             $document = $this->collection->findOne(
149 |                 array('_id' => $key),
150 |                 array('typeMap' => self::$typeMap)
151 |             );
152 |         } catch (Exception $e) {
153 |             throw ReadException::forException($e);
154 |         }
155 | 
156 |         if (null === $document) {
157 |             return $default;
158 |         }
159 | 
160 |         return $this->unserialize->__invoke($document['value']);
161 |     }
162 | 
163 |     /**
164 |      * {@inheritdoc}
165 |      */
166 |     public function getOrFail($key)
167 |     {
168 |         KeyUtil::validate($key);
169 | 
170 |         try {
171 |             $document = $this->collection->findOne(
172 |                 array('_id' => $key),
173 |                 array('typeMap' => self::$typeMap)
174 |             );
175 |         } catch (Exception $e) {
176 |             throw ReadException::forException($e);
177 |         }
178 | 
179 |         if (null === $document) {
180 |             throw NoSuchKeyException::forKey($key);
181 |         }
182 | 
183 |         return $this->unserialize->__invoke($document['value']);
184 |     }
185 | 
186 |     /**
187 |      * {@inheritdoc}
188 |      */
189 |     public function getMultiple(array $keys, $default = null)
190 |     {
191 |         KeyUtil::validateMultiple($keys);
192 | 
193 |         $values = array_fill_keys($keys, $default);
194 | 
195 |         try {
196 |             $cursor = $this->collection->find(
197 |                 array('_id' => array('$in' => array_values($keys))),
198 |                 array('typeMap' => self::$typeMap)
199 |             );
200 | 
201 |             foreach ($cursor as $document) {
202 |                 $values[$document['_id']] = $this->unserialize->__invoke($document['value']);
203 |             }
204 |         } catch (UnserializationFailedException $e) {
205 |             throw $e;
206 |         } catch (Exception $e) {
207 |             throw ReadException::forException($e);
208 |         }
209 | 
210 |         return $values;
211 |     }
212 | 
213 |     /**
214 |      * {@inheritdoc}
215 |      */
216 |     public function getMultipleOrFail(array $keys)
217 |     {
218 |         KeyUtil::validateMultiple($keys);
219 | 
220 |         $values = array();
221 | 
222 |         try {
223 |             $cursor = $this->collection->find(
224 |                 array('_id' => array('$in' => array_values($keys))),
225 |                 array('typeMap' => self::$typeMap)
226 |             );
227 | 
228 |             foreach ($cursor as $document) {
229 |                 $values[$document['_id']] = $this->unserialize->__invoke($document['value']);
230 |             }
231 |         } catch (UnserializationFailedException $e) {
232 |             throw $e;
233 |         } catch (Exception $e) {
234 |             throw ReadException::forException($e);
235 |         }
236 | 
237 |         $notFoundKeys = array_diff($keys, array_keys($values));
238 | 
239 |         if (count($notFoundKeys) > 0) {
240 |             throw NoSuchKeyException::forKeys($notFoundKeys);
241 |         }
242 | 
243 |         return $values;
244 |     }
245 | 
246 |     /**
247 |      * {@inheritdoc}
248 |      */
249 |     public function remove($key)
250 |     {
251 |         KeyUtil::validate($key);
252 | 
253 |         try {
254 |             $result = $this->collection->deleteOne(array('_id' => $key));
255 |             $deletedCount = $result->getDeletedCount();
256 |         } catch (Exception $e) {
257 |             throw WriteException::forException($e);
258 |         }
259 | 
260 |         return $deletedCount > 0;
261 |     }
262 | 
263 |     /**
264 |      * {@inheritdoc}
265 |      */
266 |     public function exists($key)
267 |     {
268 |         KeyUtil::validate($key);
269 | 
270 |         try {
271 |             $count = $this->collection->count(array('_id' => $key));
272 |         } catch (Exception $e) {
273 |             throw ReadException::forException($e);
274 |         }
275 | 
276 |         return $count > 0;
277 |     }
278 | 
279 |     /**
280 |      * {@inheritdoc}
281 |      */
282 |     public function clear()
283 |     {
284 |         try {
285 |             $this->collection->drop();
286 |         } catch (Exception $e) {
287 |             throw WriteException::forException($e);
288 |         }
289 |     }
290 | 
291 |     /**
292 |      * {@inheritdoc}
293 |      */
294 |     public function keys()
295 |     {
296 |         try {
297 |             $cursor = $this->collection->find(array(), array(
298 |                 'projection' => array('_id' => 1),
299 |             ));
300 | 
301 |             $keys = array();
302 | 
303 |             foreach ($cursor as $document) {
304 |                 $keys[] = $document['_id'];
305 |             }
306 |         } catch (Exception $e) {
307 |             throw ReadException::forException($e);
308 |         }
309 | 
310 |         return $keys;
311 |     }
312 | }
313 | 
--------------------------------------------------------------------------------
/src/NullStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Webmozart\KeyValueStore\Api\CountableStore;
 15 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 16 | use Webmozart\KeyValueStore\Api\SortableStore;
 17 | 
 18 | /**
 19 |  * A key-value store that does nothing.
 20 |  *
 21 |  * @since  1.0
 22 |  *
 23 |  * @author Bernhard Schussek 
 24 |  */
 25 | class NullStore implements SortableStore, CountableStore
 26 | {
 27 |     /**
 28 |      * {@inheritdoc}
 29 |      */
 30 |     public function set($key, $value)
 31 |     {
 32 |     }
 33 | 
 34 |     /**
 35 |      * {@inheritdoc}
 36 |      */
 37 |     public function get($key, $default = null)
 38 |     {
 39 |         return $default;
 40 |     }
 41 | 
 42 |     /**
 43 |      * {@inheritdoc}
 44 |      */
 45 |     public function getOrFail($key)
 46 |     {
 47 |         throw NoSuchKeyException::forKey($key);
 48 |     }
 49 | 
 50 |     /**
 51 |      * {@inheritdoc}
 52 |      */
 53 |     public function getMultiple(array $keys, $default = null)
 54 |     {
 55 |         return array_fill_keys($keys, $default);
 56 |     }
 57 | 
 58 |     /**
 59 |      * {@inheritdoc}
 60 |      */
 61 |     public function getMultipleOrFail(array $keys)
 62 |     {
 63 |         throw NoSuchKeyException::forKeys($keys);
 64 |     }
 65 | 
 66 |     /**
 67 |      * {@inheritdoc}
 68 |      */
 69 |     public function remove($key)
 70 |     {
 71 |         return false;
 72 |     }
 73 | 
 74 |     /**
 75 |      * {@inheritdoc}
 76 |      */
 77 |     public function exists($key)
 78 |     {
 79 |         return false;
 80 |     }
 81 | 
 82 |     /**
 83 |      * {@inheritdoc}
 84 |      */
 85 |     public function clear()
 86 |     {
 87 |     }
 88 | 
 89 |     /**
 90 |      * {@inheritdoc}
 91 |      */
 92 |     public function keys()
 93 |     {
 94 |         return array();
 95 |     }
 96 | 
 97 |     /**
 98 |      * {@inheritdoc}
 99 |      */
100 |     public function sort($flags = SORT_REGULAR)
101 |     {
102 |     }
103 | 
104 |     /**
105 |      * {@inheritdoc}
106 |      */
107 |     public function count()
108 |     {
109 |         return 0;
110 |     }
111 | }
112 | 
--------------------------------------------------------------------------------
/src/PhpRedisStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Redis;
 15 | 
 16 | /**
 17 |  * A key-value store that uses the PhpRedis extension to connect to a Redis instance.
 18 |  *
 19 |  * @since  1.0
 20 |  *
 21 |  * @author Bernhard Schussek 
 22 |  * @author Philipp Wahala 
 23 |  * @author Titouan Galopin 
 24 |  *
 25 |  * @link https://github.com/phpredis/phpredis
 26 |  */
 27 | class PhpRedisStore extends AbstractRedisStore
 28 | {
 29 |     /**
 30 |      * Creates a store backed by a PhpRedis client.
 31 |      *
 32 |      * If no client is passed, a new one is created using the default server
 33 |      * "127.0.0.1" and the default port 6379.
 34 |      *
 35 |      * @param Redis|null $client The client used to connect to Redis.
 36 |      */
 37 |     public function __construct(Redis $client = null)
 38 |     {
 39 |         if (null === $client) {
 40 |             $client = new Redis();
 41 |             $client->connect('127.0.0.1', 6379);
 42 |         }
 43 | 
 44 |         $this->client = $client;
 45 |     }
 46 | 
 47 |     /**
 48 |      * {@inheritdoc}
 49 |      */
 50 |     protected function clientNotFoundValue()
 51 |     {
 52 |         return false;
 53 |     }
 54 | 
 55 |     /**
 56 |      * {@inheritdoc}
 57 |      */
 58 |     protected function clientGet($key)
 59 |     {
 60 |         return $this->client->get($key);
 61 |     }
 62 | 
 63 |     /**
 64 |      * {@inheritdoc}
 65 |      */
 66 |     protected function clientGetMultiple(array $keys)
 67 |     {
 68 |         return $this->client->getMultiple($keys);
 69 |     }
 70 | 
 71 |     /**
 72 |      * {@inheritdoc}
 73 |      */
 74 |     protected function clientSet($key, $value)
 75 |     {
 76 |         $this->client->set($key, $value);
 77 |     }
 78 | 
 79 |     /**
 80 |      * {@inheritdoc}
 81 |      */
 82 |     protected function clientRemove($key)
 83 |     {
 84 |         return (bool) $this->client->del($key);
 85 |     }
 86 | 
 87 |     /**
 88 |      * {@inheritdoc}
 89 |      */
 90 |     protected function clientExists($key)
 91 |     {
 92 |         return (bool) $this->client->exists($key);
 93 |     }
 94 | 
 95 |     /**
 96 |      * {@inheritdoc}
 97 |      */
 98 |     protected function clientClear()
 99 |     {
100 |         $this->client->flushdb();
101 |     }
102 | 
103 |     /**
104 |      * {@inheritdoc}
105 |      */
106 |     protected function clientKeys()
107 |     {
108 |         return $this->client->keys('*');
109 |     }
110 | }
111 | 
--------------------------------------------------------------------------------
/src/PredisStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Predis\Client;
 15 | use Predis\ClientInterface;
 16 | 
 17 | /**
 18 |  * A key-value store that uses Predis to connect to a Redis instance.
 19 |  *
 20 |  * @since  1.0
 21 |  *
 22 |  * @author Bernhard Schussek 
 23 |  * @author Titouan Galopin 
 24 |  */
 25 | class PredisStore extends AbstractRedisStore
 26 | {
 27 |     /**
 28 |      * Creates a store backed by a Predis client.
 29 |      *
 30 |      * If no client is passed, a new one is created using the default server
 31 |      * "127.0.0.1" and the default port 6379.
 32 |      *
 33 |      * @param ClientInterface|null $client The client used to connect to Redis.
 34 |      */
 35 |     public function __construct(ClientInterface $client = null)
 36 |     {
 37 |         $this->client = $client ?: new Client();
 38 |     }
 39 | 
 40 |     /**
 41 |      * {@inheritdoc}
 42 |      */
 43 |     protected function clientNotFoundValue()
 44 |     {
 45 |         return null;
 46 |     }
 47 | 
 48 |     /**
 49 |      * {@inheritdoc}
 50 |      */
 51 |     protected function clientGet($key)
 52 |     {
 53 |         return $this->client->get($key);
 54 |     }
 55 | 
 56 |     /**
 57 |      * {@inheritdoc}
 58 |      */
 59 |     protected function clientGetMultiple(array $keys)
 60 |     {
 61 |         return $this->client->mget($keys);
 62 |     }
 63 | 
 64 |     /**
 65 |      * {@inheritdoc}
 66 |      */
 67 |     protected function clientSet($key, $value)
 68 |     {
 69 |         $this->client->set($key, $value);
 70 |     }
 71 | 
 72 |     /**
 73 |      * {@inheritdoc}
 74 |      */
 75 |     protected function clientRemove($key)
 76 |     {
 77 |         return (bool) $this->client->del($key);
 78 |     }
 79 | 
 80 |     /**
 81 |      * {@inheritdoc}
 82 |      */
 83 |     protected function clientExists($key)
 84 |     {
 85 |         return (bool) $this->client->exists($key);
 86 |     }
 87 | 
 88 |     /**
 89 |      * {@inheritdoc}
 90 |      */
 91 |     protected function clientClear()
 92 |     {
 93 |         $this->client->flushdb();
 94 |     }
 95 | 
 96 |     /**
 97 |      * {@inheritdoc}
 98 |      */
 99 |     protected function clientKeys()
100 |     {
101 |         return $this->client->keys('*');
102 |     }
103 | }
104 | 
--------------------------------------------------------------------------------
/src/RiakStore.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore;
 13 | 
 14 | use Basho\Riak\Riak;
 15 | use Exception;
 16 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 17 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 18 | use Webmozart\KeyValueStore\Api\ReadException;
 19 | use Webmozart\KeyValueStore\Api\WriteException;
 20 | use Webmozart\KeyValueStore\Util\KeyUtil;
 21 | use Webmozart\KeyValueStore\Util\Serializer;
 22 | 
 23 | /**
 24 |  * A key-value store backed by a Riak client.
 25 |  *
 26 |  * @since  1.0
 27 |  *
 28 |  * @author Bernhard Schussek 
 29 |  */
 30 | class RiakStore implements KeyValueStore
 31 | {
 32 |     /**
 33 |      * @var string
 34 |      */
 35 |     private $bucketName;
 36 | 
 37 |     /**
 38 |      * @var Riak
 39 |      */
 40 |     private $client;
 41 | 
 42 |     /**
 43 |      * Creates a store backed by a Riak client.
 44 |      *
 45 |      * If no client is passed, a new one is created using the default server
 46 |      * "127.0.0.1" and the default port 8098.
 47 |      *
 48 |      * @param string    $bucketName The name of the Riak bucket to use.
 49 |      * @param Riak|null $client     The client used to connect to Riak.
 50 |      */
 51 |     public function __construct($bucketName, Riak $client = null)
 52 |     {
 53 |         $this->bucketName = $bucketName;
 54 |         $this->client = $client ?: new Riak();
 55 |     }
 56 | 
 57 |     /**
 58 |      * {@inheritdoc}
 59 |      */
 60 |     public function set($key, $value)
 61 |     {
 62 |         KeyUtil::validate($key);
 63 | 
 64 |         $serialized = Serializer::serialize($value);
 65 | 
 66 |         try {
 67 |             $this->client->bucket($this->bucketName)->newBinary($key, $serialized)->store();
 68 |         } catch (Exception $e) {
 69 |             throw WriteException::forException($e);
 70 |         }
 71 |     }
 72 | 
 73 |     /**
 74 |      * {@inheritdoc}
 75 |      */
 76 |     public function get($key, $default = null)
 77 |     {
 78 |         KeyUtil::validate($key);
 79 | 
 80 |         try {
 81 |             $object = $this->client->bucket($this->bucketName)->getBinary($key);
 82 |             $exists = $object->exists();
 83 |         } catch (Exception $e) {
 84 |             throw ReadException::forException($e);
 85 |         }
 86 | 
 87 |         if (!$exists) {
 88 |             return $default;
 89 |         }
 90 | 
 91 |         return Serializer::unserialize($object->getData());
 92 |     }
 93 | 
 94 |     /**
 95 |      * {@inheritdoc}
 96 |      */
 97 |     public function getOrFail($key)
 98 |     {
 99 |         KeyUtil::validate($key);
100 | 
101 |         try {
102 |             $object = $this->client->bucket($this->bucketName)->getBinary($key);
103 |             $exists = $object->exists();
104 |         } catch (Exception $e) {
105 |             throw ReadException::forException($e);
106 |         }
107 | 
108 |         if (!$exists) {
109 |             throw NoSuchKeyException::forKey($key);
110 |         }
111 | 
112 |         return Serializer::unserialize($object->getData());
113 |     }
114 | 
115 |     /**
116 |      * {@inheritdoc}
117 |      */
118 |     public function getMultiple(array $keys, $default = null)
119 |     {
120 |         KeyUtil::validateMultiple($keys);
121 | 
122 |         $values = array();
123 | 
124 |         try {
125 |             $bucket = $this->client->bucket($this->bucketName);
126 | 
127 |             foreach ($keys as $key) {
128 |                 $object = $bucket->getBinary($key);
129 | 
130 |                 $values[$key] = $object->exists() ? $object->getData() : false;
131 |             }
132 |         } catch (Exception $e) {
133 |             throw ReadException::forException($e);
134 |         }
135 | 
136 |         foreach ($values as $key => $value) {
137 |             $values[$key] = false === $value
138 |                 ? $default
139 |                 : Serializer::unserialize($value);
140 |         }
141 | 
142 |         return $values;
143 |     }
144 | 
145 |     /**
146 |      * {@inheritdoc}
147 |      */
148 |     public function getMultipleOrFail(array $keys)
149 |     {
150 |         KeyUtil::validateMultiple($keys);
151 | 
152 |         $values = array();
153 |         $notFoundKeys = array();
154 | 
155 |         try {
156 |             $bucket = $this->client->bucket($this->bucketName);
157 | 
158 |             foreach ($keys as $key) {
159 |                 $values[$key] = $bucket->getBinary($key);
160 | 
161 |                 if (!$values[$key]->exists()) {
162 |                     $notFoundKeys[] = $key;
163 |                 }
164 |             }
165 |         } catch (Exception $e) {
166 |             throw ReadException::forException($e);
167 |         }
168 | 
169 |         if (0 !== count($notFoundKeys)) {
170 |             throw NoSuchKeyException::forKeys($notFoundKeys);
171 |         }
172 | 
173 |         foreach ($values as $key => $object) {
174 |             $values[$key] = Serializer::unserialize($object->getData());
175 |         }
176 | 
177 |         return $values;
178 |     }
179 | 
180 |     /**
181 |      * {@inheritdoc}
182 |      */
183 |     public function remove($key)
184 |     {
185 |         KeyUtil::validate($key);
186 | 
187 |         try {
188 |             $object = $this->client->bucket($this->bucketName)->get($key);
189 | 
190 |             if (!$object->exists()) {
191 |                 return false;
192 |             }
193 | 
194 |             $object->delete();
195 |         } catch (Exception $e) {
196 |             throw WriteException::forException($e);
197 |         }
198 | 
199 |         return true;
200 |     }
201 | 
202 |     /**
203 |      * {@inheritdoc}
204 |      */
205 |     public function exists($key)
206 |     {
207 |         KeyUtil::validate($key);
208 | 
209 |         try {
210 |             return $this->client->bucket($this->bucketName)->get($key)->exists();
211 |         } catch (Exception $e) {
212 |             throw ReadException::forException($e);
213 |         }
214 |     }
215 | 
216 |     /**
217 |      * {@inheritdoc}
218 |      */
219 |     public function clear()
220 |     {
221 |         try {
222 |             $bucket = $this->client->bucket($this->bucketName);
223 | 
224 |             foreach ($bucket->getKeys() as $key) {
225 |                 $bucket->get($key)->delete();
226 |             }
227 |         } catch (Exception $e) {
228 |             throw WriteException::forException($e);
229 |         }
230 |     }
231 | 
232 |     /**
233 |      * {@inheritdoc}
234 |      */
235 |     public function keys()
236 |     {
237 |         try {
238 |             return $this->client->bucket($this->bucketName)->getKeys();
239 |         } catch (Exception $e) {
240 |             throw ReadException::forException($e);
241 |         }
242 |     }
243 | }
244 | 
--------------------------------------------------------------------------------
/src/SerializingArrayStore.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore;
13 | 
14 | /**
15 |  * A key-value store backed by a PHP array with serialized entries.
16 |  *
17 |  * The contents of the store are lost when the store is released from memory.
18 |  *
19 |  * This store behaves more like persistent key-value stores than
20 |  * {@link ArrayStore}. It is useful for testing.
21 |  *
22 |  * @since  1.0
23 |  *
24 |  * @author Bernhard Schussek 
25 |  *
26 |  * @deprecated Deprecated as of version 1.0, will be removed in version
27 |  *             2.0. Use the `ArrayStore` with the `SERIALIZE` flag
28 |  *             instead.
29 |  */
30 | class SerializingArrayStore extends ArrayStore
31 | {
32 |     public function __construct(array $array = array())
33 |     {
34 |         parent::__construct($array, parent::SERIALIZE);
35 |     }
36 | }
37 | 
--------------------------------------------------------------------------------
/src/Util/KeyUtil.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Util;
13 | 
14 | use Webmozart\KeyValueStore\Api\InvalidKeyException;
15 | 
16 | /**
17 |  * Utility methods for dealing with key-value store keys.
18 |  *
19 |  * @since  1.0
20 |  *
21 |  * @author Bernhard Schussek 
22 |  */
23 | final class KeyUtil
24 | {
25 |     /**
26 |      * Validates that a key is valid.
27 |      *
28 |      * @param mixed $key The tested key.
29 |      *
30 |      * @throws InvalidKeyException If the key is invalid.
31 |      */
32 |     public static function validate($key)
33 |     {
34 |         if (!is_string($key) && !is_int($key)) {
35 |             throw InvalidKeyException::forKey($key);
36 |         }
37 |     }
38 | 
39 |     /**
40 |      * Validates that multiple keys are valid.
41 |      *
42 |      * @param array $keys The tested keys.
43 |      *
44 |      * @throws InvalidKeyException If a key is invalid.
45 |      */
46 |     public static function validateMultiple($keys)
47 |     {
48 |         foreach ($keys as $key) {
49 |             if (!is_string($key) && !is_int($key)) {
50 |                 throw InvalidKeyException::forKey($key);
51 |             }
52 |         }
53 |     }
54 | 
55 |     private function __construct()
56 |     {
57 |     }
58 | }
59 | 
--------------------------------------------------------------------------------
/src/Util/Serializer.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Util;
13 | 
14 | use Exception;
15 | use Webmozart\KeyValueStore\Api\SerializationFailedException;
16 | use Webmozart\KeyValueStore\Api\UnserializationFailedException;
17 | 
18 | /**
19 |  * Wrapper for `serialize()`/`unserialize()` that throws proper exceptions.
20 |  *
21 |  * @since  1.0
22 |  *
23 |  * @author Bernhard Schussek 
24 |  */
25 | final class Serializer
26 | {
27 |     /**
28 |      * Serializes a value.
29 |      *
30 |      * @param mixed $value The value to serialize.
31 |      *
32 |      * @return string The serialized value.
33 |      *
34 |      * @throws SerializationFailedException If the value cannot be serialized.
35 |      */
36 |     public static function serialize($value)
37 |     {
38 |         if (is_resource($value)) {
39 |             throw SerializationFailedException::forValue($value);
40 |         }
41 | 
42 |         try {
43 |             $serialized = serialize($value);
44 |         } catch (Exception $e) {
45 |             throw SerializationFailedException::forValue($value, $e->getMessage(), $e->getCode(), $e);
46 |         }
47 | 
48 |         return $serialized;
49 |     }
50 | 
51 |     /**
52 |      * Unserializes a value.
53 |      *
54 |      * @param mixed $serialized The serialized value.
55 |      *
56 |      * @return string The unserialized value.
57 |      *
58 |      * @throws UnserializationFailedException If the value cannot be unserialized.
59 |      */
60 |     public static function unserialize($serialized)
61 |     {
62 |         if (!is_string($serialized)) {
63 |             throw UnserializationFailedException::forValue($serialized);
64 |         }
65 | 
66 |         $errorMessage = null;
67 |         $errorCode = 0;
68 | 
69 |         set_error_handler(function ($errno, $errstr) use (&$errorMessage, &$errorCode) {
70 |             $errorMessage = $errstr;
71 |             $errorCode = $errno;
72 |         });
73 | 
74 |         $value = unserialize($serialized);
75 | 
76 |         restore_error_handler();
77 | 
78 |         if (null !== $errorMessage) {
79 |             if (false !== $pos = strpos($errorMessage, '): ')) {
80 |                 // cut "unserialize(%path%):" to make message more readable
81 |                 $errorMessage = substr($errorMessage, $pos + 3);
82 |             }
83 | 
84 |             throw UnserializationFailedException::forValue($serialized, $errorMessage, $errorCode);
85 |         }
86 | 
87 |         return $value;
88 |     }
89 | 
90 |     private function __construct()
91 |     {
92 |     }
93 | }
94 | 
--------------------------------------------------------------------------------
/tests/AbstractCountableStoreTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests;
13 | 
14 | /**
15 |  * @since  1.0
16 |  *
17 |  * @author Bernhard Schussek 
18 |  * @author Titouan Galopin 
19 |  */
20 | abstract class AbstractCountableStoreTest extends AbstractKeyValueStoreTest
21 | {
22 |     /**
23 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
24 |      */
25 |     abstract public function testCountThrowsReadExceptionIfReadFails();
26 | 
27 |     public function testCountCache()
28 |     {
29 |         $this->assertEquals(0, $this->store->count());
30 | 
31 |         $this->store->set('foo1', 'bar');
32 |         $this->assertEquals(1, $this->store->count());
33 | 
34 |         $this->store->set('foo2', 'bar');
35 |         $this->assertEquals(2, $this->store->count());
36 | 
37 |         $this->store->set('foo3', 'bar');
38 |         $this->assertEquals(3, $this->store->count());
39 | 
40 |         $this->store->remove('foo2');
41 |         $this->assertEquals(2, $this->store->count());
42 | 
43 |         $this->store->clear();
44 |         $this->assertEquals(0, $this->store->count());
45 |     }
46 | }
47 | 
--------------------------------------------------------------------------------
/tests/AbstractMongoDbStoreTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests;
 13 | 
 14 | use ArrayIterator;
 15 | use Exception;
 16 | use MongoDB\Client;
 17 | use Webmozart\KeyValueStore\MongoDbStore;
 18 | use Webmozart\KeyValueStore\Tests\Fixtures\TestException;
 19 | 
 20 | /**
 21 |  * @since  1.0
 22 |  *
 23 |  * @author Bernhard Schussek 
 24 |  */
 25 | abstract class AbstractMongoDbStoreTest extends AbstractKeyValueStoreTest
 26 | {
 27 |     const DATABASE_NAME = 'webmozart-key-value-store-test-db';
 28 | 
 29 |     const COLLECTION_NAME = 'test-collection';
 30 | 
 31 |     private static $supported;
 32 | 
 33 |     /**
 34 |      * @var Client
 35 |      */
 36 |     protected $client;
 37 | 
 38 |     public static function setUpBeforeClass()
 39 |     {
 40 |         parent::setUpBeforeClass();
 41 | 
 42 |         if (!class_exists('MongoDB\Client')) {
 43 |             self::$supported = false;
 44 | 
 45 |             return;
 46 |         }
 47 | 
 48 |         try {
 49 |             $client = new Client();
 50 |             $client->listDatabases();
 51 | 
 52 |             self::$supported = true;
 53 |         } catch (Exception $e) {
 54 |             self::$supported = false;
 55 |         }
 56 |     }
 57 | 
 58 |     protected function setUp()
 59 |     {
 60 |         if (!self::$supported) {
 61 |             $this->markTestSkipped('MongoDB is not running or the mongodb/mongodb package ist not installed.');
 62 |         }
 63 | 
 64 |         $this->client = new Client();
 65 | 
 66 |         parent::setUp();
 67 |     }
 68 | 
 69 |     protected function tearDown()
 70 |     {
 71 |         if (!self::$supported) {
 72 |             return;
 73 |         }
 74 | 
 75 |         parent::tearDown();
 76 | 
 77 |         $this->client->dropDatabase(self::DATABASE_NAME);
 78 |     }
 79 | 
 80 |     /**
 81 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 82 |      * @expectedExceptionMessage I failed!
 83 |      */
 84 |     public function testSetThrowsWriteExceptionIfWriteFails()
 85 |     {
 86 |         $exception = new TestException('I failed!');
 87 | 
 88 |         $collection = $this->getMockBuilder('MongoDB\Collection')
 89 |             ->disableOriginalConstructor()
 90 |             ->getMock();
 91 | 
 92 |         $collection->expects($this->once())
 93 |             ->method('replaceOne')
 94 |             ->willThrowException($exception);
 95 | 
 96 |         $store = new MongoDbStore($collection);
 97 |         $store->set('key', 'value');
 98 |     }
 99 | 
100 |     /**
101 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
102 |      * @expectedExceptionMessage I failed!
103 |      */
104 |     public function testRemoveThrowsWriteExceptionIfWriteFails()
105 |     {
106 |         $exception = new TestException('I failed!');
107 | 
108 |         $collection = $this->getMockBuilder('MongoDB\Collection')
109 |             ->disableOriginalConstructor()
110 |             ->getMock();
111 | 
112 |         $collection->expects($this->once())
113 |             ->method('deleteOne')
114 |             ->willThrowException($exception);
115 | 
116 |         $store = new MongoDbStore($collection);
117 |         $store->remove('key');
118 |     }
119 | 
120 |     /**
121 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
122 |      * @expectedExceptionMessage I failed!
123 |      */
124 |     public function testRemoveThrowsWriteExceptionIfGetDeletedCountFails()
125 |     {
126 |         $exception = new TestException('I failed!');
127 | 
128 |         $collection = $this->getMockBuilder('MongoDB\Collection')
129 |             ->disableOriginalConstructor()
130 |             ->getMock();
131 |         $result = $this->getMockBuilder('MongoDB\DeleteResult')
132 |             ->disableOriginalConstructor()
133 |             ->getMock();
134 | 
135 |         $collection->expects($this->once())
136 |             ->method('deleteOne')
137 |             ->willReturn($result);
138 | 
139 |         $result->expects($this->once())
140 |             ->method('getDeletedCount')
141 |             ->willThrowException($exception);
142 | 
143 |         $store = new MongoDbStore($collection);
144 |         $store->remove('key');
145 |     }
146 | 
147 |     /**
148 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
149 |      * @expectedExceptionMessage I failed!
150 |      */
151 |     public function testClearThrowsWriteExceptionIfWriteFails()
152 |     {
153 |         $exception = new TestException('I failed!');
154 | 
155 |         $collection = $this->getMockBuilder('MongoDB\Collection')
156 |             ->disableOriginalConstructor()
157 |             ->getMock();
158 | 
159 |         $collection->expects($this->once())
160 |             ->method('drop')
161 |             ->willThrowException($exception);
162 | 
163 |         $store = new MongoDbStore($collection);
164 |         $store->clear();
165 |     }
166 | 
167 |     /**
168 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
169 |      * @expectedExceptionMessage I failed!
170 |      */
171 |     public function testGetThrowsReadExceptionIfReadFails()
172 |     {
173 |         $exception = new TestException('I failed!');
174 | 
175 |         $collection = $this->getMockBuilder('MongoDB\Collection')
176 |             ->disableOriginalConstructor()
177 |             ->getMock();
178 | 
179 |         $collection->expects($this->once())
180 |             ->method('findOne')
181 |             ->willThrowException($exception);
182 | 
183 |         $store = new MongoDbStore($collection);
184 |         $store->get('key');
185 |     }
186 | 
187 |     /**
188 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
189 |      */
190 |     public function testGetThrowsExceptionIfNotUnserializable()
191 |     {
192 |         $collection = $this->getMockBuilder('MongoDB\Collection')
193 |             ->disableOriginalConstructor()
194 |             ->getMock();
195 | 
196 |         $collection->expects($this->once())
197 |             ->method('findOne')
198 |             ->willReturn(array('_id' => 'key', 'value' => 'foobar'));
199 | 
200 |         $store = new MongoDbStore($collection);
201 |         $store->get('key');
202 |     }
203 | 
204 |     /**
205 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
206 |      * @expectedExceptionMessage I failed!
207 |      */
208 |     public function testGetOrFailThrowsReadExceptionIfReadFails()
209 |     {
210 |         $exception = new TestException('I failed!');
211 | 
212 |         $collection = $this->getMockBuilder('MongoDB\Collection')
213 |             ->disableOriginalConstructor()
214 |             ->getMock();
215 | 
216 |         $collection->expects($this->once())
217 |             ->method('findOne')
218 |             ->willThrowException($exception);
219 | 
220 |         $store = new MongoDbStore($collection);
221 |         $store->getOrFail('key');
222 |     }
223 | 
224 |     /**
225 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
226 |      */
227 |     public function testGetOrFailThrowsExceptionIfNotUnserializable()
228 |     {
229 |         $collection = $this->getMockBuilder('MongoDB\Collection')
230 |             ->disableOriginalConstructor()
231 |             ->getMock();
232 | 
233 |         $collection->expects($this->once())
234 |             ->method('findOne')
235 |             ->willReturn(array('_id' => 'key', 'value' => 'foobar'));
236 | 
237 |         $store = new MongoDbStore($collection);
238 |         $store->getOrFail('key');
239 |     }
240 | 
241 |     /**
242 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
243 |      * @expectedExceptionMessage I failed!
244 |      */
245 |     public function testGetMultipleThrowsReadExceptionIfReadFails()
246 |     {
247 |         $exception = new TestException('I failed!');
248 | 
249 |         $collection = $this->getMockBuilder('MongoDB\Collection')
250 |             ->disableOriginalConstructor()
251 |             ->getMock();
252 | 
253 |         $collection->expects($this->once())
254 |             ->method('find')
255 |             ->willThrowException($exception);
256 | 
257 |         $store = new MongoDbStore($collection);
258 |         $store->getMultiple(array('key'));
259 |     }
260 | 
261 |     /**
262 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
263 |      */
264 |     public function testGetMultipleThrowsExceptionIfNotUnserializable()
265 |     {
266 |         $collection = $this->getMockBuilder('MongoDB\Collection')
267 |             ->disableOriginalConstructor()
268 |             ->getMock();
269 | 
270 |         $cursor = new ArrayIterator(array(
271 |             array('_id' => 'key', 'value' => 'foobar'),
272 |         ));
273 | 
274 |         $collection->expects($this->once())
275 |             ->method('find')
276 |             ->willReturn($cursor);
277 | 
278 |         $store = new MongoDbStore($collection);
279 |         $store->getMultiple(array('key'));
280 |     }
281 | 
282 |     /**
283 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
284 |      * @expectedExceptionMessage I failed!
285 |      */
286 |     public function testGetMultipleOrFailThrowsReadExceptionIfReadFails()
287 |     {
288 |         $exception = new TestException('I failed!');
289 | 
290 |         $collection = $this->getMockBuilder('MongoDB\Collection')
291 |             ->disableOriginalConstructor()
292 |             ->getMock();
293 | 
294 |         $collection->expects($this->once())
295 |             ->method('find')
296 |             ->willThrowException($exception);
297 | 
298 |         $store = new MongoDbStore($collection);
299 |         $store->getMultipleOrFail(array('key'));
300 |     }
301 | 
302 |     /**
303 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
304 |      */
305 |     public function testGetMultipleOrFailThrowsExceptionIfNotUnserializable()
306 |     {
307 |         $collection = $this->getMockBuilder('MongoDB\Collection')
308 |             ->disableOriginalConstructor()
309 |             ->getMock();
310 | 
311 |         $cursor = new ArrayIterator(array(
312 |             array('_id' => 'key', 'value' => 'foobar'),
313 |         ));
314 | 
315 |         $collection->expects($this->once())
316 |             ->method('find')
317 |             ->willReturn($cursor);
318 | 
319 |         $store = new MongoDbStore($collection);
320 |         $store->getMultipleOrFail(array('key'));
321 |     }
322 | 
323 |     /**
324 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
325 |      * @expectedExceptionMessage I failed!
326 |      */
327 |     public function testExistsThrowsReadExceptionIfReadFails()
328 |     {
329 |         $exception = new TestException('I failed!');
330 | 
331 |         $collection = $this->getMockBuilder('MongoDB\Collection')
332 |             ->disableOriginalConstructor()
333 |             ->getMock();
334 | 
335 |         $collection->expects($this->once())
336 |             ->method('count')
337 |             ->willThrowException($exception);
338 | 
339 |         $store = new MongoDbStore($collection);
340 |         $store->exists('key');
341 |     }
342 | 
343 |     /**
344 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
345 |      * @expectedExceptionMessage I failed!
346 |      */
347 |     public function testKeysThrowsReadExceptionIfReadFails()
348 |     {
349 |         $exception = new TestException('I failed!');
350 | 
351 |         $collection = $this->getMockBuilder('MongoDB\Collection')
352 |             ->disableOriginalConstructor()
353 |             ->getMock();
354 | 
355 |         $collection->expects($this->once())
356 |             ->method('find')
357 |             ->willThrowException($exception);
358 | 
359 |         $store = new MongoDbStore($collection);
360 |         $store->keys();
361 |     }
362 | }
363 | 
--------------------------------------------------------------------------------
/tests/AbstractSortableCountableStoreTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests;
 13 | 
 14 | /**
 15 |  * @since  1.0
 16 |  *
 17 |  * @author Bernhard Schussek 
 18 |  * @author Titouan Galopin 
 19 |  */
 20 | abstract class AbstractSortableCountableStoreTest extends AbstractCountableStoreTest
 21 | {
 22 |     /**
 23 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
 24 |      */
 25 |     abstract public function testSortThrowsReadExceptionIfReadFails();
 26 | 
 27 |     /**
 28 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 29 |      */
 30 |     abstract public function testSortThrowsWriteExceptionIfWriteFails();
 31 | 
 32 |     public function testSortRegularStringKeys()
 33 |     {
 34 |         $this->store->set('c', 1);
 35 |         $this->store->set('a', 2);
 36 |         $this->store->set('b', 3);
 37 | 
 38 |         $this->store->sort();
 39 | 
 40 |         $this->assertSame(array(
 41 |             'a' => 2,
 42 |             'b' => 3,
 43 |             'c' => 1,
 44 |         ), $this->store->getMultiple($this->store->keys()));
 45 |     }
 46 | 
 47 |     public function testSortRegularIntegerKeys()
 48 |     {
 49 |         $this->store->set(3, 'a');
 50 |         $this->store->set(1, 'b');
 51 |         $this->store->set(2, 'c');
 52 | 
 53 |         $this->store->sort();
 54 | 
 55 |         $this->assertSame(array(
 56 |             1 => 'b',
 57 |             2 => 'c',
 58 |             3 => 'a',
 59 |         ), $this->store->getMultiple($this->store->keys()));
 60 |     }
 61 | 
 62 |     public function testSortStringStringKeys()
 63 |     {
 64 |         $this->store->set('c', 1);
 65 |         $this->store->set('a', 2);
 66 |         $this->store->set('b', 3);
 67 | 
 68 |         $this->store->sort(SORT_STRING);
 69 | 
 70 |         $this->assertSame(array(
 71 |             'a' => 2,
 72 |             'b' => 3,
 73 |             'c' => 1,
 74 |         ), $this->store->getMultiple($this->store->keys()));
 75 |     }
 76 | 
 77 |     public function testSortNumericIntegerKeys()
 78 |     {
 79 |         $this->store->set(3, 'a');
 80 |         $this->store->set(1, 'b');
 81 |         $this->store->set(2, 'c');
 82 | 
 83 |         $this->store->sort(SORT_NUMERIC);
 84 | 
 85 |         $this->assertSame(array(
 86 |             1 => 'b',
 87 |             2 => 'c',
 88 |             3 => 'a',
 89 |         ), $this->store->getMultiple($this->store->keys()));
 90 |     }
 91 | 
 92 |     public function testSortNaturalStringKeys()
 93 |     {
 94 |         if (PHP_VERSION_ID < 50400) {
 95 |             $this->markTestSkipped('SORT_NATURAL not available');
 96 |         }
 97 | 
 98 |         $this->store->set('10', 'c');
 99 |         $this->store->set('1', 'g');
100 |         $this->store->set('100', 'a');
101 |         $this->store->set('9', 'b');
102 |         $this->store->set('7a', 'h');
103 |         $this->store->set('7b', 'd');
104 |         $this->store->set('_5', 'z');
105 | 
106 |         $this->store->sort(SORT_NATURAL);
107 | 
108 |         $this->assertSame(array(
109 |             '1' => 'g',
110 |             '7a' => 'h',
111 |             '7b' => 'd',
112 |             '9' => 'b',
113 |             '10' => 'c',
114 |             '100' => 'a',
115 |             '_5' => 'z',
116 |         ), $this->store->getMultiple($this->store->keys()));
117 |     }
118 | 
119 |     public function testSortCaseInsensitiveStringKeys()
120 |     {
121 |         if (PHP_VERSION_ID < 50400) {
122 |             $this->markTestSkipped('SORT_FLAG_CASE not available');
123 |         }
124 | 
125 |         $this->store->set('_Ac', 'A');
126 |         $this->store->set('abc', 'F');
127 |         $this->store->set('_ab', 'G');
128 |         $this->store->set('ABB', 'E');
129 |         $this->store->set('Bce', 'C');
130 |         $this->store->set('bcd', 'D');
131 |         $this->store->set('bCf', 'E');
132 | 
133 |         $this->store->sort(SORT_STRING | SORT_FLAG_CASE);
134 | 
135 |         $this->assertSame(array(
136 |             '_ab' => 'G',
137 |             '_Ac' => 'A',
138 |             'ABB' => 'E',
139 |             'abc' => 'F',
140 |             'bcd' => 'D',
141 |             'Bce' => 'C',
142 |             'bCf' => 'E',
143 |         ), $this->store->getMultiple($this->store->keys()));
144 |     }
145 | }
146 | 
--------------------------------------------------------------------------------
/tests/ArrayStoreTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests;
 13 | 
 14 | use stdClass;
 15 | use Webmozart\KeyValueStore\ArrayStore;
 16 | 
 17 | /**
 18 |  * @since  1.0
 19 |  *
 20 |  * @author Bernhard Schussek 
 21 |  */
 22 | class ArrayStoreTest extends AbstractSortableCountableStoreTest
 23 | {
 24 |     protected function createStore()
 25 |     {
 26 |         return new ArrayStore();
 27 |     }
 28 | 
 29 |     protected function createPopulatedStore(array $values)
 30 |     {
 31 |         return new ArrayStore($values);
 32 |     }
 33 | 
 34 |     public function testCreateStoreWithElements()
 35 |     {
 36 |         $object = new stdClass();
 37 |         $store = $this->createPopulatedStore(array(0 => 'a', 1 => $object));
 38 | 
 39 |         $this->assertSame('a', $store->get(0));
 40 |         $this->assertEquals($object, $store->get(1));
 41 |     }
 42 | 
 43 |     /**
 44 |      * @dataProvider provideInvalidValues
 45 |      */
 46 |     public function testSetThrowsExceptionIfValueNotSerializable($value)
 47 |     {
 48 |         // ArrayStore never serializes its values
 49 |         $this->assertTrue(true);
 50 |     }
 51 | 
 52 |     public function testSetThrowsWriteExceptionIfWriteFails()
 53 |     {
 54 |         // ArrayStore never writes a storage
 55 |         $this->assertTrue(true);
 56 |     }
 57 | 
 58 |     public function testRemoveThrowsWriteExceptionIfWriteFails()
 59 |     {
 60 |         // ArrayStore never writes a storage
 61 |         $this->assertTrue(true);
 62 |     }
 63 | 
 64 |     public function testClearThrowsWriteExceptionIfWriteFails()
 65 |     {
 66 |         // ArrayStore never writes a storage
 67 |         $this->assertTrue(true);
 68 |     }
 69 | 
 70 |     public function testGetThrowsReadExceptionIfReadFails()
 71 |     {
 72 |         // ArrayStore never reads a storage
 73 |         $this->assertTrue(true);
 74 |     }
 75 | 
 76 |     public function testGetThrowsExceptionIfNotUnserializable()
 77 |     {
 78 |         // ArrayStore never serializes its values
 79 |         $this->assertTrue(true);
 80 |     }
 81 | 
 82 |     public function testGetOrFailThrowsReadExceptionIfReadFails()
 83 |     {
 84 |         // ArrayStore never reads a storage
 85 |         $this->assertTrue(true);
 86 |     }
 87 | 
 88 |     public function testGetOrFailThrowsExceptionIfNotUnserializable()
 89 |     {
 90 |         // ArrayStore never serializes its values
 91 |         $this->assertTrue(true);
 92 |     }
 93 | 
 94 |     public function testGetMultipleThrowsReadExceptionIfReadFails()
 95 |     {
 96 |         // ArrayStore never reads a storage
 97 |         $this->assertTrue(true);
 98 |     }
 99 | 
100 |     public function testGetMultipleThrowsExceptionIfNotUnserializable()
101 |     {
102 |         // ArrayStore never serializes its values
103 |         $this->assertTrue(true);
104 |     }
105 | 
106 |     public function testGetMultipleOrFailThrowsReadExceptionIfReadFails()
107 |     {
108 |         // ArrayStore never reads a storage
109 |         $this->assertTrue(true);
110 |     }
111 | 
112 |     public function testGetMultipleOrFailThrowsExceptionIfNotUnserializable()
113 |     {
114 |         // ArrayStore never serializes its values
115 |         $this->assertTrue(true);
116 |     }
117 | 
118 |     public function testExistsThrowsReadExceptionIfReadFails()
119 |     {
120 |         // ArrayStore never reads a storage
121 |         $this->assertTrue(true);
122 |     }
123 | 
124 |     public function testKeysThrowsReadExceptionIfReadFails()
125 |     {
126 |         // ArrayStore never reads a storage
127 |         $this->assertTrue(true);
128 |     }
129 | 
130 |     public function testSortThrowsReadExceptionIfReadFails()
131 |     {
132 |         // ArrayStore never reads a storage
133 |         $this->assertTrue(true);
134 |     }
135 | 
136 |     public function testSortThrowsWriteExceptionIfWriteFails()
137 |     {
138 |         // ArrayStore never write a storage
139 |         $this->assertTrue(true);
140 |     }
141 | 
142 |     public function testCountThrowsReadExceptionIfReadFails()
143 |     {
144 |         // ArrayStore never reads a storage
145 |         $this->assertTrue(true);
146 |     }
147 | }
148 | 
--------------------------------------------------------------------------------
/tests/DbalStoreTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests;
 13 | 
 14 | use Doctrine\DBAL\Connection;
 15 | use Doctrine\DBAL\DriverManager;
 16 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 17 | use Webmozart\KeyValueStore\Api\SortableStore;
 18 | use Webmozart\KeyValueStore\DbalStore;
 19 | use Webmozart\KeyValueStore\Tests\Fixtures\TestException;
 20 | 
 21 | /**
 22 |  * @since  1.0
 23 |  *
 24 |  * @author Bernhard Schussek 
 25 |  * @author Michiel Boeckaert 
 26 |  */
 27 | class DbalStoreTest extends AbstractKeyValueStoreTest
 28 | {
 29 |     protected static $dbalStore;
 30 | 
 31 |     public static function setUpBeforeClass()
 32 |     {
 33 |         parent::setUpBeforeClass();
 34 | 
 35 |         $connection = DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'memory' => true));
 36 |         $schemaManager = $connection->getSchemaManager();
 37 |         $schema = $schemaManager->createSchema();
 38 |         self::$dbalStore = new DbalStore($connection, 'store');
 39 | 
 40 |         if (!$schema->hasTable(self::$dbalStore->getTableName())) {
 41 |             $schemaManager->createTable(self::$dbalStore->getTableForCreate());
 42 |         }
 43 |     }
 44 | 
 45 |     /**
 46 |      * @return KeyValueStore|SortableStore The created store.
 47 |      */
 48 |     protected function createStore()
 49 |     {
 50 |         return self::$dbalStore;
 51 |     }
 52 | 
 53 |     public function testSettingAValueTwiceUpdatesTheValue()
 54 |     {
 55 |         $this->store->set('a', '123');
 56 |         $this->store->set('a', '124');
 57 |         $this->assertEquals('124', $this->store->get('a'));
 58 |     }
 59 | 
 60 |     public function provideUnsafeTableNamesSoWeCanBlowUpOurDataBase()
 61 |     {
 62 |         return array(
 63 |             array(null),
 64 |             array(false),
 65 |             array(array()),
 66 |             array(''),
 67 |         );
 68 |     }
 69 | 
 70 |     /**
 71 |      * @dataProvider provideUnsafeTableNamesSoWeCanBlowUpOurDataBase
 72 |      * @expectedException \InvalidArgumentException
 73 |      */
 74 |     public function testTheTableNameNeedsToBeANotEmptyString($tableName)
 75 |     {
 76 |         $connection = $this->getConnectionMock();
 77 |         new DbalStore($connection, $tableName);
 78 |     }
 79 | 
 80 |     public function testGetTableNameWorks()
 81 |     {
 82 |         $connection = $this->getConnectionMock();
 83 |         $store = new DbalStore($connection, 'foo');
 84 |         $this->assertEquals('foo', $store->getTableName());
 85 |     }
 86 | 
 87 |     public function testGetTableNameDefaultsToStore()
 88 |     {
 89 |         $connection = $this->getConnectionMock();
 90 |         $store = new DbalStore($connection);
 91 |         $this->assertEquals('store', $store->getTableName());
 92 |     }
 93 | 
 94 |     /**
 95 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 96 |      */
 97 |     public function testSetThrowsWriteExceptionIfWriteFails()
 98 |     {
 99 |         $connection = $this->getConnectionMock();
100 |         $connection->expects($this->once())->method('fetchAssoc')->willThrowException(new TestException('I failed'));
101 | 
102 |         $store = new DbalStore($connection, 'store');
103 |         $store->set('foo', 'bar');
104 |     }
105 | 
106 |     /**
107 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
108 |      */
109 |     public function testRemoveThrowsWriteExceptionIfWriteFails()
110 |     {
111 |         $connection = $this->getConnectionMock();
112 |         $connection->expects($this->once())->method('delete')->willThrowException(new TestException('I failed'));
113 | 
114 |         $store = new DbalStore($connection, 'store');
115 |         $store->remove('foo');
116 |     }
117 | 
118 |     /**
119 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
120 |      */
121 |     public function testClearThrowsWriteExceptionIfWriteFails()
122 |     {
123 |         $connection = $this->getConnectionMock();
124 |         $connection->expects($this->once())->method('query')->willThrowException(new TestException('I failed'));
125 | 
126 |         $store = new DbalStore($connection, 'store');
127 |         $store->clear();
128 |     }
129 | 
130 |     /**
131 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
132 |      */
133 |     public function testGetThrowsReadExceptionIfReadFails()
134 |     {
135 |         $connection = $this->getConnectionMock();
136 |         $connection->expects($this->once())->method('fetchAssoc')->willThrowException(new TestException('I failed'));
137 | 
138 |         $store = new DbalStore($connection, 'store');
139 |         $store->get('foo');
140 |     }
141 | 
142 |     /**
143 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
144 |      */
145 |     public function testGetThrowsExceptionIfNotUnserializable()
146 |     {
147 |         $connection = $this->getConnectionMock();
148 |         $connection->expects($this->once())->method('fetchAssoc')
149 |             ->willReturn(array('meta_key' => 'foo', 'meta_value' => 'foo_bar'));
150 | 
151 |         $store = new DbalStore($connection, 'store');
152 |         $store->get('foo');
153 |     }
154 | 
155 |     /**
156 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
157 |      */
158 |     public function testGetOrFailThrowsReadExceptionIfReadFails()
159 |     {
160 |         $connection = $this->getConnectionMock();
161 |         $connection->expects($this->once())->method('fetchAssoc')->willThrowException(new TestException('I failed'));
162 | 
163 |         $store = new DbalStore($connection, 'store');
164 |         $store->getOrFail('foo');
165 |     }
166 | 
167 |     /**
168 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
169 |      */
170 |     public function testGetOrFailThrowsExceptionIfNotUnserializable()
171 |     {
172 |         $connection = $this->getConnectionMock();
173 |         $connection->expects($this->once())->method('fetchAssoc')
174 |             ->willReturn(array('meta_key' => 'foo', 'meta_value' => 'foo_bar'));
175 | 
176 |         $store = new DbalStore($connection, 'store');
177 |         $store->getOrFail('foo');
178 |     }
179 | 
180 |     /**
181 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
182 |      */
183 |     public function testGetMultipleThrowsReadExceptionIfReadFails()
184 |     {
185 |         $connection = $this->getConnectionMock();
186 |         $connection->expects($this->once())->method('executeQuery')->willThrowException(new TestException('I failed'));
187 | 
188 |         $store = new DbalStore($connection, 'store');
189 |         $store->getMultiple(array('foo', 'bar'));
190 |     }
191 | 
192 |     /**
193 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
194 |      */
195 |     public function testGetMultipleThrowsExceptionIfNotUnserializable()
196 |     {
197 |         $connection = $this->getConnectionMock();
198 |         $statement = $this->getStatementMock();
199 |         $connection->expects($this->once())->method('executeQuery')->willReturn($statement);
200 |         $statement->expects($this->once())->method('fetchAll')
201 |             ->willReturn(array(array('meta_key' => 'my_key', 'meta_value' => 'foo_bar')));
202 | 
203 |         $store = new DbalStore($connection, 'store');
204 |         $store->getMultiple(array('foo', 'bar'));
205 |     }
206 | 
207 |     /**
208 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
209 |      */
210 |     public function testGetMultipleOrFailThrowsReadExceptionIfReadFails()
211 |     {
212 |         $connection = $this->getConnectionMock();
213 |         $connection->expects($this->once())->method('executeQuery')->willThrowException(new TestException('I failed'));
214 | 
215 |         $store = new DbalStore($connection, 'store');
216 |         $store->getMultiple(array('foo', 'bar'));
217 |     }
218 | 
219 |     /**
220 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
221 |      */
222 |     public function testGetMultipleOrFailThrowsExceptionIfNotUnserializable()
223 |     {
224 |         $connection = $this->getConnectionMock();
225 |         $statement = $this->getStatementMock();
226 |         $connection->expects($this->once())->method('executeQuery')->willReturn($statement);
227 |         $statement->expects($this->once())->method('fetchAll')
228 |             ->willReturn(array(array('meta_key' => 'my_key', 'meta_value' => 'foo_bar')));
229 | 
230 |         $store = new DbalStore($connection, 'store');
231 |         $store->getMultipleOrFail(array('foo', 'bar'));
232 |     }
233 | 
234 |     /**
235 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
236 |      */
237 |     public function testExistsThrowsReadExceptionIfReadFails()
238 |     {
239 |         $connection = $this->getConnectionMock();
240 |         $connection->expects($this->once())->method('fetchAssoc')->willThrowException(new TestException('I failed'));
241 | 
242 |         $store = new DbalStore($connection, 'store');
243 |         $store->exists('foo');
244 |     }
245 | 
246 |     /**
247 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
248 |      */
249 |     public function testKeysThrowsReadExceptionIfReadFails()
250 |     {
251 |         $connection = $this->getConnectionMock();
252 |         $connection->expects($this->once())->method('query')->willThrowException(new TestException('I failed'));
253 | 
254 |         $store = new DbalStore($connection, 'store');
255 |         $store->keys();
256 |     }
257 | 
258 |     /**
259 |      * @return \PHPUnit_Framework_MockObject_MockObject|Connection
260 |      */
261 |     protected function getConnectionMock()
262 |     {
263 |         $connection = $this->getMockBuilder('Doctrine\DBAL\Connection')
264 |             ->disableOriginalConstructor()
265 |             ->getMock();
266 | 
267 |         return $connection;
268 |     }
269 | 
270 |     /**
271 |      * @return \PHPUnit_Framework_MockObject_MockObject
272 |      */
273 |     protected function getStatementMock()
274 |     {
275 |         $statement = $this->getMockBuilder('Doctrine\DBAL\Driver\Statement')
276 |             ->disableOriginalConstructor()
277 |             ->getMock();
278 | 
279 |         return $statement;
280 |     }
281 | }
282 | 
--------------------------------------------------------------------------------
/tests/Decorator/AbstractDecoratorTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests\Decorator;
 13 | 
 14 | use PHPUnit_Framework_MockObject_MockObject;
 15 | use PHPUnit_Framework_TestCase;
 16 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 17 | use Webmozart\KeyValueStore\Decorator\AbstractDecorator;
 18 | use Webmozart\KeyValueStore\Decorator\SortableDecorator;
 19 | 
 20 | /**
 21 |  * @since  1.0
 22 |  *
 23 |  * @author Bernhard Schussek 
 24 |  * @author Titouan Galopin 
 25 |  */
 26 | abstract class AbstractDecoratorTest extends PHPUnit_Framework_TestCase
 27 | {
 28 |     /**
 29 |      * @var PHPUnit_Framework_MockObject_MockObject|KeyValueStore
 30 |      */
 31 |     protected $innerStore;
 32 | 
 33 |     /**
 34 |      * @var SortableDecorator
 35 |      */
 36 |     protected $decorator;
 37 | 
 38 |     /**
 39 |      * @param KeyValueStore $innerStore
 40 |      *
 41 |      * @return KeyValueStore|AbstractDecorator The created store.
 42 |      */
 43 |     abstract protected function createDecorator(KeyValueStore $innerStore);
 44 | 
 45 |     protected function setUp()
 46 |     {
 47 |         $this->innerStore = $this->getMock('Webmozart\KeyValueStore\Api\KeyValueStore');
 48 |         $this->decorator = $this->createDecorator($this->innerStore);
 49 |     }
 50 | 
 51 |     protected function tearDown()
 52 |     {
 53 |         if ($this->decorator) {
 54 |             $this->decorator->clear();
 55 |         }
 56 |     }
 57 | 
 58 |     public function testGetDelegate()
 59 |     {
 60 |         $this->innerStore->expects($this->once())
 61 |             ->method('get')
 62 |             ->with('key');
 63 | 
 64 |         $this->decorator->get('key');
 65 |     }
 66 | 
 67 |     public function testGetOrFailDelegate()
 68 |     {
 69 |         $this->innerStore->expects($this->once())
 70 |             ->method('getOrFail')
 71 |             ->with('key');
 72 | 
 73 |         $this->decorator->getOrFail('key');
 74 |     }
 75 | 
 76 |     public function testGetMultipleDelegate()
 77 |     {
 78 |         $this->innerStore->expects($this->once())
 79 |             ->method('getMultiple')
 80 |             ->with(array('key1', 'key2'));
 81 | 
 82 |         $this->decorator->getMultiple(array('key1', 'key2'));
 83 |     }
 84 | 
 85 |     public function testGetMultipleOrFailDelegate()
 86 |     {
 87 |         $this->innerStore->expects($this->once())
 88 |             ->method('getMultipleOrFail')
 89 |             ->with(array('key1', 'key2'));
 90 | 
 91 |         $this->decorator->getMultipleOrFail(array('key1', 'key2'));
 92 |     }
 93 | 
 94 |     public function testSetDelegate()
 95 |     {
 96 |         $this->innerStore->expects($this->once())
 97 |             ->method('set')
 98 |             ->with('key', 'value');
 99 | 
100 |         $this->decorator->set('key', 'value');
101 |     }
102 | 
103 |     public function testRemoveDelegate()
104 |     {
105 |         $this->innerStore->expects($this->once())
106 |             ->method('remove')
107 |             ->with('key');
108 | 
109 |         $this->decorator->remove('key');
110 |     }
111 | 
112 |     public function testExistsDelegate()
113 |     {
114 |         $this->innerStore->expects($this->once())
115 |             ->method('exists')
116 |             ->with('key');
117 | 
118 |         $this->decorator->exists('key');
119 |     }
120 | 
121 |     public function testClearDelegate()
122 |     {
123 |         $this->innerStore->expects($this->once())
124 |             ->method('clear');
125 | 
126 |         $this->decorator->clear();
127 |     }
128 | 
129 |     public function testKeysDelegate()
130 |     {
131 |         $this->innerStore->expects($this->once())
132 |             ->method('keys');
133 | 
134 |         $this->decorator->keys();
135 |     }
136 | }
137 | 
--------------------------------------------------------------------------------
/tests/Decorator/CachingDecoratorTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests\Decorator;
 13 | 
 14 | use Doctrine\Common\Cache\Cache;
 15 | use PHPUnit_Framework_MockObject_MockObject;
 16 | use Webmozart\KeyValueStore\Api\InvalidKeyException;
 17 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 18 | use Webmozart\KeyValueStore\Api\NoSuchKeyException;
 19 | use Webmozart\KeyValueStore\Api\SerializationFailedException;
 20 | use Webmozart\KeyValueStore\Api\WriteException;
 21 | use Webmozart\KeyValueStore\Decorator\CachingDecorator;
 22 | 
 23 | /**
 24 |  * @since  1.0
 25 |  *
 26 |  * @author Bernhard Schussek 
 27 |  */
 28 | class CachingDecoratorTest extends AbstractDecoratorTest
 29 | {
 30 |     /**
 31 |      * @var PHPUnit_Framework_MockObject_MockObject|Cache
 32 |      */
 33 |     private $cache;
 34 | 
 35 |     protected function createDecorator(KeyValueStore $innerStore)
 36 |     {
 37 |         $this->cache = $this->getMock('Webmozart\KeyValueStore\Tests\Fixtures\TestClearableCache');
 38 | 
 39 |         return new CachingDecorator($this->innerStore, $this->cache);
 40 |     }
 41 | 
 42 |     public function testGetDelegate()
 43 |     {
 44 |         // We test the get in another way
 45 |         $this->assertTrue(true);
 46 |     }
 47 | 
 48 |     public function testGetMultipleDelegate()
 49 |     {
 50 |         // We test the getMultiple in another way
 51 |         $this->assertTrue(true);
 52 |     }
 53 | 
 54 |     public function testGetMultipleOrFailDelegate()
 55 |     {
 56 |         // We test the getMultipleOrFail in another way
 57 |         $this->assertTrue(true);
 58 |     }
 59 | 
 60 |     /**
 61 |      * @expectedException \InvalidArgumentException
 62 |      */
 63 |     public function testCreateFailsIfNeitherClearableNorFlushable()
 64 |     {
 65 |         $this->cache = $this->getMock('Doctrine\Common\Cache\Cache');
 66 | 
 67 |         new CachingDecorator($this->innerStore, $this->cache);
 68 |     }
 69 | 
 70 |     public function testSetWritesToCache()
 71 |     {
 72 |         $this->innerStore->expects($this->once())
 73 |             ->method('set')
 74 |             ->with('key', 'value');
 75 | 
 76 |         $this->cache->expects($this->once())
 77 |             ->method('save')
 78 |             ->with('key', 'value');
 79 | 
 80 |         $this->decorator->set('key', 'value');
 81 |     }
 82 | 
 83 |     public function testSetWritesTtlIfGiven()
 84 |     {
 85 |         $this->decorator = new CachingDecorator($this->innerStore, $this->cache, 100);
 86 | 
 87 |         $this->innerStore->expects($this->once())
 88 |             ->method('set')
 89 |             ->with('key', 'value');
 90 | 
 91 |         $this->cache->expects($this->once())
 92 |             ->method('save')
 93 |             ->with('key', 'value', 100);
 94 | 
 95 |         $this->decorator->set('key', 'value');
 96 |     }
 97 | 
 98 |     /**
 99 |      * @expectedException \Webmozart\KeyValueStore\Api\SerializationFailedException
100 |      */
101 |     public function testSetDoesNotWriteToCacheIfKeyValueStoreFails()
102 |     {
103 |         $this->innerStore->expects($this->once())
104 |             ->method('set')
105 |             ->with('key', 'value')
106 |             ->willThrowException(new SerializationFailedException());
107 | 
108 |         $this->cache->expects($this->never())
109 |             ->method('save');
110 | 
111 |         $this->decorator->set('key', 'value');
112 |     }
113 | 
114 |     public function testGetReturnsFromCacheIfCached()
115 |     {
116 |         $this->cache->expects($this->at(0))
117 |             ->method('contains')
118 |             ->with('key')
119 |             ->willReturn(true);
120 | 
121 |         $this->innerStore->expects($this->never())
122 |             ->method('getOrFail');
123 | 
124 |         $this->cache->expects($this->at(1))
125 |             ->method('fetch')
126 |             ->with('key')
127 |             ->willReturn('value');
128 | 
129 |         $this->assertSame('value', $this->decorator->get('key'));
130 |     }
131 | 
132 |     public function testGetWritesToCacheIfNotCached()
133 |     {
134 |         $this->cache->expects($this->at(0))
135 |             ->method('contains')
136 |             ->with('key')
137 |             ->willReturn(false);
138 | 
139 |         $this->innerStore->expects($this->once())
140 |             ->method('getOrFail')
141 |             ->with('key')
142 |             ->willReturn('value');
143 | 
144 |         $this->cache->expects($this->at(1))
145 |             ->method('save')
146 |             ->with('key', 'value');
147 | 
148 |         $this->assertSame('value', $this->decorator->get('key'));
149 |     }
150 | 
151 |     public function testGetWritesTtlIfNotCached()
152 |     {
153 |         $this->decorator = new CachingDecorator($this->innerStore, $this->cache, 100);
154 | 
155 |         $this->cache->expects($this->at(0))
156 |             ->method('contains')
157 |             ->with('key')
158 |             ->willReturn(false);
159 | 
160 |         $this->innerStore->expects($this->once())
161 |             ->method('getOrFail')
162 |             ->with('key')
163 |             ->willReturn('value');
164 | 
165 |         $this->cache->expects($this->at(1))
166 |             ->method('save')
167 |             ->with('key', 'value', 100);
168 | 
169 |         $this->assertSame('value', $this->decorator->get('key'));
170 |     }
171 | 
172 |     public function testGetDoesNotSaveToCacheIfKeyNotFound()
173 |     {
174 |         $this->cache->expects($this->once())
175 |             ->method('contains')
176 |             ->with('key')
177 |             ->willReturn(false);
178 | 
179 |         $this->innerStore->expects($this->once())
180 |             ->method('getOrFail')
181 |             ->willThrowException(NoSuchKeyException::forKey('key'));
182 | 
183 |         $this->cache->expects($this->never())
184 |             ->method('save');
185 | 
186 |         $this->assertSame('default', $this->decorator->get('key', 'default'));
187 |     }
188 | 
189 |     public function testGetOrFailReturnsFromCacheIfCached()
190 |     {
191 |         $this->cache->expects($this->at(0))
192 |             ->method('contains')
193 |             ->with('key')
194 |             ->willReturn(true);
195 | 
196 |         $this->innerStore->expects($this->never())
197 |             ->method('getOrFail');
198 | 
199 |         $this->cache->expects($this->at(1))
200 |             ->method('fetch')
201 |             ->with('key')
202 |             ->willReturn('value');
203 | 
204 |         $this->assertSame('value', $this->decorator->getOrFail('key'));
205 |     }
206 | 
207 |     public function testGetOrFailWritesToCacheIfNotCached()
208 |     {
209 |         $this->cache->expects($this->at(0))
210 |             ->method('contains')
211 |             ->with('key')
212 |             ->willReturn(false);
213 | 
214 |         $this->innerStore->expects($this->once())
215 |             ->method('getOrFail')
216 |             ->with('key')
217 |             ->willReturn('value');
218 | 
219 |         $this->cache->expects($this->at(1))
220 |             ->method('save')
221 |             ->with('key', 'value');
222 | 
223 |         $this->assertSame('value', $this->decorator->getOrFail('key'));
224 |     }
225 | 
226 |     public function testGetOrFailWritesTtlIfNotCached()
227 |     {
228 |         $this->decorator = new CachingDecorator($this->innerStore, $this->cache, 100);
229 | 
230 |         $this->cache->expects($this->at(0))
231 |             ->method('contains')
232 |             ->with('key')
233 |             ->willReturn(false);
234 | 
235 |         $this->innerStore->expects($this->once())
236 |             ->method('getOrFail')
237 |             ->with('key')
238 |             ->willReturn('value');
239 | 
240 |         $this->cache->expects($this->at(1))
241 |             ->method('save')
242 |             ->with('key', 'value', 100);
243 | 
244 |         $this->assertSame('value', $this->decorator->getOrFail('key'));
245 |     }
246 | 
247 |     /**
248 |      * @expectedException \Webmozart\KeyValueStore\Api\NoSuchKeyException
249 |      */
250 |     public function testGetOrFailForwardsNoSuchKeyException()
251 |     {
252 |         $this->cache->expects($this->once())
253 |             ->method('contains')
254 |             ->with('key')
255 |             ->willReturn(false);
256 | 
257 |         $this->innerStore->expects($this->once())
258 |             ->method('getOrFail')
259 |             ->willThrowException(NoSuchKeyException::forKey('key'));
260 | 
261 |         $this->cache->expects($this->never())
262 |             ->method('save');
263 | 
264 |         $this->decorator->getOrFail('key');
265 |     }
266 | 
267 |     public function testGetMultipleMergesCachedAndNonCachedEntries()
268 |     {
269 |         $this->cache->expects($this->exactly(3))
270 |             ->method('contains')
271 |             ->willReturnMap(array(
272 |                 array('a', false),
273 |                 array('b', true),
274 |                 array('c', false),
275 |             ));
276 | 
277 |         $this->innerStore->expects($this->once())
278 |             ->method('getMultiple')
279 |             ->with(array('a', 2 => 'c'), 'default')
280 |             ->willReturn(array(
281 |                 'a' => 'value1',
282 |                 'c' => 'default',
283 |             ));
284 | 
285 |         $this->cache->expects($this->once())
286 |             ->method('fetch')
287 |             ->with('b')
288 |             ->willReturn('value2');
289 | 
290 |         // We don't know which keys to save and which not
291 |         $this->cache->expects($this->never())
292 |             ->method('save');
293 | 
294 |         $values = $this->decorator->getMultiple(array('a', 'b', 'c'), 'default');
295 | 
296 |         // Undefined order
297 |         ksort($values);
298 | 
299 |         $this->assertSame(array(
300 |             'a' => 'value1',
301 |             'b' => 'value2',
302 |             'c' => 'default',
303 |         ), $values);
304 |     }
305 | 
306 |     public function testGetMultipleOrFailMergesCachedAndNonCachedEntries()
307 |     {
308 |         $this->cache->expects($this->exactly(3))
309 |             ->method('contains')
310 |             ->willReturnMap(array(
311 |                 array('a', false),
312 |                 array('b', true),
313 |                 array('c', false),
314 |             ));
315 | 
316 |         $this->innerStore->expects($this->once())
317 |             ->method('getMultipleOrFail')
318 |             ->with(array('a', 2 => 'c'))
319 |             ->willReturn(array(
320 |                 'a' => 'value1',
321 |                 'c' => 'value3',
322 |             ));
323 | 
324 |         $this->cache->expects($this->once())
325 |             ->method('fetch')
326 |             ->with('b')
327 |             ->willReturn('value2');
328 | 
329 |         $this->cache->expects($this->exactly(2))
330 |             ->method('save')
331 |             ->withConsecutive(array('a', 'value1'), array('c', 'value3'));
332 | 
333 |         $values = $this->decorator->getMultipleOrFail(array('a', 'b', 'c'));
334 | 
335 |         // Undefined order
336 |         ksort($values);
337 | 
338 |         $this->assertSame(array(
339 |             'a' => 'value1',
340 |             'b' => 'value2',
341 |             'c' => 'value3',
342 |         ), $values);
343 |     }
344 | 
345 |     public function testExistsQueriesCache()
346 |     {
347 |         $this->cache->expects($this->once())
348 |             ->method('contains')
349 |             ->with('key')
350 |             ->willReturn(true);
351 | 
352 |         $this->innerStore->expects($this->never())
353 |             ->method('exists');
354 | 
355 |         $this->assertTrue($this->decorator->exists('key'));
356 |     }
357 | 
358 |     /**
359 |      * @dataProvider provideTrueFalse
360 |      */
361 |     public function testExistsQueriesStoreIfNotCached($result)
362 |     {
363 |         $this->cache->expects($this->once())
364 |             ->method('contains')
365 |             ->with('key')
366 |             ->willReturn(false);
367 | 
368 |         $this->innerStore->expects($this->once())
369 |             ->method('exists')
370 |             ->with('key')
371 |             ->willReturn($result);
372 | 
373 |         $this->assertSame($result, $this->decorator->exists('key'));
374 |     }
375 | 
376 |     public function provideTrueFalse()
377 |     {
378 |         return array(
379 |             array(true),
380 |             array(false),
381 |         );
382 |     }
383 | 
384 |     public function testRemoveDeletesFromCache()
385 |     {
386 |         $this->innerStore->expects($this->once())
387 |             ->method('remove')
388 |             ->with('key');
389 | 
390 |         $this->cache->expects($this->once())
391 |             ->method('delete')
392 |             ->with('key');
393 | 
394 |         $this->decorator->remove('key');
395 |     }
396 | 
397 |     /**
398 |      * @expectedException \Webmozart\KeyValueStore\Api\InvalidKeyException
399 |      */
400 |     public function testRemoveDoesNotDeleteFromCacheIfRemovalFails()
401 |     {
402 |         $this->innerStore->expects($this->once())
403 |             ->method('remove')
404 |             ->with('key')
405 |             ->willThrowException(new InvalidKeyException());
406 | 
407 |         $this->cache->expects($this->never())
408 |             ->method('delete');
409 | 
410 |         $this->decorator->remove('key');
411 |     }
412 | 
413 |     public function testClearDeletesAllFromCache()
414 |     {
415 |         $this->cache = $this->getMock('Webmozart\KeyValueStore\Tests\\Fixtures\TestClearableCache');
416 |         $this->decorator = new CachingDecorator($this->innerStore, $this->cache);
417 | 
418 |         $this->innerStore->expects($this->once())
419 |             ->method('clear');
420 | 
421 |         $this->cache->expects($this->once())
422 |             ->method('deleteAll');
423 | 
424 |         $this->decorator->clear();
425 |     }
426 | 
427 |     /**
428 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
429 |      */
430 |     public function testClearDoesNotDeleteAllFromCacheIfClearFails()
431 |     {
432 |         $this->cache = $this->getMock('Webmozart\KeyValueStore\Tests\\Fixtures\TestClearableCache');
433 |         $this->decorator = new CachingDecorator($this->innerStore, $this->cache);
434 | 
435 |         $this->innerStore->expects($this->once())
436 |             ->method('clear')
437 |             ->willThrowException(new WriteException());
438 | 
439 |         $this->cache->expects($this->never())
440 |             ->method('deleteAll');
441 | 
442 |         $this->decorator->clear();
443 |     }
444 | 
445 |     public function testClearFlushesCache()
446 |     {
447 |         $this->cache = $this->getMock('Webmozart\KeyValueStore\Tests\\Fixtures\TestFlushableCache');
448 |         $this->decorator = new CachingDecorator($this->innerStore, $this->cache);
449 | 
450 |         $this->innerStore->expects($this->once())
451 |             ->method('clear');
452 | 
453 |         $this->cache->expects($this->once())
454 |             ->method('flushAll');
455 | 
456 |         $this->decorator->clear();
457 |     }
458 | 
459 |     public function testClearDeletesAllIfFlushableAndClearable()
460 |     {
461 |         $this->cache = $this->getMock('Webmozart\KeyValueStore\Tests\\Fixtures\TestClearableFlushableCache');
462 |         $this->decorator = new CachingDecorator($this->innerStore, $this->cache);
463 | 
464 |         $this->innerStore->expects($this->once())
465 |             ->method('clear');
466 | 
467 |         $this->cache->expects($this->once())
468 |             ->method('deleteAll');
469 | 
470 |         $this->decorator->clear();
471 |     }
472 | 
473 |     public function testKeysForwardsKeysFromStore()
474 |     {
475 |         $this->innerStore->expects($this->once())
476 |             ->method('keys')
477 |             ->willReturn(array('a', 'b', 'c'));
478 | 
479 |         $this->assertSame(array('a', 'b', 'c'), $this->decorator->keys());
480 |     }
481 | }
482 | 
--------------------------------------------------------------------------------
/tests/Decorator/CountableDecoratorTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Decorator;
13 | 
14 | use Webmozart\KeyValueStore\Api\KeyValueStore;
15 | use Webmozart\KeyValueStore\Decorator\CountableDecorator;
16 | 
17 | /**
18 |  * @since  1.0
19 |  *
20 |  * @author Bernhard Schussek 
21 |  * @author Titouan Galopin 
22 |  */
23 | class CountableDecoratorTest extends AbstractDecoratorTest
24 | {
25 |     protected function createDecorator(KeyValueStore $innerStore)
26 |     {
27 |         return new CountableDecorator($innerStore);
28 |     }
29 | 
30 |     public function testCountCache()
31 |     {
32 |         $this->innerStore->expects($this->at(0))
33 |             ->method('keys')
34 |             ->willReturn(array('key1', 'key2'));
35 | 
36 |         $this->innerStore->expects($this->at(1))
37 |             ->method('set')
38 |             ->with('key3', 'value3');
39 | 
40 |         $this->innerStore->expects($this->at(2))
41 |             ->method('keys')
42 |             ->willReturn(array('key1', 'key2', 'key3'));
43 | 
44 |         $this->assertEquals(2, $this->decorator->count());
45 |         $this->assertEquals(2, $this->decorator->count());
46 | 
47 |         $this->decorator->set('key3', 'value3');
48 | 
49 |         $this->assertEquals(3, $this->decorator->count());
50 |         $this->assertEquals(3, $this->decorator->count());
51 |     }
52 | }
53 | 
--------------------------------------------------------------------------------
/tests/Decorator/SortableDecoratorTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests\Decorator;
 13 | 
 14 | use Webmozart\KeyValueStore\Api\KeyValueStore;
 15 | use Webmozart\KeyValueStore\ArrayStore;
 16 | use Webmozart\KeyValueStore\Decorator\SortableDecorator;
 17 | 
 18 | /**
 19 |  * @since  1.0
 20 |  *
 21 |  * @author Bernhard Schussek 
 22 |  * @author Titouan Galopin 
 23 |  */
 24 | class SortableDecoratorTest extends AbstractDecoratorTest
 25 | {
 26 |     protected function createDecorator(KeyValueStore $innerStore)
 27 |     {
 28 |         return new SortableDecorator($innerStore);
 29 |     }
 30 | 
 31 |     public function testSortRegularStringKeys()
 32 |     {
 33 |         $store = new SortableDecorator(new ArrayStore());
 34 |         $store->set('c', 1);
 35 |         $store->set('a', 2);
 36 |         $store->set('b', 3);
 37 | 
 38 |         $store->sort();
 39 | 
 40 |         $this->assertSame(array(
 41 |             'a' => 2,
 42 |             'b' => 3,
 43 |             'c' => 1,
 44 |         ), $store->getMultiple($store->keys()));
 45 |     }
 46 | 
 47 |     public function testSortRegularIntegerKeys()
 48 |     {
 49 |         $store = new SortableDecorator(new ArrayStore());
 50 |         $store->set(3, 'a');
 51 |         $store->set(1, 'b');
 52 |         $store->set(2, 'c');
 53 | 
 54 |         $store->sort();
 55 | 
 56 |         $this->assertSame(array(
 57 |             1 => 'b',
 58 |             2 => 'c',
 59 |             3 => 'a',
 60 |         ), $store->getMultiple($store->keys()));
 61 |     }
 62 | 
 63 |     public function testSortStringStringKeys()
 64 |     {
 65 |         $store = new SortableDecorator(new ArrayStore());
 66 |         $store->set('c', 1);
 67 |         $store->set('a', 2);
 68 |         $store->set('b', 3);
 69 | 
 70 |         $store->sort(SORT_STRING);
 71 | 
 72 |         $this->assertSame(array(
 73 |             'a' => 2,
 74 |             'b' => 3,
 75 |             'c' => 1,
 76 |         ), $store->getMultiple($store->keys()));
 77 |     }
 78 | 
 79 |     public function testSortNumericIntegerKeys()
 80 |     {
 81 |         $store = new SortableDecorator(new ArrayStore());
 82 |         $store->set(3, 'a');
 83 |         $store->set(1, 'b');
 84 |         $store->set(2, 'c');
 85 | 
 86 |         $store->sort(SORT_NUMERIC);
 87 | 
 88 |         $this->assertSame(array(
 89 |             1 => 'b',
 90 |             2 => 'c',
 91 |             3 => 'a',
 92 |         ), $store->getMultiple($store->keys()));
 93 |     }
 94 | 
 95 |     public function testSortNaturalStringKeys()
 96 |     {
 97 |         if (PHP_VERSION_ID < 50400) {
 98 |             $this->markTestSkipped('SORT_NATURAL not available');
 99 |         }
100 | 
101 |         $store = new SortableDecorator(new ArrayStore());
102 | 
103 |         $store->set('10', 'c');
104 |         $store->set('1', 'g');
105 |         $store->set('100', 'a');
106 |         $store->set('9', 'b');
107 |         $store->set('7a', 'h');
108 |         $store->set('7b', 'd');
109 |         $store->set('_5', 'z');
110 | 
111 |         $store->sort(SORT_NATURAL);
112 | 
113 |         $this->assertSame(array(
114 |             '1' => 'g',
115 |             '7a' => 'h',
116 |             '7b' => 'd',
117 |             '9' => 'b',
118 |             '10' => 'c',
119 |             '100' => 'a',
120 |             '_5' => 'z',
121 |         ), $store->getMultiple($store->keys()));
122 |     }
123 | 
124 |     public function testSortCaseInsensitiveStringKeys()
125 |     {
126 |         if (PHP_VERSION_ID < 50400) {
127 |             $this->markTestSkipped('SORT_FLAG_CASE not available');
128 |         }
129 | 
130 |         $store = new SortableDecorator(new ArrayStore());
131 | 
132 |         $store->set('_Ac', 'A');
133 |         $store->set('abc', 'F');
134 |         $store->set('_ab', 'G');
135 |         $store->set('ABB', 'E');
136 |         $store->set('Bce', 'C');
137 |         $store->set('bcd', 'D');
138 |         $store->set('bCf', 'E');
139 | 
140 |         $store->sort(SORT_STRING | SORT_FLAG_CASE);
141 | 
142 |         $this->assertSame(array(
143 |             '_ab' => 'G',
144 |             '_Ac' => 'A',
145 |             'ABB' => 'E',
146 |             'abc' => 'F',
147 |             'bcd' => 'D',
148 |             'Bce' => 'C',
149 |             'bCf' => 'E',
150 |         ), $store->getMultiple($store->keys()));
151 |     }
152 | }
153 | 
--------------------------------------------------------------------------------
/tests/Fixtures/NotSerializable.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Fixtures;
13 | 
14 | use BadMethodCallException;
15 | 
16 | /**
17 |  * @since  1.0
18 |  *
19 |  * @author Bernhard Schussek 
20 |  */
21 | class NotSerializable
22 | {
23 |     public function __sleep()
24 |     {
25 |         throw new BadMethodCallException('You cannot serialize this object.');
26 |     }
27 | }
28 | 
--------------------------------------------------------------------------------
/tests/Fixtures/PrivateProperties.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Fixtures;
13 | 
14 | /**
15 |  * @since  1.0
16 |  *
17 |  * @author Bernhard Schussek 
18 |  */
19 | class PrivateProperties
20 | {
21 |     private $property;
22 | 
23 |     public function __construct($property)
24 |     {
25 |         $this->property = $property;
26 |     }
27 | }
28 | 
--------------------------------------------------------------------------------
/tests/Fixtures/TestClearableCache.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Fixtures;
13 | 
14 | use Doctrine\Common\Cache\Cache;
15 | use Doctrine\Common\Cache\ClearableCache;
16 | 
17 | /**
18 |  * @since  1.0
19 |  *
20 |  * @author Bernhard Schussek 
21 |  */
22 | interface TestClearableCache extends Cache, ClearableCache
23 | {
24 | }
25 | 
--------------------------------------------------------------------------------
/tests/Fixtures/TestClearableFlushableCache.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Fixtures;
13 | 
14 | use Doctrine\Common\Cache\Cache;
15 | use Doctrine\Common\Cache\ClearableCache;
16 | use Doctrine\Common\Cache\FlushableCache;
17 | 
18 | /**
19 |  * @since  1.0
20 |  *
21 |  * @author Bernhard Schussek 
22 |  */
23 | interface TestClearableFlushableCache extends Cache, ClearableCache, FlushableCache
24 | {
25 | }
26 | 
--------------------------------------------------------------------------------
/tests/Fixtures/TestException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Fixtures;
13 | 
14 | use Exception;
15 | 
16 | /**
17 |  * @since  1.0
18 |  *
19 |  * @author Bernhard Schussek 
20 |  */
21 | class TestException extends Exception
22 | {
23 | }
24 | 
--------------------------------------------------------------------------------
/tests/Fixtures/TestFlushableCache.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Fixtures;
13 | 
14 | use Doctrine\Common\Cache\Cache;
15 | use Doctrine\Common\Cache\FlushableCache;
16 | 
17 | /**
18 |  * @since  1.0
19 |  *
20 |  * @author Bernhard Schussek 
21 |  */
22 | interface TestFlushableCache extends Cache, FlushableCache
23 | {
24 | }
25 | 
--------------------------------------------------------------------------------
/tests/Fixtures/file:
--------------------------------------------------------------------------------
1 | asdfasdfasdf
2 | 
--------------------------------------------------------------------------------
/tests/NonSerializingBinaryMongoDbStoreTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests;
13 | 
14 | use Webmozart\KeyValueStore\MongoDbStore;
15 | 
16 | /**
17 |  * @since  1.0
18 |  *
19 |  * @author Bernhard Schussek 
20 |  */
21 | class NonSerializingBinaryMongoDbStoreTest extends AbstractMongoDbStoreTest
22 | {
23 |     protected function createStore()
24 |     {
25 |         $collection = $this->client->selectCollection(
26 |             self::DATABASE_NAME,
27 |             self::COLLECTION_NAME
28 |         );
29 | 
30 |         return new MongoDbStore($collection, MongoDbStore::NO_SERIALIZE | MongoDbStore::SUPPORT_BINARY);
31 |     }
32 | 
33 |     /**
34 |      * @dataProvider provideScalarValues
35 |      */
36 |     public function testSetSupportsScalarValues($value)
37 |     {
38 |         // JSON cannot handle binary data
39 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
40 | 
41 |         parent::testSetSupportsScalarValues($value);
42 |     }
43 | 
44 |     /**
45 |      * @dataProvider provideObjectValues
46 |      */
47 |     public function testSetSupportsObjectValues($value)
48 |     {
49 |         // JSON cannot handle binary data
50 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
51 | 
52 |         parent::testSetSupportsObjectValues($value);
53 |     }
54 | 
55 |     /**
56 |      * @dataProvider provideArrayValues
57 |      */
58 |     public function testSetSupportsArrayValues($value)
59 |     {
60 |         // JSON cannot handle binary data
61 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
62 | 
63 |         parent::testSetSupportsArrayValues($value);
64 |     }
65 | 
66 |     /**
67 |      * @dataProvider provideBinaryArrayValues
68 |      */
69 |     public function testSetSupportsBinaryArrayValues($value)
70 |     {
71 |         // JSON cannot handle binary data
72 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
73 | 
74 |         parent::testSetSupportsBinaryArrayValues($value);
75 |     }
76 | 
77 |     /**
78 |      * @dataProvider provideBinaryObjectValues
79 |      */
80 |     public function testSetSupportsBinaryObjectValues($value)
81 |     {
82 |         // JSON cannot handle binary data
83 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
84 | 
85 |         parent::testSetSupportsBinaryObjectValues($value);
86 |     }
87 | 
88 |     /**
89 |      * @dataProvider provideInvalidValues
90 |      */
91 |     public function testSetThrowsExceptionIfValueNotSerializable($value)
92 |     {
93 |         // JSON cannot handle binary data
94 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
95 | 
96 |         parent::testSetThrowsExceptionIfValueNotSerializable($value);
97 |     }
98 | }
99 | 
--------------------------------------------------------------------------------
/tests/NonSerializingMongoDbStoreTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests;
13 | 
14 | use Webmozart\KeyValueStore\MongoDbStore;
15 | 
16 | /**
17 |  * @since  1.0
18 |  *
19 |  * @author Bernhard Schussek 
20 |  */
21 | class NonSerializingMongoDbStoreTest extends AbstractMongoDbStoreTest
22 | {
23 |     protected function createStore()
24 |     {
25 |         $collection = $this->client->selectCollection(
26 |             self::DATABASE_NAME,
27 |             self::COLLECTION_NAME
28 |         );
29 | 
30 |         return new MongoDbStore($collection, MongoDbStore::NO_SERIALIZE);
31 |     }
32 | 
33 |     /**
34 |      * @dataProvider provideBinaryValues
35 |      */
36 |     public function testSetSupportsBinaryValues($value)
37 |     {
38 |         // JSON cannot handle binary data
39 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
40 | 
41 |         parent::testSetSupportsBinaryValues($value);
42 |     }
43 | 
44 |     /**
45 |      * @dataProvider provideBinaryArrayValues
46 |      */
47 |     public function testSetSupportsBinaryArrayValues($value)
48 |     {
49 |         // JSON cannot handle binary data
50 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
51 | 
52 |         parent::testSetSupportsBinaryArrayValues($value);
53 |     }
54 | 
55 |     /**
56 |      * @dataProvider provideBinaryObjectValues
57 |      */
58 |     public function testSetSupportsBinaryObjectValues($value)
59 |     {
60 |         // JSON cannot handle binary data
61 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
62 | 
63 |         parent::testSetSupportsBinaryObjectValues($value);
64 |     }
65 | 
66 |     /**
67 |      * @dataProvider provideObjectValues
68 |      */
69 |     public function testSetSupportsObjectValues($value)
70 |     {
71 |         // JSON cannot handle binary data
72 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
73 | 
74 |         parent::testSetSupportsObjectValues($value);
75 |     }
76 | 
77 |     /**
78 |      * @dataProvider provideInvalidValues
79 |      */
80 |     public function testSetThrowsExceptionIfValueNotSerializable($value)
81 |     {
82 |         // JSON cannot handle binary data
83 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
84 | 
85 |         parent::testSetThrowsExceptionIfValueNotSerializable($value);
86 |     }
87 | }
88 | 
--------------------------------------------------------------------------------
/tests/NullStoreTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests;
 13 | 
 14 | use PHPUnit_Framework_TestCase;
 15 | use Webmozart\KeyValueStore\NullStore;
 16 | 
 17 | /**
 18 |  * @since  1.0
 19 |  *
 20 |  * @author Bernhard Schussek 
 21 |  */
 22 | class NullStoreTest extends PHPUnit_Framework_TestCase
 23 | {
 24 |     public function testGetAlwaysReturnsDefault()
 25 |     {
 26 |         $store = new NullStore();
 27 | 
 28 |         $store->set('foo', 'bar');
 29 | 
 30 |         $this->assertSame('baz', $store->get('foo', 'baz'));
 31 |     }
 32 | 
 33 |     /**
 34 |      * @expectedException \Webmozart\KeyValueStore\Api\NoSuchKeyException
 35 |      */
 36 |     public function testGetAlwaysThrowsException()
 37 |     {
 38 |         $store = new NullStore();
 39 | 
 40 |         $store->set('foo', 'bar');
 41 | 
 42 |         $store->getOrFail('foo');
 43 |     }
 44 | 
 45 |     public function testGetMultipleAlwaysReturnsDefault()
 46 |     {
 47 |         $store = new NullStore();
 48 | 
 49 |         $store->set('foo', 'bar');
 50 | 
 51 |         $this->assertSame(array(
 52 |             'foo' => 'default',
 53 |             'bar' => 'default',
 54 |         ), $store->getMultiple(array('foo', 'bar'), 'default'));
 55 |     }
 56 | 
 57 |     /**
 58 |      * @expectedException \Webmozart\KeyValueStore\Api\NoSuchKeyException
 59 |      */
 60 |     public function testGetMultipleOrFailAlwaysThrowsException()
 61 |     {
 62 |         $store = new NullStore();
 63 | 
 64 |         $store->set('foo', 'bar');
 65 | 
 66 |         $store->getMultipleOrFail(array('foo'));
 67 |     }
 68 | 
 69 |     public function testExistsAlwaysReturnsFalse()
 70 |     {
 71 |         $store = new NullStore();
 72 | 
 73 |         $store->set('foo', 'bar');
 74 | 
 75 |         $this->assertFalse($store->exists('foo'));
 76 |     }
 77 | 
 78 |     public function testRemoveAlwaysReturnsFalse()
 79 |     {
 80 |         $store = new NullStore();
 81 | 
 82 |         $store->set('foo', 'bar');
 83 | 
 84 |         $this->assertFalse($store->remove('foo'));
 85 |     }
 86 | 
 87 |     public function testKeysAlwaysReturnsEmptyArray()
 88 |     {
 89 |         $store = new NullStore();
 90 | 
 91 |         $store->set('foo', 'bar');
 92 | 
 93 |         $this->assertSame(array(), $store->keys());
 94 |     }
 95 | 
 96 |     public function testClearDoesNothing()
 97 |     {
 98 |         $store = new NullStore();
 99 | 
100 |         $store->set('foo1', 'bar1');
101 |         $store->set('foo2', 'bar2');
102 |         $store->clear();
103 | 
104 |         $this->assertSame(array(), $store->keys());
105 |     }
106 | 
107 |     public function testSortDoesNothing()
108 |     {
109 |         $store = new NullStore();
110 | 
111 |         $store->set('foo1', 'bar1');
112 |         $store->set('foo2', 'bar2');
113 |         $store->sort();
114 | 
115 |         $this->assertSame(array(), $store->keys());
116 |     }
117 | }
118 | 
--------------------------------------------------------------------------------
/tests/PhpRedisStoreTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests;
 13 | 
 14 | use Redis;
 15 | use Webmozart\KeyValueStore\PhpRedisStore;
 16 | use Webmozart\KeyValueStore\Tests\Fixtures\TestException;
 17 | 
 18 | /**
 19 |  * @since  1.0
 20 |  *
 21 |  * @author Bernhard Schussek 
 22 |  * @author Philipp Wahala 
 23 |  */
 24 | class PhpRedisStoreTest extends AbstractKeyValueStoreTest
 25 | {
 26 |     private static $supported;
 27 | 
 28 |     public static function setUpBeforeClass()
 29 |     {
 30 |         parent::setUpBeforeClass();
 31 | 
 32 |         if (!class_exists('\Redis', false)) {
 33 |             self::$supported = false;
 34 | 
 35 |             return;
 36 |         }
 37 | 
 38 |         $redis = new Redis();
 39 | 
 40 |         self::$supported = @$redis->connect('127.0.0.1', 6379);
 41 |     }
 42 | 
 43 |     protected function setUp()
 44 |     {
 45 |         if (!self::$supported) {
 46 |             $this->markTestSkipped('PhpRedis is not available or Redis is not running.');
 47 |         }
 48 | 
 49 |         parent::setUp();
 50 |     }
 51 | 
 52 |     protected function createStore()
 53 |     {
 54 |         return new PhpRedisStore();
 55 |     }
 56 | 
 57 |     /**
 58 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 59 |      * @expectedExceptionMessage I failed!
 60 |      */
 61 |     public function testSetThrowsWriteExceptionIfWriteFails()
 62 |     {
 63 |         $exception = new TestException('I failed!');
 64 | 
 65 |         $redis = $this->getMockBuilder('Redis')
 66 |             ->disableOriginalConstructor()
 67 |             ->getMock();
 68 | 
 69 |         $redis->expects($this->once())
 70 |             ->method('set')
 71 |             ->willThrowException($exception);
 72 | 
 73 |         $store = new PhpRedisStore($redis);
 74 |         $store->set('key', 'value');
 75 |     }
 76 | 
 77 |     /**
 78 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 79 |      * @expectedExceptionMessage I failed!
 80 |      */
 81 |     public function testRemoveThrowsWriteExceptionIfWriteFails()
 82 |     {
 83 |         $exception = new TestException('I failed!');
 84 | 
 85 |         $redis = $this->getMockBuilder('Redis')
 86 |             ->disableOriginalConstructor()
 87 |             ->getMock();
 88 | 
 89 |         $redis->expects($this->once())
 90 |             ->method('del')
 91 |             ->willThrowException($exception);
 92 | 
 93 |         $store = new PhpRedisStore($redis);
 94 |         $store->remove('key');
 95 |     }
 96 | 
 97 |     /**
 98 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 99 |      * @expectedExceptionMessage I failed!
100 |      */
101 |     public function testClearThrowsWriteExceptionIfWriteFails()
102 |     {
103 |         $exception = new TestException('I failed!');
104 | 
105 |         $redis = $this->getMockBuilder('Redis')
106 |             ->disableOriginalConstructor()
107 |             ->getMock();
108 | 
109 |         $redis->expects($this->once())
110 |             ->method('flushdb')
111 |             ->willThrowException($exception);
112 | 
113 |         $store = new PhpRedisStore($redis);
114 |         $store->clear();
115 |     }
116 | 
117 |     /**
118 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
119 |      * @expectedExceptionMessage I failed!
120 |      */
121 |     public function testGetThrowsReadExceptionIfReadFails()
122 |     {
123 |         $exception = new TestException('I failed!');
124 | 
125 |         $redis = $this->getMockBuilder('Redis')
126 |             ->disableOriginalConstructor()
127 |             ->getMock();
128 | 
129 |         $redis->expects($this->once())
130 |             ->method('get')
131 |             ->willThrowException($exception);
132 | 
133 |         $store = new PhpRedisStore($redis);
134 |         $store->get('key');
135 |     }
136 | 
137 |     /**
138 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
139 |      */
140 |     public function testGetThrowsExceptionIfNotUnserializable()
141 |     {
142 |         $redis = $this->getMockBuilder('Redis')
143 |             ->disableOriginalConstructor()
144 |             ->getMock();
145 | 
146 |         $redis->expects($this->once())
147 |             ->method('get')
148 |             ->willReturn('foobar');
149 | 
150 |         $store = new PhpRedisStore($redis);
151 |         $store->get('key');
152 |     }
153 | 
154 |     /**
155 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
156 |      * @expectedExceptionMessage I failed!
157 |      */
158 |     public function testGetOrFailThrowsReadExceptionIfReadFails()
159 |     {
160 |         $exception = new TestException('I failed!');
161 | 
162 |         $redis = $this->getMockBuilder('Redis')
163 |             ->disableOriginalConstructor()
164 |             ->getMock();
165 | 
166 |         $redis->expects($this->once())
167 |             ->method('get')
168 |             ->willThrowException($exception);
169 | 
170 |         $store = new PhpRedisStore($redis);
171 |         $store->getOrFail('key');
172 |     }
173 | 
174 |     /**
175 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
176 |      */
177 |     public function testGetOrFailThrowsExceptionIfNotUnserializable()
178 |     {
179 |         $redis = $this->getMockBuilder('Redis')
180 |             ->disableOriginalConstructor()
181 |             ->getMock();
182 | 
183 |         $redis->expects($this->once())
184 |             ->method('get')
185 |             ->willReturn('foobar');
186 | 
187 |         $store = new PhpRedisStore($redis);
188 |         $store->getOrFail('key');
189 |     }
190 | 
191 |     /**
192 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
193 |      * @expectedExceptionMessage I failed!
194 |      */
195 |     public function testGetMultipleThrowsReadExceptionIfReadFails()
196 |     {
197 |         $exception = new TestException('I failed!');
198 | 
199 |         $redis = $this->getMockBuilder('Redis')
200 |             ->disableOriginalConstructor()
201 |             ->getMock();
202 | 
203 |         $redis->expects($this->once())
204 |             ->method('getMultiple')
205 |             ->willThrowException($exception);
206 | 
207 |         $store = new PhpRedisStore($redis);
208 |         $store->getMultiple(array('key'));
209 |     }
210 | 
211 |     /**
212 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
213 |      */
214 |     public function testGetMultipleThrowsExceptionIfNotUnserializable()
215 |     {
216 |         $redis = $this->getMockBuilder('Redis')
217 |             ->disableOriginalConstructor()
218 |             ->getMock();
219 | 
220 |         $redis->expects($this->once())
221 |             ->method('getMultiple')
222 |             ->willReturn(array('foobar'));
223 | 
224 |         $store = new PhpRedisStore($redis);
225 |         $store->getMultiple(array('key'));
226 |     }
227 | 
228 |     /**
229 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
230 |      * @expectedExceptionMessage I failed!
231 |      */
232 |     public function testGetMultipleOrFailThrowsReadExceptionIfReadFails()
233 |     {
234 |         $exception = new TestException('I failed!');
235 | 
236 |         $redis = $this->getMockBuilder('Redis')
237 |             ->disableOriginalConstructor()
238 |             ->getMock();
239 | 
240 |         $redis->expects($this->once())
241 |             ->method('getMultiple')
242 |             ->willThrowException($exception);
243 | 
244 |         $store = new PhpRedisStore($redis);
245 |         $store->getMultipleOrFail(array('key'));
246 |     }
247 | 
248 |     /**
249 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
250 |      */
251 |     public function testGetMultipleOrFailThrowsExceptionIfNotUnserializable()
252 |     {
253 |         $redis = $this->getMockBuilder('Redis')
254 |             ->disableOriginalConstructor()
255 |             ->getMock();
256 | 
257 |         $redis->expects($this->once())
258 |             ->method('getMultiple')
259 |             ->willReturn(array('foobar'));
260 | 
261 |         $store = new PhpRedisStore($redis);
262 |         $store->getMultipleOrFail(array('key'));
263 |     }
264 | 
265 |     /**
266 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
267 |      * @expectedExceptionMessage I failed!
268 |      */
269 |     public function testExistsThrowsReadExceptionIfReadFails()
270 |     {
271 |         $exception = new TestException('I failed!');
272 | 
273 |         $redis = $this->getMockBuilder('Redis')
274 |             ->disableOriginalConstructor()
275 |             ->getMock();
276 | 
277 |         $redis->expects($this->once())
278 |             ->method('exists')
279 |             ->willThrowException($exception);
280 | 
281 |         $store = new PhpRedisStore($redis);
282 |         $store->exists('key');
283 |     }
284 | 
285 |     /**
286 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
287 |      * @expectedExceptionMessage I failed!
288 |      */
289 |     public function testKeysThrowsReadExceptionIfReadFails()
290 |     {
291 |         $exception = new TestException('I failed!');
292 | 
293 |         $redis = $this->getMockBuilder('Redis')
294 |             ->disableOriginalConstructor()
295 |             ->getMock();
296 | 
297 |         $redis->expects($this->once())
298 |             ->method('keys')
299 |             ->willThrowException($exception);
300 | 
301 |         $store = new PhpRedisStore($redis);
302 |         $store->keys();
303 |     }
304 | }
305 | 
--------------------------------------------------------------------------------
/tests/PredisStoreTest.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  *
  8 |  * For the full copyright and license information, please view the LICENSE
  9 |  * file that was distributed with this source code.
 10 |  */
 11 | 
 12 | namespace Webmozart\KeyValueStore\Tests;
 13 | 
 14 | use Predis\Client;
 15 | use Predis\Connection\ConnectionException;
 16 | use Webmozart\KeyValueStore\PredisStore;
 17 | use Webmozart\KeyValueStore\Tests\Fixtures\TestException;
 18 | 
 19 | /**
 20 |  * @since  1.0
 21 |  *
 22 |  * @author Bernhard Schussek 
 23 |  */
 24 | class PredisStoreTest extends AbstractKeyValueStoreTest
 25 | {
 26 |     private static $supported;
 27 | 
 28 |     public static function setUpBeforeClass()
 29 |     {
 30 |         parent::setUpBeforeClass();
 31 | 
 32 |         $client = new Client();
 33 | 
 34 |         try {
 35 |             $client->connect();
 36 |             $client->disconnect();
 37 |             self::$supported = true;
 38 |         } catch (ConnectionException $e) {
 39 |             self::$supported = false;
 40 |         }
 41 |     }
 42 | 
 43 |     protected function setUp()
 44 |     {
 45 |         if (!self::$supported) {
 46 |             $this->markTestSkipped('Redis is not running.');
 47 |         }
 48 | 
 49 |         parent::setUp();
 50 |     }
 51 | 
 52 |     protected function createStore()
 53 |     {
 54 |         return new PredisStore();
 55 |     }
 56 | 
 57 |     /**
 58 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 59 |      * @expectedExceptionMessage I failed!
 60 |      */
 61 |     public function testSetThrowsWriteExceptionIfWriteFails()
 62 |     {
 63 |         $exception = new TestException('I failed!');
 64 | 
 65 |         $client = $this->getMock('Predis\ClientInterface');
 66 | 
 67 |         $client->expects($this->once())
 68 |             ->method('__call')
 69 |             ->with('set')
 70 |             ->willThrowException($exception);
 71 | 
 72 |         $store = new PredisStore($client);
 73 |         $store->set('key', 'value');
 74 |     }
 75 | 
 76 |     /**
 77 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 78 |      * @expectedExceptionMessage I failed!
 79 |      */
 80 |     public function testRemoveThrowsWriteExceptionIfWriteFails()
 81 |     {
 82 |         $exception = new TestException('I failed!');
 83 | 
 84 |         $client = $this->getMock('Predis\ClientInterface');
 85 | 
 86 |         $client->expects($this->once())
 87 |             ->method('__call')
 88 |             ->with('del')
 89 |             ->willThrowException($exception);
 90 | 
 91 |         $store = new PredisStore($client);
 92 |         $store->remove('key');
 93 |     }
 94 | 
 95 |     /**
 96 |      * @expectedException \Webmozart\KeyValueStore\Api\WriteException
 97 |      * @expectedExceptionMessage I failed!
 98 |      */
 99 |     public function testClearThrowsWriteExceptionIfWriteFails()
100 |     {
101 |         $exception = new TestException('I failed!');
102 | 
103 |         $client = $this->getMock('Predis\ClientInterface');
104 | 
105 |         $client->expects($this->once())
106 |             ->method('__call')
107 |             ->with('flushdb')
108 |             ->willThrowException($exception);
109 | 
110 |         $store = new PredisStore($client);
111 |         $store->clear();
112 |     }
113 | 
114 |     /**
115 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
116 |      * @expectedExceptionMessage I failed!
117 |      */
118 |     public function testGetThrowsReadExceptionIfReadFails()
119 |     {
120 |         $exception = new TestException('I failed!');
121 | 
122 |         $client = $this->getMock('Predis\ClientInterface');
123 | 
124 |         $client->expects($this->once())
125 |             ->method('__call')
126 |             ->with('get')
127 |             ->willThrowException($exception);
128 | 
129 |         $store = new PredisStore($client);
130 |         $store->get('key');
131 |     }
132 | 
133 |     /**
134 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
135 |      */
136 |     public function testGetThrowsExceptionIfNotUnserializable()
137 |     {
138 |         $client = $this->getMock('Predis\ClientInterface');
139 | 
140 |         $client->expects($this->once())
141 |             ->method('__call')
142 |             ->with('get')
143 |             ->willReturn('foobar');
144 | 
145 |         $store = new PredisStore($client);
146 |         $store->get('key');
147 |     }
148 | 
149 |     /**
150 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
151 |      * @expectedExceptionMessage I failed!
152 |      */
153 |     public function testGetOrFailThrowsReadExceptionIfReadFails()
154 |     {
155 |         $exception = new TestException('I failed!');
156 | 
157 |         $client = $this->getMock('Predis\ClientInterface');
158 | 
159 |         $client->expects($this->once())
160 |             ->method('__call')
161 |             ->with('get')
162 |             ->willThrowException($exception);
163 | 
164 |         $store = new PredisStore($client);
165 |         $store->getOrFail('key');
166 |     }
167 | 
168 |     /**
169 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
170 |      */
171 |     public function testGetOrFailThrowsExceptionIfNotUnserializable()
172 |     {
173 |         $client = $this->getMock('Predis\ClientInterface');
174 | 
175 |         $client->expects($this->once())
176 |             ->method('__call')
177 |             ->with('get')
178 |             ->willReturn('foobar');
179 | 
180 |         $store = new PredisStore($client);
181 |         $store->getOrFail('key');
182 |     }
183 | 
184 |     /**
185 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
186 |      * @expectedExceptionMessage I failed!
187 |      */
188 |     public function testGetMultipleThrowsReadExceptionIfReadFails()
189 |     {
190 |         $exception = new TestException('I failed!');
191 | 
192 |         $client = $this->getMock('Predis\ClientInterface');
193 | 
194 |         $client->expects($this->once())
195 |             ->method('__call')
196 |             ->with('mget')
197 |             ->willThrowException($exception);
198 | 
199 |         $store = new PredisStore($client);
200 |         $store->getMultiple(array('key'));
201 |     }
202 | 
203 |     /**
204 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
205 |      */
206 |     public function testGetMultipleThrowsExceptionIfNotUnserializable()
207 |     {
208 |         $client = $this->getMock('Predis\ClientInterface');
209 | 
210 |         $client->expects($this->once())
211 |             ->method('__call')
212 |             ->with('mget')
213 |             ->willReturn(array('foobar'));
214 | 
215 |         $store = new PredisStore($client);
216 |         $store->getMultiple(array('key'));
217 |     }
218 | 
219 |     /**
220 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
221 |      * @expectedExceptionMessage I failed!
222 |      */
223 |     public function testGetMultipleOrFailThrowsReadExceptionIfReadFails()
224 |     {
225 |         $exception = new TestException('I failed!');
226 | 
227 |         $client = $this->getMock('Predis\ClientInterface');
228 | 
229 |         $client->expects($this->once())
230 |             ->method('__call')
231 |             ->with('mget')
232 |             ->willThrowException($exception);
233 | 
234 |         $store = new PredisStore($client);
235 |         $store->getMultipleOrFail(array('key'));
236 |     }
237 | 
238 |     /**
239 |      * @expectedException \Webmozart\KeyValueStore\Api\UnserializationFailedException
240 |      */
241 |     public function testGetMultipleOrFailThrowsExceptionIfNotUnserializable()
242 |     {
243 |         $client = $this->getMock('Predis\ClientInterface');
244 | 
245 |         $client->expects($this->once())
246 |             ->method('__call')
247 |             ->with('mget')
248 |             ->willReturn(array('foobar'));
249 | 
250 |         $store = new PredisStore($client);
251 |         $store->getMultipleOrFail(array('key'));
252 |     }
253 | 
254 |     /**
255 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
256 |      * @expectedExceptionMessage I failed!
257 |      */
258 |     public function testExistsThrowsReadExceptionIfReadFails()
259 |     {
260 |         $exception = new TestException('I failed!');
261 | 
262 |         $client = $this->getMock('Predis\ClientInterface');
263 | 
264 |         $client->expects($this->once())
265 |             ->method('__call')
266 |             ->with('exists')
267 |             ->willThrowException($exception);
268 | 
269 |         $store = new PredisStore($client);
270 |         $store->exists('key');
271 |     }
272 | 
273 |     /**
274 |      * @expectedException \Webmozart\KeyValueStore\Api\ReadException
275 |      * @expectedExceptionMessage I failed!
276 |      */
277 |     public function testKeysThrowsReadExceptionIfReadFails()
278 |     {
279 |         $exception = new TestException('I failed!');
280 | 
281 |         $client = $this->getMock('Predis\ClientInterface');
282 | 
283 |         $client->expects($this->once())
284 |             ->method('__call')
285 |             ->with('keys')
286 |             ->willThrowException($exception);
287 | 
288 |         $store = new PredisStore($client);
289 |         $store->keys();
290 |     }
291 | }
292 | 
--------------------------------------------------------------------------------
/tests/SerializingArrayStoreTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests;
13 | 
14 | use Webmozart\KeyValueStore\SerializingArrayStore;
15 | 
16 | /**
17 |  * @since  1.0
18 |  *
19 |  * @author Bernhard Schussek 
20 |  */
21 | class SerializingArrayStoreTest extends ArrayStoreTest
22 | {
23 |     protected function createStore()
24 |     {
25 |         return new SerializingArrayStore();
26 |     }
27 | 
28 |     protected function createPopulatedStore(array $values)
29 |     {
30 |         return new SerializingArrayStore($values);
31 |     }
32 | }
33 | 
--------------------------------------------------------------------------------
/tests/SerializingBinaryMongoDbStoreTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests;
13 | 
14 | use Webmozart\KeyValueStore\MongoDbStore;
15 | 
16 | /**
17 |  * @since  1.0
18 |  *
19 |  * @author Bernhard Schussek 
20 |  */
21 | class SerializingBinaryMongoDbStoreTest extends AbstractMongoDbStoreTest
22 | {
23 |     protected function createStore()
24 |     {
25 |         $collection = $this->client->selectCollection(
26 |             self::DATABASE_NAME,
27 |             self::COLLECTION_NAME
28 |         );
29 | 
30 |         return new MongoDbStore($collection, MongoDbStore::SUPPORT_BINARY);
31 |     }
32 | }
33 | 
--------------------------------------------------------------------------------
/tests/SerializingMongoDbStoreTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests;
13 | 
14 | use Webmozart\KeyValueStore\MongoDbStore;
15 | 
16 | /**
17 |  * @since  1.0
18 |  *
19 |  * @author Bernhard Schussek 
20 |  */
21 | class SerializingMongoDbStoreTest extends AbstractMongoDbStoreTest
22 | {
23 |     protected function createStore()
24 |     {
25 |         $collection = $this->client->selectCollection(
26 |             self::DATABASE_NAME,
27 |             self::COLLECTION_NAME
28 |         );
29 | 
30 |         return new MongoDbStore($collection);
31 |     }
32 | 
33 |     /**
34 |      * @dataProvider provideBinaryValues
35 |      */
36 |     public function testSetSupportsBinaryValues($value)
37 |     {
38 |         // JSON cannot handle binary data
39 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
40 | 
41 |         parent::testSetSupportsBinaryValues($value);
42 |     }
43 | 
44 |     /**
45 |      * @dataProvider provideBinaryArrayValues
46 |      */
47 |     public function testSetSupportsBinaryArrayValues($value)
48 |     {
49 |         // JSON cannot handle binary data
50 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
51 | 
52 |         parent::testSetSupportsBinaryArrayValues($value);
53 |     }
54 | 
55 |     /**
56 |      * @dataProvider provideBinaryObjectValues
57 |      */
58 |     public function testSetSupportsBinaryObjectValues($value)
59 |     {
60 |         // JSON cannot handle binary data
61 |         $this->setExpectedException('\Webmozart\KeyValueStore\Api\UnsupportedValueException');
62 | 
63 |         parent::testSetSupportsBinaryObjectValues($value);
64 |     }
65 | }
66 | 
--------------------------------------------------------------------------------
/tests/Util/SerializerTest.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  *
 8 |  * For the full copyright and license information, please view the LICENSE
 9 |  * file that was distributed with this source code.
10 |  */
11 | 
12 | namespace Webmozart\KeyValueStore\Tests\Util;
13 | 
14 | use PHPUnit_Framework_TestCase;
15 | use Webmozart\KeyValueStore\Api\SerializationFailedException;
16 | use Webmozart\KeyValueStore\Api\UnserializationFailedException;
17 | use Webmozart\KeyValueStore\Tests\Fixtures\NotSerializable;
18 | use Webmozart\KeyValueStore\Util\Serializer;
19 | 
20 | /**
21 |  * @since  1.0
22 |  *
23 |  * @author Bernhard Schussek 
24 |  */
25 | class SerializerTest extends PHPUnit_Framework_TestCase
26 | {
27 |     public function testSerialize()
28 |     {
29 |         $data = (object) array('foo' => 'bar');
30 | 
31 |         $this->assertEquals($data, Serializer::unserialize(Serializer::serialize($data)));
32 |     }
33 | 
34 |     public function testSerializeFailsIfResource()
35 |     {
36 |         $data = fopen(__FILE__, 'r');
37 | 
38 |         try {
39 |             Serializer::serialize($data);
40 |             $this->fail('Expected a SerializationFailedException');
41 |         } catch (SerializationFailedException $e) {
42 |         }
43 | 
44 |         $this->assertTrue(true, 'Exception caught');
45 |     }
46 | 
47 |     public function testSerializeFailsIfNotSerializable()
48 |     {
49 |         $data = new NotSerializable();
50 | 
51 |         try {
52 |             Serializer::serialize($data);
53 |             $this->fail('Expected a SerializationFailedException');
54 |         } catch (SerializationFailedException $e) {
55 |         }
56 | 
57 |         $this->assertTrue(true, 'Exception caught');
58 |     }
59 | 
60 |     public function testUnserializeFailsIfInvalidString()
61 |     {
62 |         try {
63 |             Serializer::unserialize('foobar');
64 |             $this->fail('Expected an UnserializationFailedException');
65 |         } catch (UnserializationFailedException $e) {
66 |             $this->assertContains('Error at offset 0', $e->getMessage());
67 |         }
68 |     }
69 | 
70 |     public function testUnserializeFailsIfNoString()
71 |     {
72 |         try {
73 |             Serializer::unserialize(1234);
74 |             $this->fail('Expected an UnserializationFailedException');
75 |         } catch (UnserializationFailedException $e) {
76 |             $this->assertContains('Could not unserialize value of type integer.', $e->getMessage());
77 |         }
78 |     }
79 | }
80 | 
--------------------------------------------------------------------------------