77 Commits

Author SHA1 Message Date
Benjamin Eberlei
0c174bdb7a Merge pull request #30 from TheDistantSea/unit-of-work-identity-map-fixes
Bugfix: UoW should properly handle entities of different classes
2015-07-24 16:08:55 +02:00
Jannis Papaioannou
bcf6d01c3f Bugfix: UoW now properly handles entities of different classes 2015-07-24 15:32:46 +02:00
Benjamin Eberlei
9fa9ffb5c6 Merge pull request #25 from ryan-senn/master
Fix typo in README
2015-07-09 15:23:29 +02:00
Benjamin Eberlei
b895ef4bca Merge pull request #26 from dwurster/master
Add missing field for class metadata serialization (needed when using redis cache)
2015-07-09 15:23:18 +02:00
Benjamin Eberlei
46be2da6eb Merge pull request #29 from TheDistantSea/transient-annotation-fixes
Fix @Transient annotation -- logic bug plus broken due to typo
2015-07-09 15:09:55 +02:00
Benjamin Eberlei
1c02f0d875 Merge pull request #28 from kick-the-bucket/patch-2
Configuration::setIdConverterStrategy fatal fix
2015-07-09 15:09:03 +02:00
Jannis Papaioannou
4bebd86417 Fixing logic bug in handling @Transient annotation (it just did nothing at all) 2015-07-09 14:53:21 +02:00
Jannis Papaioannou
b8f709dd43 Fixing typo that caused fatal error 2015-07-09 14:52:45 +02:00
Kick_the_BUCKET
479258335d Configuration::setIdConverterStrategy fatal fix
Added missing use statement for Doctrine\KeyValueStore\Id\IdConverterStrategy
2015-05-28 12:43:50 +03:00
Deimantas Wurster
d168c890ac Add missing field for class metadata serialization (needed when using redis cache) 2015-05-19 18:19:02 +02:00
ryan senn
5ea631e50b Configuration loaded twice 2015-05-18 06:42:45 +00:00
ryan senn
9b600cc221 Fix typo in README 2015-05-18 02:13:36 +00:00
Benjamin Eberlei
4309604e0a Merge pull request #23 from kick-the-bucket/patch-1
Undefined property: EntityManager::$unitOfwork
2015-05-12 00:10:55 +02:00
Tomas Kmieliauskas
a5d3b1ca49 Added type hints and a missing method 2015-05-07 17:11:56 +03:00
Kick_the_BUCKET
1af55b26bd Undefined property: EntityManager::$unitOfwork
Undefined property: Doctrine\KeyValueStore\EntityManager::$unitOfwork
2015-05-07 16:12:08 +03:00
Guilherme Blanco
2dd2d84cff Merge pull request #21 from CentaurWarchief/redis/improvements
Avoiding fatalities when using `RedisStorage`
2015-04-16 17:19:16 -04:00
Andrey K
66d7ba901f Fixing doc s/$id/$key (RedisStorage::getKeyName) 2015-04-16 18:15:00 -03:00
Andrey K
f164523b41 Ensuring that json_decode will return assoc 2015-04-16 18:13:31 -03:00
Benjamin Eberlei
a275c44aa0 Merge pull request #14 from marcelaraujo/master
Add Redis support
2015-02-17 16:00:18 +01:00
Marcel Araujo
90cd03dbfd Merge branch 'master' of github.com:marcelaraujo/KeyValueStore 2014-10-09 10:51:26 -03:00
Steve Müller
12c2abd9e4 Merge pull request #20 from pierredup/patch-1
Small typo
2014-09-27 18:30:00 +02:00
Pierre du Plessis
12bfc80c81 Small typo 2014-09-27 00:06:10 +02:00
Marco Pivetta
a7771b6e58 Merge pull request #19 from cpliakas/19-em-import
The Doctrine\KeyValueStore\EntityManager class is imported twice in documentation
2014-04-09 20:28:41 +02:00
Chris Pliakas
a4ad1d1f43 Remove duplicate import of Doctrine\KeyValueStore\EntityManager. 2014-04-09 14:22:12 -04:00
Guilherme Blanco
c118048b81 Merge pull request #18 from stanlemon/simpledb
Initial AWS SimpleDB storage implementation
2014-03-31 17:30:08 -05:00
Guilherme Blanco
11baf2e373 Merge pull request #17 from stanlemon/dynamodb
Initial AWS DynamoDB storage implementation
2014-03-31 17:29:42 -05:00
Stan Lemon
fb19abf8c2 Moved protected methods to the end of the file. 2013-09-22 22:37:39 -04:00
Stan Lemon
48d611fb17 Moved protected methods to the end of the file. 2013-09-22 22:36:36 -04:00
Stan Lemon
20d78eade9 Fixed docblocks 2013-09-21 20:30:09 -04:00
Stan Lemon
c447e28a93 Fixed docblocks 2013-09-21 20:29:42 -04:00
Stan Lemon
b3e42ba4f5 Initial AWS SimpleDB storage implementation (does not include composite keys) 2013-09-21 10:06:33 -04:00
Stan Lemon
e53055b5b2 Removed unnecessary table name field from constructor 2013-09-21 09:23:03 -04:00
Stan Lemon
5de2e52135 Initial AWS DynamoDB storage implementation 2013-09-20 23:22:31 -04:00
Guilherme Blanco
780da5e7af Merge pull request #16 from stanlemon/dbal-fix
Add missing use statement and fix query used in DBALStorage.
2013-09-17 16:24:01 -07:00
Guilherme Blanco
1dec23f010 Merge pull request #15 from stanlemon/docs-fix
Fix examples
2013-09-17 16:21:32 -07:00
Stan Lemon
2d01d5b08c Added missing use statement. Scrapped plain text query for query builder (the original one was missing a where clause too). 2013-09-17 13:34:20 -04:00
Stan Lemon
aebdfbcd49 The current example lacks two use statements to be functional. Additionally the composite index example is wrong, it requires the keys to calculate. 2013-09-17 13:03:39 -04:00
Benjamin Eberlei
f175e595db Create table lazily if not exists 2013-04-08 20:22:00 +02:00
Benjamin Eberlei
2c1b550d31 Another fix 2013-04-08 20:04:21 +02:00
Benjamin Eberlei
d315cec820 Fix bug in AzureSdkTableStorage 2013-04-08 19:42:19 +02:00
Marcel Araujo
f43bed12ac Adding space between if and bracket 2013-02-13 09:46:32 -02:00
Marcel Araujo
5d9013d8ef Updated RedisStorage and added tests. 2013-02-08 16:25:55 -02:00
Marcel Araujo
8fe303c6f0 Remove doc annotations. 2013-02-08 15:36:14 -02:00
Marcel Araujo
fa5e715d86 Adding some improvements. 2013-02-08 14:02:26 -02:00
Marcel Araujo
2269b27326 Adding some fixes to follow coding style standards. 2013-02-08 13:50:22 -02:00
Marcel Araujo
e72ef607ef Adding Redis support and fix the missing class in the readme example. 2013-02-08 11:39:00 -02:00
Benjamin Eberlei
a43f35c2ec Another fix run 2013-02-01 15:40:10 +01:00
Benjamin Eberlei
3a39f01c83 Fix formatting 2013-02-01 15:39:06 +01:00
Benjamin Eberlei
e4b84b9558 Cleanup docs 2013-01-28 00:10:16 +01:00
Benjamin Eberlei
992bdd1ac5 Added documentation on configuration. 2013-01-28 00:04:37 +01:00
Benjamin Eberlei
ee75cfee7b Start with documentation 2013-01-27 17:33:11 +01:00
Benjamin Eberlei
4bd4073206 UPDATE README.md 2013-01-27 17:33:11 +01:00
Benjamin Eberlei
0d7c5f02c6 Merge pull request #11 from SimonSimCity/master
Added couchbase storage
2013-01-27 08:26:55 -08:00
Benjamin Eberlei
a21f94d723 Introduce Support for the WindowsAzure PHP SDK, deprecate the old WindowsAzureTable support. 2013-01-27 16:38:06 +01:00
Benjamin Eberlei
948f402c6f Skip MongoDB tests if extension is not installed. 2013-01-27 14:41:12 +01:00
Simon Schick
3ddf79a3d5 Skip tests for couchbase storage if extension is not installed 2012-12-03 21:17:56 +01:00
Simon Schick
b0ef144d7e Addded ext-couchbase to suggest packages in composer 2012-12-03 21:17:25 +01:00
Simon Schick
91f1752831 Replaced tabs by spaces 2012-12-03 20:58:43 +01:00
Simon Schick
ad20d188e6 Updated documentation 2012-12-03 20:48:31 +01:00
Simon Schick
3ae0b7ead4 Add couchbase storage 2012-12-03 20:47:12 +01:00
Benjamin Eberlei
f942e51a6e Merge pull request #9 from jonmchan/bugFixes-2012-10
Bug fixes 2012/10
2012-11-19 02:54:37 -08:00
Jonathan Chan
c5b8c1931d corrected erroneous readme 2012-10-12 15:03:56 -04:00
Jonathan Chan
e4e5e14a79 KeyValueStore does not support mapped superclass - any mapped class should be considered as an entity. 2012-10-09 00:03:37 -04:00
Jonathan Chan
20687435bd updated readme with CRUD examples 2012-10-03 22:50:06 +00:00
Jonathan Chan
479e2cf739 updated readme to reflect changes in EntityManager constructor - fixes #8 2012-10-03 21:05:54 +00:00
Jonathan Chan
46f58250de updated ClassMetadataFactory to fit doctrine (c6a01cc34e) changes in AbstractClassMetadataFactory 2012-10-03 20:59:28 +00:00
Jonathan Chan
066b047c13 updated ClassMetadataFactory to fit doctrine (09cf5f63bc) changes in AbstractClassMetadataFactory 2012-10-03 20:51:54 +00:00
Jonathan Chan
aea2dadbc4 updated bootstrap path to comply with new path (see https://github.com/composer/composer/issues/497) 2012-10-03 20:44:50 +00:00
Benjamin Eberlei
801400d4e9 Merge pull request #6 from Baachi/riak
Riak
2012-07-03 02:29:23 -07:00
Markus Bachmann
c7050ddb96 Replace version constraint in suggest section 2012-06-20 21:30:43 +02:00
Markus Bachmann
f8c3d9d725 Update composer file and add riak/riak-client to the "suggest" section 2012-06-20 21:11:40 +02:00
Markus Bachmann
f4ba01af29 Use the right indention 2012-06-20 21:10:59 +02:00
Markus Bachmann
76530e8b5d Replace docblocks with {@inheritDoc} 2012-06-20 21:10:40 +02:00
Markus Bachmann
692e0ca38d CS 2012-06-19 21:53:28 +02:00
Markus Bachmann
2c1a79a3ea Add Riak storage 2012-06-19 21:52:20 +02:00
Benjamin Eberlei
995d06fbc5 Add Storage and HttpStoragEException 2012-06-04 18:55:17 +02:00
Benjamin Eberlei
9fb87141b8 Fix WindowsAzureStorage and some bugs in RangeQuery 2012-06-04 18:51:30 +02:00
37 changed files with 3304 additions and 850 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
vendor
*phpunit.xml
docs/_build

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "docs/_theme"]
path = docs/_theme
url = git://github.com/doctrine/doctrine-sphinx-theme.git

