mirror of
https://github.com/doctrine/KeyValueStore.git
synced 2026-03-24 08:42:12 +01:00
Compare commits
203 Commits
v0.1
...
missing-ra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2117eef3e3 | ||
|
|
ff58187a3b | ||
|
|
e878a42d81 | ||
|
|
55f0840706 | ||
|
|
ac4c317a7e | ||
|
|
705d5fc1d1 | ||
|
|
465bd365f7 | ||
|
|
9fb5e498ed | ||
|
|
573723ab3c | ||
|
|
8ba3db4ce7 | ||
|
|
bb1ba64453 | ||
|
|
903f6a8c97 | ||
|
|
0a5917a2a9 | ||
|
|
b7daeb0d19 | ||
|
|
06e11dae33 | ||
|
|
4584d99529 | ||
|
|
54e05f9acd | ||
|
|
4d4a17aca9 | ||
|
|
b2a4e320b0 | ||
|
|
b2906e209e | ||
|
|
f29622194e | ||
|
|
2517bb04c5 | ||
|
|
a0d85c1c27 | ||
|
|
0d9c10edf2 | ||
|
|
606ca8b29d | ||
|
|
1ffab2e77d | ||
|
|
e0878ca97a | ||
|
|
7877050062 | ||
|
|
cc3e478d10 | ||
|
|
79bee991a2 | ||
|
|
f61ce21d4b | ||
|
|
58f98f8a94 | ||
|
|
902da8f693 | ||
|
|
84d5db7073 | ||
|
|
ef425578fb | ||
|
|
518f4211b0 | ||
|
|
bad3b56f4b | ||
|
|
2836bc0cfd | ||
|
|
6000d76099 | ||
|
|
b095170bdc | ||
|
|
fe7195fc2d | ||
|
|
e282c1d9f6 | ||
|
|
e2f7ea54f7 | ||
|
|
03a2413e99 | ||
|
|
2c99b71d19 | ||
|
|
fe1e155e69 | ||
|
|
ec14ab554a | ||
|
|
3c7ba8415e | ||
|
|
69832f5423 | ||
|
|
709d464881 | ||
|
|
ba3ff63080 | ||
|
|
50de14012f | ||
|
|
a3827e94b6 | ||
|
|
82486729dd | ||
|
|
f2ef7d7445 | ||
|
|
dc4eca67e4 | ||
|
|
b5c77d93cf | ||
|
|
bb723cc9c7 | ||
|
|
3c3eaad3c9 | ||
|
|
23d6c6dc5d | ||
|
|
793fe5fd16 | ||
|
|
43a1a21670 | ||
|
|
1e9593c80d | ||
|
|
8b9f7317f9 | ||
|
|
f4d0647400 | ||
|
|
56222890f7 | ||
|
|
7b92465aab | ||
|
|
f1446ee0ff | ||
|
|
4e5c6832aa | ||
|
|
aa062f3c74 | ||
|
|
5da1efcd7c | ||
|
|
19d3e788b3 | ||
|
|
b058d0b1d5 | ||
|
|
a7659c3d33 | ||
|
|
643506cf18 | ||
|
|
17b7a2e729 | ||
|
|
eb3806273b | ||
|
|
ba9548ed41 | ||
|
|
1601d59831 | ||
|
|
762c8422f5 | ||
|
|
9a8c3a6a8b | ||
|
|
ac55f6db27 | ||
|
|
ca4ffbfeb6 | ||
|
|
3627014280 | ||
|
|
5de6e13d5b | ||
|
|
2e8ba39b41 | ||
|
|
63545c934c | ||
|
|
a9b34ac958 | ||
|
|
3dd1aa7c38 | ||
|
|
d61b7e0dea | ||
|
|
802cb1520e | ||
|
|
b15bbc62fd | ||
|
|
b94d29514d | ||
|
|
d32fe1fb9d | ||
|
|
add84a7116 | ||
|
|
b919fc70f9 | ||
|
|
6b26ceb284 | ||
|
|
dd3a9e6c9e | ||
|
|
32e017b58d | ||
|
|
67e44a7683 | ||
|
|
32d528d02a | ||
|
|
927fc52193 | ||
|
|
0f6efb76f9 | ||
|
|
00c8e1fa46 | ||
|
|
82b302dc58 | ||
|
|
bb408e2503 | ||
|
|
11747c4112 | ||
|
|
f3ed9bacae | ||
|
|
78e3abb0e5 | ||
|
|
1998fc5022 | ||
|
|
f331d4c994 | ||
|
|
e775ffbe8f | ||
|
|
d5690b4108 | ||
|
|
25d4376582 | ||
|
|
dff781a668 | ||
|
|
741a04e1d9 | ||
|
|
d9f49bef92 | ||
|
|
9de4cd1c85 | ||
|
|
296947bd24 | ||
|
|
0c174bdb7a | ||
|
|
bcf6d01c3f | ||
|
|
9fa9ffb5c6 | ||
|
|
b895ef4bca | ||
|
|
46be2da6eb | ||
|
|
1c02f0d875 | ||
|
|
4bebd86417 | ||
|
|
b8f709dd43 | ||
|
|
479258335d | ||
|
|
d168c890ac | ||
|
|
5ea631e50b | ||
|
|
9b600cc221 | ||
|
|
4309604e0a | ||
|
|
a5d3b1ca49 | ||
|
|
1af55b26bd | ||
|
|
2dd2d84cff | ||
|
|
66d7ba901f | ||
|
|
f164523b41 | ||
|
|
a275c44aa0 | ||
|
|
90cd03dbfd | ||
|
|
12c2abd9e4 | ||
|
|
12bfc80c81 | ||
|
|
a7771b6e58 | ||
|
|
a4ad1d1f43 | ||
|
|
c118048b81 | ||
|
|
11baf2e373 | ||
|
|
fb19abf8c2 | ||
|
|
48d611fb17 | ||
|
|
20d78eade9 | ||
|
|
c447e28a93 | ||
|
|
b3e42ba4f5 | ||
|
|
e53055b5b2 | ||
|
|
5de2e52135 | ||
|
|
780da5e7af | ||
|
|
1dec23f010 | ||
|
|
2d01d5b08c | ||
|
|
aebdfbcd49 | ||
|
|
f175e595db | ||
|
|
2c1b550d31 | ||
|
|
d315cec820 | ||
|
|
f43bed12ac | ||
|
|
5d9013d8ef | ||
|
|
8fe303c6f0 | ||
|
|
fa5e715d86 | ||
|
|
2269b27326 | ||
|
|
e72ef607ef | ||
|
|
a43f35c2ec | ||
|
|
3a39f01c83 | ||
|
|
e4b84b9558 | ||
|
|
992bdd1ac5 | ||
|
|
ee75cfee7b | ||
|
|
4bd4073206 | ||
|
|
0d7c5f02c6 | ||
|
|
a21f94d723 | ||
|
|
948f402c6f | ||
|
|
3ddf79a3d5 | ||
|
|
b0ef144d7e | ||
|
|
91f1752831 | ||
|
|
ad20d188e6 | ||
|
|
3ae0b7ead4 | ||
|
|
f942e51a6e | ||
|
|
c5b8c1931d | ||
|
|
e4e5e14a79 | ||
|
|
20687435bd | ||
|
|
479e2cf739 | ||
|
|
46f58250de | ||
|
|
066b047c13 | ||
|
|
aea2dadbc4 | ||
|
|
801400d4e9 | ||
|
|
c7050ddb96 | ||
|
|
f8c3d9d725 | ||
|
|
f4ba01af29 | ||
|
|
76530e8b5d | ||
|
|
692e0ca38d | ||
|
|
2c1a79a3ea | ||
|
|
995d06fbc5 | ||
|
|
9fb87141b8 | ||
|
|
9bdb28fe3c | ||
|
|
0f974c26d2 | ||
|
|
208936d26a | ||
|
|
c277f42c8f | ||
|
|
b5cc4ee7c3 | ||
|
|
cbbcffaade | ||
|
|
b88ed9e58f |
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
; This file is for unifying the coding style for different editors and IDEs.
|
||||
; More information at http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
vendor
|
||||
*phpunit.xml
|
||||
docs/_build
|
||||
/composer.lock
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "docs/_theme"]
|
||||
path = docs/_theme
|
||||
url = git://github.com/doctrine/doctrine-sphinx-theme.git
|
||||
82
.php_cs
Normal file
82
.php_cs
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
$header = <<<EOF
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
This software consists of voluntary contributions made by many individuals
|
||||
and is licensed under the MIT license. For more information, see
|
||||
<http://www.doctrine-project.org>.
|
||||
EOF;
|
||||
|
||||
Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($header);
|
||||
|
||||
$config = Symfony\CS\Config\Config::create()
|
||||
->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
|
||||
->fixers([
|
||||
'blankline_after_open_tag',
|
||||
'empty_return',
|
||||
'extra_empty_lines',
|
||||
'function_typehint_space',
|
||||
'join_function',
|
||||
'method_argument_default_value',
|
||||
'multiline_array_trailing_comma',
|
||||
'no_blank_lines_after_class_opening',
|
||||
'no_empty_lines_after_phpdocs',
|
||||
'phpdoc_indent',
|
||||
'phpdoc_no_access',
|
||||
'phpdoc_no_empty_return',
|
||||
'phpdoc_no_package',
|
||||
'phpdoc_params',
|
||||
'phpdoc_scalar',
|
||||
'phpdoc_separation',
|
||||
'phpdoc_trim',
|
||||
'phpdoc_type_to_var',
|
||||
'phpdoc_types',
|
||||
'phpdoc_var_without_name',
|
||||
'pre_increment',
|
||||
'remove_leading_slash_use',
|
||||
'remove_lines_between_uses',
|
||||
'short_bool_cast',
|
||||
'single_quote',
|
||||
'spaces_after_semicolon',
|
||||
'spaces_before_semicolon',
|
||||
'spaces_cast',
|
||||
'standardize_not_equal',
|
||||
'ternary_spaces',
|
||||
'trim_array_spaces',
|
||||
'unneeded_control_parentheses',
|
||||
'unused_use',
|
||||
'whitespacy_lines',
|
||||
'align_double_arrow',
|
||||
'align_equals',
|
||||
'concat_with_spaces',
|
||||
'header_comment',
|
||||
'logical_not_operators_with_successor_space',
|
||||
'multiline_spaces_before_semicolon',
|
||||
'newline_after_open_tag',
|
||||
'ordered_use',
|
||||
'php_unit_construct',
|
||||
'phpdoc_order',
|
||||
'short_array_syntax',
|
||||
]);
|
||||
|
||||
if (null === $input->getArgument('path')) {
|
||||
$config
|
||||
->finder(
|
||||
Symfony\CS\Finder\DefaultFinder::create()
|
||||
->in('lib/')
|
||||
->in('tests/')
|
||||
);
|
||||
}
|
||||
|
||||
return $config;
|
||||
30
.travis.yml
Normal file
30
.travis.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
language: php
|
||||
|
||||
services:
|
||||
- cassandra
|
||||
- couchdb
|
||||
- mongodb
|
||||
- redis-server
|
||||
|
||||
matrix:
|
||||
include:
|
||||
-
|
||||
dist: precise
|
||||
php: 5.5
|
||||
|
||||
php:
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
|
||||
before_install:
|
||||
- if [[ ${TRAVIS_PHP_VERSION:0:1} != "7" ]]; then sh ./tests/travis.sh; fi
|
||||
- composer self-update
|
||||
|
||||
install:
|
||||
- composer --prefer-source install
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit --verbose
|
||||
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2015 Doctrine Project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
158
README.md
158
README.md
@@ -1,8 +1,8 @@
|
||||
# Doctrine Key Value Stores
|
||||
|
||||
This is a work in progress design document for this component
|
||||
[](https://travis-ci.org/doctrine/KeyValueStore)
|
||||
|
||||
The Persistence interfaces are rather overkill for many implementations in the NoSQL world that are only key-value stores with some additional features on top. Doctrine Key Value Store for the rescue. This project offers a much simpler lightweight API that is centered on a key-value API to fetch/save objects.
|
||||
The Persistence interfaces are rather overkill for many implementations in the NoSQL world that are only key-value stores with some additional features on top. Doctrine Key Value Store to the rescue. This project offers a much simpler lightweight API that is centered on a key-value API to fetch/save objects.
|
||||
|
||||
* Single- or multi-value primary keys
|
||||
* Unstructured/schema-less values that are mapped onto objects
|
||||
@@ -12,7 +12,7 @@ The Persistence interfaces are rather overkill for many implementations in the N
|
||||
* No support for references to other objects
|
||||
* EventListener for ODM/ORM that allows to manage key-value entities and collections of them as properties (postLoad, postUpdate, postPersist, postRemove)
|
||||
* Stripped down Object Manager Interface
|
||||
* Data-mapper as any other Doctrine library and persistence and data-objects are seperated.
|
||||
* Data-mapper as any other Doctrine library and persistence and data-objects are separated.
|
||||
* Inheritance (Single- or Multiple-Storage)
|
||||
|
||||
## Implementations
|
||||
@@ -22,11 +22,13 @@ Following vendors are targeted:
|
||||
* Microsoft Azure Table (Implemented)
|
||||
* Doctrine\Common\Cache provider (Implemented)
|
||||
* RDBMS (Implemented)
|
||||
* Couchbase
|
||||
* Amazon DynamoDB
|
||||
* CouchDB
|
||||
* MongoDB
|
||||
* Riak
|
||||
* Couchbase (Implemented)
|
||||
* Amazon DynamoDB (Implemented)
|
||||
* CouchDB (Implemented)
|
||||
* Cassandra
|
||||
* MongoDB (Implemented)
|
||||
* Riak (Implemented)
|
||||
* Redis (Implemented)
|
||||
|
||||
We happily accept contributions for any of the drivers.
|
||||
|
||||
@@ -34,39 +36,67 @@ We happily accept contributions for any of the drivers.
|
||||
|
||||
Suppose we track e-mail campaigns based on campaign id and recipients.
|
||||
|
||||
use Doctrine\KeyValueStore\Mapping\Annotations as KeyValue;
|
||||
```php
|
||||
<?php
|
||||
use Doctrine\KeyValueStore\Mapping\Annotations as KeyValue;
|
||||
|
||||
/**
|
||||
* @KeyValue\Entity(storageName="responses")
|
||||
*/
|
||||
class Response
|
||||
/**
|
||||
* @KeyValue\Entity(storageName="responses")
|
||||
*/
|
||||
class Response
|
||||
{
|
||||
const RECEIVE = 0;
|
||||
const OPEN = 10;
|
||||
const CLICK = 20;
|
||||
const ACTION = 30;
|
||||
|
||||
/** @KeyValue\Id */
|
||||
private $campaign;
|
||||
/** @KeyValue\Id */
|
||||
private $recipient;
|
||||
private $status;
|
||||
private $date;
|
||||
|
||||
public function __construct($campaign, $recipient, $status)
|
||||
{
|
||||
const RECIEVE = 0;
|
||||
const OPEN = 10;
|
||||
const CLICK = 20;
|
||||
const ACTION = 30;
|
||||
|
||||
/** @KeyValue\Id */
|
||||
private $campaign;
|
||||
/** @KeyValue\Id */
|
||||
private $recipient;
|
||||
private $status;
|
||||
private $date;
|
||||
|
||||
public function __construct($campaign, $recipient, $status)
|
||||
{
|
||||
$this->campaign = $campaign;
|
||||
$this->recipient = $recipient;
|
||||
$this->status = $status;
|
||||
}
|
||||
$this->campaign = $campaign;
|
||||
$this->recipient = $recipient;
|
||||
$this->status = $status;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
$response = new Response("1234", "kontakt@beberlei.de", Response::RECIEVE);
|
||||
### Create
|
||||
|
||||
$entityManager->persist($response);
|
||||
//.... persists as much as you can :-)
|
||||
```php
|
||||
<?php
|
||||
$response = new Response("1234", "kontakt@beberlei.de", Response::RECEIVE);
|
||||
|
||||
$entityManager->flush();
|
||||
$entityManager->persist($response);
|
||||
//.... persists as much as you can :-)
|
||||
|
||||
$entityManager->flush();
|
||||
```
|
||||
|
||||
### Read
|
||||
|
||||
```php
|
||||
<?php
|
||||
$response = $entityManager->find("Response",array("campaign" => "1234","recipient" => "kontakt@beberlei.de"));
|
||||
```
|
||||
|
||||
### Update
|
||||
|
||||
same as create, just reuse the same id.
|
||||
|
||||
### Delete
|
||||
|
||||
```php
|
||||
<?php
|
||||
$response = $entityManager->find("Response",array("1234","kontakt@beberlei.de"));
|
||||
$entityManager->remove($response);
|
||||
$entityManager->flush();
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -74,37 +104,49 @@ There is no factory yet that simplifies the creation process, here is the
|
||||
full code necessary to instantiate a KeyValue EntityManager with a Doctrine
|
||||
Cache backend:
|
||||
|
||||
use Doctrine\KeyValueStore\EntityManager;
|
||||
use Doctrine\KeyValueStore\Mapping\AnnotationDriver;
|
||||
use Doctrine\KeyValueStore\Storage\DoctrineCacheStorage;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
```php
|
||||
<?php
|
||||
use Doctrine\KeyValueStore\EntityManager;
|
||||
use Doctrine\KeyValueStore\Configuration;
|
||||
use Doctrine\KeyValueStore\Mapping\AnnotationDriver;
|
||||
use Doctrine\KeyValueStore\Storage\DoctrineCacheStorage;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
|
||||
$storage = new DoctrineCacheStorage($cache);
|
||||
$cache = new ArrayCache;
|
||||
$metadata = new AnnotationDriver(new AnnotationReader);
|
||||
$entityManager = new EntityManager($storage, $cache, $metadata);
|
||||
$cache = new ArrayCache;
|
||||
$storage = new DoctrineCacheStorage($cache);
|
||||
|
||||
$reader = new AnnotationReader();
|
||||
$metadata = new AnnotationDriver($reader);
|
||||
$config = new Configuration();
|
||||
$config->setMappingDriverImpl($metadata);
|
||||
$config->setMetadataCache($cache);
|
||||
|
||||
$entityManager = new EntityManager($storage, $config);
|
||||
```
|
||||
|
||||
If you want to use WindowsAzure Table you can use the following configuration
|
||||
to instantiate the storage:
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTableStorage;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\SharedKeyLiteAuthorization;
|
||||
use Doctrine\KeyValueStore\Http\SocketClient;
|
||||
```php
|
||||
use Doctrine\KeyValueStore\Storage\AzureSdkTableStorage;
|
||||
use WindowsAzure\Common\ServicesBuilder;
|
||||
|
||||
$name = ""; // Windows Azure Storage Account Name
|
||||
$key = ""; // Windows Azure Storage Account Key
|
||||
$connectionString = ""; // Windows Azure Connection string
|
||||
$builder = ServicesBuilder::getInstance();
|
||||
$client = $builder->createTableService($connectionString);
|
||||
|
||||
$auth = new SharedKeyLiteAuthorization($name, $key);
|
||||
$storage = new WindowsAzureTableStorage(new SocketClient(), $name, $auth);
|
||||
$storage = new AzureSdkTableStorage($client);
|
||||
```
|
||||
|
||||
If you want to use Doctrine DBAL as backend:
|
||||
|
||||
$params = array();
|
||||
$tableName = "storage";
|
||||
$idColumnName = "id";
|
||||
$dataColumnName = "serialized_data";
|
||||
|
||||
$conn = DriverManager::getConnection($params);
|
||||
$storage = new DBALStorage($conn, $tableName, $idColumnName, $dataColumnName);
|
||||
```php
|
||||
$params = array();
|
||||
$tableName = "storage";
|
||||
$idColumnName = "id";
|
||||
$dataColumnName = "serialized_data";
|
||||
|
||||
$conn = DriverManager::getConnection($params);
|
||||
$storage = new DBALStorage($conn, $tableName, $idColumnName, $dataColumnName);
|
||||
```
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
{
|
||||
"name": "doctrine/key-value-store",
|
||||
"require": {
|
||||
"doctrine/common": "*"
|
||||
"php": "^5.5|^7.0",
|
||||
"doctrine/common": "^2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"datastax/php-driver": "^1.0",
|
||||
"doctrine/couchdb": "^2.0@alpha",
|
||||
"phpunit/phpunit": "^4.8|^5.0",
|
||||
"aws/aws-sdk-php": "^3.8",
|
||||
"riak/riak-client": "dev-master"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "to use the DynamoDB storage",
|
||||
"doctrine/couchdb": "to use the CouchDB storage",
|
||||
"ext-couchbase": "to use the Couchbase storage",
|
||||
"riak/riak-client": "to use the Riak storage"
|
||||
},
|
||||
"description": "Simple Key-Value Store Abstraction Layer that maps to PHP objects, allowing for many backends.",
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\KeyValueStore\\": "lib/"
|
||||
"psr-4": {
|
||||
"Doctrine\\KeyValueStore\\": "lib/Doctrine/KeyValueStore"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Tests\\": "tests/Doctrine/Tests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
composer.lock
generated
9
composer.lock
generated
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"hash": "09b80610c08784c764e1df9edca9b53f",
|
||||
"packages": [
|
||||
{
|
||||
"package": "doctrine\/common",
|
||||
"version": "master-dev"
|
||||
}
|
||||
]
|
||||
}
|
||||
153
docs/Makefile
Normal file
153
docs/Makefile
Normal file
@@ -0,0 +1,153 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DoctrineKeyValueStore.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DoctrineKeyValueStore.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/DoctrineKeyValueStore"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DoctrineKeyValueStore"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
1
docs/_theme
Submodule
1
docs/_theme
Submodule
Submodule docs/_theme added at 5aa024c928
242
docs/conf.py
Normal file
242
docs/conf.py
Normal file
@@ -0,0 +1,242 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Doctrine KeyValueStore documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Jan 27 16:47:49 2013.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Doctrine KeyValueStore'
|
||||
copyright = u'2013, Doctrine Team'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'doctrine'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ['_theme']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'DoctrineKeyValueStoredoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'DoctrineKeyValueStore.tex', u'Doctrine KeyValueStore Documentation',
|
||||
u'Doctrine Team', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'doctrinekeyvaluestore', u'Doctrine KeyValueStore Documentation',
|
||||
[u'Doctrine Team'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'DoctrineKeyValueStore', u'Doctrine KeyValueStore Documentation',
|
||||
u'Doctrine Team', 'DoctrineKeyValueStore', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
19
docs/index.rst
Normal file
19
docs/index.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
Welcome to Doctrine KeyValueStore's documentation!
|
||||
==================================================
|
||||
|
||||
The Doctrine KeyValueStore project allows you to map PHP Objects
|
||||
to a large number of key-value databases. To some degree these
|
||||
databases are exchangeable, when working on a CRUD level.
|
||||
|
||||
For some databases range queries are also supported that allow
|
||||
you to do range queries with parititioning.
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
* :doc:`Configuration <reference/configuration>`
|
||||
* :doc:`Basic Usage <reference/basic-usage>`
|
||||
* **Mapping Drivers**:
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` |
|
||||
:doc:`XML <reference/xml-mapping>` |
|
||||
:doc:`YAML <reference/yaml-mapping>`
|
||||
190
docs/make.bat
Normal file
190
docs/make.bat
Normal file
@@ -0,0 +1,190 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\DoctrineKeyValueStore.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\DoctrineKeyValueStore.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
||||
86
docs/reference/annotations-reference.rst
Normal file
86
docs/reference/annotations-reference.rst
Normal file
@@ -0,0 +1,86 @@
|
||||
Annotations Reference
|
||||
=====================
|
||||
|
||||
Index
|
||||
-----
|
||||
|
||||
- :ref:`@Entity <annref_entity>`
|
||||
- :ref:`@Id <annref_id>`
|
||||
- :ref:`@Transient <annref_transient>`
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. _annref_entity:
|
||||
|
||||
@Entity
|
||||
~~~~~~~
|
||||
|
||||
Required annotation to mark a PHP class as an entity. Doctrine manages
|
||||
the persistence of all classes marked as entities.
|
||||
|
||||
Optional attributes:
|
||||
|
||||
|
||||
- **storageName**: Specifies the storage name used to prevent conflicts.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity(storageName="admin")
|
||||
*/
|
||||
class User
|
||||
{
|
||||
//...
|
||||
}
|
||||
|
||||
.. _annref_id:
|
||||
|
||||
@Id
|
||||
~~~~~~~
|
||||
|
||||
This annotation marks the identifier used to store the entity.
|
||||
More properties can be marked with this annotation, but at least one
|
||||
property has to be @Id.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
*/
|
||||
private $username;
|
||||
}
|
||||
|
||||
.. _annref_transient:
|
||||
|
||||
@Transient
|
||||
~~~~~~~
|
||||
|
||||
This annotation is used to prevent the property to be stored.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @Transient
|
||||
*/
|
||||
private $temporaryData;
|
||||
}
|
||||
127
docs/reference/basic-usage.rst
Normal file
127
docs/reference/basic-usage.rst
Normal file
@@ -0,0 +1,127 @@
|
||||
Basic Usage
|
||||
===========
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
This guide covers getting started with the Doctrine Key Value Store.
|
||||
|
||||
To use the KeyValueStore you actually need:
|
||||
|
||||
- PHP 5.5 or above
|
||||
- Composer Package Manager (`Install Composer
|
||||
<http://getcomposer.org/doc/00-intro.md>`_)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
To install the KeyValueStore in your project just run the Composer command:
|
||||
|
||||
..
|
||||
|
||||
$ composer require doctrine/key-value-store
|
||||
|
||||
or add it to your composer.json file with:
|
||||
|
||||
..
|
||||
|
||||
{
|
||||
"require": {
|
||||
"doctrine/key-value-store": "^1.0"
|
||||
}
|
||||
}
|
||||
|
||||
Usage Examples
|
||||
--------------
|
||||
|
||||
In the guide examples we suppose to track e-mail campaigns
|
||||
based on campaign id and recipients.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\KeyValueStore\Mapping\Annotations as KeyValue;
|
||||
|
||||
/**
|
||||
* @KeyValue\Entity(storageName="responses")
|
||||
*/
|
||||
class Response
|
||||
{
|
||||
const RECEIVE = 0;
|
||||
const OPEN = 10;
|
||||
const CLICK = 20;
|
||||
const ACTION = 30;
|
||||
|
||||
/**
|
||||
* @KeyValue\Id
|
||||
*/
|
||||
private $campaign;
|
||||
|
||||
/**
|
||||
* @KeyValue\Id
|
||||
*/
|
||||
private $recipient;
|
||||
|
||||
private $status;
|
||||
private $date;
|
||||
|
||||
public function __construct($campaign, $recipient, $status)
|
||||
{
|
||||
$this->campaign = $campaign;
|
||||
$this->recipient = $recipient;
|
||||
$this->status = $status;
|
||||
}
|
||||
}
|
||||
|
||||
Create
|
||||
------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$response = new Response(
|
||||
'1234',
|
||||
'kontakt@beberlei.de',
|
||||
Response::RECEIVE
|
||||
);
|
||||
|
||||
$entityManager->persist($response);
|
||||
// persists as much as you can
|
||||
|
||||
$entityManager->flush();
|
||||
|
||||
Read
|
||||
----
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$response = $entityManager->find(
|
||||
'Response',
|
||||
array(
|
||||
'campaign' => '1234',
|
||||
'recipient' => 'kontakt@beberlei.de',
|
||||
)
|
||||
);
|
||||
|
||||
Update
|
||||
------
|
||||
|
||||
Same as create, just reuse the same id.
|
||||
|
||||
Delete
|
||||
------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$response = $entityManager->find(
|
||||
'Response',
|
||||
array(
|
||||
'1234',
|
||||
'kontakt@beberlei.de',
|
||||
)
|
||||
);
|
||||
$entityManager->remove($response);
|
||||
$entityManager->flush();
|
||||
259
docs/reference/configuration.rst
Normal file
259
docs/reference/configuration.rst
Normal file
@@ -0,0 +1,259 @@
|
||||
Configuration
|
||||
=============
|
||||
|
||||
The configuration of the KeyValueStore consists of two steps.
|
||||
|
||||
* Mapping Configuration
|
||||
* Storage Configuration
|
||||
|
||||
Mapping Configuration
|
||||
---------------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\KeyValueStore\Configuration;
|
||||
use Doctrine\KeyValueStore\Mapping\AnnotationDriver;
|
||||
|
||||
// 1. create Configuration instance
|
||||
$config = new Configuration();
|
||||
|
||||
// 2. Caching for Metadata
|
||||
$cache = new ArrayCache();
|
||||
$config->setMetadataCache($cache);
|
||||
|
||||
// 3. Annotation Metadata Driver
|
||||
$reader = new AnnotationReader();
|
||||
$metadata = new AnnotationDriver($reader);
|
||||
$config->setMappingDriverImpl($metadata);
|
||||
|
||||
The mapping configuration is handled through a configuration object.
|
||||
|
||||
1. In the first step, a configuration object is created.
|
||||
2. We need a caching mechanism for the configuration for performance. This
|
||||
should be different in development and production. The ``ArrayCache`` is a
|
||||
request-based cache, which is useful in development. Have a look at the
|
||||
`Doctrine Common documentation
|
||||
<http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/caching.html>`_
|
||||
for production caches.
|
||||
3. Finally you have to create a metadata driver, in this example the
|
||||
``AnnotationDriver`` that allows configurating mapping with Docblock
|
||||
annotations.
|
||||
|
||||
Storage Configuration
|
||||
---------------------
|
||||
|
||||
Independent from the mapping configuration, which is the same for all key-value
|
||||
database backends, you have to configure the actual storage you want to use.
|
||||
|
||||
This configuration is obviously specific to all the different storage drivers.
|
||||
So far the following drivers exist (and are documented here):
|
||||
|
||||
* PHP Array
|
||||
* Doctrine Cache Backend
|
||||
* SQL Backend with Doctrine DBAL
|
||||
* Microsoft Windows Azure Table
|
||||
* Couchbase
|
||||
* CouchDB
|
||||
* MongoDB
|
||||
* Riak
|
||||
|
||||
Also all those storage backends obviously have different dependencies in terms
|
||||
of PHP libraries or PHP PECL extensions.
|
||||
|
||||
PHP Array
|
||||
---------
|
||||
|
||||
PHP array is used mainly for development and teesting purposes.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\ArrayStorage;
|
||||
|
||||
$storage = new ArrayStorage();
|
||||
|
||||
Doctrine Cache Backend
|
||||
----------------------
|
||||
|
||||
The Doctrine Cache Backend uses the `Caching Framework
|
||||
<https://github.com/doctrine/cache>`_ from Doctrine as a backend. Depending on
|
||||
the cache driver you get a persistent or in-memory key value store with this
|
||||
solution. See the `Doctrine Common documentation
|
||||
<http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/caching.html>`_
|
||||
for more details about the different supported drivers.
|
||||
|
||||
Here is an example of configurating the Cache Storage using Redis:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\Common\Cache\RedisCache;
|
||||
use Doctrine\KeyValueStore\Storage\DoctrineCacheStorage;
|
||||
use Redis;
|
||||
|
||||
$conn = new Redis(/** connection **/);
|
||||
$cache = new RedisCache();
|
||||
$cache->setRedis($conn);
|
||||
$storage = new DoctrineCacheStorage($cache);
|
||||
|
||||
Doctrine DBAL Backend
|
||||
---------------------
|
||||
|
||||
You can use a relational database as backend. It uses a very simple
|
||||
table as storage with one primary key and a blob field that stores
|
||||
the properties.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\KeyValueStore\Storage\DBALStorage;
|
||||
|
||||
$tableName = 'storage';
|
||||
$keyColumn = 'id';
|
||||
$dataColumn = 'serialized_data';
|
||||
|
||||
$conn = DriverManager::getConnection(array(
|
||||
// configuration
|
||||
));
|
||||
$storage = new DBALStorage($conn, $tableName, $keyColumn, $dataColumn);
|
||||
|
||||
Microsoft Windows Azure Table
|
||||
-----------------------------
|
||||
|
||||
Microsoft offers a NoSQL solution as part of their `Windows Azure
|
||||
<http://www.windowsazure.com/en-us/>`_ service. You can use that
|
||||
as a storage layer through the Windows Azure PHP SDK:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\AzureSdkTableStorage;
|
||||
use WindowsAzure\Common\ServicesBuilder;
|
||||
|
||||
$connectionString = ''; // Windows Azure Connection string
|
||||
$builder = ServicesBuilder::getInstance();
|
||||
$client = $builder->createTableService($connectionString);
|
||||
|
||||
$storage = new AzureSdkTableStorage($client);
|
||||
|
||||
Cassandra
|
||||
---------
|
||||
|
||||
Cassandra is supported through the `PECL extension <https://pecl.php.net/package/cassandra>`_
|
||||
and the `DataStax PHP driver <https://github.com/datastax/php-driver>`_:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Cassandra;
|
||||
use Cassandra\SimpleStatement;
|
||||
use Doctrine\KeyValueStore\Storage\CassandraStorage;
|
||||
|
||||
$cluster = Cassandra::cluster()->build();
|
||||
$session = $cluster->connect();
|
||||
$session->execute(new SimpleStatement('USE doctrine'));
|
||||
|
||||
$storage = new CassandraStorage($session);
|
||||
|
||||
Couchbase
|
||||
---------
|
||||
|
||||
Until the version 1.2 also Couchbase is supported:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\CouchbaseStorage;
|
||||
|
||||
$conn = new Couchbase(/* connection parameters */);
|
||||
|
||||
$storage = new CouchbaseStorage($conn);
|
||||
|
||||
CouchDB
|
||||
-------
|
||||
|
||||
CouchDB storage setup based on `doctrine/couchdb-client <https://github.com/doctrine/couchdb-client>`_:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\CouchDB\CouchDBClient;
|
||||
use Doctrine\KeyValueStore\Storage\CouchDbStorage;
|
||||
|
||||
$client = CouchDBClient::create(array(
|
||||
'dbname' => 'doctrine_example',
|
||||
));
|
||||
|
||||
$storage = new CouchDbStorage($client);
|
||||
|
||||
DynamoDb
|
||||
---------
|
||||
|
||||
DynamoDb is supported through the `AWS SDK for PHP <https://aws.amazon.com/sdk-for-php/>`_
|
||||
Create your tables via the AWS DynamoDb console or using the `PHP based API <http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelPHPTableOperationsExample.html>`_
|
||||
See the `AWS docs <http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/UsingPHP.html#PHPSDKCredentialsSet>`_ for more information on configuring credentials for the client.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
$sdk = new \Aws\Sdk([...]);
|
||||
$client = $sdk->createDynamoDb();
|
||||
|
||||
$storage = new DynamoDbStorage(
|
||||
$client,
|
||||
// Optional key name, defaults to Id.
|
||||
null,
|
||||
// Optional table name/ key name pairs.
|
||||
// This example uses a table called Awesome keyed by MyKey.
|
||||
['storage_keys' => ['Awesome' => 'MyKey']]
|
||||
);
|
||||
|
||||
MongoDB
|
||||
-------
|
||||
|
||||
Mongo support is provided using a `Mongo <http://php.net/manual/en/class.mongo.php>`_
|
||||
instance, the collection name and the database name.
|
||||
|
||||
Both the options ``collection`` and ``database`` are required.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\MongoDbStorage;
|
||||
|
||||
$conn = new \Mongo(/* connection parameters and options */);
|
||||
|
||||
$storage = new MongoDbStorage($conn, array(
|
||||
'collection' => 'your_collection',
|
||||
'database' => 'your_database',
|
||||
));
|
||||
|
||||
Riak
|
||||
----
|
||||
|
||||
Riak support is provided through the library `riak/riak-client <https://github.com/nacmartin/riak-client>`_ :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\RiakStorage;
|
||||
use Riak\Client;
|
||||
|
||||
$conn = new Riak(/* connection parameters */);
|
||||
|
||||
$storage = new RiakStorage($conn);
|
||||
40
docs/reference/xml-mapping.rst
Normal file
40
docs/reference/xml-mapping.rst
Normal file
@@ -0,0 +1,40 @@
|
||||
XML Mapping
|
||||
===========
|
||||
|
||||
To use the XML driver you must configure the directory where XML mappings are
|
||||
located:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\KeyValueStore\Configuration;
|
||||
use Doctrine\KeyValueStore\EntityManager;
|
||||
use Doctrine\KeyValueStore\Mapping\XmlDriver;
|
||||
|
||||
$cache = new ArrayCache;
|
||||
$metadata = new XmlDriver('/path/to/xml/mappings');
|
||||
$storage = // your preferred storage
|
||||
|
||||
$config = new Configuration();
|
||||
$config->setMappingDriverImpl($metadata);
|
||||
$config->setMetadataCache($cache);
|
||||
|
||||
return new EntityManager($storage, $config);
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
// App.Doctrine.KeyValueStore.User.dcm.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
|
||||
<entity name="App\Doctrine\KeyValueStore\User" storage-name="users">
|
||||
<id>id</id>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
35
docs/reference/yaml-mapping.rst
Normal file
35
docs/reference/yaml-mapping.rst
Normal file
@@ -0,0 +1,35 @@
|
||||
YAML Mapping
|
||||
============
|
||||
|
||||
To use the YAML driver you must configure the directory where YAML mappings are
|
||||
located:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\KeyValueStore\Configuration;
|
||||
use Doctrine\KeyValueStore\EntityManager;
|
||||
use Doctrine\KeyValueStore\Mapping\YamlDriver;
|
||||
|
||||
$cache = new ArrayCache;
|
||||
$metadata = new YamlDriver('/path/to/yaml/mappings');
|
||||
$storage = // your preferred storage
|
||||
|
||||
$config = new Configuration();
|
||||
$config->setMappingDriverImpl($metadata);
|
||||
$config->setMetadataCache($cache);
|
||||
|
||||
return new EntityManager($storage, $config);
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# App.Doctrine.KeyValueStore.User.dcm.xml
|
||||
App\Doctrine\KeyValueStore\User:
|
||||
storageName: users
|
||||
id:
|
||||
- id
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,15 +14,16 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore;
|
||||
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\KeyValueStore\Id\IdConverterStrategy;
|
||||
use Doctrine\KeyValueStore\Id\NullIdConverter;
|
||||
|
||||
/**
|
||||
@@ -43,7 +45,7 @@ class Configuration
|
||||
*/
|
||||
public function getMappingDriverImpl()
|
||||
{
|
||||
if ( ! isset($this->config['mappingDriver'])) {
|
||||
if (! isset($this->config['mappingDriver'])) {
|
||||
throw KeyValueStoreException::mappingDriverMissing();
|
||||
}
|
||||
|
||||
@@ -54,6 +56,7 @@ class Configuration
|
||||
* Set the mapping driver implementation.
|
||||
*
|
||||
* @param \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver $driver
|
||||
*
|
||||
* @return \Doctrine\KeyValueStore\Configuration
|
||||
*/
|
||||
public function setMappingDriverImpl(MappingDriver $driver)
|
||||
@@ -66,6 +69,7 @@ class Configuration
|
||||
* Set the Metadata Mapping cache used with this configuration.
|
||||
*
|
||||
* @param \Doctrine\Common\Cache\Cache $cache
|
||||
*
|
||||
* @return \Doctrine\KeyValueStore\Configuration
|
||||
*/
|
||||
public function setMetadataCache(Cache $cache)
|
||||
@@ -81,7 +85,7 @@ class Configuration
|
||||
*/
|
||||
public function getMetadataCache()
|
||||
{
|
||||
if ( ! isset($this->config['metadataCache'])) {
|
||||
if (! isset($this->config['metadataCache'])) {
|
||||
$this->config['metadataCache'] = new ArrayCache();
|
||||
}
|
||||
|
||||
@@ -92,6 +96,7 @@ class Configuration
|
||||
* Set the ID Converter Strategy
|
||||
*
|
||||
* @param \Doctrine\KeyValueStore\Id\IdConverterStrategy
|
||||
*
|
||||
* @return \Doctrine\KeyValueStore\Configuration
|
||||
*/
|
||||
public function setIdConverterStrategy(IdConverterStrategy $strategy)
|
||||
@@ -107,11 +112,10 @@ class Configuration
|
||||
*/
|
||||
public function getIdConverterStrategy()
|
||||
{
|
||||
if ( ! isset($this->config['idConverter'])) {
|
||||
if (! isset($this->config['idConverter'])) {
|
||||
$this->config['idConverter'] = new NullIdConverter();
|
||||
}
|
||||
|
||||
return $this->config['idConverter'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,17 +14,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\Storage;
|
||||
use Doctrine\KeyValueStore\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\KeyValueStore\Storage\Storage;
|
||||
|
||||
/**
|
||||
* EntityManager for KeyValue stored objects.
|
||||
@@ -33,19 +32,19 @@ use Doctrine\Common\Cache\Cache;
|
||||
class EntityManager
|
||||
{
|
||||
/**
|
||||
* @var Doctrine\KeyValueStore\UnitOfWork
|
||||
* @var UnitOfWork
|
||||
*/
|
||||
private $unitOfWork;
|
||||
|
||||
/**
|
||||
* @var Doctrine\KeyValueStore\Storage\Storage
|
||||
* @var Storage
|
||||
*/
|
||||
private $storageDriver;
|
||||
|
||||
/**
|
||||
* Create a new EntityManager
|
||||
*
|
||||
* @param Storage $storageDriver
|
||||
* @param Storage $storageDriver
|
||||
* @param Configuration $config
|
||||
*/
|
||||
public function __construct(Storage $storageDriver, Configuration $config)
|
||||
@@ -60,13 +59,14 @@ class EntityManager
|
||||
/**
|
||||
* Find objects by key
|
||||
*
|
||||
* @param string $className
|
||||
* @param string $className
|
||||
* @param string|array $key
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function find($className, $key)
|
||||
{
|
||||
return $this->unitOfWork->reconsititute($className, $key);
|
||||
return $this->unitOfWork->reconstititute($className, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,6 +78,7 @@ class EntityManager
|
||||
*
|
||||
* @param string $className
|
||||
* @param string $partitionKey
|
||||
*
|
||||
* @return \Doctrine\KeyValueStore\Query\RangeQuery
|
||||
*/
|
||||
public function createRangeQuery($className, $partitionKey)
|
||||
@@ -89,7 +90,6 @@ class EntityManager
|
||||
* Persist new object in key value storage.
|
||||
*
|
||||
* @param object $object
|
||||
* @return void
|
||||
*/
|
||||
public function persist($object)
|
||||
{
|
||||
@@ -100,7 +100,6 @@ class EntityManager
|
||||
* Remove object
|
||||
*
|
||||
* @param object $object
|
||||
* @return void
|
||||
*/
|
||||
public function remove($object)
|
||||
{
|
||||
@@ -110,8 +109,6 @@ class EntityManager
|
||||
/**
|
||||
* Flush all outstanding changes from the managed object-graph into the
|
||||
* key-value storage.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
@@ -119,7 +116,7 @@ class EntityManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Doctrine\KeyValueStore\Storage\Storage
|
||||
* @return Storage
|
||||
*/
|
||||
public function unwrap()
|
||||
{
|
||||
@@ -141,11 +138,11 @@ class EntityManager
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @return \Doctrine\KeyValueStore\Mapping\ClassMetadata
|
||||
*
|
||||
* @return Mapping\ClassMetadata
|
||||
*/
|
||||
public function getClassMetadata($className)
|
||||
{
|
||||
return $this->unitOfwork->getClassMetadata($className);
|
||||
return $this->unitOfWork->getClassMetadata($className);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -23,18 +24,20 @@ namespace Doctrine\KeyValueStore\Http;
|
||||
* Yet another HTTP client
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*
|
||||
* @deprecated This class is deprecated and will be removed in 2.0.
|
||||
*/
|
||||
interface Client
|
||||
{
|
||||
/**
|
||||
* Send HTTP Request
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param string|null $body
|
||||
* @param array $headers
|
||||
* @param array $headers
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
function request($method, $url, $body = null, array $headers = array());
|
||||
public function request($method, $url, $body = null, array $headers = []);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,15 +14,18 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Http;
|
||||
|
||||
/**
|
||||
* HTTP Response
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*
|
||||
* @deprecated This class is deprecated and will be removed in 2.0.
|
||||
*/
|
||||
class Response
|
||||
{
|
||||
@@ -29,12 +33,12 @@ class Response
|
||||
|
||||
private $body;
|
||||
|
||||
private $headers = array();
|
||||
private $headers = [];
|
||||
|
||||
public function __construct($code, $body, array $headers)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->body = $body;
|
||||
$this->code = $code;
|
||||
$this->body = $body;
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
@@ -62,14 +66,14 @@ class Response
|
||||
* Get HTTP Response header
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return null|string|array
|
||||
*/
|
||||
public function getHeader($name)
|
||||
{
|
||||
if ( ! isset($this->headers[$name])) {
|
||||
return null;
|
||||
if (! isset($this->headers[$name])) {
|
||||
return;
|
||||
}
|
||||
return $this->headers[$name];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -25,9 +26,13 @@ namespace Doctrine\KeyValueStore\Http;
|
||||
* extension dependencies.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
*
|
||||
* @link www.doctrine-project.com
|
||||
* @since 1.0
|
||||
*
|
||||
* @author Kore Nordmann <kore@arbitracker.org>
|
||||
*
|
||||
* @deprecated This class is deprecated and will be removed in 2.0.
|
||||
*/
|
||||
class SocketClient implements Client
|
||||
{
|
||||
@@ -42,11 +47,11 @@ class SocketClient implements Client
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options = array(
|
||||
private $options = [
|
||||
'keep-alive' => true,
|
||||
);
|
||||
];
|
||||
|
||||
public function __construct(array $options = array())
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->options = array_merge($this->options, $options);
|
||||
}
|
||||
@@ -56,21 +61,18 @@ class SocketClient implements Client
|
||||
*
|
||||
* Checks if the connection already has been established, or tries to
|
||||
* establish the connection, if not done yet.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function checkConnection($host, $port)
|
||||
{
|
||||
$host = ($port == 443) ? "ssl://" . $host : "tcp://" . $host;
|
||||
$host = ($port == 443) ? 'ssl://' . $host : 'tcp://' . $host;
|
||||
|
||||
// If the connection could not be established, fsockopen sadly does not
|
||||
// only return false (as documented), but also always issues a warning.
|
||||
if ( ( $this->connection === null ) &&
|
||||
( ( $this->connection = @stream_socket_client($host . ":" . $port, $errno, $errstr ) ) === false ) )
|
||||
{
|
||||
if (($this->connection === null) &&
|
||||
(($this->connection = @stream_socket_client($host . ':' . $port, $errno, $errstr)) === false)) {
|
||||
// This is a bit hackisch...
|
||||
$this->connection = null;
|
||||
throw new \RuntimeException("fail");
|
||||
throw new \RuntimeException('fail');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,13 +84,14 @@ class SocketClient implements Client
|
||||
* @param string $method
|
||||
* @param string $path
|
||||
* @param string $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildRequest($method, $url, $data, $headers )
|
||||
protected function buildRequest($method, $url, $data, $headers)
|
||||
{
|
||||
$parts = parse_url($url);
|
||||
$host = $parts['host'];
|
||||
$path = $parts['path'];
|
||||
$host = $parts['host'];
|
||||
$path = $parts['path'];
|
||||
|
||||
// Create basic request headers
|
||||
$request = "$method $path HTTP/1.1\r\nHost: {$host}\r\n";
|
||||
@@ -96,17 +99,17 @@ class SocketClient implements Client
|
||||
// Set keep-alive header, which helps to keep to connection
|
||||
// initilization costs low, especially when the database server is not
|
||||
// available in the locale net.
|
||||
$request .= "Connection: " . ( $this->options['keep-alive'] ? 'Keep-Alive' : 'Close' ) . "\r\n";
|
||||
$request .= 'Connection: ' . ($this->options['keep-alive'] ? 'Keep-Alive' : 'Close') . "\r\n";
|
||||
|
||||
// Also add headers and request body if data should be sent to the
|
||||
// server. Otherwise just add the closing mark for the header section
|
||||
// of the request.
|
||||
foreach ($headers as $name => $header) {
|
||||
$request .= $name . ": " . $header . "\r\n";
|
||||
$request .= $name . ': ' . $header . "\r\n";
|
||||
}
|
||||
$request = rtrim($request) . "\r\n\r\n";
|
||||
|
||||
if ( $data !== null ) {
|
||||
if ($data !== null) {
|
||||
$request .= $data;
|
||||
}
|
||||
|
||||
@@ -124,40 +127,44 @@ class SocketClient implements Client
|
||||
* @param string $method
|
||||
* @param string $path
|
||||
* @param string $data
|
||||
* @param bool $raw
|
||||
* @param bool $raw
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function request($method, $url, $data = null, array $headers = array())
|
||||
public function request($method, $url, $data = null, array $headers = [])
|
||||
{
|
||||
// Try establishing the connection to the server
|
||||
$parts = parse_url($url);
|
||||
$host = $parts['host'];
|
||||
$host = $parts['host'];
|
||||
$this->checkConnection($host, $parts['scheme']=='https' ? 443 : 80);
|
||||
|
||||
// Send the build request to the server
|
||||
if ( fwrite( $this->connection, $request = $this->buildRequest( $method, $url, $data, $headers ) ) === false ) {
|
||||
if (fwrite($this->connection, $request = $this->buildRequest($method, $url, $data, $headers)) === false) {
|
||||
// Reestablish which seems to have been aborted
|
||||
//
|
||||
// The recursion in this method might be problematic if the
|
||||
// connection establishing mechanism does not correctly throw an
|
||||
// exception on failure.
|
||||
$this->connection = null;
|
||||
return $this->request( $method, $url, $data, $headers );
|
||||
return $this->request($method, $url, $data, $headers);
|
||||
}
|
||||
|
||||
// Read server response headers
|
||||
$rawHeaders = '';
|
||||
$headers = array(
|
||||
'connection' => ( $this->options['keep-alive'] ? 'Keep-Alive' : 'Close' ),
|
||||
);
|
||||
$headers = [
|
||||
'connection' => ($this->options['keep-alive'] ? 'Keep-Alive' : 'Close'),
|
||||
];
|
||||
|
||||
// Remove leading newlines, should not accur at all, actually.
|
||||
while ( ( ( $line = fgets( $this->connection ) ) !== false ) &&
|
||||
( ( $lineContent = rtrim( $line ) ) === '' ) );
|
||||
while (true) {
|
||||
if (! (($line = fgets($this->connection)) !== false) || ! (($lineContent = rtrim($line)) === '')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Throw exception, if connection has been aborted by the server, and
|
||||
// leave handling to the user for now.
|
||||
if ( $line === false ) {
|
||||
if ($line === false) {
|
||||
// Reestablish which seems to have been aborted
|
||||
//
|
||||
// The recursion in this method might be problematic if the
|
||||
@@ -167,7 +174,7 @@ class SocketClient implements Client
|
||||
// An aborted connection seems to happen here on long running
|
||||
// requests, which cause a connection timeout at server side.
|
||||
$this->connection = null;
|
||||
return $this->request( $method, $url, $data, $raw );
|
||||
return $this->request($method, $url, $data, $raw);
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -175,32 +182,29 @@ class SocketClient implements Client
|
||||
$rawHeaders .= $lineContent . "\n";
|
||||
|
||||
// Extract header values
|
||||
if ( preg_match( '(^HTTP/(?P<version>\d+\.\d+)\s+(?P<status>\d+))S', $lineContent, $match ) )
|
||||
{
|
||||
if (preg_match('(^HTTP/(?P<version>\d+\.\d+)\s+(?P<status>\d+))S', $lineContent, $match)) {
|
||||
$headers['version'] = $match['version'];
|
||||
$headers['status'] = (int) $match['status'];
|
||||
} else {
|
||||
list($key, $value) = explode(':', $lineContent, 2);
|
||||
$headers[strtolower($key)] = ltrim($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
list( $key, $value ) = explode( ':', $lineContent, 2 );
|
||||
$headers[strtolower( $key )] = ltrim( $value );
|
||||
}
|
||||
} while ( ( ( $line = fgets( $this->connection ) ) !== false ) &&
|
||||
( ( $lineContent = rtrim( $line ) ) !== '' ) );
|
||||
} while ((($line = fgets($this->connection)) !== false) &&
|
||||
(($lineContent = rtrim($line)) !== ''));
|
||||
|
||||
// Read response body
|
||||
$body = '';
|
||||
if ( !isset( $headers['transfer-encoding'] ) ||
|
||||
( $headers['transfer-encoding'] !== 'chunked' ) ) {
|
||||
if (! isset($headers['transfer-encoding']) ||
|
||||
($headers['transfer-encoding'] !== 'chunked')) {
|
||||
// HTTP 1.1 supports chunked transfer encoding, if the according
|
||||
// header is not set, just read the specified amount of bytes.
|
||||
$bytesToRead = (int) ( isset( $headers['content-length'] ) ? $headers['content-length'] : 0 );
|
||||
$bytesToRead = (int) (isset($headers['content-length']) ? $headers['content-length'] : 0);
|
||||
|
||||
// Read body only as specified by chunk sizes, everything else
|
||||
// are just footnotes, which are not relevant for us.
|
||||
while ( $bytesToRead > 0 ) {
|
||||
$body .= $read = fgets( $this->connection, $bytesToRead + 1 );
|
||||
$bytesToRead -= strlen( $read );
|
||||
while ($bytesToRead > 0) {
|
||||
$body .= $read = fgets($this->connection, $bytesToRead + 1);
|
||||
$bytesToRead -= strlen($read);
|
||||
}
|
||||
} else {
|
||||
// When transfer-encoding=chunked has been specified in the
|
||||
@@ -208,43 +212,41 @@ class SocketClient implements Client
|
||||
// until the server has finished. Ignore all additional HTTP
|
||||
// options after that.
|
||||
do {
|
||||
$line = rtrim( fgets( $this->connection ) );
|
||||
$line = rtrim(fgets($this->connection));
|
||||
|
||||
// Get bytes to read, with option appending comment
|
||||
if ( preg_match( '(^([0-9a-fA-F]+)(?:;.*)?$)', $line, $match ) ) {
|
||||
$bytesToRead = hexdec( $match[1] );
|
||||
if (preg_match('(^([0-9a-fA-F]+)(?:;.*)?$)', $line, $match)) {
|
||||
$bytesToRead = hexdec($match[1]);
|
||||
|
||||
// Read body only as specified by chunk sizes, everything else
|
||||
// are just footnotes, which are not relevant for us.
|
||||
$bytesLeft = $bytesToRead;
|
||||
while ( $bytesLeft > 0 )
|
||||
{
|
||||
$body .= $read = fread( $this->connection, $bytesLeft + 2 );
|
||||
$bytesLeft -= strlen( $read );
|
||||
while ($bytesLeft > 0) {
|
||||
$body .= $read = fread($this->connection, $bytesLeft + 2);
|
||||
$bytesLeft -= strlen($read);
|
||||
}
|
||||
}
|
||||
} while ( $bytesToRead > 0 );
|
||||
} while ($bytesToRead > 0);
|
||||
|
||||
// Chop off \r\n from the end.
|
||||
$body = substr( $body, 0, -2 );
|
||||
$body = substr($body, 0, -2);
|
||||
}
|
||||
|
||||
// Reset the connection if the server asks for it.
|
||||
if ( $headers['connection'] !== 'Keep-Alive' ) {
|
||||
fclose( $this->connection );
|
||||
if ($headers['connection'] !== 'Keep-Alive') {
|
||||
fclose($this->connection);
|
||||
$this->connection = null;
|
||||
}
|
||||
|
||||
// Handle some response state as special cases
|
||||
switch ( $headers['status'] ) {
|
||||
switch ($headers['status']) {
|
||||
case 301:
|
||||
case 302:
|
||||
case 303:
|
||||
case 307:
|
||||
return $this->request( $method, $headers['location'], $data, $raw );
|
||||
return $this->request($method, $headers['location'], $data, $raw);
|
||||
}
|
||||
|
||||
return new Response( $headers['status'], $body, $headers );
|
||||
return new Response($headers['status'], $body, $headers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -25,15 +26,17 @@ class CompositeIdHandler implements IdHandlingStrategy
|
||||
{
|
||||
public function normalizeId(ClassMetadata $metadata, $key)
|
||||
{
|
||||
if (!$metadata->isCompositeKey && !is_array($key)) {
|
||||
$id = array($metadata->identifier[0] => $key);
|
||||
} else if (!is_array($key)) {
|
||||
throw new \InvalidArgumentException("Array of identifier key-value pairs is expected!");
|
||||
if (! $metadata->isCompositeKey && ! is_array($key)) {
|
||||
$id = [$metadata->identifier[0] => $key];
|
||||
} elseif (! is_array($key)) {
|
||||
throw new \InvalidArgumentException('Array of identifier key-value pairs is expected!');
|
||||
} else {
|
||||
$id = array();
|
||||
$id = [];
|
||||
foreach ($metadata->identifier as $field) {
|
||||
if (!isset($key[$field])) {
|
||||
throw new \InvalidArgumentException("Missing identifier field $field in request for the primary key.");
|
||||
if (! isset($key[$field])) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Missing identifier field $field in request for the primary key."
|
||||
);
|
||||
}
|
||||
$id[$field] = $key[$field];
|
||||
}
|
||||
@@ -49,7 +52,6 @@ class CompositeIdHandler implements IdHandlingStrategy
|
||||
|
||||
public function hash($key)
|
||||
{
|
||||
return implode('__##__', (array)$key);
|
||||
return implode('__##__', (array) $key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -30,7 +31,6 @@ namespace Doctrine\KeyValueStore\Id;
|
||||
*/
|
||||
interface IdConverterStrategy
|
||||
{
|
||||
function serialize($class, $data);
|
||||
function unserialize($class, $data);
|
||||
public function serialize($class, $data);
|
||||
public function unserialize($class, $data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -32,26 +33,28 @@ interface IdHandlingStrategy
|
||||
* Given an unstructured key format and a class metadata, generate a key.
|
||||
*
|
||||
* @param ClassMetadata $metadata
|
||||
* @param string|array $key
|
||||
* @param string|array $key
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
function normalizeId(ClassMetadata $metadata, $key);
|
||||
public function normalizeId(ClassMetadata $metadata, $key);
|
||||
|
||||
/**
|
||||
* Extract identifier from an object
|
||||
*
|
||||
* @param ClassMetadata $metadata
|
||||
* @param object $object
|
||||
* @param object $object
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
function getIdentifier(ClassMetadata $metadata, $object);
|
||||
public function getIdentifier(ClassMetadata $metadata, $object);
|
||||
|
||||
/**
|
||||
* Given a normalized key, generate a hash version for it.
|
||||
*
|
||||
* @param array|string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function hash($key);
|
||||
public function hash($key);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -31,4 +32,3 @@ class NullIdConverter implements IdConverterStrategy
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -44,4 +45,3 @@ class SingleIdHandler implements IdHandlingStrategy
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
48
lib/Doctrine/KeyValueStore/InvalidArgumentException.php
Normal file
48
lib/Doctrine/KeyValueStore/InvalidArgumentException.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore;
|
||||
|
||||
class InvalidArgumentException extends KeyValueStoreException
|
||||
{
|
||||
public static function invalidType($name, $expectedType, &$actual)
|
||||
{
|
||||
return new static(
|
||||
sprintf('The %s must be a %s, got "%s" instead.', $name, $expectedType, gettype($actual)),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
public static function invalidLength($name, $min, $max)
|
||||
{
|
||||
return new static(
|
||||
sprintf('The %s must be at least %d but no more than %d chars.', $name, $min, $max),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
public static function invalidTableName($name)
|
||||
{
|
||||
return new static(
|
||||
sprintf('Invalid table name: %s', $name),
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -21,9 +22,8 @@ namespace Doctrine\KeyValueStore;
|
||||
|
||||
class KeyValueStoreException extends \Exception
|
||||
{
|
||||
static public function mappingDriverMissing()
|
||||
public static function mappingDriverMissing()
|
||||
{
|
||||
return new self("No mapping driver was assigned to the configuration. Use \$config->setMappingDriverImpl()");
|
||||
return new self('No mapping driver was assigned to the configuration. Use $config->setMappingDriverImpl()');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,20 +14,31 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Mapping;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
|
||||
class AnnotationDriver implements MappingDriver
|
||||
{
|
||||
/**
|
||||
* Doctrine common annotations reader.
|
||||
*
|
||||
* @var AnnotationReader
|
||||
*/
|
||||
private $reader;
|
||||
|
||||
public function __construct($reader)
|
||||
/**
|
||||
* Constructor with required dependencies.
|
||||
*
|
||||
* @param $reader AnnotationReader Doctrine common annotations reader.
|
||||
*/
|
||||
public function __construct(AnnotationReader $reader)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
}
|
||||
@@ -34,34 +46,40 @@ class AnnotationDriver implements MappingDriver
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @param string $className
|
||||
* @param string $className
|
||||
* @param ClassMetadata $metadata
|
||||
*/
|
||||
function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$class = $metadata->getReflectionClass();
|
||||
if (!$class) {
|
||||
if (! $class) {
|
||||
// this happens when running annotation driver in combination with
|
||||
// static reflection services. This is not the nicest fix
|
||||
$class = new \ReflectionClass($metadata->name);
|
||||
}
|
||||
|
||||
$entityAnnot = $this->reader->getClassAnnotation($class, 'Doctrine\KeyValueStore\Mapping\Annotations\Entity');
|
||||
if (!$entityAnnot) {
|
||||
throw new \InvalidArgumentException($metadata->name . " is not a valid key-value-store entity.");
|
||||
if (! $entityAnnot) {
|
||||
throw new \InvalidArgumentException($metadata->name . ' is not a valid key-value-store entity.');
|
||||
}
|
||||
$metadata->storageName = $entityAnnot->storageName;
|
||||
|
||||
// Evaluate annotations on properties/fields
|
||||
foreach ($class->getProperties() as $property) {
|
||||
$idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\KeyValueStore\Mapping\Annotations\Id');
|
||||
$transientAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\KeyValueStore\Mapping\Annotations\Transient');
|
||||
$idAnnot = $this->reader->getPropertyAnnotation(
|
||||
$property,
|
||||
'Doctrine\KeyValueStore\Mapping\Annotations\Id'
|
||||
);
|
||||
$transientAnnot = $this->reader->getPropertyAnnotation(
|
||||
$property,
|
||||
'Doctrine\KeyValueStore\Mapping\Annotations\Transient'
|
||||
);
|
||||
if ($idAnnot) {
|
||||
$metadata->mapIdentifier($property->getName());
|
||||
} else if ($transientAnnot) {
|
||||
$metdata->skipTransientField($property->getName());
|
||||
} elseif ($transientAnnot) {
|
||||
$metadata->skipTransientField($property->getName());
|
||||
} else {
|
||||
$metadata->mapField(array('fieldName' => $property->getName()));
|
||||
$metadata->mapField(['fieldName' => $property->getName()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +89,7 @@ class AnnotationDriver implements MappingDriver
|
||||
*
|
||||
* @return array The names of all mapped classes known to this driver.
|
||||
*/
|
||||
function getAllClassNames()
|
||||
public function getAllClassNames()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -81,11 +99,11 @@ class AnnotationDriver implements MappingDriver
|
||||
* MappedSuperclass.
|
||||
*
|
||||
* @param string $className
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isTransient($className)
|
||||
public function isTransient($className)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -21,12 +22,12 @@ namespace Doctrine\KeyValueStore\Mapping\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
class Entity
|
||||
final class Entity
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $storageName;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -21,8 +22,8 @@ namespace Doctrine\KeyValueStore\Mapping\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
class Id
|
||||
final class Id
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -21,8 +22,8 @@ namespace Doctrine\KeyValueStore\Mapping\Annotations;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target("PROPERTY")
|
||||
*/
|
||||
class Transient
|
||||
final class Transient
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,27 +14,28 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Mapping;
|
||||
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata as BaseClassMetadata;
|
||||
use ReflectionClass;
|
||||
|
||||
class ClassMetadata implements BaseClassMetadata
|
||||
{
|
||||
public $name;
|
||||
public $storageName;
|
||||
public $rootClassName;
|
||||
public $fields = array();
|
||||
public $identifier = array();
|
||||
public $isCompositeKey = false;
|
||||
public $transientFields = array();
|
||||
public $reflFields = array();
|
||||
public $fields = [];
|
||||
public $identifier = [];
|
||||
public $isCompositeKey = false;
|
||||
public $transientFields = [];
|
||||
public $reflFields = [];
|
||||
public $reflClass;
|
||||
|
||||
private $_prototype;
|
||||
private $prototype;
|
||||
|
||||
public function __construct($className)
|
||||
{
|
||||
@@ -42,20 +44,23 @@ class ClassMetadata implements BaseClassMetadata
|
||||
|
||||
public function mapIdentifier($fieldName)
|
||||
{
|
||||
$this->identifier[] = $fieldName;
|
||||
$this->identifier[] = $fieldName;
|
||||
$this->isCompositeKey = count($this->identifier) > 1;
|
||||
$this->mapField(array('fieldName' => $fieldName, 'id' => true));
|
||||
$this->mapField(['fieldName' => $fieldName, 'id' => true]);
|
||||
}
|
||||
|
||||
public function mapField($mapping)
|
||||
{
|
||||
if ( ! isset($this->transientFields[$mapping['fieldName']])) {
|
||||
if (! isset($this->transientFields[$mapping['fieldName']])) {
|
||||
$this->fields[$mapping['fieldName']] = $mapping;
|
||||
}
|
||||
}
|
||||
|
||||
public function skipTransientField($fieldName)
|
||||
{
|
||||
// it's necessary to unset because ClassMetadataFactory::initializeReflection has already run
|
||||
// and the fields have all been mapped -- even the transient ones
|
||||
unset($this->fields[$fieldName]);
|
||||
$this->transientFields[$fieldName] = true;
|
||||
}
|
||||
|
||||
@@ -66,21 +71,21 @@ class ClassMetadata implements BaseClassMetadata
|
||||
*/
|
||||
public function newInstance()
|
||||
{
|
||||
if ($this->_prototype === null) {
|
||||
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
|
||||
if ($this->prototype === null) {
|
||||
$this->prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
|
||||
}
|
||||
|
||||
return clone $this->_prototype;
|
||||
return clone $this->prototype;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return array('fields', 'isCompositeKey', 'identifier', 'name');
|
||||
return ['fields', 'isCompositeKey', 'identifier', 'name', 'storageName'];
|
||||
}
|
||||
|
||||
public function getIdentifierValues($object)
|
||||
{
|
||||
$id = array();
|
||||
$id = [];
|
||||
foreach ($this->identifier as $field) {
|
||||
$value = $this->reflFields[$field]->getValue($object);
|
||||
if ($value !== null) {
|
||||
@@ -89,12 +94,16 @@ class ClassMetadata implements BaseClassMetadata
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fully-qualified class name of this persistent class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getName(){}
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mapped identifier field name.
|
||||
@@ -103,54 +112,80 @@ class ClassMetadata implements BaseClassMetadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getIdentifier(){}
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionClass instance for this mapped class.
|
||||
*
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
function getReflectionClass(){}
|
||||
public function getReflectionClass()
|
||||
{
|
||||
return new ReflectionClass($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given field name is a mapped identifier for this class.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isIdentifier($fieldName){}
|
||||
public function isIdentifier($fieldName)
|
||||
{
|
||||
return in_array($fieldName, $this->identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given field is a mapped property for this class.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function hasField($fieldName){}
|
||||
public function hasField($fieldName)
|
||||
{
|
||||
return isset($this->fields[$fieldName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given field is a mapped association for this class.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function hasAssociation($fieldName){}
|
||||
public function hasAssociation($fieldName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given field is a mapped single valued association for this class.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isSingleValuedAssociation($fieldName){}
|
||||
public function isSingleValuedAssociation($fieldName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given field is a mapped collection valued association for this class.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isCollectionValuedAssociation($fieldName){}
|
||||
public function isCollectionValuedAssociation($fieldName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A numerically indexed list of field names of this persistent class.
|
||||
@@ -159,14 +194,20 @@ class ClassMetadata implements BaseClassMetadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getFieldNames(){}
|
||||
public function getFieldNames()
|
||||
{
|
||||
return array_column($this->fields, 'fieldName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of identifier field names numerically indexed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getIdentifierFieldNames(){}
|
||||
public function getIdentifierFieldNames()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* A numerically indexed list of association names of this persistent class.
|
||||
@@ -175,7 +216,9 @@ class ClassMetadata implements BaseClassMetadata
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getAssociationNames(){}
|
||||
public function getAssociationNames()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type name of this field.
|
||||
@@ -184,32 +227,44 @@ class ClassMetadata implements BaseClassMetadata
|
||||
* integer, string, boolean, float/double, datetime.
|
||||
*
|
||||
* @param string $fieldName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getTypeOfField($fieldName){}
|
||||
public function getTypeOfField($fieldName)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target class name of the given association.
|
||||
*
|
||||
* @param string $assocName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getAssociationTargetClass($assocName){}
|
||||
public function getAssociationTargetClass($assocName)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the association is the inverse side of a bidirectional association
|
||||
*
|
||||
* @param string $assocName
|
||||
* @return boolean
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isAssociationInverseSide($assocName){}
|
||||
public function isAssociationInverseSide($assocName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target field of the owning side of the association
|
||||
*
|
||||
* @param string $assocName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getAssociationMappedByTargetField($assocName){}
|
||||
public function getAssociationMappedByTargetField($assocName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,17 +14,17 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Mapping;
|
||||
|
||||
use Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\KeyValueStore\Mapping\ClassMetadata as KeyValueMetadata;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Common\Persistence\Mapping\ReflectionService;
|
||||
use Doctrine\KeyValueStore\Mapping\ClassMetadata as KeyValueMetadata;
|
||||
|
||||
/**
|
||||
* Load Metadata of an entity.
|
||||
@@ -45,25 +46,25 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
|
||||
protected function getFqcnFromAlias($namespaceAlias, $simpleClassName)
|
||||
{
|
||||
throw new \InvalidArgumentException("aliasing is not supported.");
|
||||
throw new \InvalidArgumentException('aliasing is not supported.');
|
||||
}
|
||||
|
||||
protected function doLoadMetadata($class, $parent, $rootEntityFound)
|
||||
protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents)
|
||||
{
|
||||
$this->getDriver()->loadMetadataForClass($class->name, $class);
|
||||
|
||||
if ($parent) {
|
||||
$class->rootClassName = $parent->name;
|
||||
$class->storageName = $parent->storageName;
|
||||
$class->storageName = $parent->storageName;
|
||||
}
|
||||
|
||||
if ( ! $class->storageName) {
|
||||
$parts = explode("\\", $class->name);
|
||||
if (! $class->storageName) {
|
||||
$parts = explode('\\', $class->name);
|
||||
$class->storageName = end($parts);
|
||||
}
|
||||
|
||||
if (!$class->identifier) {
|
||||
throw new \InvalidArgumentException("Class " . $class->name . " has no identifier.");
|
||||
if (! $class->identifier) {
|
||||
throw new \InvalidArgumentException('Class ' . $class->name . ' has no identifier.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +91,16 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
$class->reflClass = $reflService->getClass($class->name);
|
||||
if ($class->reflClass) {
|
||||
foreach ($class->reflClass->getProperties() as $property) {
|
||||
$class->mapField(array('fieldName' => $property->getName()));
|
||||
$class->mapField(['fieldName' => $property->getName()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* copied from doctrine/common - tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php
|
||||
*/
|
||||
protected function isEntity(ClassMetadata $class)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
118
lib/Doctrine/KeyValueStore/Mapping/XmlDriver.php
Normal file
118
lib/Doctrine/KeyValueStore/Mapping/XmlDriver.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Mapping;
|
||||
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata as CommonClassMetadata;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
|
||||
use Doctrine\Common\Persistence\Mapping\MappingException;
|
||||
|
||||
class XmlDriver extends FileDriver
|
||||
{
|
||||
const DEFAULT_FILE_EXTENSION = '.dcm.xml';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
|
||||
{
|
||||
parent::__construct($locator, $fileExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a mapping file with the given name and returns a map
|
||||
* from class/entity names to their corresponding file driver elements.
|
||||
*
|
||||
* @param string $file The mapping file to load.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function loadMappingFile($file)
|
||||
{
|
||||
$result = [];
|
||||
$xmlElement = simplexml_load_file($file);
|
||||
|
||||
if (isset($xmlElement->entity)) {
|
||||
foreach ($xmlElement->entity as $entityElement) {
|
||||
$entityName = (string) $entityElement['name'];
|
||||
$result[$entityName] = $entityElement;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @param string $className
|
||||
* @param CommonClassMetadata $metadata
|
||||
*/
|
||||
public function loadMetadataForClass($className, CommonClassMetadata $metadata)
|
||||
{
|
||||
try {
|
||||
$xmlRoot = $this->getElement($className);
|
||||
} catch (MappingException $exception) {
|
||||
throw new \InvalidArgumentException($metadata->name . ' is not a valid key-value-store entity.');
|
||||
}
|
||||
|
||||
if ($xmlRoot->getName() != 'entity') {
|
||||
throw new \InvalidArgumentException($metadata->name . ' is not a valid key-value-store entity.');
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($className);
|
||||
|
||||
if (isset($xmlRoot['storage-name'])) {
|
||||
$metadata->storageName = $xmlRoot['storage-name'];
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
if (isset($xmlRoot->id)) {
|
||||
foreach ($xmlRoot->id as $id) {
|
||||
$ids[] = (string) $id;
|
||||
}
|
||||
}
|
||||
|
||||
$transients = [];
|
||||
if (isset($xmlRoot->transient)) {
|
||||
foreach ($xmlRoot->transient as $transient) {
|
||||
$transients[] = (string) $transient;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($class->getProperties() as $property) {
|
||||
if (in_array($property->getName(), $ids)) {
|
||||
$metadata->mapIdentifier($property->getName());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($property->getName(), $transients)) {
|
||||
$metadata->skipTransientField($property->getName());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$metadata->mapField([
|
||||
'fieldName' => $property->getName(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
102
lib/Doctrine/KeyValueStore/Mapping/YamlDriver.php
Normal file
102
lib/Doctrine/KeyValueStore/Mapping/YamlDriver.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Mapping;
|
||||
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata as CommonClassMetadata;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
|
||||
use Doctrine\Common\Persistence\Mapping\MappingException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class YamlDriver extends FileDriver
|
||||
{
|
||||
const DEFAULT_FILE_EXTENSION = '.dcm.yml';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
|
||||
{
|
||||
parent::__construct($locator, $fileExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a mapping file with the given name and returns a map
|
||||
* from class/entity names to their corresponding file driver elements.
|
||||
*
|
||||
* @param string $file The mapping file to load.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function loadMappingFile($file)
|
||||
{
|
||||
return Yaml::parse(file_get_contents($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @param string $className
|
||||
* @param CommonClassMetadata $metadata
|
||||
*/
|
||||
public function loadMetadataForClass($className, CommonClassMetadata $metadata)
|
||||
{
|
||||
/** @var \Doctrine\KeyValueStore\Mapping\ClassMetadata $metadata */
|
||||
try {
|
||||
$element = $this->getElement($className);
|
||||
} catch (MappingException $exception) {
|
||||
throw new \InvalidArgumentException($metadata->name . ' is not a valid key-value-store entity.');
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($className);
|
||||
|
||||
if (isset($element['storageName'])) {
|
||||
$metadata->storageName = $element['storageName'];
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
if (isset($element['id'])) {
|
||||
$ids = $element['id'];
|
||||
}
|
||||
|
||||
$transients = [];
|
||||
if (isset($element['transient'])) {
|
||||
$transients = $element['transient'];
|
||||
}
|
||||
|
||||
foreach ($class->getProperties() as $property) {
|
||||
if (in_array($property->getName(), $ids)) {
|
||||
$metadata->mapIdentifier($property->getName());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($property->getName(), $transients)) {
|
||||
$metadata->skipTransientField($property->getName());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$metadata->mapField([
|
||||
'fieldName' => $property->getName(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
lib/Doctrine/KeyValueStore/NotFoundException.php
Normal file
29
lib/Doctrine/KeyValueStore/NotFoundException.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore;
|
||||
|
||||
class NotFoundException extends KeyValueStoreException
|
||||
{
|
||||
public static function notFoundByKey($key)
|
||||
{
|
||||
return new static(sprintf('Could not find an item with key: %s', $key), 0);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -29,14 +30,14 @@ use Doctrine\KeyValueStore\EntityManager;
|
||||
*/
|
||||
class RangeQuery
|
||||
{
|
||||
const CONDITION_EQ = 'eq';
|
||||
const CONDITION_LE = 'le';
|
||||
const CONDITION_LT = 'lt';
|
||||
const CONDITION_GT = 'gt';
|
||||
const CONDITION_GE = 'ge';
|
||||
const CONDITION_NEQ = 'neq';
|
||||
const CONDITION_BETWEEN = 'between';
|
||||
const CONDITION_STARTSWITH = 'startswith';
|
||||
const CONDITION_EQ = 'eq';
|
||||
const CONDITION_LE = 'le';
|
||||
const CONDITION_LT = 'lt';
|
||||
const CONDITION_GT = 'gt';
|
||||
const CONDITION_GE = 'ge';
|
||||
const CONDITION_NEQ = 'neq';
|
||||
const CONDITION_BETWEEN = 'between';
|
||||
const CONDITION_STARTSWITH = 'startswith';
|
||||
|
||||
/**
|
||||
* @param string
|
||||
@@ -51,7 +52,7 @@ class RangeQuery
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $rangeConditions = array();
|
||||
protected $conditions = [];
|
||||
|
||||
/**
|
||||
* Limit result to only a set of entities.
|
||||
@@ -65,7 +66,7 @@ class RangeQuery
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hints = array();
|
||||
protected $hints = [];
|
||||
|
||||
/**
|
||||
* @var EntityManager
|
||||
@@ -74,8 +75,8 @@ class RangeQuery
|
||||
|
||||
public function __construct(EntityManager $em, $className, $partitionKey)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->className = $className;
|
||||
$this->em = $em;
|
||||
$this->className = $className;
|
||||
$this->partitionKey = $partitionKey;
|
||||
}
|
||||
|
||||
@@ -114,11 +115,12 @@ class RangeQuery
|
||||
* Add range equals condition to range key.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return RangeQuery
|
||||
*/
|
||||
public function rangeEquals($value)
|
||||
{
|
||||
$this->conditions[] = array(self::CONDITION_EQ, $value);
|
||||
$this->conditions[] = [self::CONDITION_EQ, $value];
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -126,11 +128,12 @@ class RangeQuery
|
||||
* Add range not equals condition to range key.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return RangeQuery
|
||||
*/
|
||||
public function rangeNotEquals($value)
|
||||
{
|
||||
$this->conditions[] = array(self::CONDITION_NEQ, $value);
|
||||
$this->conditions[] = [self::CONDITION_NEQ, $value];
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -138,11 +141,12 @@ class RangeQuery
|
||||
* Add range less than condition to range key.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return RangeQuery
|
||||
*/
|
||||
public function rangeLessThan($value)
|
||||
{
|
||||
$this->conditions[] = array(self::CONDITION_LT, $value);
|
||||
$this->conditions[] = [self::CONDITION_LT, $value];
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -150,11 +154,12 @@ class RangeQuery
|
||||
* Add range less than equals condition to range key.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return RangeQuery
|
||||
*/
|
||||
public function rangeLessThanEquals($value)
|
||||
{
|
||||
$this->conditions[] = array(self::CONDITION_LE, $value);
|
||||
$this->conditions[] = [self::CONDITION_LE, $value];
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -162,11 +167,12 @@ class RangeQuery
|
||||
* Add range greater than condition to range key.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return RangeQuery
|
||||
*/
|
||||
public function rangeGreaterThan($value)
|
||||
{
|
||||
$this->conditions[] = array(self::CONDITION_GT, $value);
|
||||
$this->conditions[] = [self::CONDITION_GT, $value];
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -174,11 +180,12 @@ class RangeQuery
|
||||
* Add range greater than equals condition to range key.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return RangeQuery
|
||||
*/
|
||||
public function rangeGreaterThanEquals($value)
|
||||
{
|
||||
$this->conditions[] = array(self::CONDITION_GE, $value);
|
||||
$this->conditions[] = [self::CONDITION_GE, $value];
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -195,22 +202,29 @@ class RangeQuery
|
||||
/**
|
||||
* Execute query and return a result iterator.
|
||||
*
|
||||
* @return ResultIterator
|
||||
* @return array
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$storage = $this->em->unwrap();
|
||||
|
||||
if ( ! ($storage instanceof RangeQueryStorage)) {
|
||||
throw new \RuntimeException("The storage backend " . $this->storage->getName() . " does not support range queries.");
|
||||
if (! $storage instanceof RangeQueryStorage) {
|
||||
throw new \RuntimeException(
|
||||
'The storage backend ' . $storage->getName() . ' does not support range queries.'
|
||||
);
|
||||
}
|
||||
|
||||
$uow = $em->getUnitOfWork();
|
||||
$uow = $this->em->getUnitOfWork();
|
||||
$class = $this->em->getClassMetadata($this->className);
|
||||
|
||||
return $storage>executeRangeQuery($this, $class->storageName, $class->identifiers, function ($row) use($uow, $class) {
|
||||
return $uow->createEntity($class, $data);
|
||||
});
|
||||
$rowHydration = function ($row) use ($uow, $class) {
|
||||
$key = [];
|
||||
foreach ($class->identifier as $id) {
|
||||
$key[$id] = $row[$id];
|
||||
}
|
||||
|
||||
return $uow->createEntity($class, $key, $row);
|
||||
};
|
||||
return $storage->executeRangeQuery($this, $class->storageName, $class->identifier, $rowHydration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -28,14 +29,14 @@ namespace Doctrine\KeyValueStore\Query;
|
||||
interface RangeQueryStorage
|
||||
{
|
||||
/**
|
||||
* Execute the range query and return a ResultIterator
|
||||
* Execute the range query and return an array
|
||||
*
|
||||
* @param RangeQuery $query
|
||||
* @param string $storageName
|
||||
* @param array $key
|
||||
* @param Closure $hydrateRow
|
||||
* @return ResultIterator
|
||||
* @param string $storageName
|
||||
* @param array $key
|
||||
* @param Closure $hydrateRow
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function executeRangeQuery(RangeQuery $query, $storageName, $key, \Closure $hydrateRow = null);
|
||||
public function executeRangeQuery(RangeQuery $query, $storageName, $key, \Closure $hydrateRow = null);
|
||||
}
|
||||
|
||||
|
||||
136
lib/Doctrine/KeyValueStore/Storage/ArrayStorage.php
Normal file
136
lib/Doctrine/KeyValueStore/Storage/ArrayStorage.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
|
||||
/**
|
||||
* Array storage, mainly used for development purposes.
|
||||
*
|
||||
* @author Emanuele Minotto <minottoemanuele@gmail.com>
|
||||
*/
|
||||
class ArrayStorage implements Storage
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $data = [];
|
||||
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this storage support composite primary keys?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this storage require composite primary keys?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert data into the storage key specified.
|
||||
*
|
||||
* @param array|string $key
|
||||
* @param array $data
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$this->update($storageName, $key, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update data into the given key.
|
||||
*
|
||||
* @param array|string $key
|
||||
* @param array $data
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
if (!isset($this->data[$storageName])) {
|
||||
$this->data[$storageName] = [];
|
||||
}
|
||||
|
||||
$this->data[$storageName][serialize($key)] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete data at key
|
||||
*
|
||||
* @param array|string $key
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
if (!isset($this->data[$storageName])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($this->data[$storageName][serialize($key)])) {
|
||||
return;
|
||||
}
|
||||
|
||||
unset($this->data[$storageName][serialize($key)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find data at key
|
||||
*
|
||||
* @param array|string $key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
if (!isset($this->data[$storageName])) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if (!isset($this->data[$storageName][serialize($key)])) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
unset($this->data[$storageName][serialize($key)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name of the underlying storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'array';
|
||||
}
|
||||
}
|
||||
254
lib/Doctrine/KeyValueStore/Storage/AzureSdkTableStorage.php
Normal file
254
lib/Doctrine/KeyValueStore/Storage/AzureSdkTableStorage.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\KeyValueStore\Query\RangeQueryStorage;
|
||||
use WindowsAzure\Common\ServiceException;
|
||||
use WindowsAzure\Table\Models\EdmType;
|
||||
use WindowsAzure\Table\Models\Entity;
|
||||
use WindowsAzure\Table\TableRestProxy;
|
||||
|
||||
/**
|
||||
* Storage implementation for Microsoft Windows Azure Table using the PHP SDK.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class AzureSdkTableStorage implements Storage, RangeQueryStorage
|
||||
{
|
||||
/**
|
||||
* @var \WindowsAzure\Table\TableRestProxy
|
||||
*/
|
||||
private $client;
|
||||
|
||||
public function __construct(TableRestProxy $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$entity = $this->createEntity($key, $data);
|
||||
|
||||
try {
|
||||
$this->client->insertEntity($storageName, $entity);
|
||||
} catch (ServiceException $e) {
|
||||
if ($e->getCode() == 404) {
|
||||
$this->client->createTable($storageName);
|
||||
} else {
|
||||
throw new StorageException(
|
||||
'Could not save entity in table, WindowsAzure SDK client reported error: ' . $e->getMessage(),
|
||||
$e->getCode(),
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$entity = $this->createEntity($key, $data);
|
||||
|
||||
try {
|
||||
$this->client->updateEntity($storageName, $entity);
|
||||
} catch (ServiceException $e) {
|
||||
throw new StorageException(
|
||||
'Could not update entity in table, WindowsAzure SDK client reported error: ' . $e->getMessage(),
|
||||
$e->getCode(),
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
list($partitonKey, $rowKey) = array_values($key);
|
||||
|
||||
try {
|
||||
$this->client->deleteEntity($storageName, $partitonKey, $rowKey);
|
||||
} catch (ServiceException $e) {
|
||||
throw new StorageException(
|
||||
'Could not delete entity in table, WindowsAzure SDK client reported error: ' . $e->getMessage(),
|
||||
$e->getCode(),
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
list($partitonKey, $rowKey) = array_values($key);
|
||||
|
||||
try {
|
||||
$result = $this->client->getEntity($storageName, $partitonKey, $rowKey);
|
||||
} catch (ServiceException $e) {
|
||||
if ($e->getCode() === 404) {
|
||||
throw new NotFoundException();
|
||||
} else {
|
||||
throw new StorageException(
|
||||
'Could not find entity in table, WindowsAzure SDK client reported error: ' . $e->getMessage(),
|
||||
$e->getCode(),
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->getProperties($result->getEntity());
|
||||
}
|
||||
|
||||
private function getProperties(Entity $entity)
|
||||
{
|
||||
$properties = [];
|
||||
|
||||
foreach ($entity->getProperties() as $name => $property) {
|
||||
if ($name === 'PartitionKey') {
|
||||
$name = 'dist';
|
||||
} elseif ($name === 'RowKey') {
|
||||
$name = 'range';
|
||||
}
|
||||
|
||||
$properties[$name] = $property->getValue();
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'azure_table_sdk';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function executeRangeQuery(RangeQuery $query, $storageName, $key, \Closure $hydrateRow = null)
|
||||
{
|
||||
$filters = ['PartitionKey eq ' . $this->quoteFilterValue($query->getPartitionKey())];
|
||||
|
||||
foreach ($query->getConditions() as $condition) {
|
||||
if (! in_array($condition[0], ['eq', 'neq', 'le', 'lt', 'ge', 'gt'])) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Windows Azure Table only supports eq, neq, le, lt, ge, gt as conditions.'
|
||||
);
|
||||
}
|
||||
$filters[] = 'RowKey ' . $condition[0] . ' ' . $this->quoteFilterValue($condition[1]);
|
||||
}
|
||||
|
||||
$filter = '(' . implode(' and ', $filters) . ')';
|
||||
$result = $this->client->queryEntities($storageName, $filter);
|
||||
|
||||
$rows = [];
|
||||
|
||||
foreach ($result->getEntities() as $entity) {
|
||||
$row = $this->getProperties($entity);
|
||||
$rows[] = $hydrateRow ? $hydrateRow($row) : $row;
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
private function quoteFilterValue($value)
|
||||
{
|
||||
return "'" . str_replace("'", '', $value) . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create entity object with key and data values.
|
||||
*
|
||||
* @param array $key
|
||||
* @param array $data
|
||||
*
|
||||
* @return \WindowsAzure\Table\Model\Entity
|
||||
*/
|
||||
private function createEntity(array $key, array $data)
|
||||
{
|
||||
list($partitonKey, $rowKey) = array_values($key);
|
||||
|
||||
$entity = new Entity();
|
||||
$entity->setPartitionKey((string) $partitonKey);
|
||||
$entity->setRowKey((string) $rowKey);
|
||||
|
||||
foreach ($data as $variable => $value) {
|
||||
$type = $this->getPropertyType($value);
|
||||
$entity->addProperty($variable, $type, $value);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer the property type of variables.
|
||||
*/
|
||||
private function getPropertyType($propertyValue)
|
||||
{
|
||||
if ($propertyValue instanceof \DateTime) {
|
||||
return EdmType::DATETIME;
|
||||
} elseif (is_float($propertyValue)) {
|
||||
return EdmType::DOUBLE;
|
||||
} elseif (is_int($propertyValue)) {
|
||||
return EdmType::INT32;
|
||||
} elseif (is_bool($propertyValue)) {
|
||||
return EdmType::BOOLEAN;
|
||||
}
|
||||
|
||||
return EdmType::STRING;
|
||||
}
|
||||
}
|
||||
195
lib/Doctrine/KeyValueStore/Storage/CassandraStorage.php
Normal file
195
lib/Doctrine/KeyValueStore/Storage/CassandraStorage.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Cassandra\ExecutionOptions;
|
||||
use Cassandra\Session;
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\KeyValueStore\Query\RangeQueryStorage;
|
||||
|
||||
/**
|
||||
* Cassandra Storage Engine for KeyValueStore.
|
||||
*
|
||||
* Uses the PHP Driver from Datastax.
|
||||
*
|
||||
* @uses https://github.com/datastax/php-driver
|
||||
*/
|
||||
class CassandraStorage implements Storage, RangeQueryStorage
|
||||
{
|
||||
/**
|
||||
* @var \Cassandra\Session
|
||||
*/
|
||||
private $session;
|
||||
|
||||
public function __construct(Session $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$keys = $values = [];
|
||||
|
||||
foreach ($key as $name => $value) {
|
||||
$keys[] = $name;
|
||||
$values[] = $value;
|
||||
}
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
$keys[] = $name;
|
||||
$values[] = $value;
|
||||
}
|
||||
|
||||
$stmt = $this->session->prepare('INSERT INTO ' . $storageName . ' (' . implode(', ', $keys) . ') VALUES (' . implode(', ', array_fill(0, count($values), '?')) . ')');
|
||||
|
||||
$options = new ExecutionOptions([
|
||||
'arguments' => $values,
|
||||
]);
|
||||
|
||||
$this->session->execute($stmt, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$where = [];
|
||||
$set = [];
|
||||
|
||||
foreach ($key as $name => $value) {
|
||||
$where[] = $name . ' = ?';
|
||||
}
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
$set[] = $name . ' = ?';
|
||||
}
|
||||
|
||||
$stmt = $this->session->prepare('UPDATE ' . $storageName . ' SET ' . implode(', ', $set) . ' WHERE ' . implode(' AND ', $where));
|
||||
|
||||
$values = array_merge(array_values($data), array_values($key));
|
||||
|
||||
$options = new ExecutionOptions([
|
||||
'arguments' => $values,
|
||||
]);
|
||||
|
||||
$this->session->execute($stmt, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$where = [];
|
||||
|
||||
foreach ($key as $name => $value) {
|
||||
$where[] = $name . ' = ?';
|
||||
}
|
||||
|
||||
$stmt = $this->session->prepare('DELETE FROM ' . $storageName . ' WHERE ' . implode(' AND ', $where));
|
||||
|
||||
$options = new ExecutionOptions([
|
||||
'arguments' => array_values($key),
|
||||
]);
|
||||
|
||||
$this->session->execute($stmt, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$where = [];
|
||||
|
||||
foreach ($key as $name => $value) {
|
||||
$where[] = $name . ' = ?';
|
||||
}
|
||||
|
||||
$stmt = $this->session->prepare('SELECT * FROM ' . $storageName . ' WHERE ' . implode(' AND ', $where));
|
||||
|
||||
$options = new ExecutionOptions([
|
||||
'arguments' => array_values($key),
|
||||
]);
|
||||
|
||||
$result = $this->session->execute($stmt, $options);
|
||||
$rows = iterator_to_array($result);
|
||||
|
||||
if (! isset($rows[0])) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
$data = [];
|
||||
foreach ($rows[0] as $column => $value) {
|
||||
if (isset($key[$column])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[$column] = $value;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function executeRangeQuery(RangeQuery $query, $storageName, $key, \Closure $hydrateRow = null)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'cassandra';
|
||||
}
|
||||
}
|
||||
211
lib/Doctrine/KeyValueStore/Storage/CouchDbStorage.php
Normal file
211
lib/Doctrine/KeyValueStore/Storage/CouchDbStorage.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\CouchDB\CouchDBClient;
|
||||
use Doctrine\CouchDB\Mango\MangoQuery;
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\KeyValueStore\Query\RangeQueryStorage;
|
||||
|
||||
/**
|
||||
* Key-Value-Storage using a Doctrine CouchDB Client library as backend.
|
||||
*
|
||||
* CouchDB requires scalar identifiers, so the `flattenKey` method is used
|
||||
* to flatten passed keys.
|
||||
*
|
||||
* @author Emanuele Minotto <minottoemanuele@gmail.com>
|
||||
*/
|
||||
final class CouchDbStorage implements Storage, RangeQueryStorage
|
||||
{
|
||||
/**
|
||||
* @var CouchDBClient
|
||||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* @param CouchDBClient $client
|
||||
*/
|
||||
public function __construct(CouchDBClient $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$key = $this->flattenKey($storageName, $key);
|
||||
$this->client->putDocument($data, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$key = $this->flattenKey($storageName, $key);
|
||||
$this->client->putDocument($data, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$key = $this->flattenKey($storageName, $key);
|
||||
$this->client->deleteDocument($key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$key = $this->flattenKey($storageName, $key);
|
||||
return $this->client->findDocument($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'couchdb';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $storageName
|
||||
* @param array|string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function flattenKey($storageName, $key)
|
||||
{
|
||||
$finalKey = $storageName . '-';
|
||||
|
||||
if (is_string($key)) {
|
||||
return $finalKey . $key;
|
||||
}
|
||||
|
||||
if (! is_array($key)) {
|
||||
throw new \InvalidArgumentException('The key should be a string or a flat array.');
|
||||
}
|
||||
|
||||
foreach ($key as $property => $value) {
|
||||
$finalKey .= sprintf('%s:%s-', $property, $value);
|
||||
}
|
||||
|
||||
return $finalKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function executeRangeQuery(RangeQuery $query, $storageName, $key, \Closure $hydrateRow = null)
|
||||
{
|
||||
$mangoQuery = new MangoQuery();
|
||||
$partitionKey = $query->getPartitionKey();
|
||||
|
||||
$conditions = [];
|
||||
foreach ($query->getConditions() as $condition) {
|
||||
switch ($condition[0]) {
|
||||
case RangeQuery::CONDITION_LE:
|
||||
$conditions[] = [
|
||||
$partitionKey => [
|
||||
'$lte' => $condition[1],
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
case RangeQuery::CONDITION_GE:
|
||||
$conditions[] = [
|
||||
$partitionKey => [
|
||||
'$gte' => $condition[1],
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
case RangeQuery::CONDITION_NEQ:
|
||||
$conditions[] = [
|
||||
$partitionKey => [
|
||||
'$ne' => $condition[1],
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
case RangeQuery::CONDITION_STARTSWITH:
|
||||
$conditions[] = [
|
||||
$partitionKey => [
|
||||
'$regex' => '^'.$condition[1],
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
default:
|
||||
$conditions[] = [
|
||||
$partitionKey => [
|
||||
'$'.$condition[0] => $condition[1],
|
||||
],
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$mangoQuery
|
||||
->select(['_id', $key])
|
||||
->where(['$and' => $conditions])
|
||||
->limit($query->getLimit());
|
||||
|
||||
$results = [];
|
||||
$mangoResults = $this->client->find($query);
|
||||
|
||||
foreach ($mangoResults as $mangoResult) {
|
||||
$results[] = $hydrateRow($mangoResult);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
116
lib/Doctrine/KeyValueStore/Storage/CouchbaseStorage.php
Normal file
116
lib/Doctrine/KeyValueStore/Storage/CouchbaseStorage.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
|
||||
/**
|
||||
* @author Simon Schick <simonsimcity@gmail.com>
|
||||
*/
|
||||
class CouchbaseStorage implements Storage
|
||||
{
|
||||
/**
|
||||
* @var \Couchbase
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Couchbase $couchbase
|
||||
*/
|
||||
public function __construct(\Couchbase $couchbase)
|
||||
{
|
||||
$this->client = $couchbase;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$this->client->add($key, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$this->client->replace($key, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$this->client->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$value = $this->client->get($key);
|
||||
|
||||
if ($value === null) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name of the underlying storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'couchbase';
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,12 +14,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
|
||||
/**
|
||||
* Relational databased backed system.
|
||||
*
|
||||
@@ -33,11 +37,15 @@ class DBALStorage implements Storage
|
||||
private $keyColumn;
|
||||
private $dataColumn;
|
||||
|
||||
public function __construct(Connection $conn, $table = 'storage', $keyColumn = 'id', $dataColumn = 'serialized_data')
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->table = $table;
|
||||
$this->keyColumn = $keyColumn;
|
||||
public function __construct(
|
||||
Connection $conn,
|
||||
$table = 'storage',
|
||||
$keyColumn = 'id',
|
||||
$dataColumn = 'serialized_data'
|
||||
) {
|
||||
$this->conn = $conn;
|
||||
$this->table = $table;
|
||||
$this->keyColumn = $keyColumn;
|
||||
$this->dataColumn = $dataColumn;
|
||||
}
|
||||
|
||||
@@ -70,17 +78,16 @@ class DBALStorage implements Storage
|
||||
* Insert data into the storage key specified.
|
||||
*
|
||||
* @param array|string $key
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @param array $data
|
||||
*/
|
||||
function insert($storageName, $key, array $data)
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
try {
|
||||
$this->conn->insert($this->table, array(
|
||||
$this->keyColumn => $key,
|
||||
$this->dataColumn => serialize($data)
|
||||
));
|
||||
} catch(\Exception $e) {
|
||||
$this->conn->insert($this->table, [
|
||||
$this->keyColumn => $key,
|
||||
$this->dataColumn => serialize($data),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,18 +95,17 @@ class DBALStorage implements Storage
|
||||
* Update data into the given key.
|
||||
*
|
||||
* @param array|string $key
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @param array $data
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
try {
|
||||
$this->conn->update($this->table, array(
|
||||
$this->dataColumn => serialize($data)
|
||||
), array(
|
||||
$this->keyColumn => $key
|
||||
));
|
||||
} catch(\Exception $e) {
|
||||
$this->conn->update($this->table, [
|
||||
$this->dataColumn => serialize($data),
|
||||
], [
|
||||
$this->keyColumn => $key,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,13 +113,12 @@ class DBALStorage implements Storage
|
||||
* Delete data at key
|
||||
*
|
||||
* @param array|string $key
|
||||
* @return void
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
try {
|
||||
$this->conn->delete($this->table, array($this->keyColumn => $key));
|
||||
} catch(\Exception $e) {
|
||||
$this->conn->delete($this->table, [$this->keyColumn => $key]);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,16 +126,24 @@ class DBALStorage implements Storage
|
||||
* Find data at key
|
||||
*
|
||||
* @param array|string $key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$sql = "SELECT " . $this->dataColumn . " FROM " . $this->table . " " .
|
||||
$this->keyColumn = " = ?";
|
||||
$stmt = $this->conn->executeQuery($sql, array($key));
|
||||
$qb = $this->conn->createQueryBuilder();
|
||||
|
||||
$qb->select('s.' . $this->dataColumn)
|
||||
->from($this->table, 's')
|
||||
->where($this->keyColumn . ' = ?')
|
||||
->setParameters([$key]);
|
||||
|
||||
$stmt = $qb->execute();
|
||||
|
||||
$data = $stmt->fetchColumn();
|
||||
if (!$data) {
|
||||
return null;
|
||||
|
||||
if (! $data) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return unserialize($data);
|
||||
@@ -146,4 +159,3 @@ class DBALStorage implements Storage
|
||||
return 'dbal';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -40,7 +41,7 @@ class DoctrineCacheStorage implements Storage
|
||||
|
||||
public function __construct(Cache $cache, $supportsCompositeKeys = true)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cache = $cache;
|
||||
$this->supportsCompositeKeys = $supportsCompositeKeys;
|
||||
}
|
||||
|
||||
@@ -61,14 +62,14 @@ class DoctrineCacheStorage implements Storage
|
||||
|
||||
private function flattenKey($storageName, $key)
|
||||
{
|
||||
if ( ! $this->supportsCompositeKeys) {
|
||||
return $storageName . "-" . $key;
|
||||
if (! $this->supportsCompositeKeys) {
|
||||
return $storageName . '-' . $key;
|
||||
}
|
||||
|
||||
$hash = $storageName . "-oid:";
|
||||
$hash = $storageName . '-oid:';
|
||||
ksort($key);
|
||||
foreach ($key as $property => $value) {
|
||||
$hash .= "$property=$value;";
|
||||
$hash .= $property . '=' . $value . ';';
|
||||
}
|
||||
return $hash;
|
||||
}
|
||||
@@ -102,4 +103,3 @@ class DoctrineCacheStorage implements Storage
|
||||
return 'doctrine_cache';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
322
lib/Doctrine/KeyValueStore/Storage/DynamoDbStorage.php
Normal file
322
lib/Doctrine/KeyValueStore/Storage/DynamoDbStorage.php
Normal file
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Aws\DynamoDb\DynamoDbClient;
|
||||
use Aws\DynamoDb\Marshaler;
|
||||
use Doctrine\KeyValueStore\InvalidArgumentException;
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
|
||||
/**
|
||||
* DyanmoDb storage
|
||||
*
|
||||
* @author Stan Lemon <stosh1985@gmail.com>
|
||||
*/
|
||||
class DynamoDbStorage implements Storage
|
||||
{
|
||||
/**
|
||||
* The key that DynamoDb uses to indicate the name of the table.
|
||||
*/
|
||||
const TABLE_NAME_KEY = 'TableName';
|
||||
|
||||
/**
|
||||
* The key that DynamoDb uses to indicate whether or not to do a consistent read.
|
||||
*/
|
||||
const CONSISTENT_READ_KEY = 'ConsistentRead';
|
||||
|
||||
/**
|
||||
* The key that is used to refer to the DynamoDb table key.
|
||||
*/
|
||||
const TABLE_KEY = 'Key';
|
||||
|
||||
/**
|
||||
* The key that is used to refer to the marshaled item for DynamoDb table.
|
||||
*/
|
||||
const TABLE_ITEM_KEY = 'Item';
|
||||
|
||||
/**
|
||||
* @var \Aws\DynamoDb\DynamoDbClient
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var Marshaler
|
||||
*/
|
||||
private $marshaler;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $defaultKeyName = 'Id';
|
||||
|
||||
/**
|
||||
* A associative array where the key is the table name and the value is the name of the key.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $tableKeys = [];
|
||||
|
||||
/**
|
||||
* @param DynamoDbClient $client The client for connecting to AWS DynamoDB.
|
||||
* @param Marshaler|null $marshaler (optional) Marshaller for converting data to/from DynamoDB format.
|
||||
* @param string $defaultKeyName (optional) Default name to use for keys.
|
||||
* @param array $tableKeys $tableKeys (optional) An associative array for keys representing table names and values
|
||||
* representing key names for those tables.
|
||||
*/
|
||||
public function __construct(
|
||||
DynamoDbClient $client,
|
||||
Marshaler $marshaler = null,
|
||||
$defaultKeyName = null,
|
||||
array $tableKeys = []
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->marshaler = $marshaler ?: new Marshaler();
|
||||
|
||||
if ($defaultKeyName !== null) {
|
||||
$this->setDefaultKeyName($defaultKeyName);
|
||||
}
|
||||
|
||||
foreach ($tableKeys as $table => $keyName) {
|
||||
$this->setKeyForTable($table, $keyName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a DynamoDB key name.
|
||||
*
|
||||
* @param $name mixed The name to validate.
|
||||
*
|
||||
* @throws InvalidArgumentException When the key name is invalid.
|
||||
*/
|
||||
private function validateKeyName($name)
|
||||
{
|
||||
if (! is_string($name)) {
|
||||
throw InvalidArgumentException::invalidType('key', 'string', $name);
|
||||
}
|
||||
|
||||
$len = strlen($name);
|
||||
if ($len > 255 || $len < 1) {
|
||||
throw InvalidArgumentException::invalidLength('name', 1, 255);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a DynamoDB table name.
|
||||
*
|
||||
* @see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html
|
||||
*
|
||||
* @param $name string The table name to validate.
|
||||
*
|
||||
* @throws InvalidArgumentException When the name is invalid.
|
||||
*/
|
||||
private function validateTableName($name)
|
||||
{
|
||||
if (! is_string($name)) {
|
||||
throw InvalidArgumentException::invalidType('key', 'string', $name);
|
||||
}
|
||||
|
||||
if (! preg_match('/^[a-z0-9_.-]{3,255}$/i', $name)) {
|
||||
throw InvalidArgumentException::invalidTableName($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default key name for storage tables.
|
||||
*
|
||||
* @param $name string The default name to use for the key.
|
||||
*
|
||||
* @throws InvalidArgumentException When the key name is invalid.
|
||||
*/
|
||||
private function setDefaultKeyName($name)
|
||||
{
|
||||
$this->validateKeyName($name);
|
||||
$this->defaultKeyName = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default key name.
|
||||
*
|
||||
* @return string The default key name.
|
||||
*/
|
||||
public function getDefaultKeyName()
|
||||
{
|
||||
return $this->defaultKeyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a key name for a specific table.
|
||||
*
|
||||
* @param $table string The name of the table.
|
||||
* @param $key string The name of the string.
|
||||
*
|
||||
* @throws InvalidArgumentException When the key or table name is invalid.
|
||||
*/
|
||||
private function setKeyForTable($table, $key)
|
||||
{
|
||||
$this->validateTableName($table);
|
||||
$this->validateKeyName($key);
|
||||
$this->tableKeys[$table] = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a specific name for a key for a given table. The default is returned if this table does not have
|
||||
* an actual override.
|
||||
*
|
||||
* @param string $tableName The name of the table.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getKeyNameForTable($tableName)
|
||||
{
|
||||
return isset($this->tableKeys[$tableName]) ?
|
||||
$this->tableKeys[$tableName] :
|
||||
$this->defaultKeyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a key to be in a valid format for lookups for DynamoDB. If passing an array, that means that the key
|
||||
* is the name of the key and the value is the actual value for the lookup.
|
||||
*
|
||||
* @param string $storageName Table name.
|
||||
* @param string $key Key name.
|
||||
*
|
||||
* @return array The key in DynamoDB format.
|
||||
*/
|
||||
private function prepareKey($storageName, $key)
|
||||
{
|
||||
if (is_array($key)) {
|
||||
$keyValue = reset($key);
|
||||
$keyName = key($key);
|
||||
} else {
|
||||
$keyValue = $key;
|
||||
$keyName = $this->getKeyNameForTable($storageName);
|
||||
}
|
||||
|
||||
return $this->marshaler->marshalItem([$keyName => $keyValue]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$this->client->putItem([
|
||||
self::TABLE_NAME_KEY => $storageName,
|
||||
self::TABLE_ITEM_KEY => $this->prepareKey($storageName, $key) + $this->marshaler->marshalItem($this->prepareData($data)),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
//We are using PUT so we just replace the original item, if the key
|
||||
//does not exist, it will be created.
|
||||
$this->insert($storageName, $key, $this->prepareData($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$this->client->deleteItem([
|
||||
self::TABLE_NAME_KEY => $storageName,
|
||||
self::TABLE_KEY => $this->prepareKey($storageName, $key),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$item = $this->client->getItem([
|
||||
self::TABLE_NAME_KEY => $storageName,
|
||||
self::CONSISTENT_READ_KEY => true,
|
||||
self::TABLE_KEY => $this->prepareKey($storageName, $key),
|
||||
]);
|
||||
|
||||
if (! $item) {
|
||||
throw NotFoundException::notFoundByKey($key);
|
||||
}
|
||||
|
||||
$item = $item->get(self::TABLE_ITEM_KEY);
|
||||
|
||||
return $this->marshaler->unmarshalItem($item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name of the underlying storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'dynamodb';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare data by removing empty item attributes.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareData($data)
|
||||
{
|
||||
$callback = function ($value) {
|
||||
return $value !== null && $value !== [] && $value !== '';
|
||||
};
|
||||
|
||||
foreach ($data as &$value) {
|
||||
if (is_array($value)) {
|
||||
$value = $this->prepareData($value);
|
||||
}
|
||||
}
|
||||
return array_filter($data, $callback);
|
||||
}
|
||||
}
|
||||
175
lib/Doctrine/KeyValueStore/Storage/MongoDbStorage.php
Normal file
175
lib/Doctrine/KeyValueStore/Storage/MongoDbStorage.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
|
||||
/**
|
||||
* MongoDb storage
|
||||
*
|
||||
* @author Markus Bachmann <markus.bachmann@bachi.biz>
|
||||
*/
|
||||
class MongoDbStorage implements Storage
|
||||
{
|
||||
/**
|
||||
* @var \Mongo
|
||||
*/
|
||||
protected $mongo;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $dbOptions;
|
||||
|
||||
/**
|
||||
* @var \MongoCollection
|
||||
*/
|
||||
protected $collection;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Mongo $mongo
|
||||
* @param array $dbOptions
|
||||
*/
|
||||
public function __construct(\Mongo $mongo, array $dbOptions = [])
|
||||
{
|
||||
$this->mongo = $mongo;
|
||||
$this->dbOptions = array_merge([
|
||||
'database' => '',
|
||||
'collection' => '',
|
||||
], $dbOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the mongodb collection
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
if (null !== $this->collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->dbOptions['database'])) {
|
||||
throw new \RuntimeException('The option "database" must be set');
|
||||
}
|
||||
if (empty($this->dbOptions['collection'])) {
|
||||
throw new \RuntimeException('The option "collection" must be set');
|
||||
}
|
||||
|
||||
$this->collection = $this
|
||||
->mongo
|
||||
->selectDB($this->dbOptions['database'])
|
||||
->selectCollection($this->dbOptions['collection']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$value = [
|
||||
'key' => $key,
|
||||
'value' => $data,
|
||||
];
|
||||
|
||||
$this->collection->insert($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$value = [
|
||||
'key' => $key,
|
||||
'value' => $data,
|
||||
];
|
||||
|
||||
$this->collection->update(['key' => $key], $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$this->collection->remove(['key' => $key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$value = $this->collection->findOne(['key' => $key], ['value']);
|
||||
|
||||
if ($value) {
|
||||
return $value['value'];
|
||||
}
|
||||
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name of the underlying storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'mongodb';
|
||||
}
|
||||
}
|
||||
149
lib/Doctrine/KeyValueStore/Storage/RedisStorage.php
Normal file
149
lib/Doctrine/KeyValueStore/Storage/RedisStorage.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
|
||||
/**
|
||||
* @author Marcel Araujo <admin@marcelaraujo.me>
|
||||
*/
|
||||
class RedisStorage implements Storage
|
||||
{
|
||||
/**
|
||||
* @var \Redis
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $dbOptions;
|
||||
|
||||
/**
|
||||
* Redis Key Prefix
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $keyPrefix = 'doctrine:storage:';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Redis $redis
|
||||
* @param array $dbOptions
|
||||
*/
|
||||
public function __construct($redis, $dbOptions = [])
|
||||
{
|
||||
$this->client = $redis;
|
||||
|
||||
$this->dbOptions = array_merge([
|
||||
'keyPrefix' => $this->keyPrefix,
|
||||
], $dbOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$this->client->set($this->getKeyName($key), json_encode($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$this->client->set($this->getKeyName($key), json_encode($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$key = $this->getKeyName($key);
|
||||
|
||||
if ($this->client->exists($key)) {
|
||||
$this->client->delete($key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$key = $this->getKeyName($key);
|
||||
|
||||
if (! $this->client->exists($key)) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return json_decode($this->client->get($key), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name of the underlying storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'redis';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add prefix to Redis key space name
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyName($key)
|
||||
{
|
||||
return $this->keyPrefix . $key;
|
||||
}
|
||||
}
|
||||
136
lib/Doctrine/KeyValueStore/Storage/RiakStorage.php
Normal file
136
lib/Doctrine/KeyValueStore/Storage/RiakStorage.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
use Riak\Client;
|
||||
|
||||
/**
|
||||
* @author Markus Bachmann <markus.bachmann@bachi.biz>
|
||||
*/
|
||||
class RiakStorage implements Storage
|
||||
{
|
||||
/**
|
||||
* @var \Riak\Client
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Riak\Client $riak
|
||||
* @param string $bucketName
|
||||
*/
|
||||
public function __construct(Client $riak)
|
||||
{
|
||||
$this->client = $riak;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$bucket = $this->client->bucket($storageName);
|
||||
$object = $bucket->newObject($key, $data);
|
||||
$object->store();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$bucket = $this->client->bucket($storageName);
|
||||
/** @var $object \Riak\Object */
|
||||
$object = $bucket->get($key);
|
||||
|
||||
$object->setData($data);
|
||||
$object->store();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$bucket = $this->client->bucket($storageName);
|
||||
|
||||
/** @var $object \Riak\Object */
|
||||
$object = $bucket->get($key);
|
||||
|
||||
if (! $object->exists()) {
|
||||
// object does not exist, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
$object->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$bucket = $this->client->bucket($storageName);
|
||||
|
||||
/** @var $object \Riak\Object */
|
||||
$object = $bucket->get($key);
|
||||
|
||||
if (! $object->exists()) {
|
||||
throw new NotFoundException;
|
||||
}
|
||||
|
||||
return $object->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'riak';
|
||||
}
|
||||
}
|
||||
184
lib/Doctrine/KeyValueStore/Storage/SimpleDbStorage.php
Normal file
184
lib/Doctrine/KeyValueStore/Storage/SimpleDbStorage.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Aws\SimpleDb\Exception\NoSuchDomainException;
|
||||
use Aws\SimpleDb\Exception\SimpleDbException;
|
||||
use Aws\SimpleDb\SimpleDbClient;
|
||||
use Doctrine\KeyValueStore\KeyValueStoreException;
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
|
||||
/**
|
||||
* SimpleDb storage
|
||||
*
|
||||
* @author Stan Lemon <stosh1985@gmail.com>
|
||||
*/
|
||||
class SimpleDbStorage implements Storage
|
||||
{
|
||||
/**
|
||||
* @var \Aws\SimpleDb\SimpleDbClient
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Aws\SimpleDb\SimpleDbClient $client
|
||||
*/
|
||||
public function __construct(SimpleDbClient $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsPartialUpdates()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function supportsCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function requiresCompositePrimaryKeys()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$this->createDomain($storageName);
|
||||
|
||||
$this->client->putAttributes([
|
||||
'DomainName' => $storageName,
|
||||
'ItemName' => $key,
|
||||
'Attributes' => $this->makeAttributes($data),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
return $this->insert($storageName, $key, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$this->client->deleteAttributes([
|
||||
'DomainName' => $storageName,
|
||||
'ItemName' => $key,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$select = 'select * from ' . $storageName . ' where itemName() = \'' . $key . '\'';
|
||||
|
||||
$iterator = $this->client->select([
|
||||
'SelectExpression' => $select,
|
||||
]);
|
||||
|
||||
$results = $iterator->get('Items');
|
||||
|
||||
if (count($results)) {
|
||||
$result = array_shift($results);
|
||||
|
||||
$data = ['id' => $result['Name']];
|
||||
|
||||
foreach ($result['Attributes'] as $attribute) {
|
||||
$data[$attribute['Name']] = $attribute['Value'];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name of the underlying storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'simpledb';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
*/
|
||||
protected function createDomain($domainName)
|
||||
{
|
||||
try {
|
||||
$domain = $this->client->domainMetadata(['DomainName' => $domainName]);
|
||||
} catch (NoSuchDomainException $e) {
|
||||
$this->client->createDomain(['DomainName' => $domainName]);
|
||||
|
||||
$domain = $this->client->domainMetadata(['DomainName' => $domainName]);
|
||||
} catch (SimpleDbException $e) {
|
||||
throw new KeyValueStoreException($e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param array $data
|
||||
*/
|
||||
protected function makeAttributes($data)
|
||||
{
|
||||
$attributes = [];
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
if ($value !== null && $value !== [] && $value !== '') {
|
||||
$attributes[] = [
|
||||
'Name' => $name,
|
||||
'Value' => $value,
|
||||
'Replace' => true,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -47,68 +48,67 @@ interface Storage
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function supportsPartialUpdates();
|
||||
public function supportsPartialUpdates();
|
||||
|
||||
/**
|
||||
* Does this storage support composite primary keys?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function supportsCompositePrimaryKeys();
|
||||
public function supportsCompositePrimaryKeys();
|
||||
|
||||
/**
|
||||
* Does this storage require composite primary keys?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function requiresCompositePrimaryKeys();
|
||||
public function requiresCompositePrimaryKeys();
|
||||
|
||||
/**
|
||||
* Insert data into the storage key specified.
|
||||
*
|
||||
* @param string $storageName
|
||||
* @param string $storageName
|
||||
* @param array|string $key
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @param array $data
|
||||
*/
|
||||
function insert($storageName, $key, array $data);
|
||||
public function insert($storageName, $key, array $data);
|
||||
|
||||
/**
|
||||
* Update data into the given key.
|
||||
*
|
||||
* @param string $storageName
|
||||
* @param string $storageName
|
||||
* @param array|string $key
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @param array $data
|
||||
*/
|
||||
function update($storageName, $key, array $data);
|
||||
public function update($storageName, $key, array $data);
|
||||
|
||||
/**
|
||||
* Delete data at key
|
||||
*
|
||||
* @param string $storageName
|
||||
* @param string $storageName
|
||||
* @param array|string $key
|
||||
* @return void
|
||||
*/
|
||||
function delete($storageName, $key);
|
||||
public function delete($storageName, $key);
|
||||
|
||||
/**
|
||||
* Find data at key
|
||||
*
|
||||
* Important note: The returned array does contain the identifier (again)!
|
||||
*
|
||||
* @param string $storageName
|
||||
*
|
||||
* @param string $storageName
|
||||
* @param array|string $key
|
||||
*
|
||||
* @throws Doctrine\KeyValueStore\NotFoundException When data with key is not found.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function find($storageName, $key);
|
||||
public function find($storageName, $key);
|
||||
|
||||
/**
|
||||
* Return a name of the underlying storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getName();
|
||||
public function getName();
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
lib/Doctrine/KeyValueStore/Storage/StorageException.php
Normal file
27
lib/Doctrine/KeyValueStore/Storage/StorageException.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\KeyValueStoreException;
|
||||
|
||||
class StorageException extends KeyValueStoreException
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,16 +14,20 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage\WindowsAzureTable;
|
||||
|
||||
/**
|
||||
* Abstraction for WindowsAzure Authorization Schemes
|
||||
*
|
||||
* @link http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*
|
||||
* @deprecated This class is deprecated and will be removed in 2.0.
|
||||
*/
|
||||
interface AuthorizationSchema
|
||||
{
|
||||
@@ -33,9 +38,9 @@ interface AuthorizationSchema
|
||||
* @param string $path
|
||||
* @param string $queryString
|
||||
* @param string $body
|
||||
* @param array $headers
|
||||
* @param array $headers
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function signRequest($method, $path, $queryString, $body, array $headers);
|
||||
public function signRequest($method, $path, $queryString, $body, array $headers);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage\WindowsAzureTable;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\StorageException;
|
||||
|
||||
/**
|
||||
* @deprecated This class is deprecated and will be removed in 2.0.
|
||||
*/
|
||||
class HttpStorageException extends StorageException
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,12 +14,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage\WindowsAzureTable;
|
||||
|
||||
/**
|
||||
* @deprecated This class is deprecated and will be removed in 2.0.
|
||||
*/
|
||||
class SharedKeyAuthorization implements AuthorizationSchema
|
||||
{
|
||||
/**
|
||||
@@ -33,7 +37,7 @@ class SharedKeyAuthorization implements AuthorizationSchema
|
||||
public function __construct($accountName, $accountKey)
|
||||
{
|
||||
$this->accountName = $accountName;
|
||||
$this->accountKey = base64_decode($accountKey);
|
||||
$this->accountKey = base64_decode($accountKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,13 +46,13 @@ class SharedKeyAuthorization implements AuthorizationSchema
|
||||
*/
|
||||
public function signRequest($method, $path, $queryString, $body, array $headers)
|
||||
{
|
||||
$canonicalResource = "/" . $this->accountName . $path;
|
||||
$stringToSign = $method . "\n" .
|
||||
$canonicalResource = '/' . $this->accountName . $path;
|
||||
$stringToSign = $method . "\n" .
|
||||
md5($body) . "\n" .
|
||||
"application/atom+xml\n" .
|
||||
$headers['x-ms-date'] . "\n" .
|
||||
$canonicalResource;
|
||||
return "Authorization: SharedKey " . $this->accountName . ":" . base64_encode(hash_hmac('sha256', $stringToSign, $this->accountKey, true));
|
||||
return 'Authorization: SharedKey ' . $this->accountName . ':' .
|
||||
base64_encode(hash_hmac('sha256', $stringToSign, $this->accountKey, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,12 +14,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage\WindowsAzureTable;
|
||||
|
||||
/**
|
||||
* @deprecated This class is deprecated and will be removed in 2.0.
|
||||
*/
|
||||
class SharedKeyLiteAuthorization implements AuthorizationSchema
|
||||
{
|
||||
/**
|
||||
@@ -33,7 +37,7 @@ class SharedKeyLiteAuthorization implements AuthorizationSchema
|
||||
public function __construct($accountName, $accountKey)
|
||||
{
|
||||
$this->accountName = $accountName;
|
||||
$this->accountKey = base64_decode($accountKey);
|
||||
$this->accountKey = base64_decode($accountKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,10 +46,10 @@ class SharedKeyLiteAuthorization implements AuthorizationSchema
|
||||
*/
|
||||
public function signRequest($method, $path, $queryString, $body, array $headers)
|
||||
{
|
||||
$canonicalResource = "/" . $this->accountName . $path;
|
||||
$stringToSign = $headers['x-ms-date'] . "\n" .
|
||||
$canonicalResource = '/' . $this->accountName . $path;
|
||||
$stringToSign = $headers['x-ms-date'] . "\n" .
|
||||
$canonicalResource;
|
||||
return "Authorization: SharedKeyLite " . $this->accountName . ":" . base64_encode(hash_hmac('sha256', $stringToSign, $this->accountKey, true));
|
||||
return 'Authorization: SharedKeyLite ' . $this->accountName . ':' .
|
||||
base64_encode(hash_hmac('sha256', $stringToSign, $this->accountKey, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,16 +14,18 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Http\Client;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\AuthorizationSchema;
|
||||
use Doctrine\KeyValueStore\NotFoundException;
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\KeyValueStore\Query\RangeQueryStorage;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\AuthorizationSchema;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\HttpStorageException;
|
||||
|
||||
/**
|
||||
* Storage implementation for Microsoft Windows Azure Table.
|
||||
@@ -30,13 +33,15 @@ use Doctrine\KeyValueStore\Query\RangeQueryStorage;
|
||||
* Using a HTTP client to communicate with the REST API of Azure Table.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*
|
||||
* @deprecated This class is deprecated and will be removed in 2.0, use the AzureSdkTableStorage instead.
|
||||
*/
|
||||
class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
{
|
||||
const WINDOWS_AZURE_TABLE_BASEURL = 'https://%s.table.core.windows.net';
|
||||
|
||||
const METADATA_NS = 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata';
|
||||
const DATA_NS = 'http://schemas.microsoft.com/ado/2007/08/dataservices';
|
||||
const DATA_NS = 'http://schemas.microsoft.com/ado/2007/08/dataservices';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@@ -56,7 +61,7 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
</entry>';
|
||||
|
||||
const XML_TEMPLATE_TABLE = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
|
||||
<title />
|
||||
<updated></updated>
|
||||
<author>
|
||||
@@ -70,12 +75,12 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
</content>
|
||||
</entry>';
|
||||
|
||||
const TYPE_INT32 = 'Edm.Int32';
|
||||
const TYPE_INT64 = 'Edm.Int64';
|
||||
const TYPE_INT32 = 'Edm.Int32';
|
||||
const TYPE_INT64 = 'Edm.Int64';
|
||||
const TYPE_DATETIME = 'Edm.DateTime';
|
||||
const TYPE_BOOLEAN = 'Edm.Boolean';
|
||||
const TYPE_DOUBLE = 'Edm.Double';
|
||||
const TYPE_BINARY = 'Edm.Binary';
|
||||
const TYPE_BOOLEAN = 'Edm.Boolean';
|
||||
const TYPE_DOUBLE = 'Edm.Double';
|
||||
const TYPE_BINARY = 'Edm.Binary';
|
||||
|
||||
/**
|
||||
* @var \Doctrine\KeyValueStore\Http\Client
|
||||
@@ -98,16 +103,16 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
private $now;
|
||||
|
||||
/**
|
||||
* @param HttpClient $client
|
||||
* @param HttpClient $client
|
||||
* @param AuthorizationSchema $authorization
|
||||
*/
|
||||
public function __construct(Client $client, $accountName, AuthorizationSchema $authorization, \DateTime $now = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->client = $client;
|
||||
$this->authorization = $authorization;
|
||||
$this->baseUrl = sprintf(self::WINDOWS_AZURE_TABLE_BASEURL, $accountName);
|
||||
$this->now = $now ? clone $now : new \DateTime();
|
||||
$this->now->setTimeZone(new \DateTimeZone("UTC"));
|
||||
$this->baseUrl = sprintf(self::WINDOWS_AZURE_TABLE_BASEURL, $accountName);
|
||||
$this->now = $now ? clone $now : new \DateTime();
|
||||
$this->now->setTimeZone(new \DateTimeZone('UTC'));
|
||||
}
|
||||
|
||||
public function supportsPartialUpdates()
|
||||
@@ -127,9 +132,9 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
|
||||
public function insert($storageName, $key, array $data)
|
||||
{
|
||||
$headers = array(
|
||||
$headers = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
);
|
||||
];
|
||||
// TODO: This sucks
|
||||
$tableName = $storageName;
|
||||
|
||||
@@ -144,39 +149,57 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
$contentNodes->item(0)->appendChild($propertiesNode);
|
||||
$xml = $dom->saveXML();
|
||||
|
||||
$url = $this->baseUrl . '/' . $tableName;
|
||||
$url = $this->baseUrl . '/' . $tableName;
|
||||
$response = $this->request('POST', $url, $xml, $headers);
|
||||
|
||||
if ($response->getStatusCode() == 404) {
|
||||
$this->createTable($tableName);
|
||||
$this->insert($storageName, $key, $data);
|
||||
} elseif ($response->getStatusCode() >= 400) {
|
||||
$this->convertResponseToException($response);
|
||||
}
|
||||
}
|
||||
|
||||
private function convertResponseToException($response)
|
||||
{
|
||||
$dom = new \DomDocument('1.0', 'UTF-8');
|
||||
$dom->loadXML($response->getBody());
|
||||
|
||||
$node = $dom->getElementsByTagName('Message')->item(0);
|
||||
|
||||
throw new HttpStorageException(
|
||||
$node ? $node->nodeValue : 'An error has occured'
|
||||
);
|
||||
}
|
||||
|
||||
public function createTable($tableName)
|
||||
{
|
||||
$headers = array(
|
||||
$headers = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
);
|
||||
];
|
||||
|
||||
$dom = $this->createDomDocumentRequestBody(self::XML_TEMPLATE_TABLE);
|
||||
$dom = $this->createDomDocumentRequestBody(self::XML_TEMPLATE_TABLE);
|
||||
$tableNode = $dom->getElementsByTagNameNS(self::DATA_NS, 'TableName')->item(0);
|
||||
$tableNode->appendChild($dom->createTextNode($tableName));
|
||||
$xml = $dom->saveXML();
|
||||
|
||||
$url = $this->baseUrl . '/Tables';
|
||||
$url = $this->baseUrl . '/Tables';
|
||||
$response = $this->request('POST', $url, $xml, $headers);
|
||||
|
||||
if ($response->getStatusCode() != 201) {
|
||||
$this->convertResponseToException($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function update($storageName, $key, array $data)
|
||||
{
|
||||
$headers = array(
|
||||
$headers = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'x-ms-date' => $this->now(),
|
||||
'If-Match' => '*',
|
||||
);
|
||||
'x-ms-date' => $this->now(),
|
||||
'If-Match' => '*',
|
||||
];
|
||||
// TODO: This sucks
|
||||
$tableName = $storageName;
|
||||
|
||||
@@ -186,10 +209,14 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
|
||||
$this->serializeKeys($propertiesNode, $key);
|
||||
$this->serializeProperties($propertiesNode, $key, $data);
|
||||
$keys = array_values($key);
|
||||
$clientUrl = $this->baseUrl . '/' . $tableName . ("(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')");
|
||||
$url = $this->baseUrl . '/' . $tableName . rawurlencode("(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')");
|
||||
$idNode = $dom->getElementsByTagName('id')->item(0);
|
||||
$keys = array_values($key);
|
||||
$clientUrl = $this->baseUrl . '/' . $tableName . (
|
||||
"(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')"
|
||||
);
|
||||
$url = $this->baseUrl . '/' . $tableName . rawurlencode(
|
||||
"(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')"
|
||||
);
|
||||
$idNode = $dom->getElementsByTagName('id')->item(0);
|
||||
$idNode->appendChild($dom->createTextNode($clientUrl));
|
||||
|
||||
$contentNodes = $dom->getElementsByTagName('content');
|
||||
@@ -197,42 +224,58 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
$xml = $dom->saveXML();
|
||||
|
||||
$response = $this->request('PUT', $url, $xml, $headers);
|
||||
|
||||
if ($response->getStatusCode() >= 400) {
|
||||
$this->convertResponseToException($response);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete($storageName, $key)
|
||||
{
|
||||
$headers = array(
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'x-ms-date' => $this->now(),
|
||||
$headers = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'x-ms-date' => $this->now(),
|
||||
'Content-Length' => 0,
|
||||
'If-Match' => '*',
|
||||
);
|
||||
'If-Match' => '*',
|
||||
];
|
||||
|
||||
// TODO: This sucks
|
||||
$tableName = $storageName;
|
||||
$keys = array_values($key);
|
||||
$url = $this->baseUrl . '/' . $tableName . rawurlencode("(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')");
|
||||
$keys = array_values($key);
|
||||
$url = $this->baseUrl . '/' . $tableName . rawurlencode(
|
||||
"(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')"
|
||||
);
|
||||
|
||||
$this->request('DELETE', $url, '', $headers);
|
||||
$response = $this->request('DELETE', $url, '', $headers);
|
||||
|
||||
if ($response->getStatusCode() >= 400) {
|
||||
$this->convertResponseToException($response);
|
||||
}
|
||||
}
|
||||
|
||||
public function find($storageName, $key)
|
||||
{
|
||||
$headers = array(
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'x-ms-date' => $this->now(),
|
||||
$headers = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'x-ms-date' => $this->now(),
|
||||
'Content-Length' => 0,
|
||||
);
|
||||
];
|
||||
|
||||
// TODO: This sucks
|
||||
$tableName = $storageName;
|
||||
$keys = array_values($key);
|
||||
$url = $this->baseUrl . '/' . $tableName . rawurlencode("(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')");
|
||||
$keys = array_values($key);
|
||||
$url = $this->baseUrl . '/' . $tableName . rawurlencode(
|
||||
"(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')"
|
||||
);
|
||||
|
||||
$response = $this->request('GET', $url, '', $headers);
|
||||
|
||||
if ($response->getStatusCode() != 200) {
|
||||
// Todo: do stuff
|
||||
if ($response->getStatusCode() == 404) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() >= 400) {
|
||||
$this->convertResponseToException($response);
|
||||
}
|
||||
|
||||
$dom = new \DomDocument('1.0', 'UTF-8');
|
||||
@@ -241,7 +284,7 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
$xpath = new \DOMXpath($dom);
|
||||
$xpath->registerNamespace('d', 'http://schemas.microsoft.com/ado/2007/08/dataservices');
|
||||
$xpath->registerNamespace('m', 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata');
|
||||
$xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom");
|
||||
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
|
||||
$entries = $xpath->evaluate('/atom:entry');
|
||||
|
||||
return $this->createRow(array_keys($key), $xpath, $entries->item(0));
|
||||
@@ -251,21 +294,21 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
{
|
||||
$properties = $xpath->evaluate('atom:content/m:properties/d:*', $entry);
|
||||
|
||||
$data = array();
|
||||
$data = [];
|
||||
list($partitionKey, $rowKey) = $keyNames;
|
||||
|
||||
foreach ($properties as $property) {
|
||||
$name = substr($property->tagName, 2);
|
||||
if ($name == "PartitionKey") {
|
||||
if ($name == 'PartitionKey') {
|
||||
$name = $partitionKey;
|
||||
} else if ($name == "RowKey") {
|
||||
} elseif ($name == 'RowKey') {
|
||||
$name = $rowKey;
|
||||
}
|
||||
|
||||
$value = $property->nodeValue;
|
||||
if ($property->hasAttributeNS(self::METADATA_NS, 'null')) {
|
||||
$value = null;
|
||||
} else if ($property->hasAttributeNS(self::METADATA_NS, 'type')) {
|
||||
} elseif ($property->hasAttributeNS(self::METADATA_NS, 'type')) {
|
||||
$type = $property->getAttributeNS(self::METADATA_NS, 'type');
|
||||
switch ($type) {
|
||||
case self::TYPE_BOOLEAN:
|
||||
@@ -275,7 +318,7 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
$value = new \DateTime(substr($value, 0, 19), new \DateTimeZone('UTC'));
|
||||
break;
|
||||
case self::TYPE_INT32:
|
||||
$value = (int)$value;
|
||||
$value = (int) $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -287,31 +330,33 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
|
||||
public function executeRangeQuery(RangeQuery $query, $storageName, $key, \Closure $hydrateRow = null)
|
||||
{
|
||||
$headers = array(
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'x-ms-date' => $this->now(),
|
||||
$headers = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'x-ms-date' => $this->now(),
|
||||
'Content-Length' => 0,
|
||||
);
|
||||
];
|
||||
|
||||
$filters = array("PartitionKey eq " . $this->quoteFilterValue($query->getPartitionKey()));
|
||||
$filters = ['PartitionKey eq ' . $this->quoteFilterValue($query->getPartitionKey())];
|
||||
foreach ($query->getConditions() as $condition) {
|
||||
if ( ! in_array($condition[0], array('eq', 'neq', 'le', 'lt', 'ge', 'gt'))) {
|
||||
throw new \InvalidArgumentException("Windows Azure Table only supports eq, neq, le, lt, ge, gt as conditions.");
|
||||
if (! in_array($condition[0], ['eq', 'neq', 'le', 'lt', 'ge', 'gt'])) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Windows Azure Table only supports eq, neq, le, lt, ge, gt as conditions.'
|
||||
);
|
||||
}
|
||||
$filters[] = $key[1] . " " . $condition[0] . " " . $this->quoteFilterValue($condition[1]);
|
||||
$filters[] = $key[1] . ' ' . $condition[0] . ' ' . $this->quoteFilterValue($condition[1]);
|
||||
}
|
||||
|
||||
// TODO: This sucks
|
||||
$tableName = $storageName;
|
||||
$url = $this->baseUrl . '/' . $tableName . '()?$filter=' . rawurlencode(implode(' ', $filters));
|
||||
$url = $this->baseUrl . '/' . $tableName . '()?$filter=' . rawurlencode(implode(' ', $filters));
|
||||
if ($query->getLimit()) {
|
||||
$url .= '&$top=' . $query->getLimit();
|
||||
}
|
||||
|
||||
$response = $this->request('GET', $url, '', $headers);
|
||||
|
||||
if ($response->getStatusCode() != 200) {
|
||||
// Todo: do stuff
|
||||
if ($response->getStatusCode() >= 400) {
|
||||
$this->convertResponseToException($response);
|
||||
}
|
||||
|
||||
$dom = new \DomDocument('1.0', 'UTF-8');
|
||||
@@ -320,12 +365,12 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
$xpath = new \DOMXpath($dom);
|
||||
$xpath->registerNamespace('d', 'http://schemas.microsoft.com/ado/2007/08/dataservices');
|
||||
$xpath->registerNamespace('m', 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata');
|
||||
$xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom");
|
||||
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
|
||||
$entries = $xpath->evaluate('/atom:feed/atom:entry');
|
||||
|
||||
$results = array();
|
||||
$results = [];
|
||||
foreach ($entries as $entry) {
|
||||
$data = $this->createRow($key, $xpath, $entry);
|
||||
$data = $this->createRow($key, $xpath, $entry);
|
||||
$results[] = $hydrateRow ? $hydrateRow($data) : $data;
|
||||
}
|
||||
|
||||
@@ -338,7 +383,7 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
return $value;
|
||||
}
|
||||
|
||||
return "'" . str_replace("'", "", $value) . "'";
|
||||
return "'" . str_replace("'", '', $value) . "'";
|
||||
}
|
||||
|
||||
public function getName()
|
||||
@@ -372,7 +417,7 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
if ($propertyValue instanceof \DateTime) {
|
||||
return self::TYPE_DATETIME;
|
||||
}
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
private function convertPropertyValue($propertyValue, $type)
|
||||
@@ -382,7 +427,7 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
$propertyValue = $this->isoDate($propertyValue);
|
||||
break;
|
||||
case self::TYPE_BOOLEAN:
|
||||
$propertyValue = $propertyValue ? "1" : "0";
|
||||
$propertyValue = $propertyValue ? '1' : '0';
|
||||
break;
|
||||
}
|
||||
return $propertyValue;
|
||||
@@ -394,7 +439,11 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
foreach ($key as $keyName => $keyValue) {
|
||||
switch ($keys) {
|
||||
case 0:
|
||||
$partitionKey = $propertiesNode->ownerDocument->createElementNS(self::DATA_NS, 'PartitionKey', $keyValue);
|
||||
$partitionKey = $propertiesNode->ownerDocument->createElementNS(
|
||||
self::DATA_NS,
|
||||
'PartitionKey',
|
||||
$keyValue
|
||||
);
|
||||
$propertiesNode->appendChild($partitionKey);
|
||||
break;
|
||||
case 1:
|
||||
@@ -402,27 +451,27 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
$propertiesNode->appendChild($rowKey);
|
||||
break;
|
||||
default:
|
||||
throw new \RuntimeException("Only exactly 2 composite key fields allowed.");
|
||||
throw new \RuntimeException('Only exactly 2 composite key fields allowed.');
|
||||
}
|
||||
$keys++;
|
||||
++$keys;
|
||||
}
|
||||
}
|
||||
|
||||
private function request($method, $url, $xml, $headers)
|
||||
{
|
||||
$parts = parse_url($url);
|
||||
$requestDate = $this->now->format('D, d M Y H:i:s') . ' GMT';
|
||||
$headers['Content-Length'] = strlen($xml);
|
||||
$headers['Date'] = $requestDate;
|
||||
$headers['x-ms-date'] = $requestDate;
|
||||
$authorizationHeader = $this->authorization->signRequest(
|
||||
$parts = parse_url($url);
|
||||
$requestDate = $this->now->format('D, d M Y H:i:s') . ' GMT';
|
||||
$headers['Content-Length'] = strlen($xml);
|
||||
$headers['Date'] = $requestDate;
|
||||
$headers['x-ms-date'] = $requestDate;
|
||||
$authorizationHeader = $this->authorization->signRequest(
|
||||
$method,
|
||||
isset($parts['path']) ? $parts['path'] : '/',
|
||||
isset($parts['query']) ? $parts['query'] : '',
|
||||
$xml,
|
||||
$headers
|
||||
);
|
||||
$authorizationParts = explode(":" , $authorizationHeader, 2);
|
||||
$authorizationParts = explode(':', $authorizationHeader, 2);
|
||||
$headers[$authorizationParts[0]] = ltrim($authorizationParts[1]);
|
||||
return $this->client->request($method, $url, $xml, $headers);
|
||||
}
|
||||
@@ -430,11 +479,11 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
private function serializeProperties($propertiesNode, array $key, array $data)
|
||||
{
|
||||
foreach ($data as $propertyName => $propertyValue) {
|
||||
if ( isset($key[$propertyName])) {
|
||||
if (isset($key[$propertyName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $this->getPropertyType($propertyValue);
|
||||
$type = $this->getPropertyType($propertyValue);
|
||||
$propertyValue = $this->convertPropertyValue($propertyValue, $type);
|
||||
|
||||
$property = $propertiesNode->ownerDocument->createElementNS(self::DATA_NS, $propertyName, $propertyValue);
|
||||
@@ -446,4 +495,3 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,13 +14,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\KeyValueStore;
|
||||
|
||||
use Doctrine\KeyValueStore\Id\NullIdConverter;
|
||||
use Doctrine\KeyValueStore\Id\IdHandlingStrategy;
|
||||
use Doctrine\KeyValueStore\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\KeyValueStore\Storage\Storage;
|
||||
|
||||
/**
|
||||
* UnitOfWork to handle all KeyValueStore entities based on the configured
|
||||
@@ -29,8 +32,17 @@ use Doctrine\KeyValueStore\Id\NullIdConverter;
|
||||
*/
|
||||
class UnitOfWork
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadataFactory
|
||||
*/
|
||||
private $cmf;
|
||||
/**
|
||||
* @var Storage
|
||||
*/
|
||||
private $storageDriver;
|
||||
/**
|
||||
* @var IdHandlingStrategy
|
||||
*/
|
||||
private $idHandler;
|
||||
|
||||
/**
|
||||
@@ -44,12 +56,12 @@ class UnitOfWork
|
||||
private $identifiers;
|
||||
|
||||
private $originalData;
|
||||
private $scheduledInsertions = array();
|
||||
private $scheduledDeletions = array();
|
||||
private $identityMap = array();
|
||||
private $scheduledInsertions = [];
|
||||
private $scheduledDeletions = [];
|
||||
private $identityMap = [];
|
||||
private $idConverter;
|
||||
|
||||
public function __construct($cmf, $storageDriver, $config = null)
|
||||
public function __construct(ClassMetadataFactory $cmf, Storage $storageDriver, Configuration $config = null)
|
||||
{
|
||||
$this->cmf = $cmf;
|
||||
$this->storageDriver = $storageDriver;
|
||||
@@ -59,36 +71,47 @@ class UnitOfWork
|
||||
new Id\SingleIdHandler();
|
||||
}
|
||||
|
||||
private function tryGetById($id)
|
||||
public function getClassMetadata($className)
|
||||
{
|
||||
$idHash = $this->idHandler->hash($id);
|
||||
if (isset($this->identityMap[$idHash])) {
|
||||
return $this->identityMap[$idHash];
|
||||
}
|
||||
return null;
|
||||
return $this->cmf->getMetadataFor($className);
|
||||
}
|
||||
|
||||
public function reconsititute($className, $key)
|
||||
private function tryGetById($className, $id)
|
||||
{
|
||||
$idHash = $this->idHandler->hash($id);
|
||||
if (isset($this->identityMap[$className][$idHash])) {
|
||||
return $this->identityMap[$className][$idHash];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public function reconstititute($className, $key)
|
||||
{
|
||||
$class = $this->cmf->getMetadataFor($className);
|
||||
$id = $this->idHandler->normalizeId($class, $key);
|
||||
$data = $this->storageDriver->find($class->storageName, $id);
|
||||
|
||||
if (! $data) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
return $this->createEntity($class, $id, $data);
|
||||
}
|
||||
|
||||
public function createEntity($class, $id, $data)
|
||||
{
|
||||
if ( isset($data['php_class'])) {
|
||||
if ( $data['php_class'] !== $class->name && ! is_subclass_of($data['php_class'], $class->name)) {
|
||||
throw new \RuntimeException("Row is of class '" . $data['php_class'] . "' which is not a subtype of expected " . $class->name);
|
||||
if (isset($data['php_class'])) {
|
||||
if ($data['php_class'] !== $class->name && ! is_subclass_of($data['php_class'], $class->name)) {
|
||||
throw new \RuntimeException(
|
||||
"Row is of class '" . $data['php_class'] . "' which is not a subtype of expected " . $class->name
|
||||
);
|
||||
}
|
||||
$class = $this->cmf->getMetadataFor($data['php_class']);
|
||||
}
|
||||
unset($data['php_class']);
|
||||
|
||||
$object = $this->tryGetById($id);
|
||||
if ( $object) {
|
||||
$object = $this->tryGetById($class->name, $id);
|
||||
if ($object) {
|
||||
return $object;
|
||||
}
|
||||
|
||||
@@ -106,9 +129,9 @@ class UnitOfWork
|
||||
}
|
||||
}
|
||||
|
||||
$idHash = $this->idHandler->hash($id);
|
||||
$this->identityMap[$idHash] = $object;
|
||||
$this->identifiers[$oid] = $id;
|
||||
$idHash = $this->idHandler->hash($id);
|
||||
$this->identityMap[$class->name][$idHash] = $object;
|
||||
$this->identifiers[$oid] = $id;
|
||||
|
||||
return $object;
|
||||
}
|
||||
@@ -116,16 +139,16 @@ class UnitOfWork
|
||||
private function computeChangeSet($class, $object)
|
||||
{
|
||||
$snapshot = $this->getObjectSnapshot($class, $object);
|
||||
$changeSet = array();
|
||||
$changeSet = [];
|
||||
$originalData = $this->originalData[spl_object_hash($object)];
|
||||
|
||||
foreach ($snapshot as $field => $value) {
|
||||
if ( ! isset($originalData[$field]) || $originalData[$field] !== $value) {
|
||||
if (! isset($originalData[$field]) || $originalData[$field] !== $value) {
|
||||
$changeSet[$field] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $changeSet && ! $this->storageDriver->supportsPartialUpdates()) {
|
||||
if ($changeSet && ! $this->storageDriver->supportsPartialUpdates()) {
|
||||
$changeSet = array_merge($originalData, $changeSet);
|
||||
}
|
||||
return $changeSet;
|
||||
@@ -133,16 +156,16 @@ class UnitOfWork
|
||||
|
||||
private function getObjectSnapshot($class, $object)
|
||||
{
|
||||
$data = array();
|
||||
$data = [];
|
||||
|
||||
foreach ($class->reflFields as $fieldName => $reflProperty) {
|
||||
if ( ! isset( $class->fields[$fieldName]['id'])) {
|
||||
if (! isset($class->fields[$fieldName]['id'])) {
|
||||
$data[$fieldName] = $reflProperty->getValue($object);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (get_object_vars($object) as $property => $value) {
|
||||
if ( ! isset($data[$property])) {
|
||||
if (! isset($data[$property])) {
|
||||
$data[$property] = $value;
|
||||
}
|
||||
}
|
||||
@@ -160,49 +183,53 @@ class UnitOfWork
|
||||
$class = $this->cmf->getMetadataFor(get_class($object));
|
||||
$id = $this->idHandler->getIdentifier($class, $object);
|
||||
|
||||
if ( ! $id) {
|
||||
throw new \RuntimeException("Trying to persist entity that has no id.");
|
||||
if (! $id) {
|
||||
throw new \RuntimeException('Trying to persist entity that has no id.');
|
||||
}
|
||||
|
||||
$idHash = $this->idHandler->hash($id);
|
||||
|
||||
if (isset($this->identityMap[$idHash])) {
|
||||
throw new \RuntimeException("Object with ID already exists.");
|
||||
if (isset($this->identityMap[$class->name][$idHash])) {
|
||||
throw new \RuntimeException('Object with ID already exists.');
|
||||
}
|
||||
|
||||
$this->scheduledInsertions[$oid] = $object;
|
||||
$this->identityMap[$idHash] = $object;
|
||||
$this->scheduledInsertions[$oid] = $object;
|
||||
$this->identityMap[$class->name][$idHash] = $object;
|
||||
}
|
||||
|
||||
public function scheduleForDelete($object)
|
||||
{
|
||||
$oid = spl_object_hash($object);
|
||||
if (!isset($this->identifiers[$oid])) {
|
||||
throw new \RuntimeException("Object scheduled for deletion is not managed. Only managed objects can be deleted.");
|
||||
if (! isset($this->identifiers[$oid])) {
|
||||
throw new \RuntimeException(
|
||||
'Object scheduled for deletion is not managed. Only managed objects can be deleted.'
|
||||
);
|
||||
}
|
||||
$this->scheduledDeletions[$oid] = $object;
|
||||
}
|
||||
|
||||
private function processIdentityMap()
|
||||
{
|
||||
foreach ($this->identityMap as $object) {
|
||||
$hash = spl_object_hash($object);
|
||||
foreach ($this->identityMap as $className => $entities) {
|
||||
foreach ($entities as $object) {
|
||||
$hash = spl_object_hash($object);
|
||||
|
||||
if ( isset($this->scheduledInsertions[$hash])) {
|
||||
continue;
|
||||
}
|
||||
if (isset($this->scheduledInsertions[$hash])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$metadata = $this->cmf->getMetadataFor(get_class($object));
|
||||
$changeSet = $this->computeChangeSet($metadata, $object);
|
||||
$metadata = $this->cmf->getMetadataFor($className);
|
||||
$changeSet = $this->computeChangeSet($metadata, $object);
|
||||
|
||||
if ($changeSet) {
|
||||
$changeSet['php_class'] = $metadata->name;
|
||||
$this->storageDriver->update($metadata->storageName, $this->identifiers[$hash], $changeSet);
|
||||
if ($changeSet) {
|
||||
$changeSet['php_class'] = $metadata->name;
|
||||
$this->storageDriver->update($metadata->storageName, $this->identifiers[$hash], $changeSet);
|
||||
|
||||
if ($this->storageDriver->supportsPartialUpdates()) {
|
||||
$this->originalData[$hash] = array_merge($this->originalData[$hash], $changeSet);
|
||||
} else {
|
||||
$this->originalData[$hash] = $changeSet;
|
||||
if ($this->storageDriver->supportsPartialUpdates()) {
|
||||
$this->originalData[$hash] = array_merge($this->originalData[$hash], $changeSet);
|
||||
} else {
|
||||
$this->originalData[$hash] = $changeSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,8 +242,8 @@ class UnitOfWork
|
||||
$id = $this->idHandler->getIdentifier($class, $object);
|
||||
$id = $this->idConverter->serialize($class, $id);
|
||||
|
||||
if ( ! $id) {
|
||||
throw new \RuntimeException("Trying to persist entity that has no id.");
|
||||
if (! $id) {
|
||||
throw new \RuntimeException('Trying to persist entity that has no id.');
|
||||
}
|
||||
|
||||
$data = $this->getObjectSnapshot($class, $object);
|
||||
@@ -227,9 +254,9 @@ class UnitOfWork
|
||||
|
||||
$this->storageDriver->insert($class->storageName, $id, $data);
|
||||
|
||||
$this->originalData[$oid] = $data;
|
||||
$this->identifiers[$oid] = $id;
|
||||
$this->identityMap[$idHash] = $object;
|
||||
$this->originalData[$oid] = $data;
|
||||
$this->identifiers[$oid] = $id;
|
||||
$this->identityMap[$class->name][$idHash] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +270,7 @@ class UnitOfWork
|
||||
|
||||
$this->storageDriver->delete($class->storageName, $id);
|
||||
|
||||
unset($this->identifiers[$oid], $this->originalData[$oid], $this->identityMap[$idHash]);
|
||||
unset($this->identifiers[$oid], $this->originalData[$oid], $this->identityMap[$class->name][$idHash]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,17 +280,16 @@ class UnitOfWork
|
||||
$this->processInsertions();
|
||||
$this->processDeletions();
|
||||
|
||||
$this->scheduledInsertions = array();
|
||||
$this->scheduledDeletions = array();
|
||||
$this->scheduledInsertions = [];
|
||||
$this->scheduledDeletions = [];
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
$this->scheduledInsertions = array();
|
||||
$this->scheduledDeletions = array();
|
||||
$this->identifiers = array();
|
||||
$this->originalData = array();
|
||||
$this->identityMap = array();
|
||||
$this->scheduledInsertions = [];
|
||||
$this->scheduledDeletions = [];
|
||||
$this->identifiers = [];
|
||||
$this->originalData = [];
|
||||
$this->identityMap = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore;
|
||||
|
||||
use Doctrine\KeyValueStore\Configuration;
|
||||
@@ -16,17 +35,16 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
public function testDefaultCacheDriver()
|
||||
{
|
||||
$config = new Configuration();
|
||||
$cache = $config->getMetadataCache();
|
||||
$cache = $config->getMetadataCache();
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Common\Cache\Cache', $cache);
|
||||
}
|
||||
|
||||
public function testDefaultIdConverterStrategy()
|
||||
{
|
||||
$config = new Configuration();
|
||||
$config = new Configuration();
|
||||
$strategy = $config->getIdConverterStrategy();
|
||||
|
||||
$this->assertInstanceOf('Doctrine\KeyValueStore\Id\NullIdConverter', $strategy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,7 +14,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
@@ -30,7 +31,6 @@ abstract class BasicCrudTestCase extends KeyValueStoreTestCase
|
||||
public function setUp()
|
||||
{
|
||||
$this->storage = $this->createStorage();
|
||||
$this->manager = $this->createManager($this->storage);
|
||||
}
|
||||
|
||||
abstract protected function createStorage();
|
||||
@@ -41,12 +41,17 @@ abstract class BasicCrudTestCase extends KeyValueStoreTestCase
|
||||
|
||||
abstract protected function find($id);
|
||||
|
||||
public function testPersistItem()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testPersistItem($mappingDriver)
|
||||
{
|
||||
$post = new Post();
|
||||
$post->id = "1";
|
||||
$post->headline = "asdf";
|
||||
$post->text = "foo";
|
||||
$this->manager = $this->createManager($this->storage, $mappingDriver);
|
||||
|
||||
$post = new Post();
|
||||
$post->id = '1';
|
||||
$post->headline = 'asdf';
|
||||
$post->text = 'foo';
|
||||
|
||||
$this->manager->persist($post);
|
||||
$this->manager->flush();
|
||||
@@ -54,12 +59,17 @@ abstract class BasicCrudTestCase extends KeyValueStoreTestCase
|
||||
$this->assertKeyExists($post->id);
|
||||
}
|
||||
|
||||
public function testPersistAndRetrieveItem()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testPersistAndRetrieveItem($mappingDriver)
|
||||
{
|
||||
$post = new Post();
|
||||
$post->id = "1";
|
||||
$post->headline = "asdf";
|
||||
$post->text = "foo";
|
||||
$this->manager = $this->createManager($this->storage, $mappingDriver);
|
||||
|
||||
$post = new Post();
|
||||
$post->id = '1';
|
||||
$post->headline = 'asdf';
|
||||
$post->text = 'foo';
|
||||
|
||||
$this->manager->persist($post);
|
||||
$this->manager->flush();
|
||||
@@ -68,9 +78,14 @@ abstract class BasicCrudTestCase extends KeyValueStoreTestCase
|
||||
$this->assertSame($post, $post2);
|
||||
}
|
||||
|
||||
public function testRetrieveItem()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testRetrieveItem($mappingDriver)
|
||||
{
|
||||
$this->populate(1, array('id' => 1, 'headline' => 'test', 'body' => 'tset', 'foo' => 'bar', 'php_class' => __NAMESPACE__ . '\\Post'));
|
||||
$this->manager = $this->createManager($this->storage, $mappingDriver);
|
||||
|
||||
$this->populate(1, ['id' => 1, 'headline' => 'test', 'body' => 'tset', 'foo' => 'bar', 'php_class' => __NAMESPACE__ . '\\Post']);
|
||||
|
||||
$post = $this->manager->find(__NAMESPACE__ . '\\Post', 1);
|
||||
|
||||
@@ -82,39 +97,49 @@ abstract class BasicCrudTestCase extends KeyValueStoreTestCase
|
||||
$this->assertSame($post, $post2);
|
||||
}
|
||||
|
||||
public function testUpdateClass()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testUpdateClass($mappingDriver)
|
||||
{
|
||||
$post = new Post();
|
||||
$post->id = "1";
|
||||
$post->headline = "asdf";
|
||||
$post->text = "foo";
|
||||
$this->manager = $this->createManager($this->storage, $mappingDriver);
|
||||
|
||||
$post = new Post();
|
||||
$post->id = '1';
|
||||
$post->headline = 'asdf';
|
||||
$post->text = 'foo';
|
||||
|
||||
$this->manager->persist($post);
|
||||
$this->manager->flush();
|
||||
|
||||
$post->body = "bar";
|
||||
$post->text = "baz";
|
||||
$post->body = 'bar';
|
||||
$post->text = 'baz';
|
||||
|
||||
$this->manager->flush();
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'id' => 1,
|
||||
'headline' => 'asdf',
|
||||
'body' => 'bar',
|
||||
'text' => 'baz',
|
||||
'php_class' => __NAMESPACE__ . '\\Post'
|
||||
),
|
||||
[
|
||||
'id' => 1,
|
||||
'headline' => 'asdf',
|
||||
'body' => 'bar',
|
||||
'text' => 'baz',
|
||||
'php_class' => __NAMESPACE__ . '\\Post',
|
||||
],
|
||||
$this->find(1)
|
||||
);
|
||||
}
|
||||
|
||||
public function testRemoveClass()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testRemoveClass($mappingDriver)
|
||||
{
|
||||
$post = new Post();
|
||||
$post->id = "1";
|
||||
$post->headline = "asdf";
|
||||
$post->text = "foo";
|
||||
$this->manager = $this->createManager($this->storage, $mappingDriver);
|
||||
|
||||
$post = new Post();
|
||||
$post->id = '1';
|
||||
$post->headline = 'asdf';
|
||||
$post->text = 'foo';
|
||||
|
||||
$this->manager->persist($post);
|
||||
$this->manager->flush();
|
||||
@@ -126,6 +151,15 @@ abstract class BasicCrudTestCase extends KeyValueStoreTestCase
|
||||
|
||||
$this->assertKeyNotExists($post->id);
|
||||
}
|
||||
|
||||
public function mappingDrivers()
|
||||
{
|
||||
return [
|
||||
['annotation'],
|
||||
['yaml'],
|
||||
['xml'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,5 +171,4 @@ class Post
|
||||
public $id;
|
||||
public $headline;
|
||||
public $body;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Functional;
|
||||
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
@@ -11,28 +30,27 @@ class CompositeBasicCrudTest extends BasicCrudTestCase
|
||||
protected function createStorage()
|
||||
{
|
||||
$this->cache = new ArrayCache();
|
||||
$storage = new DoctrineCacheStorage($this->cache);
|
||||
$storage = new DoctrineCacheStorage($this->cache);
|
||||
return $storage;
|
||||
}
|
||||
|
||||
public function assertKeyExists($id)
|
||||
{
|
||||
$this->assertTrue($this->cache->contains("post-oid:id=".$id.";"));
|
||||
$this->assertTrue($this->cache->contains('post-oid:id=' . $id . ';'));
|
||||
}
|
||||
|
||||
public function assertKeyNotExists($id)
|
||||
{
|
||||
$this->assertFalse($this->cache->contains("post-oid:id=".$id.";"));
|
||||
$this->assertFalse($this->cache->contains('post-oid:id=' . $id . ';'));
|
||||
}
|
||||
|
||||
public function populate($id, array $data)
|
||||
{
|
||||
$this->cache->save("post-oid:id=".$id.";", $data);
|
||||
$this->cache->save('post-oid:id=' . $id . ';', $data);
|
||||
}
|
||||
|
||||
public function find($id)
|
||||
{
|
||||
return $this->cache->fetch("post-oid:id=".$id.";");
|
||||
return $this->cache->fetch('post-oid:id=' . $id . ';');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Functional;
|
||||
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\KeyValueStore\Mapping\Annotations as KVS;
|
||||
use Doctrine\KeyValueStore\Storage\DoctrineCacheStorage;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\Tests\KeyValueStoreTestCase;
|
||||
|
||||
class InheritanceTest extends KeyValueStoreTestCase
|
||||
@@ -11,24 +30,24 @@ class InheritanceTest extends KeyValueStoreTestCase
|
||||
private $manager;
|
||||
protected $storage;
|
||||
|
||||
public function setUp()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testInheritance($mappingDriver)
|
||||
{
|
||||
$cache = new ArrayCache();
|
||||
$storage = new DoctrineCacheStorage($cache);
|
||||
$this->manager = $this->createManager($storage);
|
||||
}
|
||||
$cache = new ArrayCache();
|
||||
$storage = new DoctrineCacheStorage($cache);
|
||||
$this->manager = $this->createManager($storage, $mappingDriver);
|
||||
|
||||
public function testInheritance()
|
||||
{
|
||||
$parent = new ParentEntity;
|
||||
$parent->id = 1;
|
||||
$parent->foo = "foo";
|
||||
$parent = new ParentEntity;
|
||||
$parent->id = 1;
|
||||
$parent->foo = 'foo';
|
||||
$this->manager->persist($parent);
|
||||
|
||||
$child = new ChildEntity;
|
||||
$child->id = 2;
|
||||
$child->foo = "bar";
|
||||
$child->bar = "baz";
|
||||
$child = new ChildEntity;
|
||||
$child->id = 2;
|
||||
$child->foo = 'bar';
|
||||
$child->bar = 'baz';
|
||||
|
||||
$this->manager->persist($child);
|
||||
$this->manager->flush();
|
||||
@@ -45,6 +64,15 @@ class InheritanceTest extends KeyValueStoreTestCase
|
||||
$this->assertEquals('bar', $child->foo);
|
||||
$this->assertEquals('baz', $child->bar);
|
||||
}
|
||||
|
||||
public function mappingDrivers()
|
||||
{
|
||||
return [
|
||||
['annotation'],
|
||||
['yaml'],
|
||||
['xml'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,41 +14,50 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Functional;
|
||||
|
||||
use Doctrine\Tests\KeyValueStoreTestCase;
|
||||
use Doctrine\KeyValueStore\Mapping\Annotations as KVS;
|
||||
use Doctrine\Tests\KeyValueStoreTestCase;
|
||||
|
||||
class PersistTest extends KeyValueStoreTestCase
|
||||
{
|
||||
public function testPersistUnmappedThrowsException()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testPersistUnmappedThrowsException($mappingDriver)
|
||||
{
|
||||
$manager = $this->createManager();
|
||||
$manager = $this->createManager(null, $mappingDriver);
|
||||
|
||||
$this->setExpectedException('InvalidArgumentException', 'stdClass is not a valid key-value-store entity.');
|
||||
$manager->persist(new \stdClass());
|
||||
}
|
||||
|
||||
public function testPersistWithoutIdThrowsException()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testPersistWithoutIdThrowsException($mappingDriver)
|
||||
{
|
||||
$manager = $this->createManager();
|
||||
$manager = $this->createManager(null, $mappingDriver);
|
||||
$persist = new PersistEntity();
|
||||
|
||||
$this->setExpectedException('RuntimeException', 'Trying to persist entity that has no id.');
|
||||
$manager->persist($persist);
|
||||
}
|
||||
|
||||
public function testPersistKnownIdThrowsException()
|
||||
/**
|
||||
* @dataProvider mappingDrivers
|
||||
*/
|
||||
public function testPersistKnownIdThrowsException($mappingDriver)
|
||||
{
|
||||
$manager = $this->createManager();
|
||||
$persist = new PersistEntity();
|
||||
$manager = $this->createManager(null, $mappingDriver);
|
||||
$persist = new PersistEntity();
|
||||
$persist->id = 1;
|
||||
|
||||
$persist2 = new PersistEntity();
|
||||
$persist2 = new PersistEntity();
|
||||
$persist2->id = 1;
|
||||
|
||||
$manager->persist($persist);
|
||||
@@ -55,6 +65,15 @@ class PersistTest extends KeyValueStoreTestCase
|
||||
$this->setExpectedException('RuntimeException', 'Object with ID already exists.');
|
||||
$manager->persist($persist2);
|
||||
}
|
||||
|
||||
public function mappingDrivers()
|
||||
{
|
||||
return [
|
||||
['annotation'],
|
||||
['yaml'],
|
||||
['xml'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Functional;
|
||||
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
@@ -11,23 +30,23 @@ class SingleBasicCrudTest extends BasicCrudTestCase
|
||||
protected function createStorage()
|
||||
{
|
||||
$this->cache = new ArrayCache();
|
||||
$storage = new DoctrineCacheStorage($this->cache, false);
|
||||
$storage = new DoctrineCacheStorage($this->cache, false);
|
||||
return $storage;
|
||||
}
|
||||
|
||||
public function assertKeyExists($id)
|
||||
{
|
||||
$this->assertTrue($this->cache->contains("post-".$id));
|
||||
$this->assertTrue($this->cache->contains('post-' . $id));
|
||||
}
|
||||
|
||||
public function assertKeyNotExists($id)
|
||||
{
|
||||
$this->assertFalse($this->cache->contains("post-".$id));
|
||||
$this->assertFalse($this->cache->contains('post-' . $id));
|
||||
}
|
||||
|
||||
public function populate($id, array $data)
|
||||
{
|
||||
$this->cache->save("post-".$id, $data);
|
||||
$this->cache->save('post-' . $id, $data);
|
||||
}
|
||||
|
||||
public function find($id)
|
||||
@@ -35,4 +54,3 @@ class SingleBasicCrudTest extends BasicCrudTestCase
|
||||
return $this->storage->find('post', $id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Functional\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\KeyValueStore\Storage\AzureSdkTableStorage;
|
||||
use Doctrine\Tests\KeyValueStoreTestCase;
|
||||
use WindowsAzure\Common\ServicesBuilder;
|
||||
|
||||
class AzureSdkTableTest extends KeyValueStoreTestCase
|
||||
{
|
||||
private $storage;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (empty($GLOBALS['DOCTRINE_KEYVALUE_AZURE_NAME']) || empty($GLOBALS['DOCTRINE_KEYVALUE_AZURE_KEY'])) {
|
||||
$this->markTestSkipped('Missing Azure credentials.');
|
||||
}
|
||||
|
||||
$connectionString = sprintf(
|
||||
'DefaultEndpointsProtocol=http;AccountName=%s;AccountKey=%s',
|
||||
$GLOBALS['DOCTRINE_KEYVALUE_AZURE_NAME'],
|
||||
$GLOBALS['DOCTRINE_KEYVALUE_AZURE_KEY']
|
||||
);
|
||||
$tableProxy = ServicesBuilder::getInstance()->createTableService($connectionString);
|
||||
|
||||
$this->storage = new AzureSdkTableStorage($tableProxy);
|
||||
}
|
||||
|
||||
public function testCrud()
|
||||
{
|
||||
$storage = $this->storage;
|
||||
|
||||
$key = ['dist' => 'sdktest', 'range' => time()];
|
||||
$storage->insert('test', $key, ['foo' => 'bar']);
|
||||
$data = $storage->find('test', $key);
|
||||
|
||||
$this->assertInstanceOf('DateTime', $data['Timestamp']);
|
||||
$this->assertEquals('bar', $data['foo']);
|
||||
$this->assertEquals('sdktest', $data['dist']);
|
||||
$this->assertEquals($key['range'], $data['range']);
|
||||
|
||||
$storage->update('test', $key, ['foo' => 'baz', 'bar' => 'baz']);
|
||||
$data = $storage->find('test', $key);
|
||||
|
||||
$this->assertEquals('baz', $data['foo']);
|
||||
$this->assertEquals('baz', $data['bar']);
|
||||
|
||||
$storage->delete('test', $key);
|
||||
|
||||
$this->setExpectedException("Doctrine\KeyValueStore\NotFoundException");
|
||||
$storage->find('test', $key);
|
||||
}
|
||||
|
||||
public function testTypes()
|
||||
{
|
||||
$storage = $this->storage;
|
||||
|
||||
$data = [
|
||||
'string' => 'foo',
|
||||
'date' => new \DateTime('now'),
|
||||
'int' => 1234,
|
||||
'float' => 123.45,
|
||||
'bool' => false,
|
||||
];
|
||||
|
||||
$key = ['dist' => 'sdktest', 'range' => time()+1];
|
||||
$storage->insert('test', $key, $data);
|
||||
$data = $storage->find('test', $key);
|
||||
|
||||
$this->assertInstanceOf('DateTime', $data['date']);
|
||||
$this->assertInternalType('string', $data['string']);
|
||||
$this->assertInternalType('int', $data['int']);
|
||||
$this->assertInternalType('float', $data['float']);
|
||||
$this->assertInternalType('bool', $data['bool']);
|
||||
}
|
||||
|
||||
public function testQueryRange()
|
||||
{
|
||||
$rangeQuery = new RangeQuery($this->createManager(), 'test', 'sdktest');
|
||||
$rangeQuery->rangeLessThan(time());
|
||||
|
||||
$data = $this->storage->executeRangeQuery($rangeQuery, 'test', ['dist', 'range'], function ($row) {
|
||||
return $row;
|
||||
});
|
||||
|
||||
$this->assertTrue(count($data) > 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Functional\Storage;
|
||||
|
||||
use Cassandra;
|
||||
use Doctrine\KeyValueStore\Storage\CassandraStorage;
|
||||
|
||||
/**
|
||||
* @requires extension cassandra
|
||||
*/
|
||||
class CassandraTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $session;
|
||||
private $storage;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$cluster = Cassandra::cluster()->build();
|
||||
$this->session = $cluster->connect();
|
||||
|
||||
try {
|
||||
$this->session->execute(new \Cassandra\SimpleStatement('DROP KEYSPACE doctrine'));
|
||||
} catch (\Cassandra\Exception\RuntimeException $e) {
|
||||
// Cannot drop non existing keyspace 'doctrine'.
|
||||
}
|
||||
|
||||
$cql = "CREATE KEYSPACE doctrine WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };";
|
||||
$statement = new \Cassandra\SimpleStatement($cql);
|
||||
$this->session->execute($statement);
|
||||
|
||||
$this->session->execute(new \Cassandra\SimpleStatement('USE doctrine'));
|
||||
|
||||
$cql = 'CREATE TABLE books (id int, author text, title text, PRIMARY KEY (id));';
|
||||
|
||||
$this->session->execute(new \Cassandra\SimpleStatement($cql));
|
||||
$this->storage = new CassandraStorage($this->session);
|
||||
}
|
||||
|
||||
public function testInsert()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$this->storage->insert('books', ['id' => 1], $data);
|
||||
|
||||
$cql = 'SELECT * FROM books WHERE id = 1';
|
||||
$result = $this->session->execute(new \Cassandra\SimpleStatement($cql));
|
||||
$rows = iterator_to_array($result);
|
||||
|
||||
$this->assertEquals('1', $rows[0]['id']);
|
||||
$this->assertEquals('John Doe', $rows[0]['author']);
|
||||
$this->assertEquals('example book', $rows[0]['title']);
|
||||
}
|
||||
|
||||
public function testFind()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$this->storage->insert('books', ['id' => 2], $data);
|
||||
|
||||
$this->assertEquals($data, $this->storage->find('books', ['id' => 2]));
|
||||
}
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$this->storage->insert('books', ['id' => 3], $data);
|
||||
$this->storage->update('books', ['id' => 3], ['author' => 'Jane Doe']);
|
||||
|
||||
$this->assertEquals(
|
||||
['author' => 'Jane Doe', 'title' => 'example book'],
|
||||
$this->storage->find('books', ['id' => 3])
|
||||
);
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$this->storage->insert('books', ['id' => 4], $data);
|
||||
$this->storage->delete('books', ['id' => 4]);
|
||||
|
||||
$this->setExpectedException('Doctrine\KeyValueStore\NotFoundException');
|
||||
|
||||
$this->storage->find('books', ['id' => 4]);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Functional\Storage;
|
||||
|
||||
use Doctrine\Tests\KeyValueStoreTestCase;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTableStorage;
|
||||
use Doctrine\KeyValueStore\Http\SocketClient;
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\SharedKeyLiteAuthorization;
|
||||
use Doctrine\KeyValueStore\Http\SocketClient;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTableStorage;
|
||||
use Doctrine\Tests\KeyValueStoreTestCase;
|
||||
|
||||
class WindowsAzureTableTest extends KeyValueStoreTestCase
|
||||
{
|
||||
@@ -16,7 +35,7 @@ class WindowsAzureTableTest extends KeyValueStoreTestCase
|
||||
parent::setUp();
|
||||
|
||||
if (empty($GLOBALS['DOCTRINE_KEYVALUE_AZURE_NAME']) || empty($GLOBALS['DOCTRINE_KEYVALUE_AZURE_KEY'])) {
|
||||
$this->markTestSkipped("Missing Azure credentials.");
|
||||
$this->markTestSkipped('Missing Azure credentials.');
|
||||
}
|
||||
|
||||
switch ($GLOBALS['DOCTRINE_KEYVALUE_AZURE_AUTHSCHEMA']) {
|
||||
@@ -39,24 +58,25 @@ class WindowsAzureTableTest extends KeyValueStoreTestCase
|
||||
{
|
||||
$storage = $this->storage;
|
||||
|
||||
$key = array("dist" => "foo", "range" => time());
|
||||
$storage->insert("test", $key, array("foo" => "bar"));
|
||||
$data = $storage->find("test", $key);
|
||||
$key = ['dist' => 'foo', 'range' => time()];
|
||||
$storage->insert('test', $key, ['foo' => 'bar']);
|
||||
$data = $storage->find('test', $key);
|
||||
|
||||
$this->assertInstanceOf('DateTime', $data['Timestamp']);
|
||||
$this->assertEquals('bar', $data['foo']);
|
||||
$this->assertEquals('foo', $data['dist']);
|
||||
$this->assertEquals($key['range'], $data['range']);
|
||||
|
||||
$storage->update("test", $key, array("foo" => "baz", "bar" => "baz"));
|
||||
$data = $storage->find("test", $key);
|
||||
$storage->update('test', $key, ['foo' => 'baz', 'bar' => 'baz']);
|
||||
$data = $storage->find('test', $key);
|
||||
|
||||
$this->assertEquals('baz', $data['foo']);
|
||||
$this->assertEquals('baz', $data['bar']);
|
||||
|
||||
$storage->delete("test", $key);
|
||||
$data = $storage->find("test", $key);
|
||||
$this->assertEquals(array(), $data);
|
||||
$storage->delete('test', $key);
|
||||
|
||||
$this->setExpectedException("Doctrine\KeyValueStore\NotFoundException");
|
||||
$storage->find('test', $key);
|
||||
}
|
||||
|
||||
public function testQueryRange()
|
||||
@@ -64,11 +84,10 @@ class WindowsAzureTableTest extends KeyValueStoreTestCase
|
||||
$rangeQuery = new RangeQuery($this->createManager(), 'test', 'foo');
|
||||
$rangeQuery->rangeLessThan(time());
|
||||
|
||||
$data = $this->storage->executeRangeQuery($rangeQuery, 'test', array('dist', 'range'), function($row) {
|
||||
$data = $this->storage->executeRangeQuery($rangeQuery, 'test', ['dist', 'range'], function ($row) {
|
||||
return $row;
|
||||
});
|
||||
|
||||
$this->assertTrue(count($data) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Mapping;
|
||||
|
||||
use Doctrine\KeyValueStore\Mapping\ClassMetadata;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Doctrine\KeyValueStore\Mapping\ClassMetadata
|
||||
*/
|
||||
class ClassMetadataTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $metadata;
|
||||
@@ -20,34 +43,147 @@ class ClassMetadataTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testIdentifier()
|
||||
{
|
||||
$this->metadata->mapIdentifier("id");
|
||||
$this->metadata->mapIdentifier('id');
|
||||
$this->assertFalse($this->metadata->isCompositeKey);
|
||||
|
||||
$this->metadata->mapIdentifier("id2");
|
||||
$this->metadata->mapIdentifier('id2');
|
||||
|
||||
$this->assertEquals(array("id", "id2"), $this->metadata->identifier);
|
||||
$this->assertEquals(['id', 'id2'], $this->metadata->identifier);
|
||||
$this->assertTrue($this->metadata->isCompositeKey);
|
||||
}
|
||||
|
||||
public function testIdentifierfield()
|
||||
{
|
||||
$this->metadata->mapIdentifier("id");
|
||||
$this->metadata->mapIdentifier('id');
|
||||
|
||||
$this->assertEquals(array('id' => array('fieldName' => 'id', 'id' => true)), $this->metadata->fields);
|
||||
$this->assertEquals(['id' => ['fieldName' => 'id', 'id' => true]], $this->metadata->fields);
|
||||
}
|
||||
|
||||
public function testMapField()
|
||||
{
|
||||
$this->metadata->mapField(array('fieldName' => 'metadata'));
|
||||
$this->assertEquals(array('metadata' => array('fieldName' => 'metadata')), $this->metadata->fields);
|
||||
$this->metadata->mapField(['fieldName' => 'metadata']);
|
||||
$this->assertEquals(['metadata' => ['fieldName' => 'metadata']], $this->metadata->fields);
|
||||
}
|
||||
|
||||
public function testSkipTransientColumns()
|
||||
{
|
||||
$this->metadata->skipTransientField('metadata');
|
||||
$this->metadata->mapField(array('fieldName' => 'metadata'));
|
||||
$this->metadata->mapField(['fieldName' => 'metadata']);
|
||||
|
||||
$this->assertEquals(array(), $this->metadata->fields);
|
||||
$this->assertEquals([], $this->metadata->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getIdentifier
|
||||
*/
|
||||
public function testGetIdentifier()
|
||||
{
|
||||
$identifier = $this->metadata->getIdentifier();
|
||||
|
||||
$this->assertInternalType('array', $identifier);
|
||||
|
||||
foreach ($identifier as $key => $value) {
|
||||
$this->assertInternalType('integer', $key);
|
||||
$this->assertInternalType('string', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getReflectionClass
|
||||
*/
|
||||
public function testGetReflectionClass()
|
||||
{
|
||||
$reflectionClass = $this->metadata->getReflectionClass();
|
||||
|
||||
$this->assertInstanceOf(ReflectionClass::class, $reflectionClass);
|
||||
$this->assertSame(__CLASS__, $reflectionClass->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isIdentifier
|
||||
*/
|
||||
public function testIsIdentifier()
|
||||
{
|
||||
$this->metadata->mapIdentifier('id');
|
||||
|
||||
$this->assertTrue($this->metadata->isIdentifier('id'));
|
||||
$this->assertFalse($this->metadata->isIdentifier('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::hasField
|
||||
*/
|
||||
public function testHasField()
|
||||
{
|
||||
$this->metadata->mapField(['fieldName' => 'foo']);
|
||||
|
||||
$this->assertTrue($this->metadata->hasField('foo'));
|
||||
$this->assertFalse($this->metadata->hasField('bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::hasAssociation
|
||||
*/
|
||||
public function testHasAssociation()
|
||||
{
|
||||
$this->assertFalse($this->metadata->hasAssociation(sha1(rand())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isSingleValuedAssociation
|
||||
*/
|
||||
public function testIsSingleValuedAssociation()
|
||||
{
|
||||
$this->assertFalse($this->metadata->isSingleValuedAssociation(sha1(rand())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isCollectionValuedAssociation
|
||||
*/
|
||||
public function testIsCollectionValuedAssociation()
|
||||
{
|
||||
$this->assertFalse($this->metadata->isCollectionValuedAssociation(sha1(rand())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getFieldNames
|
||||
*/
|
||||
public function testGetFieldNames()
|
||||
{
|
||||
$this->metadata->mapField(['fieldName' => 'foo']);
|
||||
|
||||
$fieldNames = $this->metadata->getFieldNames();
|
||||
|
||||
$this->assertInternalType('array', $fieldNames);
|
||||
|
||||
foreach ($fieldNames as $key => $value) {
|
||||
$this->assertInternalType('integer', $key);
|
||||
$this->assertInternalType('string', $value);
|
||||
}
|
||||
|
||||
$this->assertSame(['foo'], $fieldNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getIdentifierFieldNames
|
||||
*/
|
||||
public function testGetIdentifierFieldNames()
|
||||
{
|
||||
$identifierFieldNames = $this->metadata->getIdentifierFieldNames();
|
||||
|
||||
$this->assertInternalType('array', $identifierFieldNames);
|
||||
|
||||
foreach ($identifierFieldNames as $key => $value) {
|
||||
$this->assertInternalType('integer', $key);
|
||||
$this->assertInternalType('string', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isAssociationInverseSide
|
||||
*/
|
||||
public function testIsAssociationInverseSide()
|
||||
{
|
||||
$this->assertFalse($this->metadata->isAssociationInverseSide(sha1(rand())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
250
tests/Doctrine/Tests/KeyValueStore/Query/RangeQueryTest.php
Normal file
250
tests/Doctrine/Tests/KeyValueStore/Query/RangeQueryTest.php
Normal file
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Query;
|
||||
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\KeyValueStore\EntityManager;
|
||||
use Doctrine\KeyValueStore\Query\RangeQuery;
|
||||
use Doctrine\KeyValueStore\Storage\DoctrineCacheStorage;
|
||||
use PHPUnit_Framework_TestCase;
|
||||
use ReflectionClass;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Doctrine\KeyValueStore\Query\RangeQuery
|
||||
*/
|
||||
class RangeQueryTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var EntityManager
|
||||
*/
|
||||
private $entityManager;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $className;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $partitionKey;
|
||||
|
||||
/**
|
||||
* @var RangeQuery
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Sets up the fixture, for example, opens a network connection.
|
||||
* This method is called before a test is executed.
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$this->entityManager = $this
|
||||
->getMockBuilder(EntityManager::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->className = sha1(rand());
|
||||
$this->partitionKey = sha1(rand());
|
||||
|
||||
$this->object = new RangeQuery(
|
||||
$this->entityManager,
|
||||
$this->className,
|
||||
$this->partitionKey
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::setLimit
|
||||
* @covers ::getLimit
|
||||
*/
|
||||
public function testLimit()
|
||||
{
|
||||
$limit = rand();
|
||||
|
||||
$setterOutput = $this->object->setLimit($limit);
|
||||
|
||||
$this->assertInstanceOf(RangeQuery::class, $setterOutput);
|
||||
$this->assertSame($limit, $this->object->getLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getClassName
|
||||
*/
|
||||
public function testGetClassName()
|
||||
{
|
||||
$this->assertSame(
|
||||
$this->className,
|
||||
$this->object->getClassName()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getPartitionKey
|
||||
*/
|
||||
public function testGetPartitionKey()
|
||||
{
|
||||
$this->assertSame(
|
||||
$this->partitionKey,
|
||||
$this->object->getPartitionKey()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getConditions
|
||||
*/
|
||||
public function testGetConditions()
|
||||
{
|
||||
$reflectionClass = new ReflectionClass($this->object);
|
||||
$constants = $reflectionClass->getConstants();
|
||||
|
||||
$conditions = $this->object->getConditions();
|
||||
|
||||
$this->assertInternalType('array', $conditions);
|
||||
|
||||
foreach ($conditions as $condition) {
|
||||
$this->assertArrayHasKey($condition[0], $constants);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::rangeEquals
|
||||
* @depends testGetConditions
|
||||
*/
|
||||
public function testRangeEquals()
|
||||
{
|
||||
$value = 'test';
|
||||
|
||||
$output = $this->object->rangeEquals($value);
|
||||
$this->assertInstanceOf(RangeQuery::class, $output);
|
||||
|
||||
$conditions = $this->object->getConditions();
|
||||
$this->assertArraySubset(
|
||||
[[RangeQuery::CONDITION_EQ, $value]],
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::rangeNotEquals
|
||||
* @depends testGetConditions
|
||||
*/
|
||||
public function testRangeNotEquals()
|
||||
{
|
||||
$value = 'test';
|
||||
|
||||
$output = $this->object->rangeNotEquals($value);
|
||||
$this->assertInstanceOf(RangeQuery::class, $output);
|
||||
|
||||
$conditions = $this->object->getConditions();
|
||||
$this->assertArraySubset(
|
||||
[[RangeQuery::CONDITION_NEQ, $value]],
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::rangeLessThan
|
||||
* @depends testGetConditions
|
||||
*/
|
||||
public function testRangeLessThan()
|
||||
{
|
||||
$value = 'test';
|
||||
|
||||
$output = $this->object->rangeLessThan($value);
|
||||
$this->assertInstanceOf(RangeQuery::class, $output);
|
||||
|
||||
$conditions = $this->object->getConditions();
|
||||
$this->assertArraySubset(
|
||||
[[RangeQuery::CONDITION_LT, $value]],
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::rangeLessThanEquals
|
||||
* @depends testGetConditions
|
||||
*/
|
||||
public function testRangeLessThanEquals()
|
||||
{
|
||||
$value = 'test';
|
||||
|
||||
$output = $this->object->rangeLessThanEquals($value);
|
||||
$this->assertInstanceOf(RangeQuery::class, $output);
|
||||
|
||||
$conditions = $this->object->getConditions();
|
||||
$this->assertArraySubset(
|
||||
[[RangeQuery::CONDITION_LE, $value]],
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::rangeGreaterThan
|
||||
* @depends testGetConditions
|
||||
*/
|
||||
public function testRangeGreaterThan()
|
||||
{
|
||||
$value = 'test';
|
||||
|
||||
$output = $this->object->rangeGreaterThan($value);
|
||||
$this->assertInstanceOf(RangeQuery::class, $output);
|
||||
|
||||
$conditions = $this->object->getConditions();
|
||||
$this->assertArraySubset(
|
||||
[[RangeQuery::CONDITION_GT, $value]],
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::rangeGreaterThanEquals
|
||||
* @depends testGetConditions
|
||||
*/
|
||||
public function testRangeGreaterThanEquals()
|
||||
{
|
||||
$value = 'test';
|
||||
|
||||
$output = $this->object->rangeGreaterThanEquals($value);
|
||||
$this->assertInstanceOf(RangeQuery::class, $output);
|
||||
|
||||
$conditions = $this->object->getConditions();
|
||||
$this->assertArraySubset(
|
||||
[[RangeQuery::CONDITION_GE, $value]],
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function testWrongExecute()
|
||||
{
|
||||
$this->entityManager
|
||||
->method('unwrap')
|
||||
->willReturn(new DoctrineCacheStorage(new ArrayCache));
|
||||
|
||||
$this->setExpectedException(RuntimeException::class);
|
||||
$this->object->execute();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
abstract class AbstractStorageTestCase extends \PHPUnit_Framework_TestCase
|
||||
@@ -20,19 +39,19 @@ abstract class AbstractStorageTestCase extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testInsertCompositeKey()
|
||||
{
|
||||
if ( ! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped("Composite keys need to be supported for this test to run.");
|
||||
if (! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped('Composite keys need to be supported for this test to run.');
|
||||
}
|
||||
|
||||
$key = array('dist' => 'foo', 'range' => 100);
|
||||
$data = array(
|
||||
'dist' => 'foo',
|
||||
'range' => 100,
|
||||
'name' => 'Test',
|
||||
'value' => 1,
|
||||
'amount' => 200.23,
|
||||
'timestamp' => new \DateTime("2012-03-26 12:12:12")
|
||||
);
|
||||
$key = ['dist' => 'foo', 'range' => 100];
|
||||
$data = [
|
||||
'dist' => 'foo',
|
||||
'range' => 100,
|
||||
'name' => 'Test',
|
||||
'value' => 1,
|
||||
'amount' => 200.23,
|
||||
'timestamp' => new \DateTime('2012-03-26 12:12:12'),
|
||||
];
|
||||
|
||||
$this->mockInsertCompositeKey($key, $data);
|
||||
$this->storage->insert('stdClass', $key, $data);
|
||||
@@ -40,19 +59,19 @@ abstract class AbstractStorageTestCase extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testUpdateCompositeKey()
|
||||
{
|
||||
if ( ! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped("Composite keys need to be supported for this test to run.");
|
||||
if (! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped('Composite keys need to be supported for this test to run.');
|
||||
}
|
||||
|
||||
$key = array('dist' => 'foo', 'range' => 100);
|
||||
$data = array(
|
||||
'dist' => 'foo',
|
||||
'range' => 100,
|
||||
'name' => 'Test',
|
||||
'value' => 1,
|
||||
'amount' => 200.23,
|
||||
'timestamp' => new \DateTime("2012-03-26 12:12:12")
|
||||
);
|
||||
$key = ['dist' => 'foo', 'range' => 100];
|
||||
$data = [
|
||||
'dist' => 'foo',
|
||||
'range' => 100,
|
||||
'name' => 'Test',
|
||||
'value' => 1,
|
||||
'amount' => 200.23,
|
||||
'timestamp' => new \DateTime('2012-03-26 12:12:12'),
|
||||
];
|
||||
|
||||
$this->mockUpdateCompositeKey($key, $data);
|
||||
$this->storage->update('stdClass', $key, $data);
|
||||
@@ -60,11 +79,11 @@ abstract class AbstractStorageTestCase extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testDeleteCompositeKey()
|
||||
{
|
||||
if ( ! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped("Composite keys need to be supported for this test to run.");
|
||||
if (! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped('Composite keys need to be supported for this test to run.');
|
||||
}
|
||||
|
||||
$key = array('dist' => 'foo', 'range' => 100);
|
||||
$key = ['dist' => 'foo', 'range' => 100];
|
||||
|
||||
$this->mockDeleteCompositeKey($key);
|
||||
$this->storage->delete('stdClass', $key);
|
||||
@@ -72,29 +91,28 @@ abstract class AbstractStorageTestCase extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFindCompositeKey()
|
||||
{
|
||||
if ( ! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped("Composite keys need to be supported for this test to run.");
|
||||
if (! $this->storage->supportsCompositePrimaryKeys()) {
|
||||
$this->markTestSkipped('Composite keys need to be supported for this test to run.');
|
||||
}
|
||||
|
||||
$key = array('dist' => 'foo', 'range' => 100);
|
||||
$key = ['dist' => 'foo', 'range' => 100];
|
||||
|
||||
$this->mockFindCompositeKey($key);
|
||||
$data = $this->storage->find('stdClass', $key);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'dist' => 'foo',
|
||||
'range' => '100',
|
||||
'timestamp' => new \DateTime('2008-09-18 23:46:19', new \DateTimeZone("UTC")),
|
||||
'name' => 'Test',
|
||||
'value' => 23,
|
||||
'amount' => 200.23,
|
||||
'bool' => true,
|
||||
), $data);
|
||||
$this->assertEquals([
|
||||
'dist' => 'foo',
|
||||
'range' => '100',
|
||||
'timestamp' => new \DateTime('2008-09-18 23:46:19', new \DateTimeZone('UTC')),
|
||||
'name' => 'Test',
|
||||
'value' => 23,
|
||||
'amount' => 200.23,
|
||||
'bool' => true,
|
||||
], $data);
|
||||
}
|
||||
|
||||
abstract function mockInsertCompositeKey($key, $data);
|
||||
abstract function mockUpdateCompositeKey($key, $data);
|
||||
abstract function mockDeleteCompositeKey($key);
|
||||
abstract function mockFindCompositeKey($key);
|
||||
abstract public function mockInsertCompositeKey($key, $data);
|
||||
abstract public function mockUpdateCompositeKey($key, $data);
|
||||
abstract public function mockDeleteCompositeKey($key);
|
||||
abstract public function mockFindCompositeKey($key);
|
||||
}
|
||||
|
||||
|
||||
102
tests/Doctrine/Tests/KeyValueStore/Storage/ArrayStorageTest.php
Normal file
102
tests/Doctrine/Tests/KeyValueStore/Storage/ArrayStorageTest.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\ArrayStorage;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* @author Emanuele Minotto <minottoemanuele@gmail.com>
|
||||
*/
|
||||
class ArrayStorageTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var ArrayStorage
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
protected function setup()
|
||||
{
|
||||
$this->storage = new ArrayStorage();
|
||||
}
|
||||
|
||||
public function testSupportsPartialUpdates()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsPartialUpdates());
|
||||
}
|
||||
|
||||
public function testSupportsCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testRequiresCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->requiresCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider methodsProvider
|
||||
*/
|
||||
public function testInsert($method)
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$this->storage->$method('foo', 'bar', $data);
|
||||
|
||||
$reflector = new ReflectionProperty(ArrayStorage::class, 'data');
|
||||
$reflector->setAccessible(true);
|
||||
|
||||
$storedValue = $reflector->getValue($this->storage);
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'foo' => [
|
||||
serialize('bar') => $data,
|
||||
],
|
||||
],
|
||||
$storedValue
|
||||
);
|
||||
|
||||
$this->storage->$method('foo', 'bar', $data);
|
||||
$this->assertCount(1, $storedValue);
|
||||
$this->assertCount(1, $storedValue['foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function methodsProvider()
|
||||
{
|
||||
return [
|
||||
['insert'],
|
||||
['update'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertEquals('array', $this->storage->getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\CouchDbStorage;
|
||||
|
||||
/**
|
||||
* CouchDb storage testcase
|
||||
*
|
||||
* @author Emanuele Minotto <minottoemanuele@gmail.com>
|
||||
*
|
||||
* @covers \Doctrine\KeyValueStore\Storage\CouchDbStorage
|
||||
*/
|
||||
class CouchDbStorageTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $couchdb;
|
||||
|
||||
/**
|
||||
* @var CouchDbStorage
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$client = $this->getMockBuilder('\Doctrine\CouchDB\HTTP\StreamClient')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->couchdb = $this->getMockBuilder('\Doctrine\CouchDB\CouchDBClient')
|
||||
->setConstructorArgs([
|
||||
$client,
|
||||
'test',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$this->storage = new CouchDbStorage($this->couchdb);
|
||||
}
|
||||
|
||||
public function testSupportsPartialUpdates()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsPartialUpdates());
|
||||
}
|
||||
|
||||
public function testSupportsCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testRequiresCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->requiresCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testInsert()
|
||||
{
|
||||
$data = range(0, 10);
|
||||
|
||||
$storedDataset = null;
|
||||
|
||||
$this->couchdb->expects($this->once())
|
||||
->method('putDocument')
|
||||
->will($this->returnCallback(function (array $data, $id) use (&$storedDataset) {
|
||||
$storedDataset = [$id, null];
|
||||
}));
|
||||
|
||||
$storageName = rand();
|
||||
$key = sha1(rand());
|
||||
|
||||
$this->storage->insert($storageName, $key, $data);
|
||||
$this->assertNotNull($storedDataset);
|
||||
|
||||
$this->assertSame([$storageName . '-' . $key, null], $storedDataset);
|
||||
}
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$data = range(0, 10);
|
||||
|
||||
$storedDataset = null;
|
||||
|
||||
$this->couchdb->method('putDocument')
|
||||
->will($this->returnCallback(function (array $data, $id) use (&$storedDataset) {
|
||||
$storedDataset = [$id, null];
|
||||
}));
|
||||
|
||||
$storageName = rand();
|
||||
$key = sha1(rand());
|
||||
|
||||
$this->storage->insert($storageName, $key, $data);
|
||||
$this->assertNotNull($storedDataset);
|
||||
|
||||
$this->assertSame([$storageName . '-' . $key, null], $storedDataset);
|
||||
|
||||
$data = range(0, 20);
|
||||
|
||||
$this->storage->insert($storageName, $key, $data);
|
||||
$this->assertNotNull($storedDataset);
|
||||
|
||||
$this->assertSame([$storageName . '-' . $key, null], $storedDataset);
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$storedDataset = [
|
||||
'test-foobar' => [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
],
|
||||
];
|
||||
|
||||
$this->couchdb->expects($this->once())
|
||||
->method('deleteDocument')
|
||||
->will($this->returnCallback(function ($key) use (&$storedDataset) {
|
||||
foreach ($storedDataset as $id => $row) {
|
||||
if ($id === $key) {
|
||||
unset($storedDataset[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
$this->storage->delete('test', 'foobar');
|
||||
|
||||
$this->assertCount(0, $storedDataset);
|
||||
}
|
||||
|
||||
public function testFind()
|
||||
{
|
||||
$storedDataset = [
|
||||
'test-foobar' => [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
],
|
||||
];
|
||||
|
||||
$this->couchdb->expects($this->once())
|
||||
->method('findDocument')
|
||||
->will($this->returnCallback(function ($key) use (&$storedDataset) {
|
||||
if (isset($storedDataset[$key])) {
|
||||
return $storedDataset[$key];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
));
|
||||
|
||||
$data = $this->storage->find('test', 'foobar');
|
||||
|
||||
$this->assertEquals($storedDataset['test-foobar'], $data);
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertEquals('couchdb', $this->storage->getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\CouchbaseStorage;
|
||||
|
||||
/**
|
||||
* Couchbase storage testcase
|
||||
*
|
||||
* @author Simon Schick <simonsimcity@gmail.com>
|
||||
*
|
||||
* @requires extension couchbase
|
||||
*/
|
||||
class CouchbaseStorageTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $couchbase;
|
||||
|
||||
/**
|
||||
* @var CouchbaseStorage
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->couchbase = $this->getMockBuilder('\Couchbase')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->storage = new CouchbaseStorage($this->couchbase);
|
||||
}
|
||||
|
||||
public function testSupportsPartialUpdates()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsPartialUpdates());
|
||||
}
|
||||
|
||||
public function testSupportsCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testRequiresCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->requiresCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testInsert()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$dbDataset = [];
|
||||
|
||||
$this->couchbase->expects($this->once())
|
||||
->method('add')
|
||||
->will($this->returnCallback(function ($key, $data) use (&$dbDataset) {
|
||||
$dbDataset[] = ['key' => $key, 'value' => $data];
|
||||
}));
|
||||
|
||||
$this->storage->insert('', '1', $data);
|
||||
$this->assertCount(1, $dbDataset);
|
||||
|
||||
$this->assertEquals([['key' => '1', 'value' => $data]], $dbDataset);
|
||||
}
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$dbDataset = [];
|
||||
|
||||
$this->couchbase->expects($this->once())
|
||||
->method('replace')
|
||||
->will($this->returnCallback(function ($key, $data) use (&$dbDataset) {
|
||||
$dbDataset[$key] = $data;
|
||||
}));
|
||||
|
||||
$this->storage->update('', '1', $data);
|
||||
|
||||
$this->assertEquals(['1' => $data], $dbDataset);
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$dataset = [
|
||||
'foobar' => [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
],
|
||||
];
|
||||
|
||||
$this->couchbase->expects($this->once())
|
||||
->method('delete')
|
||||
->will($this->returnCallback(function ($key) use (&$dataset) {
|
||||
foreach ($dataset as $id => $row) {
|
||||
if ($id === $key) {
|
||||
unset($dataset[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
$this->storage->delete('test', 'foobar');
|
||||
|
||||
$this->assertCount(0, $dataset);
|
||||
}
|
||||
|
||||
public function testFind()
|
||||
{
|
||||
$dataset = [
|
||||
'foobar' => [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
],
|
||||
];
|
||||
|
||||
$this->couchbase->expects($this->once())
|
||||
->method('get')
|
||||
->will($this->returnCallback(function ($key) use (&$dataset) {
|
||||
if (isset($dataset[$key])) {
|
||||
return $dataset[$key];
|
||||
}
|
||||
return;
|
||||
}
|
||||
));
|
||||
|
||||
$data = $this->storage->find('test', 'foobar');
|
||||
|
||||
$this->assertEquals($dataset['foobar'], $data);
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertEquals('couchbase', $this->storage->getName());
|
||||
}
|
||||
}
|
||||
346
tests/Doctrine/Tests/KeyValueStore/Storage/DynamoDbTest.php
Normal file
346
tests/Doctrine/Tests/KeyValueStore/Storage/DynamoDbTest.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\DynamoDbStorage;
|
||||
|
||||
/**
|
||||
* @covers \Doctrine\KeyValueStore\Storage\DynamoDbStorage
|
||||
*/
|
||||
class DynamoDbTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private function getDynamoDbMock($methods = [])
|
||||
{
|
||||
$client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient')->disableOriginalConstructor();
|
||||
|
||||
if (count($methods)) {
|
||||
$client->setMethods($methods);
|
||||
}
|
||||
|
||||
return $client->getMock();
|
||||
}
|
||||
|
||||
private function getDynamoDbResultMock($methods = [])
|
||||
{
|
||||
$result = $this->getMockBuilder('Aws\Result')->disableOriginalConstructor();
|
||||
|
||||
if (count($methods)) {
|
||||
$result->setMethods($methods);
|
||||
}
|
||||
|
||||
return $result->getMock();
|
||||
}
|
||||
|
||||
public function testTheStorageName()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->assertSame('dynamodb', $storage->getName());
|
||||
}
|
||||
|
||||
public function testDefaultKeyName()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->assertAttributeSame('Id', 'defaultKeyName', $storage);
|
||||
}
|
||||
|
||||
public function testThatTableKeysInitiallyEmpty()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->assertAttributeSame([], 'tableKeys', $storage);
|
||||
}
|
||||
|
||||
public function testDefaultKeyCannotBeSomethingOtherThanString()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$this->setExpectedException(
|
||||
'\Doctrine\KeyValueStore\KeyValueStoreException',
|
||||
'The key must be a string, got "array" instead.'
|
||||
);
|
||||
new DynamoDbStorage($client, null, []);
|
||||
}
|
||||
|
||||
public function testTableKeysMustAllBeStringsOrElse()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$this->setExpectedException(
|
||||
'\Doctrine\KeyValueStore\KeyValueStoreException',
|
||||
'The key must be a string, got "object" instead.'
|
||||
);
|
||||
new DynamoDbStorage($client, null, null, ['mytable' => 'hello', 'yourtable' => new \stdClass()]);
|
||||
}
|
||||
|
||||
public function testKeyNameMustBeUnder255Bytes()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$this->setExpectedException(
|
||||
'\Doctrine\KeyValueStore\KeyValueStoreException',
|
||||
'The name must be at least 1 but no more than 255 chars.'
|
||||
);
|
||||
new DynamoDbStorage($client, null, str_repeat('a', 256));
|
||||
}
|
||||
|
||||
public function invalidTableNames()
|
||||
{
|
||||
return [
|
||||
['a2'],
|
||||
['yo%'],
|
||||
['что'],
|
||||
['h@llo'],
|
||||
];
|
||||
}
|
||||
|
||||
public function validTableNames()
|
||||
{
|
||||
return [
|
||||
['MyTable'],
|
||||
['This_is0k-...'],
|
||||
['hello_world'],
|
||||
['...........00....'],
|
||||
];
|
||||
}
|
||||
|
||||
private function invokeMethod($methodName, $obj, array $args = null)
|
||||
{
|
||||
$relf = new \ReflectionObject($obj);
|
||||
$method = $relf->getMethod($methodName);
|
||||
$method->setAccessible(true);
|
||||
|
||||
if ($args) {
|
||||
return $method->invokeArgs($obj, $args);
|
||||
}
|
||||
|
||||
return $method->invoke($obj);
|
||||
}
|
||||
|
||||
public function testTableNameMustBeAString()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->setExpectedException('\Doctrine\KeyValueStore\InvalidArgumentException');
|
||||
$this->invokeMethod('setKeyForTable', $storage, [[], 'Id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider invalidTableNames
|
||||
*/
|
||||
public function testTableNameValidatesAgainstInvalidTableNames($tableName)
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->setExpectedException('\Doctrine\KeyValueStore\KeyValueStoreException');
|
||||
$this->invokeMethod('setKeyForTable', $storage, [$tableName, 'Id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validTableNames
|
||||
*/
|
||||
public function testTableNameValidatesAgainstValidTableNames($tableName)
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->invokeMethod('setKeyForTable', $storage, [$tableName, 'Id']);
|
||||
|
||||
$this->assertAttributeSame([$tableName => 'Id'], 'tableKeys', $storage);
|
||||
}
|
||||
|
||||
public function testThatYouCanHaveMultipleTablesWithOverrides()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->invokeMethod('setKeyForTable', $storage, ['Aaa', '2']);
|
||||
$this->invokeMethod('setKeyForTable', $storage, ['Bbb', '1']);
|
||||
|
||||
$this->assertAttributeSame(['Aaa' => '2', 'Bbb' => '1'], 'tableKeys', $storage);
|
||||
}
|
||||
|
||||
public function testGetterForDefaultKeyName()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client, null, 'CustomKey');
|
||||
$this->assertSame('CustomKey', $storage->getDefaultKeyName());
|
||||
}
|
||||
|
||||
public function testGetWillReturnDefaultKeyForUnrecognizedTableName()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client, null, 'CustomKey');
|
||||
$this->assertSame('CustomKey', $this->invokeMethod('getKeyNameForTable', $storage, ['whatever_this_is']));
|
||||
}
|
||||
|
||||
public function testGetWillReturnCorrectKeyForRecognizedTableName()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
$storage = new DynamoDbStorage($client, null, 'CustomKey', ['MyTable' => 'Yesss']);
|
||||
$this->assertSame('Yesss', $this->invokeMethod('getKeyNameForTable', $storage, ['MyTable']));
|
||||
}
|
||||
|
||||
public function testThatSomeStorageHasDifferentKey()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
|
||||
$storage = new DynamoDbStorage($client, null, 'sauce', ['this' => 'that', 'yolo' => 'now']);
|
||||
|
||||
$this->assertSame(['that' => ['N' => '111']], $this->invokeMethod('prepareKey', $storage, ['this', 111]));
|
||||
}
|
||||
|
||||
public function testThatSomeStorageUsesDefaultKey()
|
||||
{
|
||||
$client = $this->getDynamoDbMock();
|
||||
|
||||
$storage = new DynamoDbStorage($client, null, 'sauce', ['this' => 'that', 'yolo' => 'now']);
|
||||
|
||||
$this->assertSame(['sauce' => ['S' => 'hello']], $this->invokeMethod('prepareKey', $storage, ['MyTable', 'hello']));
|
||||
}
|
||||
|
||||
public function testInsertingCallsAPutItem()
|
||||
{
|
||||
$client = $this->getDynamoDbMock(['putItem']);
|
||||
|
||||
$client->expects($this->once())->method('putItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'Item' => [
|
||||
'Id' => ['S' => 'stuff'],
|
||||
'hi' => ['S' => 'there'],
|
||||
'yo' => ['BOOL' => false],
|
||||
],
|
||||
]));
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$storage->insert('MyTable', 'stuff', ['hi' => 'there', 'yo' => false]);
|
||||
}
|
||||
|
||||
public function testInsertingPreparesNestedAttributes()
|
||||
{
|
||||
$client = $this->getDynamoDbMock(['putItem']);
|
||||
|
||||
$client->expects($this->once())->method('putItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'Item' => [
|
||||
'Id' => ['S' => 'stuff'],
|
||||
'hi' => ['S' => 'there'],
|
||||
'what' => ['L' => [
|
||||
['S' => 'Yep'],
|
||||
]],
|
||||
'yo' => ['BOOL' => false],
|
||||
],
|
||||
]));
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$storage->insert('MyTable', 'stuff', ['hi' => 'there', 'yo' => false, 'what' => ['Yep', '']]);
|
||||
}
|
||||
|
||||
public function testUpdateActuallyAlsoCallsInsert()
|
||||
{
|
||||
$client = $this->getDynamoDbMock(['putItem']);
|
||||
|
||||
$client->expects($this->once())->method('putItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'Item' => [
|
||||
'Id' => ['S' => 'stuff'],
|
||||
'hi' => ['S' => 'there'],
|
||||
'yo' => ['BOOL' => false],
|
||||
],
|
||||
]));
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$storage->update('MyTable', 'stuff', ['hi' => 'there', 'yo' => false]);
|
||||
}
|
||||
|
||||
public function testDeleteItem()
|
||||
{
|
||||
$client = $this->getDynamoDbMock(['deleteItem']);
|
||||
|
||||
$client->expects($this->once())->method('deleteItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'Key' => ['Id' => ['S' => 'abc123']],
|
||||
]));
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$storage->delete('MyTable', 'abc123');
|
||||
}
|
||||
|
||||
public function testDeleteItemWithKeyValuePair()
|
||||
{
|
||||
$client = $this->getDynamoDbMock(['deleteItem']);
|
||||
|
||||
$client->expects($this->once())->method('deleteItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'Key' => ['Id' => ['S' => 'abc123']],
|
||||
]));
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$storage->delete('MyTable', ['Id' => 'abc123']);
|
||||
}
|
||||
|
||||
public function testPassingArrayAsKeyIsAPassthruToInsert()
|
||||
{
|
||||
$client = $this->getDynamoDbMock(['deleteItem']);
|
||||
|
||||
$client->expects($this->once())->method('deleteItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'Key' => ['Id' => ['S' => 'abc123']],
|
||||
]));
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$storage->delete('MyTable', 'abc123');
|
||||
}
|
||||
|
||||
public function testTryingToFindAnItemThatDoesNotExist()
|
||||
{
|
||||
$client = $this->getDynamoDbMock(['getItem']);
|
||||
$client->expects($this->once())->method('getItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'ConsistentRead' => true,
|
||||
'Key' => ['Id' => ['N' => '1000']],
|
||||
]))->willReturn(null);
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$this->setExpectedException(
|
||||
'\Doctrine\KeyValueStore\NotFoundException',
|
||||
'Could not find an item with key: 1000'
|
||||
);
|
||||
$storage->find('MyTable', 1000);
|
||||
}
|
||||
|
||||
public function testFindAnItemThatExists()
|
||||
{
|
||||
$result = $this->getDynamoDbResultMock(['get']);
|
||||
$result->expects($this->once())->method('get')->with('Item')->willReturn([
|
||||
'hello' => ['S' => 'world'],
|
||||
]);
|
||||
|
||||
$client = $this->getDynamoDbMock(['getItem']);
|
||||
$client->expects($this->once())->method('getItem')->with($this->equalTo([
|
||||
'TableName' => 'MyTable',
|
||||
'ConsistentRead' => true,
|
||||
'Key' => ['Id' => ['N' => '1000']],
|
||||
]))->willReturn($result);
|
||||
|
||||
$storage = new DynamoDbStorage($client);
|
||||
$actualResult = $storage->find('MyTable', 1000);
|
||||
|
||||
$this->assertSame(['hello' => 'world'], $actualResult);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\MongoDbStorage;
|
||||
|
||||
/**
|
||||
* MongoDb storage testcase
|
||||
*
|
||||
* @author Markus Bachmann <markus.bachmann@bachi.biz>
|
||||
*
|
||||
* @requires extension mongo
|
||||
*/
|
||||
class MongoDbStorageTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->mongo = $this
|
||||
->getMockBuilder('\Mongo')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->mongodb = $this->getMockBuilder('\MongoDB')->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->mongo->expects($this->any())
|
||||
->method('selectDB')
|
||||
->will($this->returnValue($this->mongodb));
|
||||
|
||||
$this->collection = $this->getMockBuilder('MongoCollection')->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->mongodb->expects($this->once())
|
||||
->method('selectCollection')
|
||||
->will($this->returnValue($this->collection));
|
||||
|
||||
$this->storage = new MongoDbStorage($this->mongo, [
|
||||
'collection' => 'test',
|
||||
'database' => 'test',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testInsert()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$dbDataset = [];
|
||||
|
||||
$this->collection->expects($this->once())
|
||||
->method('insert')
|
||||
->will($this->returnCallback(function ($data) use (&$dbDataset) {
|
||||
$dbDataset[] = $data;
|
||||
}));
|
||||
|
||||
$this->storage->insert('mongodb', '1', $data);
|
||||
$this->assertCount(1, $dbDataset);
|
||||
|
||||
$this->assertEquals([['key' => '1', 'value' => $data]], $dbDataset);
|
||||
}
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$dbDataset = [];
|
||||
|
||||
$this->collection->expects($this->once())
|
||||
->method('update')
|
||||
->will($this->returnCallback(function ($citeria, $data) use (&$dbDataset) {
|
||||
$dbDataset = [$citeria, $data];
|
||||
}));
|
||||
|
||||
$this->storage->update('mongodb', '1', $data);
|
||||
|
||||
$this->assertEquals(['key' => '1'], $dbDataset[0]);
|
||||
$this->assertEquals(['key' => '1', 'value' => $data], $dbDataset[1]);
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$dataset = [
|
||||
[
|
||||
'key' => 'foobar',
|
||||
'value' => [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$this->collection->expects($this->once())
|
||||
->method('remove')
|
||||
->will($this->returnCallback(function ($citeria) use (&$dataset) {
|
||||
foreach ($dataset as $key => $row) {
|
||||
if ($row['key'] === $citeria['key']) {
|
||||
unset($dataset[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
$this->storage->delete('test', 'foobar');
|
||||
|
||||
$this->assertCount(0, $dataset);
|
||||
}
|
||||
|
||||
public function testFind()
|
||||
{
|
||||
$dataset = [
|
||||
[
|
||||
'key' => 'foobar',
|
||||
'value' => [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$this->collection->expects($this->once())
|
||||
->method('findOne')
|
||||
->will($this->returnCallback(function ($citeria, $fields) use (&$dataset) {
|
||||
foreach ($dataset as $key => $row) {
|
||||
if ($row['key'] === $citeria['key']) {
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
$data = $this->storage->find('test', 'foobar');
|
||||
|
||||
$this->assertEquals($dataset[0]['value'], $data);
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->storage->initialize();
|
||||
|
||||
$this->assertEquals('mongodb', $this->storage->getName());
|
||||
}
|
||||
}
|
||||
117
tests/Doctrine/Tests/KeyValueStore/Storage/RedisStorageTest.php
Normal file
117
tests/Doctrine/Tests/KeyValueStore/Storage/RedisStorageTest.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\RedisStorage;
|
||||
|
||||
/**
|
||||
* @author Marcel Araujo <admin@marcelaraujo.me>
|
||||
*
|
||||
* @requires extension redis
|
||||
*/
|
||||
class RedisStorageTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var RedisStorage
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $redis;
|
||||
|
||||
protected function setup()
|
||||
{
|
||||
$this->redis = $this->getMockBuilder('\Redis')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->redis->expects($this->any())
|
||||
->method('connect')
|
||||
->with('127.0.0.1', '6379')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->storage = new RedisStorage($this->redis);
|
||||
}
|
||||
|
||||
public function testSupportsPartialUpdates()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsPartialUpdates());
|
||||
}
|
||||
|
||||
public function testSupportsCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testRequiresCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->requiresCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testInsert()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe',
|
||||
'title' => 'example book',
|
||||
];
|
||||
|
||||
$dbDataset = [];
|
||||
|
||||
$this->redis->expects($this->once())
|
||||
->method('set')
|
||||
->will($this->returnCallback(function ($key, $data) use (&$dbDataset) {
|
||||
$dbDataset[] = ['key' => $key, 'value' => $data];
|
||||
}));
|
||||
|
||||
$this->storage->insert('redis', '1', $data);
|
||||
|
||||
$this->assertCount(1, $dbDataset);
|
||||
$this->assertEquals([['key' => $this->storage->getKeyName('1'), 'value' => json_encode($data)]], $dbDataset);
|
||||
}
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$data = [
|
||||
'author' => 'John Doe Updated',
|
||||
'title' => 'example book updated',
|
||||
];
|
||||
|
||||
$dbDataset = [];
|
||||
|
||||
$this->redis->expects($this->once())
|
||||
->method('set')
|
||||
->will($this->returnCallback(function ($key, $data) use (&$dbDataset) {
|
||||
$dbDataset[] = ['key' => $key, 'value' => $data];
|
||||
}));
|
||||
|
||||
$this->storage->update('redis', '1', $data);
|
||||
|
||||
$this->assertCount(1, $dbDataset);
|
||||
$this->assertEquals([['key' => $this->storage->getKeyName('1'), 'value' => json_encode($data)]], $dbDataset);
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertEquals('redis', $this->storage->getName());
|
||||
}
|
||||
}
|
||||
252
tests/Doctrine/Tests/KeyValueStore/Storage/RiakStorageTest.php
Normal file
252
tests/Doctrine/Tests/KeyValueStore/Storage/RiakStorageTest.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\RiakStorage;
|
||||
|
||||
/**
|
||||
* @author Markus Bachmann <markus.bachmann@bachi.biz>
|
||||
*/
|
||||
class RiakStorageTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var RiakStorage
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $riak;
|
||||
|
||||
protected function setup()
|
||||
{
|
||||
if (PHP_MAJOR_VERSION >= 7) {
|
||||
$this->markTestSkipped('Riak extension is not available for PHP versions >= 7');
|
||||
}
|
||||
|
||||
$this->riak = $this->getMockBuilder('Riak\\Client')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->storage = new RiakStorage($this->riak);
|
||||
}
|
||||
|
||||
public function testSupportsPartialUpdates()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsPartialUpdates());
|
||||
}
|
||||
|
||||
public function testSupportsCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->supportsCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testRequiresCompositePrimaryKeys()
|
||||
{
|
||||
$this->assertFalse($this->storage->requiresCompositePrimaryKeys());
|
||||
}
|
||||
|
||||
public function testInsert()
|
||||
{
|
||||
$bucket = $this->getMockBuilder('Riak\Bucket')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->riak->expects($this->once())
|
||||
->method('bucket')
|
||||
->will($this->returnValue($bucket));
|
||||
|
||||
$objectMock = $this->getMockBuilder('Riak\Object')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('store');
|
||||
|
||||
$that = $this;
|
||||
$bucket->expects($this->once())
|
||||
->method('newObject')
|
||||
->will($this->returnCallback(function ($key, $data) use ($objectMock, $that) {
|
||||
$that->assertEquals('foobar', $key);
|
||||
$that->assertEquals(['title' => 'Riak test'], $data);
|
||||
return $objectMock;
|
||||
}));
|
||||
|
||||
$this->storage->insert('riak-test', 'foobar', ['title' => 'Riak test']);
|
||||
}
|
||||
|
||||
public function testUpdate()
|
||||
{
|
||||
$objectMock = $this->getMockBuilder('Riak\Object')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$bucket = $this->getMockBuilder('Riak\Bucket')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->riak->expects($this->once())
|
||||
->method('bucket')
|
||||
->will($this->returnValue($bucket));
|
||||
|
||||
$bucket->expects($this->once())
|
||||
->method('get')
|
||||
->will($this->returnValue($objectMock));
|
||||
|
||||
$that = $this;
|
||||
$objectMock->expects($this->once())
|
||||
->method('setData')
|
||||
->will($this->returnCallback(function ($data) use ($that) {
|
||||
$that->assertEquals(['title' => 'Riak cookbook'], $data);
|
||||
}));
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('store');
|
||||
|
||||
$this->storage->update('riak-test', 'foobar', ['title' => 'Riak cookbook']);
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$objectMock = $this->getMockBuilder('Riak\Object')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$bucket = $this->getMockBuilder('Riak\Bucket')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->riak->expects($this->once())
|
||||
->method('bucket')
|
||||
->will($this->returnValue($bucket));
|
||||
|
||||
$bucket->expects($this->once())
|
||||
->method('get')
|
||||
->with('foobar')
|
||||
->will($this->returnValue($objectMock));
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('exists')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('delete');
|
||||
|
||||
$this->storage->delete('riak-test', 'foobar');
|
||||
}
|
||||
|
||||
public function testDeleteWithNotExistKey()
|
||||
{
|
||||
$objectMock = $this->getMockBuilder('Riak\Object')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$bucket = $this->getMockBuilder('Riak\Bucket')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->riak->expects($this->once())
|
||||
->method('bucket')
|
||||
->will($this->returnValue($bucket));
|
||||
|
||||
$bucket->expects($this->once())
|
||||
->method('get')
|
||||
->with('foobar')
|
||||
->will($this->returnValue($objectMock));
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('exists')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$objectMock->expects($this->never())
|
||||
->method('delete');
|
||||
|
||||
$this->storage->delete('riak-test', 'foobar');
|
||||
}
|
||||
|
||||
public function testFind()
|
||||
{
|
||||
$objectMock = $this->getMockBuilder('Riak\Object')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$bucket = $this->getMockBuilder('Riak\Bucket')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->riak->expects($this->once())
|
||||
->method('bucket')
|
||||
->will($this->returnValue($bucket));
|
||||
|
||||
$bucket->expects($this->once())
|
||||
->method('get')
|
||||
->with('foobar')
|
||||
->will($this->returnValue($objectMock));
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('exists')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('getData')
|
||||
->will($this->returnValue(['title' => 'Riak Test']));
|
||||
|
||||
$this->assertEquals(['title' => 'Riak Test'], $this->storage->find('riaktest', 'foobar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Doctrine\KeyValueStore\NotFoundException
|
||||
*/
|
||||
public function testFindWithNotExistKey()
|
||||
{
|
||||
$objectMock = $this->getMockBuilder('Riak\Object')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$bucket = $this->getMockBuilder('Riak\Bucket')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->riak->expects($this->once())
|
||||
->method('bucket')
|
||||
->will($this->returnValue($bucket));
|
||||
|
||||
$bucket->expects($this->once())
|
||||
->method('get')
|
||||
->with('foobar')
|
||||
->will($this->returnValue($objectMock));
|
||||
|
||||
$objectMock->expects($this->once())
|
||||
->method('exists')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$objectMock->expects($this->never())
|
||||
->method('getData');
|
||||
|
||||
$this->storage->find('riak-test', 'foobar');
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertEquals('riak', $this->storage->getName());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage\WindowsAzureTable;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\SharedKeyLiteAuthorization;
|
||||
@@ -11,31 +29,30 @@ class SharedKeyLiteTest extends \PHPUnit_Framework_TestCase
|
||||
public function setUp()
|
||||
{
|
||||
$this->auth = new SharedKeyLiteAuthorization(
|
||||
"testing",
|
||||
"abcdefg"
|
||||
'testing',
|
||||
'abcdefg'
|
||||
);
|
||||
}
|
||||
|
||||
public function testKeyGeneration1()
|
||||
{
|
||||
$authorization = $this->auth->signRequest('GET', '/', '', '', array(
|
||||
"x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"
|
||||
));
|
||||
$authorization = $this->auth->signRequest('GET', '/', '', '', [
|
||||
'x-ms-date' => 'Wed, 29 Apr 2009 13:12:47 GMT',
|
||||
]);
|
||||
$this->assertEquals(
|
||||
"Authorization: SharedKeyLite testing:vZdOn/j0gW5FG0kAUG9NhSBO9eBjZqfe6RwALPYUtqU=",
|
||||
'Authorization: SharedKeyLite testing:vZdOn/j0gW5FG0kAUG9NhSBO9eBjZqfe6RwALPYUtqU=',
|
||||
$authorization
|
||||
);
|
||||
}
|
||||
|
||||
public function testKeyGeneration2()
|
||||
{
|
||||
$authorization = $this->auth->signRequest('GET', '/test', '', '', array(
|
||||
"x-ms-date" => "Wed, 29 Apr 2009 13:12:47 GMT"
|
||||
));
|
||||
$authorization = $this->auth->signRequest('GET', '/test', '', '', [
|
||||
'x-ms-date' => 'Wed, 29 Apr 2009 13:12:47 GMT',
|
||||
]);
|
||||
$this->assertEquals(
|
||||
"Authorization: SharedKeyLite testing:HJTSiRDtMsQVsFVispSHkcODeFykLO+WEuOepwmh51o=",
|
||||
'Authorization: SharedKeyLite testing:HJTSiRDtMsQVsFVispSHkcODeFykLO+WEuOepwmh51o=',
|
||||
$authorization
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\KeyValueStore\Storage;
|
||||
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\SharedKeyAuthorization;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTableStorage;
|
||||
use Doctrine\KeyValueStore\Http\Client;
|
||||
use Doctrine\KeyValueStore\Http\Response;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTable\AuthorizationSchema;
|
||||
use Doctrine\KeyValueStore\Storage\WindowsAzureTableStorage;
|
||||
|
||||
class WindowsAzureTableStorageTest extends AbstractStorageTestCase
|
||||
{
|
||||
@@ -12,8 +31,14 @@ class WindowsAzureTableStorageTest extends AbstractStorageTestCase
|
||||
|
||||
protected function createStorage()
|
||||
{
|
||||
$this->client = $this->getMock('Doctrine\KeyValueStore\Http\Client');
|
||||
$auth = $this->getMock('Doctrine\KeyValueStore\Storage\WindowsAzureTable\AuthorizationSchema');
|
||||
$this->client = $this
|
||||
->getMockBuilder(Client::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$auth = $this
|
||||
->getMockBuilder(AuthorizationSchema::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$auth->expects($this->any())->method('signRequest')->will($this->returnValue('Authorization: SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM='));
|
||||
|
||||
$storage = new WindowsAzureTableStorage(
|
||||
@@ -25,13 +50,13 @@ class WindowsAzureTableStorageTest extends AbstractStorageTestCase
|
||||
|
||||
public function mockInsertCompositeKey($key, $data)
|
||||
{
|
||||
$expectedHeaders = array(
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'Content-Length' => 617,
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
);
|
||||
$expectedHeaders = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'Content-Length' => 620,
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
];
|
||||
|
||||
$this->client->expects($this->at(0))
|
||||
->method('request')
|
||||
@@ -50,7 +75,7 @@ class WindowsAzureTableStorageTest extends AbstractStorageTestCase
|
||||
<content type="application/xml">
|
||||
|
||||
<m:properties>
|
||||
<d:PartitionKey>foo</d:PartitionKey><d:RowKey>100</d:RowKey><d:name>Test</d:name><d:value>1</d:value><d:amount>200.23</d:amount><d:timestamp>2012-03-26T12:12:12+02:00</d:timestamp></m:properties></content>
|
||||
<d:PartitionKey>foo</d:PartitionKey><d:RowKey>100</d:RowKey><d:name>Test</d:name><d:value>1</d:value><d:amount>200.23</d:amount><d:timestamp>2012-03-26T12:12:12.0000000Z</d:timestamp></m:properties></content>
|
||||
</entry>
|
||||
|
||||
XML
|
||||
@@ -80,7 +105,7 @@ XML
|
||||
</content>
|
||||
</entry>
|
||||
XML
|
||||
, array()
|
||||
, []
|
||||
|
||||
))
|
||||
);
|
||||
@@ -88,20 +113,20 @@ XML
|
||||
|
||||
public function mockUpdateCompositeKey($key, $data)
|
||||
{
|
||||
$expectedHeaders = array(
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'Content-Length' => 704,
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'If-Match' => '*',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
);
|
||||
$expectedHeaders = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'Content-Length' => 707,
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'If-Match' => '*',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
];
|
||||
|
||||
$this->client->expects($this->at(0))
|
||||
->method('request')
|
||||
->with(
|
||||
$this->equalTo('PUT'),
|
||||
$this->equalTo("https://teststore.table.core.windows.net/stdClass". rawurlencode("(PartitionKey='foo', RowKey='100')")),
|
||||
$this->equalTo('https://teststore.table.core.windows.net/stdClass' . rawurlencode("(PartitionKey='foo', RowKey='100')")),
|
||||
$this->equalTo(<<<XML
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
|
||||
@@ -114,53 +139,52 @@ XML
|
||||
<content type="application/xml">
|
||||
|
||||
<m:properties>
|
||||
<d:PartitionKey>foo</d:PartitionKey><d:RowKey>100</d:RowKey><d:name>Test</d:name><d:value>1</d:value><d:amount>200.23</d:amount><d:timestamp>2012-03-26T12:12:12+02:00</d:timestamp></m:properties></content>
|
||||
<d:PartitionKey>foo</d:PartitionKey><d:RowKey>100</d:RowKey><d:name>Test</d:name><d:value>1</d:value><d:amount>200.23</d:amount><d:timestamp>2012-03-26T12:12:12.0000000Z</d:timestamp></m:properties></content>
|
||||
</entry>
|
||||
|
||||
XML
|
||||
),
|
||||
$this->equalTo($expectedHeaders))
|
||||
->will($this->returnValue(new Response(204, "", array()))
|
||||
->will($this->returnValue(new Response(204, '', []))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function mockDeleteCompositeKey($key)
|
||||
{
|
||||
$expectedHeaders = array(
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
$expectedHeaders = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'Content-Length' => 0,
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'If-Match' => '*',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
);
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'If-Match' => '*',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
];
|
||||
|
||||
$this->client->expects($this->at(0))
|
||||
->method('request')
|
||||
->with(
|
||||
$this->equalTo('DELETE'),
|
||||
$this->equalTo("https://teststore.table.core.windows.net/stdClass". rawurlencode("(PartitionKey='foo', RowKey='100')")),
|
||||
$this->equalTo('https://teststore.table.core.windows.net/stdClass' . rawurlencode("(PartitionKey='foo', RowKey='100')")),
|
||||
$this->equalTo(''),
|
||||
$this->equalTo($expectedHeaders)
|
||||
)->will($this->returnValue(new Response(204, "", array())));
|
||||
)->will($this->returnValue(new Response(204, '', [])));
|
||||
}
|
||||
|
||||
public function mockFindCompositeKey($key)
|
||||
{
|
||||
$expectedHeaders = array(
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
$expectedHeaders = [
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'Content-Length' => 0,
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
);
|
||||
'x-ms-date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Date' => 'Mon, 26 Mar 2012 10:10:10 GMT',
|
||||
'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
|
||||
];
|
||||
|
||||
$this->client->expects($this->at(0))
|
||||
->method('request')
|
||||
->with(
|
||||
$this->equalTo('GET'),
|
||||
$this->equalTo("https://teststore.table.core.windows.net/stdClass". rawurlencode("(PartitionKey='foo', RowKey='100')")),
|
||||
$this->equalTo('https://teststore.table.core.windows.net/stdClass' . rawurlencode("(PartitionKey='foo', RowKey='100')")),
|
||||
$this->equalTo(''),
|
||||
$this->equalTo($expectedHeaders)
|
||||
)->will($this->returnValue(
|
||||
@@ -188,11 +212,9 @@ XML
|
||||
</content>
|
||||
</entry>
|
||||
XML
|
||||
, array()
|
||||
, []
|
||||
|
||||
))
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -13,27 +14,41 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests;
|
||||
|
||||
use Doctrine\KeyValueStore\EntityManager;
|
||||
use Doctrine\KeyValueStore\Configuration;
|
||||
use Doctrine\KeyValueStore\Mapping\AnnotationDriver;
|
||||
use Doctrine\KeyValueStore\Storage\DoctrineCacheStorage;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Doctrine\KeyValueStore\Configuration;
|
||||
use Doctrine\KeyValueStore\EntityManager;
|
||||
use Doctrine\KeyValueStore\Mapping;
|
||||
use Doctrine\KeyValueStore\Storage\DoctrineCacheStorage;
|
||||
|
||||
abstract class KeyValueStoreTestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function createManager($storage = null)
|
||||
public function createManager($storage = null, $driver = 'annotation')
|
||||
{
|
||||
$cache = new ArrayCache;
|
||||
$cache = new ArrayCache;
|
||||
$storage = $storage ?: new DoctrineCacheStorage($cache);
|
||||
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
$metadata = new AnnotationDriver($reader);
|
||||
switch ($driver) {
|
||||
case 'annotation':
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
$metadata = new Mapping\AnnotationDriver($reader);
|
||||
|
||||
break;
|
||||
case 'yaml':
|
||||
$metadata = new Mapping\YamlDriver(__DIR__ . '/fixtures/yaml');
|
||||
|
||||
break;
|
||||
case 'xml':
|
||||
$metadata = new Mapping\XmlDriver(__DIR__ . '/fixtures/xml');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$config = new Configuration();
|
||||
$config->setMappingDriverImpl($metadata);
|
||||
$config->setMetadataCache($cache);
|
||||
@@ -41,4 +56,3 @@ abstract class KeyValueStoreTestCase extends \PHPUnit_Framework_TestCase
|
||||
return new EntityManager($storage, $config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
|
||||
<entity name="Doctrine\Tests\KeyValueStore\Functional\ChildEntity">
|
||||
<id>id</id>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
|
||||
<entity name="Doctrine\Tests\KeyValueStore\Functional\ParentEntity">
|
||||
<id>id</id>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
|
||||
<entity name="Doctrine\Tests\KeyValueStore\Functional\PersistEntity">
|
||||
<id>id</id>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
9
tests/Doctrine/Tests/fixtures/xml/Doctrine.Tests.KeyValueStore.Functional.Post.dcm.xml
vendored
Normal file
9
tests/Doctrine/Tests/fixtures/xml/Doctrine.Tests.KeyValueStore.Functional.Post.dcm.xml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
|
||||
<entity name="Doctrine\Tests\KeyValueStore\Functional\Post" storage-name="post">
|
||||
<id>id</id>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -0,0 +1,3 @@
|
||||
Doctrine\Tests\KeyValueStore\Functional\ChildEntity:
|
||||
id:
|
||||
- id
|
||||
@@ -0,0 +1,3 @@
|
||||
Doctrine\Tests\KeyValueStore\Functional\ParentEntity:
|
||||
id:
|
||||
- id
|
||||
@@ -0,0 +1,3 @@
|
||||
Doctrine\Tests\KeyValueStore\Functional\PersistEntity:
|
||||
id:
|
||||
- id
|
||||
4
tests/Doctrine/Tests/fixtures/yaml/Doctrine.Tests.KeyValueStore.Functional.Post.dcm.yml
vendored
Normal file
4
tests/Doctrine/Tests/fixtures/yaml/Doctrine.Tests.KeyValueStore.Functional.Post.dcm.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Doctrine\Tests\KeyValueStore\Functional\Post:
|
||||
storageName: post
|
||||
id:
|
||||
- id
|
||||
@@ -1,6 +1,24 @@
|
||||
<?php
|
||||
|
||||
if (!@include __DIR__ . '/../vendor/.composer/autoload.php') {
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
if (! @include __DIR__ . '/../vendor/autoload.php') {
|
||||
die(<<<'EOT'
|
||||
You must set up the project dependencies, run the following commands:
|
||||
wget http://getcomposer.org/composer.phar
|
||||
@@ -12,7 +30,3 @@ EOT
|
||||
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile(__DIR__ . '/../lib/Doctrine/KeyValueStore/Mapping/Annotations/Entity.php');
|
||||
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile(__DIR__ . '/../lib/Doctrine/KeyValueStore/Mapping/Annotations/Id.php');
|
||||
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile(__DIR__ . '/../lib/Doctrine/KeyValueStore/Mapping/Annotations/Transient.php');
|
||||
|
||||
$loader = new \Doctrine\Common\ClassLoader("Doctrine\Tests", __DIR__);
|
||||
$loader->register();
|
||||
|
||||
|
||||
13
tests/travis.sh
Normal file
13
tests/travis.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
# Cassandra installation
|
||||
sudo sh -c "echo 'JVM_OPTS=\"\${JVM_OPTS} -Djava.net.preferIPv4Stack=false\"' >> /usr/local/cassandra/conf/cassandra-env.sh"
|
||||
sudo service cassandra start
|
||||
sudo apt-add-repository -y ppa:linuxjedi/ppa
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libuv-dev libssl-dev
|
||||
cd /tmp && git clone https://github.com/datastax/php-driver.git && cd php-driver && git submodule update --init
|
||||
cd ext && ./install.sh && cd "$TRAVIS_BUILD_DIR"
|
||||
echo "extension=cassandra.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`
|
||||
# PHP extensions
|
||||
yes | pecl install mongo
|
||||
# PECL extensions
|
||||
echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||
Reference in New Issue
Block a user