Skip to content

Commit

Permalink
Cleaned up code a bit and started implementing converter strategy for…
Browse files Browse the repository at this point in the history
… IDs.
  • Loading branch information
beberlei committed Apr 5, 2012
1 parent 6b11cc2 commit 867d0a7
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 35 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ The Persistence interfaces are rather overkill for many implementations in the N
Following vendors are targeted:

* Microsoft Azure Table (Implemented)
* Doctrine\Common\Cache provider (Implemented)
* RDBMS (Implemented)
* Couchbase
* Amazon DynamoDB
* CouchDB
* MongoDB
* Couchbase
* Riak
* Doctrine\Common\Cache provider (Implemented)
* RDBMS (Implemented)

We happly accept contributions for any of the drivers.
We happily accept contributions for any of the drivers.

## Example

Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/KeyValueStore/EntityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ class EntityManager
*/
private $storageDriver;

public function __construct(Storage $storageDriver, Cache $cache, MappingDriver $mappingDriver)
public function __construct(Storage $storageDriver, Cache $cache, MappingDriver $mappingDriver, array $idConverters = array())
{
$cmf = new ClassMetadataFactory($mappingDriver);
$cmf->setCacheDriver($cache);

$this->unitOfWork = new UnitOfWork($cmf, $storageDriver);
$this->unitOfWork = new UnitOfWork($cmf, $storageDriver, $idConverters);
$this->storageDriver = $storageDriver;
}

Expand Down
36 changes: 36 additions & 0 deletions lib/Doctrine/KeyValueStore/Id/IdConverterStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\KeyValueStore\Id;