151
README.md
View File

@@ -1,8 +1,6 @@
# Doctrine Key Value Stores
This is a work in progress design document for this component
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
@@ -22,11 +20,12 @@ Following vendors are targeted:
* Microsoft Azure Table (Implemented)
* Doctrine\Common\Cache provider (Implemented)
* RDBMS (Implemented)
* Couchbase
* Couchbase (Implemented)
* Amazon DynamoDB
* CouchDB
* MongoDB
* Riak
* MongoDB (Implemented)
* Riak (Implemented)
* Redis (Implemented)
We happily accept contributions for any of the drivers.
@@ -34,39 +33,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 +101,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);
```

View File

@@ -1,7 +1,22 @@
{
"name": "doctrine/key-value-store",
"require": {
"doctrine/common": "2.1.*"
"doctrine/common": "*"
},
"require-dev": {
"riak/riak-client": "dev-master",
"microsoft/windowsazure": "dev-master"
},
"repositories": [
{
"type": "pear",
"url": "http://pear.php.net"
}
],
"suggest": {
"riak/riak-client": "to use the Riak storage",
"ext-couchbase": "to use the Couchbase storage",
"aws/aws-sdk-php": "to use the DynamoDB storage"
},
"description": "Simple Key-Value Store Abstraction Layer that maps to PHP objects, allowing for many backends.",
"license": "MIT",

752
composer.lock generated
View File

@@ -1,18 +1,752 @@
{
"hash": "1423c223b88271745223ad54dac71bfc",
"hash": "bf53cb71537abb0dbed5002bbc4411f1",
"packages": [
{
"package": "doctrine/common",
"version": "2.1.x-dev",
"source-reference": "41794945e795e108060eddb3342c9e13524b9b3e"
"name": "doctrine/annotations",
"version": "v1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "v1.0"
},
"dist": {
"type": "zip",
"url": "https://github.com/doctrine/annotations/archive/v1.0.zip",
"reference": "v1.0",
"shasum": ""
},
"require": {
"php": ">=5.3.2",
"doctrine/lexer": "1.*"
},
"require-dev": {
"doctrine/cache": "1.*"
},
"time": "2013-01-12 19:23:32",
"type": "library",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Annotations\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"parser",
"docblock"
]
},
{
"name": "doctrine/cache",
"version": "v1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "v1.0"
},
"dist": {
"type": "zip",
"url": "https://github.com/doctrine/cache/archive/v1.0.zip",
"reference": "v1.0",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"time": "2013-01-10 22:43:46",
"type": "library",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Cache\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
}
],
"description": "Caching library offering an object-oriented API for many cache backends",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
]
},
{
"name": "doctrine/collections",
"version": "v1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
"reference": "v1.0"
},
"dist": {
"type": "zip",
"url": "https://github.com/doctrine/collections/archive/v1.0.zip",
"reference": "v1.0",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"time": "2013-01-12 16:36:50",
"type": "library",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Collections\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
}
],
"description": "Collections Abstraction library",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"collections",
"iterator",
"array"
]
},
{
"name": "doctrine/common",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common",
"reference": "f0b548aa55bb7dac36d79061270a085dd38635b4"
},
"dist": {
"type": "zip",
"url": "https://github.com/doctrine/common/archive/a5482b347530bb8522e355b399e5ff4983433a40.zip",
"reference": "a5482b347530bb8522e355b399e5ff4983433a40",
"shasum": ""
},
"require": {
"php": ">=5.3.2",
"doctrine/inflector": "1.*",
"doctrine/cache": "1.*",
"doctrine/collections": "1.*",
"doctrine/lexer": "1.*",
"doctrine/annotations": "1.*"
},
"time": "2012-06-18 14:14:07",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.4.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
}
],
"description": "Common Library for Doctrine projects",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"collections",
"spl",
"eventmanager",
"annotations",
"persistence"
]
},
{
"name": "doctrine/inflector",
"version": "v1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "v1.0"
},
"dist": {
"type": "zip",
"url": "https://github.com/doctrine/inflector/archive/v1.0.zip",
"reference": "v1.0",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"time": "2013-01-10 21:49:15",
"type": "library",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Inflector\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"string",
"inflection",
"singuarlize",
"pluarlize"
]
},
{
"name": "doctrine/lexer",
"version": "v1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "v1.0"
},
"dist": {
"type": "zip",
"url": "https://github.com/doctrine/lexer/archive/v1.0.zip",
"reference": "v1.0",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"time": "2013-01-12 18:59:04",
"type": "library",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"parser",
"lexer"
]
}
],
"packages-dev": [
{
"name": "microsoft/windowsazure",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/WindowsAzure/azure-sdk-for-php",
"reference": "d8daa05ad1852e0c70a85d15a6db88f7e3b23405"
},
"dist": {
"type": "zip",
"url": "https://github.com/WindowsAzure/azure-sdk-for-php/archive/d8daa05ad1852e0c70a85d15a6db88f7e3b23405.zip",
"reference": "d8daa05ad1852e0c70a85d15a6db88f7e3b23405",
"shasum": ""
},
"require": {
"pear-pear/http_request2": "*",
"pear-pear/mail_mime": "*",
"pear-pear/mail_mimedecode": "*"
},
"time": "2012-12-17 23:41:42",
"type": "library",
"autoload": {
"psr-0": {
"WindowsAzure\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Azure PHP SDK",
"email": "azurephpsdk@microsoft.com"
}
],
"description": "This project provides a set of PHP client libraries that make it easy to access Windows Azure tables, blobs, queues, service runtime and service management APIs.",
"keywords": [
"php",
"sdk",
"azure"
]
},
{
"name": "pear-pear.php.net/Archive_Tar",
"version": "1.3.10",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/Archive_Tar-1.3.10.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=4.3.0.0"
},
"replace": {
"pear-pear/archive_tar": "== 1.3.10.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "This class provides handling of tar files in PHP.\nIt supports creating, listing, extracting and adding to tar files.\nGzip support is available if PHP has the zlib extension built-in or\nloaded. Bz2 compression is also supported with the bz2 extension loaded."
},
{
"name": "pear-pear.php.net/Console_Getopt",
"version": "1.3.1",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/Console_Getopt-1.3.1.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=4.3.0.0"
},
"replace": {
"pear-pear/console_getopt": "== 1.3.1.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "This is a PHP implementation of &quot;getopt&quot; supporting both\nshort and long options."
},
{
"name": "pear-pear.php.net/HTTP_Request2",
"version": "2.1.1",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/HTTP_Request2-2.1.1.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=5.2.0.0",
"pear-pear.php.net/net_url2": ">=2.0.0.0",
"pear-pear.php.net/pear": ">=1.9.2.0"
},
"replace": {
"pear-pear/http_request2": "== 2.1.1.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "PHP5 rewrite of HTTP_Request package (with parts of HTTP_Client). Provides\ncleaner API and pluggable Adapters:\n * Socket adapter, based on old HTTP_Request code,\n * Curl adapter, wraps around PHP's cURL extension,\n * Mock adapter, to use for testing packages dependent on HTTP_Request2.\nSupports POST requests with data and file uploads, basic and digest\nauthentication, cookies, managing cookies across requests, proxies, gzip and\ndeflate encodings, redirects, monitoring the request progress with Observers..."
},
{
"name": "pear-pear.php.net/Mail_Mime",
"version": "1.8.7",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/Mail_Mime-1.8.7.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=4.3.0.0"
},
"replace": {
"pear-pear/mail_mime": "== 1.8.7.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "Mail_Mime provides classes to deal with the creation and manipulation of MIME messages.\nIt allows people to create e-mail messages consisting of:\n* Text Parts\n* HTML Parts\n* Inline HTML Images\n* Attachments\n* Attached messages\n\nIt supports big messages, base64 and quoted-printable encodings and\nnon-ASCII characters in filenames, subjects, recipients, etc. encoded\nusing RFC2047 and/or RFC2231."
},
{
"name": "pear-pear.php.net/Mail_mimeDecode",
"version": "1.5.5",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/Mail_mimeDecode-1.5.5.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=4.3.0.0",
"pear-pear.php.net/mail_mime": ">1.4.0.0"
},
"replace": {
"pear-pear/mail_mimedecode": "== 1.5.5.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "Provides a class to deal with the decoding and interpreting of mime messages.\n This package used to be part of the Mail_Mime package, but has been split off."
},
{
"name": "pear-pear.php.net/Net_URL2",
"version": "2.0.0",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/Net_URL2-2.0.0.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=5.0.0.0"
},
"replace": {
"pear-pear/net_url2": "== 2.0.0.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "Provides parsing of URLs into their constituent parts (scheme, host, path etc.), URL generation, and resolving of relative URLs."
},
{
"name": "pear-pear.php.net/PEAR",
"version": "1.9.4",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/PEAR-1.9.4.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=4.4.0.0,!=5.0.0.0,!=5.1.0.0,!=5.1.1.0,!=5.1.2.0,!=5.1.3.0,!=5.1.4.0,!=5.1.5.0",
"pear-pear.php.net/archive_tar": ">=1.3.7.0",
"pear-pear.php.net/structures_graph": ">=1.0.2.0",
"pear-pear.php.net/console_getopt": ">=1.2.0.0",
"pear-pear.php.net/xml_util": ">=1.2.0.0",
"ext-xml": "*",
"ext-pcre": "*"
},
"conflict": {
"pear-pear.php.net/pear_frontend_web": "<=0.4.0.0",
"pear-pear.php.net/pear_frontend_gtk": "<0.4.0.0"
},
"replace": {
"pear-pear/pear": "== 1.9.4.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "The PEAR package contains:\n * the PEAR installer, for creating, distributing\n and installing packages\n * the PEAR_Exception PHP5 error handling mechanism\n * the PEAR_ErrorStack advanced error handling mechanism\n * the PEAR_Error error handling mechanism\n * the OS_Guess class for retrieving info about the OS\n where PHP is running on\n * the System class for quick handling of common operations\n with files and directories\n * the PEAR base class\n Features in a nutshell:\n * full support for channels\n * pre-download dependency validation\n * new package.xml 2.0 format allows tremendous flexibility while maintaining BC\n * support for optional dependency groups and limited support for sub-packaging\n * robust dependency support\n * full dependency validation on uninstall\n * remote install for hosts with only ftp access - no more problems with\n restricted host installation\n * full support for mirroring\n * support for bundling several packages into a single tarball\n * support for static dependencies on a url-based package\n * support for custom file roles and installation tasks"
},
{
"name": "pear-pear.php.net/Structures_Graph",
"version": "1.0.4",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/Structures_Graph-1.0.4.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=4.2.0.0"
},
"replace": {
"pear-pear/structures_graph": "== 1.0.4.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed\nand undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing\nas well as for characteristic extraction from the graph topology."
},
{
"name": "pear-pear.php.net/XML_Util",
"version": "1.2.1",
"dist": {
"type": "file",
"url": "http://pear.php.net/get/XML_Util-1.2.1.tgz",
"reference": null,
"shasum": null
},
"require": {
"php": ">=4.3.0.0",
"ext-pcre": "*"
},
"replace": {
"pear-pear/xml_util": "== 1.2.1.0"
},
"type": "pear-library",
"autoload": {
"classmap": [
""
]
},
"include-path": [
"/"
],
"description": "Selection of methods that are often needed when working with XML documents. Functionality includes creating of attribute lists from arrays, creation of tags, validation of XML names and more."
},
{
"name": "riak/riak-client",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/nacmartin/riak-client",
"reference": "cea446f04d759caaef44020a2064a38b41cbdfab"
},
"dist": {
"type": "zip",
"url": "https://github.com/nacmartin/riak-client/archive/cea446f04d759caaef44020a2064a38b41cbdfab.zip",
"reference": "cea446f04d759caaef44020a2064a38b41cbdfab",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"time": "2012-04-29 11:47:45",
"type": "library",
"autoload": {
"psr-0": {
"Riak": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache 2.0"
],
"authors": [
{
"name": "Nacho Martín",
"email": "nitram.ohcan@gmail.com"
},
{
"name": "Kevin Burns"
},
{
"name": "Jeffrey Massung"
},
{
"name": "Mark Phillips"
},
{
"name": "Bryank Fink"
},
{
"name": "Abel Perez"
},
{
"name": "Scoyy Lystig Fritchie"
},
{
"name": "Jon Meredith"
},
{
"name": "dreverri"
},
{
"name": "fakepop"
}
],
"description": "Riak client",
"homepage": "http://wiki.basho.com/Riak.html",
"keywords": [
"persistence",
"riak"
]
}
],
"packages-dev": null,
"aliases": [
],
"minimum-stability": "dev",
"stability-flags": [
]
"minimum-stability": "stable",
"stability-flags": {
"riak/riak-client": 20,
"microsoft/windowsazure": 20
}
}

153
docs/Makefile Normal file
View 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

Submodule docs/_theme added at 5aa024c928

242
docs/conf.py Normal file
View 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'

17
docs/index.rst Normal file
View File

@@ -0,0 +1,17 @@
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:
.. toctree::
:maxdepth: 2
reference/configuration

190
docs/make.bat Normal file
View 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

View File

@@ -0,0 +1,142 @@
Configuration
=============
The configuration of the KeyValueStore consists of two steps.
* Mapping Configuration
* Storage Configuration
Mapping Configuration
---------------------
.. code-block:: php
<?php
use Doctrine\KeyValueStore\Configuration;
use Doctrine\KeyValueStore\Mapping\AnnotationDriver;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Annotations\AnnotationReader;
// 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):
* Doctrine Cache Backend
* SQL Backend with Doctrine DBAL
* Microsoft Windows Azure Table
* Couchbase
* MongoDB
* Riak
Also all those storage backends obviously have different dependencies in terms
of PHP libraries or PHP PECL extensions.
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\KeyValueStore\Storage\DBALStorage;
use Doctrine\DBAL\DriverManager;
$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);
Couchbase
^^^^^^^^^
To be written
MongoDB
^^^^^^^
To be written
Riak
^^^^
to be written

View File

@@ -19,10 +19,10 @@
namespace Doctrine\KeyValueStore;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\KeyValueStore\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\KeyValueStore\Id\IdConverterStrategy;
use Doctrine\KeyValueStore\Id\NullIdConverter;
/**
@@ -40,7 +40,7 @@ class Configuration
/**
* Get mapping driver implementation used with this configuration.
*
* @return \Doctrine\KeyValueStore\Persistence\Mapping\Driver\MappingDriver
* @return \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
*/
public function getMappingDriverImpl()
{
@@ -54,7 +54,7 @@ class Configuration
/**
* Set the mapping driver implementation.
*
* @param \Doctrine\KeyValueStore\Persistence\Mapping\Driver\MappingDriver $driver
* @param \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver $driver
* @return \Doctrine\KeyValueStore\Configuration
*/
public function setMappingDriverImpl(MappingDriver $driver)

View File

@@ -22,7 +22,6 @@ namespace Doctrine\KeyValueStore;
use Doctrine\KeyValueStore\Storage\Storage;
use Doctrine\KeyValueStore\Mapping\ClassMetadataFactory;
use Doctrine\KeyValueStore\Query\RangeQuery;
use Doctrine\Common\Cache\Cache;
/**
* EntityManager for KeyValue stored objects.
@@ -32,12 +31,12 @@ use Doctrine\Common\Cache\Cache;
class EntityManager
{
/**
* @var Doctrine\KeyValueStore\UnitOfWork
* @var UnitOfWork
*/
private $unitOfWork;
/**
* @var Doctrine\KeyValueStore\Storage\Storage
* @var Storage
*/
private $storageDriver;
@@ -118,7 +117,7 @@ class EntityManager
}
/**
* @return Doctrine\KeyValueStore\Storage\Storage
* @return Storage
*/
public function unwrap()
{
@@ -140,7 +139,7 @@ class EntityManager
/**
* @param string $className
* @return \Doctrine\KeyValueStore\Mapping\ClassMetadata
* @return Mapping\ClassMetadata
*/
public function getClassMetadata($className)
{

View File

@@ -20,7 +20,7 @@
namespace Doctrine\KeyValueStore\Mapping;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\KeyValueStore\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
class AnnotationDriver implements MappingDriver
{
@@ -59,7 +59,7 @@ class AnnotationDriver implements MappingDriver
if ($idAnnot) {
$metadata->mapIdentifier($property->getName());
} else if ($transientAnnot) {
$metdata->skipTransientField($property->getName());
$metadata->skipTransientField($property->getName());
} else {
$metadata->mapField(array('fieldName' => $property->getName()));
}

View File

@@ -28,12 +28,5 @@ class Entity
* @var string
*/
public $storageName;
public function __construct($values)
{
if (isset($values['storageName'])) {
$this->storageName = $values['storageName'];
}
}
}

View File

@@ -56,6 +56,9 @@ class ClassMetadata implements BaseClassMetadata
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;
}
@@ -75,7 +78,7 @@ class ClassMetadata implements BaseClassMetadata
public function __sleep()
{
return array('fields', 'isCompositeKey', 'identifier', 'name');
return array('fields', 'isCompositeKey', 'identifier', 'name', 'storageName');
}
public function getIdentifierValues($object)

View File

@@ -19,12 +19,11 @@
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\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\KeyValueStore\Persistence\Mapping\ReflectionService;
use Doctrine\KeyValueStore\Mapping\ClassMetadata as KeyValueMetadata;
use Doctrine\KeyValueStore\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
/**
* Load Metadata of an entity.
@@ -49,7 +48,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
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);
@@ -95,5 +94,13 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
}
}
}
/**
* copied from doctrine/common - tests/Doctrine/Tests/Common/Persistence/Mapping/ClassMetadataFactoryTest.php
*/
protected function isEntity(ClassMetadata $class)
{
return true;
}
}

View File

@@ -1,364 +0,0 @@
<?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\Persistence\Mapping;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\KeyValueStore\Persistence\Mapping\ReflectionService;
/**
* The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
* metadata mapping informations of a class which describes how a class should be mapped
* to a relational database.
*
* This class was abstracted from the ORM ClassMetadataFactory
*
* @since 2.2
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
{
/**
* Salt used by specific Object Manager implementation.
*
* @var string
*/
protected $cacheSalt = "\$CLASSMETADATA";
/**
* @var \Doctrine\Common\Cache\Cache
*/
private $cacheDriver;
/**
* @var array
*/
private $loadedMetadata = array();
/**
* @var bool
*/
protected $initialized = false;
/**
* @var ReflectionService
*/
private $reflectionService;
/**
* Sets the cache driver used by the factory to cache ClassMetadata instances.
*
* @param Doctrine\Common\Cache\Cache $cacheDriver
*/
public function setCacheDriver(Cache $cacheDriver = null)
{
$this->cacheDriver = $cacheDriver;
}
/**
* Gets the cache driver used by the factory to cache ClassMetadata instances.
*
* @return Doctrine\Common\Cache\Cache
*/
public function getCacheDriver()
{
return $this->cacheDriver;
}
/**
* Return an array of all the loaded metadata currently in memory.
*
* @return array
*/
public function getLoadedMetadata()
{
return $this->loadedMetadata;
}
/**
* Forces the factory to load the metadata of all classes known to the underlying
* mapping driver.
*
* @return array The ClassMetadata instances of all mapped classes.
*/
public function getAllMetadata()
{
if ( ! $this->initialized) {
$this->initialize();
}
$driver = $this->getDriver();
$metadata = array();
foreach ($driver->getAllClassNames() as $className) {
$metadata[] = $this->getMetadataFor($className);
}
return $metadata;
}
/**
* Lazy initialization of this stuff, especially the metadata driver,
* since these are not needed at all when a metadata cache is active.
*
* @return void
*/
abstract protected function initialize();
/**
* Get the fully qualified class-name from the namespace alias.
*
* @param string $namespaceAlias
* @param string $simpleClassName
* @return string
*/
abstract protected function getFqcnFromAlias($namespaceAlias, $simpleClassName);
/**
* Return the mapping driver implementation.
*
* @return \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
*/
abstract protected function getDriver();
/**
* Wakeup reflection after ClassMetadata gets unserialized from cache.
*
* @param ClassMetadata $class
* @param ReflectionService $reflService
* @return void
*/
abstract protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService);
/**
* Initialize Reflection after ClassMetadata was constructed.
*
* @param ClassMetadata $class
* @param ReflectionService $reflService
* @return void
*/
abstract protected function initializeReflection(ClassMetadata $class, ReflectionService $reflService);
/**
* Gets the class metadata descriptor for a class.
*
* @param string $className The name of the class.
* @return \Doctrine\Common\Persistence\Mapping\ClassMetadata
*/
public function getMetadataFor($className)
{
if ( ! isset($this->loadedMetadata[$className])) {
$realClassName = $className;
// Check for namespace alias
if (strpos($className, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $className);
$realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
if (isset($this->loadedMetadata[$realClassName])) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
return $this->loadedMetadata[$realClassName];
}
}
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt)) !== false) {
$this->loadedMetadata[$realClassName] = $cached;
$this->wakeupReflection($cached, $this->getReflectionService());
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
$this->cacheDriver->save(
$loadedClassName . $this->cacheSalt, $this->loadedMetadata[$loadedClassName], null
);
}
}
} else {
$this->loadMetadata($realClassName);
}
if ($className != $realClassName) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
}
}
return $this->loadedMetadata[$className];
}
/**
* Checks whether the factory has the metadata for a class loaded already.
*
* @param string $className
* @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise.
*/
public function hasMetadataFor($className)
{
return isset($this->loadedMetadata[$className]);
}
/**
* Sets the metadata descriptor for a specific class.
*
* NOTE: This is only useful in very special cases, like when generating proxy classes.
*
* @param string $className
* @param ClassMetadata $class
*/
public function setMetadataFor($className, $class)
{
$this->loadedMetadata[$className] = $class;
}
/**
* Get array of parent classes for the given entity class
*
* @param string $name
* @return array $parentClasses
*/
protected function getParentClasses($name)
{
// Collect parent classes, ignoring transient (not-mapped) classes.
$parentClasses = array();
foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
if ( ! $this->getDriver()->isTransient($parentClass)) {
$parentClasses[] = $parentClass;
}
}
return $parentClasses;
}
/**
* Loads the metadata of the class in question and all it's ancestors whose metadata
* is still not loaded.
*
* @param string $name The name of the class for which the metadata should get loaded.
*
* @return array
*/
protected function loadMetadata($name)
{
if ( ! $this->initialized) {
$this->initialize();
}
$loaded = array();
$parentClasses = $this->getParentClasses($name);
$parentClasses[] = $name;
// Move down the hierarchy of parent classes, starting from the topmost class
$parent = null;
$rootEntityFound = false;
$visited = array();
$reflService = $this->getReflectionService();
foreach ($parentClasses as $className) {
if (isset($this->loadedMetadata[$className])) {
$parent = $this->loadedMetadata[$className];
if (isset($parent->isMappedSuperclass) && $parent->isMappedSuperclass === false) {
$rootEntityFound = true;
array_unshift($visited, $className);
}
continue;
}
$class = $this->newClassMetadataInstance($className);
$this->initializeReflection($class, $reflService);
$this->doLoadMetadata($class, $parent, $rootEntityFound);
$this->loadedMetadata[$className] = $class;
$parent = $class;
if (isset($parent->isMappedSuperclass) && $class->isMappedSuperclass === false) {
$rootEntityFound = true;
array_unshift($visited, $className);
}
$this->wakeupReflection($class, $reflService);
$loaded[] = $className;
}
return $loaded;
}
/**
* Actually load the metadata from the underlying metadata
*
* @param ClassMetadata $class
* @param ClassMetadata $parent
* @param bool $rootEntityFound
* @return void
*/
abstract protected function doLoadMetadata($class, $parent, $rootEntityFound);
/**
* Creates a new ClassMetadata instance for the given class name.
*
* @param string $className
* @return ClassMetadata
*/
abstract protected function newClassMetadataInstance($className);
/**
* Check if this class is mapped by this Object Manager + ClassMetadata configuration
*
* @param $class
* @return bool
*/
public function isTransient($class)
{
if ( ! $this->initialized) {
$this->initialize();
}
return $this->getDriver()->isTransient($class);
}
/**
* Set reflectionService.
*
* @param ReflectionService $reflectionService
*/
public function setReflectionService(ReflectionService $reflectionService)
{
$this->reflectionService = $reflectionService;
}
/**
* Get the reflection service associated with this metadata factory.
*
* @return ReflectionService
*/
public function getReflectionService()
{
if ($this->reflectionService === null) {
$this->reflectionService = new RuntimeReflectionService();
}
return $this->reflectionService;
}
}

View File

@@ -1,56 +0,0 @@
<?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\Persistence\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
/**
* Contract for metadata drivers.
*
* @since 2.2
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
interface MappingDriver
{
/**
* Loads the metadata for the specified class into the provided container.
*
* @param string $className
* @param ClassMetadata $metadata
*/
function loadMetadataForClass($className, ClassMetadata $metadata);
/**
* Gets the names of all mapped classes known to this driver.
*
* @return array The names of all mapped classes known to this driver.
*/
function getAllClassNames();
/**
* Whether the class with the specified name should have its metadata loaded.
* This is only the case if it is either mapped as an Entity or a
* MappedSuperclass.
*
* @param string $className
* @return boolean
*/
function isTransient($className);
}

View File

@@ -1,80 +0,0 @@
<?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\Persistence\Mapping;
/**
* Very simple reflection service abstraction.
*
* This is required inside metadata layers that may require either
* static or runtime reflection.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
interface ReflectionService
{
/**
* Return an array of the parent classes (not interfaces) for the given class.
*
* @param string $class
* @return array
*/
function getParentClasses($class);
/**
* Return the shortname of a class.
*
* @param string $class
* @return string
*/
function getClassShortName($class);
/**
* @param string $class
* @return string
*/
function getClassNamespace($class);
/**
* Return a reflection class instance or null
*
* @param string $class
* @return \ReflectionClass|null
*/
function getClass($class);
/**
* Return an accessible property (setAccessible(true)) or null.
*
* @param string $class
* @param string $property
* @return \ReflectionProperty|null
*/
function getAccessibleProperty($class, $property);
/**
* Check if the class have a public method with the given name.
*
* @param mixed $class
* @param mixed $method
* @return bool
*/
function hasPublicMethod($class, $method);
}

View File

@@ -1,102 +0,0 @@
<?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\Persistence\Mapping;
use ReflectionClass;
use ReflectionProperty;
/**
* PHP Runtime Reflection Service
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class RuntimeReflectionService implements ReflectionService
{
/**
* Return an array of the parent classes (not interfaces) for the given class.
*
* @param string $class
* @return array
*/
public function getParentClasses($class)
{
return class_parents($class);
}
/**
* Return the shortname of a class.
*
* @param string $class
* @return string
*/
public function getClassShortName($class)
{
$r = new ReflectionClass($class);
return $r->getShortName();
}
/**
* @param string $class
* @return string
*/
public function getClassNamespace($class)
{
$r = new ReflectionClass($class);
return $r->getNamespaceName();
}
/**
* Return a reflection class instance or null
*
* @param string $class
* @return ReflectionClass|null
*/
public function getClass($class)
{
return new ReflectionClass($class);
}
/**
* Return an accessible property (setAccessible(true)) or null.
*
* @param string $class
* @param string $property
* @return ReflectionProperty|null
*/
public function getAccessibleProperty($class, $property)
{
$property = new ReflectionProperty($class, $property);
$property->setAccessible(true);
return $property;
}
/**
* Check if the class have a public method with the given name.
*
* @param mixed $class
* @param mixed $method
* @return bool
*/
public function hasPublicMethod($class, $method)
{
return method_exists($class, $method) && is_callable(array($class, $method));
}
}

View File

@@ -1,107 +0,0 @@
<?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\Persistence\Mapping;
use ReflectionClass;
use ReflectionProperty;
/**
* PHP Runtime Reflection Service
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class StaticReflectionService implements ReflectionService
{
/**
* Return an array of the parent classes (not interfaces) for the given class.
*
* @param string $class
* @return array
*/
public function getParentClasses($class)
{
return array();
}
/**
* Return the shortname of a class.
*
* @param string $className
* @return string
*/
public function getClassShortName($className)
{
if (strpos($className, '\\') !== false) {
$className = substr($className, strrpos($className, "\\")+1);
}
return $className;
}
/**
* Return the namespace of a class.
*
* @param string $className
* @return string
*/
public function getClassNamespace($className)
{
$namespace = '';
if (strpos($className, '\\') !== false) {
$namespace = strrev(substr( strrev($className), strpos(strrev($className), '\\')+1 ));
}
return $namespace;
}
/**
* Return a reflection class instance or null
*
* @param string $class
* @return ReflectionClass|null
*/
public function getClass($class)
{
return null;
}
/**
* Return an accessible property (setAccessible(true)) or null.
*
* @param string $class
* @param string $property
* @return ReflectionProperty|null
*/
public function getAccessibleProperty($class, $property)
{
return null;
}
/**
* Check if the class have a public method with the given name.
*
* @param mixed $class
* @param mixed $method
* @return bool
*/
public function hasPublicMethod($class, $method)
{
return method_exists($class, $method) && is_callable(array($class, $method));
}
}

View File

@@ -0,0 +1,247 @@
<?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 WindowsAzure\Table\TableRestProxy;
use WindowsAzure\Table\Models\Entity;
use WindowsAzure\Table\Models\EdmType;
use WindowsAzure\Common\ServiceException;
use Doctrine\KeyValueStore\NotFoundException;
use Doctrine\KeyValueStore\Query\RangeQuery;
use Doctrine\KeyValueStore\Query\RangeQueryStorage;
/**
* 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 = array();
foreach ($entity->getProperties() as $name => $property) {
if ($name === 'PartitionKey') {
$name = 'dist';
} else if ($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 = array("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.");
}
$filters[] = "RowKey " . $condition[0] . " " . $this->quoteFilterValue($condition[1]);
}
$filter = '(' . implode(" and ", $filters) . ')';
$result = $this->client->queryEntities($storageName, $filter);
$rows = array();
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;
} else if (is_float($propertyValue)) {
return EdmType::DOUBLE;
} else if (is_int($propertyValue)) {
return EdmType::INT32;
} else if (is_bool($propertyValue)) {
return EdmType::BOOLEAN;
}
return EdmType::STRING;
}
}

View 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';
}
}

View File

@@ -20,6 +20,7 @@
namespace Doctrine\KeyValueStore\Storage;
use Doctrine\KeyValueStore\NotFoundException;
use Doctrine\DBAL\Connection;
/**
* Relational databased backed system.
@@ -127,10 +128,17 @@ class DBALStorage implements Storage
*/
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(array($key));
$stmt = $qb->execute();
$data = $stmt->fetchColumn();
if (!$data) {
throw new NotFoundException();
}

View File

@@ -0,0 +1,206 @@
<?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 Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Exception\ResourceNotFoundException;
use Aws\DynamoDb\Iterator\ItemIterator;
/**
* DyanmoDb storage
*
* @author Stan Lemon <stosh1985@gmail.com>
*/
class DynamoDbStorage implements Storage
{
/**
* @var \Aws\DynamoDb\DynamoDbClient
*/
protected $client;
/**
* Constructor
*
* @param \Aws\DynamoDb\DynamoDbClient $client
*/
public function __construct(DynamoDbClient $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->createTable($storageName);
$this->prepareData($key, $data);
$result = $this->client->putItem(array(
'TableName' => $storageName,
'Item' => $this->client->formatAttributes($data),
'ReturnConsumedCapacity' => 'TOTAL'
));
}
/**
* {@inheritDoc}
*/
public function update($storageName, $key, array $data)
{
$this->prepareData($key, $data);
unset($data['id']);
foreach ($data as $k => $v) {
$data[$k] = array(
"Value" => $this->client->formatValue($v),
);
}
$result = $this->client->updateItem(array(
'TableName' => $storageName,
'Key' => array(
"id" => array('S' => $key)
),
"AttributeUpdates" => $data,
));
}
/**
* {@inheritDoc}
*/
public function delete($storageName, $key)
{
$result = $this->client->deleteItem(array(
'TableName' => $storageName,
'Key' => array(
'id' => array('S' => $key),
)
));
}
/**
* {@inheritDoc}
*/
public function find($storageName, $key)
{
$iterator = new ItemIterator($this->client->getScanIterator(array(
"TableName" => $storageName,
"Key" => array(
"Id" => array('S' => $key),
),
)));
$results = $iterator->toArray();
if (count($results)) {
return array_shift($results);
}
throw new NotFoundException();
}
/**
* Return a name of the underlying storage.
*
* @return string
*/
public function getName()
{
return 'dynamodb';
}
/**
* @param string $tableName
*/
protected function createTable($tableName)
{
try {
$this->client->describeTable(array(
'TableName' => $tableName,
));
} catch(ResourceNotFoundException $e) {
$this->client->createTable(array(
'AttributeDefinitions' => array(
array(
'AttributeName' => 'id',
'AttributeType' => 'S',
),
),
'TableName' => $tableName,
'KeySchema' => array(
array(
'AttributeName' => 'id',
'KeyType' => 'HASH',
),
),
'ProvisionedThroughput' => array(
'ReadCapacityUnits' => 1,
'WriteCapacityUnits' => 1,
),
));
}
}
/**
* @param string $key
* @param array $data
*/
protected function prepareData($key, &$data)
{
$data = array_merge($data, array(
'id' => $key,
));
foreach ($data as $key => $value) {
if ($value === null || $value === array() || $value === '') {
unset($data[$key]);
}
}
}
}

View File

@@ -0,0 +1,148 @@
<?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 = array())
{
$this->client = $redis;
$this->dbOptions = array_merge(array(
'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;
}
}

View File

@@ -0,0 +1,137 @@
<?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';
}
}

View File

@@ -0,0 +1,183 @@
<?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\KeyValueStoreException;
use Aws\SimpleDb\SimpleDbClient;
use Aws\SimpleDb\Exception\NoSuchDomainException;
use Aws\SimpleDb\Exception\SimpleDbException;
/**
* 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(array(
'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(array(
'DomainName' => $storageName,
'ItemName' => $key,
));
}
/**
* {@inheritDoc}
*/
public function find($storageName, $key)
{
$select = "select * from {$storageName} where itemName() = '{$key}'";
$iterator = $this->client->select(array(
'SelectExpression' => $select,
));
$results = $iterator->get('Items');
if (count($results)) {
$result = array_shift($results);
$data = array('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(array('DomainName' => $domainName));
} catch (NoSuchDomainException $e) {
$this->client->createDomain(array('DomainName' => $domainName));
$domain = $this->client->domainMetadata(array('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 = array();
foreach ($data as $name => $value) {
if ($value !== null && $value !== array() && $value !== '') {
$attributes[] = array(
'Name' => $name,
'Value' => $value,
'Replace' => true,
);
}
}
return $attributes;
}
}

View File

@@ -32,6 +32,7 @@ use Doctrine\KeyValueStore\NotFoundException;
* Using a HTTP client to communicate with the REST API of Azure Table.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @deprecated Use the AzureSdkTableStorage instead, this will be unmaintained.
*/
class WindowsAzureTableStorage implements Storage, RangeQueryStorage
{
@@ -164,20 +165,11 @@ class WindowsAzureTableStorage implements Storage, RangeQueryStorage
$dom = new \DomDocument('1.0', 'UTF-8');
$dom->loadXML($response->getBody());
$message = "";
$nodeList = $dom->getElementsByTagName('Message');
if ($nodeList->length > 0) {
$message = $nodeList->item(0)->nodeValue;
throw new HttpStorageException($message);
}
$node = $dom->getElementsByTagName('Message')->item(0);
$nodeList = $dom->getElementsByTagName('message');
if ($nodeList->length > 0) {
$message = $nodeList->item(0)->nodeValue;
throw new HttpStorageException($message);
}
throw new HttpStorageException($response->getBody());
throw new HttpStorageException(
$node ? $node->nodeValue : "An error has occured"
);
}
public function createTable($tableName)

View File

@@ -19,7 +19,9 @@
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 +31,17 @@ use Doctrine\KeyValueStore\Id\NullIdConverter;
*/
class UnitOfWork
{
/**
* @var ClassMetadataFactory
*/
private $cmf;
/**
* @var Storage
*/
private $storageDriver;
/**
* @var IdHandlingStrategy
*/
private $idHandler;
/**
@@ -49,7 +60,7 @@ class UnitOfWork
private $identityMap = array();
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,16 +70,16 @@ class UnitOfWork
new Id\SingleIdHandler();
}
public function getClassMetadata($name)
public function getClassMetadata($className)
{
return $this->cmf->getMetadataFor($name);
return $this->cmf->getMetadataFor($className);
}
private function tryGetById($id)
private function tryGetById($className, $id)
{
$idHash = $this->idHandler->hash($id);
if (isset($this->identityMap[$idHash])) {
return $this->identityMap[$idHash];
if (isset($this->identityMap[$className][$idHash])) {
return $this->identityMap[$className][$idHash];
}
return null;
}
@@ -96,7 +107,7 @@ class UnitOfWork
}
unset($data['php_class']);
$object = $this->tryGetById($id);
$object = $this->tryGetById($class->name, $id);
if ( $object) {
return $object;
}
@@ -115,9 +126,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;
}
@@ -175,12 +186,12 @@ class UnitOfWork
$idHash = $this->idHandler->hash($id);
if (isset($this->identityMap[$idHash])) {
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)
@@ -194,24 +205,26 @@ class UnitOfWork
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;
}
}
}
}
@@ -236,9 +249,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;
}
}
@@ -252,7 +265,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]);
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace Doctrine\Tests\KeyValueStore\Functional\Storage;
use Doctrine\Tests\KeyValueStoreTestCase;
use Doctrine\KeyValueStore\Storage\AzureSdkTableStorage;
use Doctrine\KeyValueStore\Query\RangeQuery;
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 = array("dist" => "sdktest", "range" => time());
$storage->insert("test", $key, array("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, array("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 = array(
"string" => "foo",
"date" => new \DateTime("now"),
"int" => 1234,
"float" => 123.45,
"bool" => false,
);
$key = array("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', array('dist', 'range'), function($row) {
return $row;
});
$this->assertTrue(count($data) > 0);
}
}

View File

@@ -0,0 +1,145 @@
<?php
namespace Doctrine\Tests\KeyValueStore\Storage;
use Doctrine\KeyValueStore\Storage\CouchbaseStorage;
/**
* Couchbase storage testcase
*
* @author Simon Schick <simonsimcity@gmail.com>
*/
class CouchbaseStorageTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $couchbase;
/**
* @var CouchbaseStorage
*/
private $storage;
protected function setUp()
{
if (!class_exists('\Couchbase'))
$this->markTestSkipped("The PHP extension 'couchbase' is not installed");
$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 = array(
'author' => 'John Doe',
'title' => 'example book',
);
$dbDataset = array();
$this->couchbase->expects($this->once())
->method('add')
->will($this->returnCallback(function($key, $data) use (&$dbDataset) {
$dbDataset[] = array('key' => $key, 'value' => $data);
}));
$this->storage->insert('', '1', $data);
$this->assertCount(1, $dbDataset);
$this->assertEquals(array(array('key' => '1', 'value' => $data)), $dbDataset);
}
public function testUpdate()
{
$data = array(
'author' => 'John Doe',
'title' => 'example book',
);
$dbDataset = array();
$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(array('1' => $data), $dbDataset);
}
public function testDelete()
{
$dataset = array(
'foobar' => array(
'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 = array(
'foobar' => array(
'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 null;
}
));
$data = $this->storage->find('test', 'foobar');
$this->assertEquals($dataset['foobar'], $data);
}
public function testGetName()
{
$this->assertEquals('couchbase', $this->storage->getName());
}
}

View File

@@ -13,8 +13,8 @@ class MongoDbStorageTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if ( ! class_exists('Mongo')) {
$this->markTestSkipped('Mongo needs to be installed');
if ( ! extension_loaded('mongodb')) {
$this->markTestSkipped('MongoDB Extension is not installed.');
}
$this->mongo = $this->getMock('\Mongo');

View File

@@ -0,0 +1,103 @@
<?php
namespace Doctrine\Tests\KeyValueStore\Storage;
use Doctrine\KeyValueStore\Storage\RedisStorage;
/**
* @author Marcel Araujo <admin@marcelaraujo.me>
*/
class RedisStorageTest extends \PHPUnit_Framework_TestCase
{
/**
* @var RedisStorage
*/
private $storage;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $redis;
protected function setup()
{
if ( ! extension_loaded('redis')) {
$this->markTestSkipped('Redis Extension is not installed.');
}
$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 = array(
'author' => 'John Doe',
'title' => 'example book',
);
$dbDataset = array();
$this->redis->expects($this->once())
->method('set')
->will($this->returnCallback(function($key, $data) use (&$dbDataset) {
$dbDataset[] = array('key' => $key, 'value' => $data);
}));
$this->storage->insert('redis', '1', $data);
$this->assertCount(1, $dbDataset);
$this->assertEquals(array(array('key' => $this->storage->getKeyName('1'), 'value' => json_encode($data))), $dbDataset);
}
public function testUpdate()
{
$data = array(
'author' => 'John Doe Updated',
'title' => 'example book updated',
);
$dbDataset = array();
$this->redis->expects($this->once())
->method('set')
->will($this->returnCallback(function($key, $data) use (&$dbDataset) {
$dbDataset[] = array('key' => $key, 'value' => $data);
}));
$this->storage->update('redis', '1', $data);
$this->assertCount(1, $dbDataset);
$this->assertEquals(array(array('key' => $this->storage->getKeyName('1'), 'value' => json_encode($data))), $dbDataset);
}
public function testGetName()
{
$this->assertEquals('redis', $this->storage->getName());
}
}

View File

@@ -0,0 +1,233 @@
<?php
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()
{
$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(array('title' => 'Riak test'), $data);
return $objectMock;
}));
$this->storage->insert('riak-test', 'foobar', array('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(array('title' => 'Riak cookbook'), $data);
}));
$objectMock->expects($this->once())
->method('store');
$this->storage->update('riak-test', 'foobar', array('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(array('title' => 'Riak Test')));
$this->assertEquals(array('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());
}
}

View File

@@ -1,6 +1,6 @@
<?php
if (!@include __DIR__ . '/../vendor/.composer/autoload.php') {
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