/**
* Serialization Interface for Identifiers
*
* This is used to simply convert other entities to serialized identifiers
* and back, for example if an Object-Relational-Mapper Entity is part
* of a key this strategy converts it to its identifier and back.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
interface IdConverterStrategy
{
function serialize($class, $id);
function unserialize($class, $id);
}

34 changes: 34 additions & 0 deletions lib/Doctrine/KeyValueStore/Id/NullIdConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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 LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace Doctrine\KeyValueStore\Id;

class NullIdConverter implements IdConverterStrategy
{
public function serialize($class, $id)
{
return $id;
}

public function unserialize($class, $id)
{
return $id;
}
}

70 changes: 42 additions & 28 deletions lib/Doctrine/KeyValueStore/UnitOfWork.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,34 @@

namespace Doctrine\KeyValueStore;

use Doctrine\KeyValueStore\Id\NullIdConverter;

/**
* UnitOfWork to handle all KeyValueStore entities based on the configured
* storage mechanism.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class UnitOfWork
{
private $cmf;
private $storageDriver;
private $idHandler;
private $identityMap = array();
private $identifiers;
private $originalData;
private $scheduledInsertions = array();
private $scheduledDeletions = array();
private $scheduledDeletions = array();
private $identityMap = array();
private $idConverter;

public function __construct($cmf, $storageDriver)
public function __construct($cmf, $storageDriver, $idConverter = null)
{
$this->cmf = $cmf;
$this->cmf = $cmf;
$this->storageDriver = $storageDriver;
$this->idHandler = $storageDriver->supportsCompositePrimaryKeys() ?
new Id\CompositeIdHandler() :
new Id\SingleIdHandler();
$this->idConverter = $idConverter ?: new NullIdConverter();
$this->idHandler = $storageDriver->supportsCompositePrimaryKeys() ?
new Id\CompositeIdHandler() :
new Id\SingleIdHandler();
}

public function tryGetById($id)
Expand All @@ -51,8 +61,8 @@ public function tryGetById($id)
public function reconsititute($className, $key)
{
$class = $this->cmf->getMetadataFor($className);
$id = $this->idHandler->normalizeId($class, $key);
$data = $this->storageDriver->find($class->storageName, $id);
$id = $this->idHandler->normalizeId($class, $key);
$data = $this->storageDriver->find($class->storageName, $id);

return $this->createEntity($class, $id, $data);
}
Expand All @@ -71,7 +81,8 @@ public function createEntity($class, $id, $data)
if ( ! $object) {
$object = $class->newInstance();
}
$oid = spl_object_hash($object);

$oid = spl_object_hash($object);
$this->originalData[$oid] = $data;

foreach ($data as $property => $value) {
Expand All @@ -84,16 +95,17 @@ public function createEntity($class, $id, $data)

$idHash = $this->idHandler->hash($id);
$this->identityMap[$idHash] = $object;
$this->identifiers[$oid] = $id;
$this->identifiers[$oid] = $id;

return $object;
}

private function computeChangeSet($class, $object)
{
$snapshot = $this->getObjectSnapshot($class, $object);
$changeSet = array();
$snapshot = $this->getObjectSnapshot($class, $object);
$changeSet = array();
$originalData = $this->originalData[spl_object_hash($object)];

foreach ($snapshot as $field => $value) {
if ( ! isset($originalData[$field]) || $originalData[$field] !== $value) {
$changeSet[$field] = $value;
Expand All @@ -109,6 +121,7 @@ private function computeChangeSet($class, $object)
private function getObjectSnapshot($class, $object)
{
$data = array();

foreach ($class->reflFields as $fieldName => $reflProperty) {
if ( ! isset( $class->fields[$fieldName]['id'])) {
$data[$fieldName] = $reflProperty->getValue($object);
Expand All @@ -132,7 +145,7 @@ public function scheduleForInsert($object)
}

$class = $this->cmf->getMetadataFor(get_class($object));
$id = $this->idHandler->getIdentifier($class, $object);
$id = $this->idHandler->getIdentifier($class, $object);

if ( ! $id) {
throw new \RuntimeException("Trying to persist entity that has no id.");
Expand All @@ -143,8 +156,9 @@ public function scheduleForInsert($object)
if (isset($this->identityMap[$idHash])) {
throw new \RuntimeException("Object with ID already exists.");
}

$this->scheduledInsertions[$oid] = $object;
$this->identityMap[$idHash] = $object;
$this->identityMap[$idHash] = $object;
}

public function scheduleForDelete($object)
Expand All @@ -165,7 +179,7 @@ private function processIdentityMap()
continue;
}

$metadata = $this->cmf->getMetadataFor(get_class($object));
$metadata = $this->cmf->getMetadataFor(get_class($object));
$changeSet = $this->computeChangeSet($metadata, $object);

if ($changeSet) {
Expand All @@ -185,32 +199,32 @@ private function processInsertions()
{
foreach ($this->scheduledInsertions as $object) {
$class = $this->cmf->getMetadataFor(get_class($object));
$id = $this->idHandler->getIdentifier($class, $object);
$id = $this->idHandler->getIdentifier($class, $object);

if ( ! $id) {
throw new \RuntimeException("Trying to persist entity that has no id.");
}

$data = $this->getObjectSnapshot($class, $object);
$data = $this->getObjectSnapshot($class, $object);
$data['php_class'] = $class->name;

$oid = spl_object_hash($object);
$idHash = $this->idHandler->hash($id);

$this->storageDriver->insert($class->storageName, $id, $data);

$this->originalData[$oid] = $data;
$this->identifiers[$oid] = $id;
$this->originalData[$oid] = $data;
$this->identifiers[$oid] = $id;
$this->identityMap[$idHash] = $object;
}
}

private function processDeletions()
{
foreach ($this->scheduledDeletions as $object) {
$class = $this->cmf->getMetadataFor(get_class($object));
$oid = spl_object_hash($object);
$id = $this->identifiers[$oid];
$class = $this->cmf->getMetadataFor(get_class($object));
$oid = spl_object_hash($object);
$id = $this->identifiers[$oid];
$idHash = $this->idHandler->hash($id);

$this->storageDriver->delete($class->storageName, $id);
Expand All @@ -226,16 +240,16 @@ public function commit()
$this->processDeletions();

$this->scheduledInsertions = array();
$this->scheduledDeletions = array();
$this->scheduledDeletions = array();
}

public function clear()
{
$this->scheduledInsertions = array();
$this->scheduledDeletions = array();
$this->identifiers = array();
$this->originalData = array();
$this->identityMap = array();
$this->scheduledDeletions = array();
$this->identifiers = array();
$this->originalData = array();
$this->identityMap = array();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,16 @@ public function testUpdateClass()

$this->manager->flush();

$this->assertEquals(array('id' => 1, 'headline' => 'asdf', 'body' => 'bar', 'text' => 'baz', 'php_class' => __NAMESPACE__ . '\\Post'), $this->find(1));
$this->assertEquals(
array(
'id' => 1,
'headline' => 'asdf',
'body' => 'bar',
'text' => 'baz',
'php_class' => __NAMESPACE__ . '\\Post'
),
$this->find(1)
);
}

public function testRemoveClass()
Expand Down

0 comments on commit 867d0a7

Please sign in to comment.