From ec1cc43e92ac25194e6fdd0802d6c7624632f1af Mon Sep 17 00:00:00 2001 From: Magomogo Date: Wed, 18 Sep 2013 12:26:01 +0700 Subject: [PATCH] initial version of property bag collections --- .../Persisted/CollectableModelInterface.php | 12 +++ .../Persisted/CollectionOwnerInterface.php | 8 ++ .../Container/ContainerInterface.php | 13 +-- lib/Magomogo/Persisted/Container/Memory.php | 27 +++--- lib/Magomogo/Persisted/Container/SqlDb.php | 60 +++++++++--- .../Container/SqlDb/NamesInterface.php | 2 + .../Container/SqlDb/SchemaCreator.php | 27 ++++-- .../Persisted/PropertyBagCollection.php | 94 +++++++++++++++++++ test/Persisted/Container/MemoryTest.php | 5 + test/Persisted/PropertyBagCollectionTest.php | 75 +++++++++++++++ test/Person/ModelTest.php | 1 + .../Magomogo/Persisted/Test/DbNames.php | 5 + .../Persisted/Test/Employee/Model.php | 2 +- .../Persisted/Test/Employee/Properties.php | 3 +- .../Persisted/Test/JobRecord/Properties.php | 2 +- .../Persisted/Test/Keymarker/Collection.php | 22 +++++ .../Persisted/Test/Keymarker/Model.php | 11 ++- .../Magomogo/Persisted/Test/Person/Model.php | 4 +- .../Persisted/Test/Person/Properties.php | 45 ++------- 19 files changed, 334 insertions(+), 84 deletions(-) create mode 100644 lib/Magomogo/Persisted/CollectableModelInterface.php create mode 100644 lib/Magomogo/Persisted/CollectionOwnerInterface.php create mode 100644 lib/Magomogo/Persisted/PropertyBagCollection.php create mode 100644 test/Persisted/PropertyBagCollectionTest.php create mode 100644 test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php diff --git a/lib/Magomogo/Persisted/CollectableModelInterface.php b/lib/Magomogo/Persisted/CollectableModelInterface.php new file mode 100644 index 0000000..07bcaf6 --- /dev/null +++ b/lib/Magomogo/Persisted/CollectableModelInterface.php @@ -0,0 +1,12 @@ +saveProperties($leftProperties); - $this->manyToManyReferences[$referenceName] = array(); + $this->saveProperties($ownerProperties); + $this->manyToManyReferences[$collectionBag] = array(); foreach ($connections as $rightProperties) { - $this->manyToManyReferences[$referenceName][] = array( - 'left' => $leftProperties->id($this), + $this->manyToManyReferences[$collectionBag][] = array( + 'left' => $ownerProperties->id($this), 'right' => $rightProperties, ); $this->saveProperties($rightProperties); @@ -87,15 +88,15 @@ public function referToMany($referenceName, $leftProperties, array $connections) } /** - * @param string $referenceName - * @param PropertyBag $leftProperties + * @param string $collectionBag + * @param PropertyBag $ownerProperties * @return array */ - public function listReferences($referenceName, $leftProperties) + public function listReferences($collectionBag, $ownerProperties) { $connections = array(); - foreach ($this->manyToManyReferences[$referenceName] as $pair) { - if ($leftProperties->id($this) === $pair['left']) { + foreach ($this->manyToManyReferences[$collectionBag] as $pair) { + if ($ownerProperties->id($this) === $pair['left']) { $connections[] = $pair['right']; } } diff --git a/lib/Magomogo/Persisted/Container/SqlDb.php b/lib/Magomogo/Persisted/Container/SqlDb.php index 4c4a797..d20eade 100644 --- a/lib/Magomogo/Persisted/Container/SqlDb.php +++ b/lib/Magomogo/Persisted/Container/SqlDb.php @@ -2,9 +2,11 @@ namespace Magomogo\Persisted\Container; use Doctrine\DBAL\Connection; +use Magomogo\Persisted\CollectionOwnerInterface; use Magomogo\Persisted\Container\SqlDb\NamesInterface; use Magomogo\Persisted\ModelInterface; use Magomogo\Persisted\PossessionInterface; +use Magomogo\Persisted\PropertyBagCollection; use Magomogo\Persisted\PropertyBag; use Magomogo\Persisted\Exception; @@ -44,6 +46,9 @@ public function loadProperties($propertyBag) if ($propertyBag instanceof PossessionInterface) { $this->collectReferences($row, $propertyBag->foreign()); } + if ($propertyBag instanceof CollectionOwnerInterface) { + $this->collectCollections($propertyBag); + } return $propertyBag; } @@ -64,8 +69,13 @@ public function saveProperties($propertyBag) foreach ($propertyBag as $name => $property) { $row[$this->db->quoteIdentifier($name)] = $this->toDbValue($property); } + $this->commit($row, $propertyBag); + + if ($propertyBag instanceof CollectionOwnerInterface) { + $this->saveCollections($propertyBag); + } - return $this->commit($row, $propertyBag); + return $propertyBag; } /** @@ -79,15 +89,18 @@ public function deleteProperties(array $propertyBags) } /** - * @param string $referenceName - * @param \Magomogo\Persisted\PropertyBag $leftProperties - * @param array $connections + * @param PropertyBagCollection $collectionBag + * @param \Magomogo\Persisted\PropertyBag $ownerProperties + * @param $connections + * @internal param array $connections */ - public function referToMany($referenceName, $leftProperties, array $connections) + public function referToMany($collectionBag, $ownerProperties, array $connections) { + $referenceName = $this->names->manyToManyRelationName($collectionBag, $ownerProperties); + $this->db->delete( $this->db->quoteIdentifier($referenceName), - array($this->db->quoteIdentifier($this->names->classToName($leftProperties)) => $leftProperties->id($this)) + array($this->db->quoteIdentifier($this->names->classToName($ownerProperties)) => $ownerProperties->id($this)) ); /** @var PropertyBag $rightProperties */ @@ -95,7 +108,7 @@ public function referToMany($referenceName, $leftProperties, array $connections) $this->db->insert( $this->db->quoteIdentifier($referenceName), array( - $this->db->quoteIdentifier($this->names->classToName($leftProperties)) => $leftProperties->id($this), + $this->db->quoteIdentifier($this->names->classToName($ownerProperties)) => $ownerProperties->id($this), $this->db->quoteIdentifier($this->names->classToName($rightProperties)) => $rightProperties->id($this), ) ); @@ -103,18 +116,19 @@ public function referToMany($referenceName, $leftProperties, array $connections) } /** - * @param string $referenceName - * @param \Magomogo\Persisted\PropertyBag $leftProperties + * @param PropertyBagCollection $collectionBag + * @param \Magomogo\Persisted\PropertyBag $ownerProperties * @return array */ - public function listReferences($referenceName, $leftProperties) + public function listReferences($collectionBag, $ownerProperties) { - $leftPropertiesName = $this->names->classToName($leftProperties); + $referenceName = $this->names->manyToManyRelationName($collectionBag, $ownerProperties); + $leftPropertiesName = $this->names->classToName($ownerProperties); $list = $this->db->fetchAll( 'SELECT * FROM ' . $this->db->quoteIdentifier($referenceName) . ' WHERE ' . $this->db->quoteIdentifier($leftPropertiesName) . '=?', - array($leftProperties->id($this)) + array($ownerProperties->id($this)) ); $connections = array(); @@ -211,6 +225,28 @@ private function collectReferences(array $row, $references) return $references; } + /** + * @param CollectionOwnerInterface $propertyBag + */ + private function collectCollections($propertyBag) + { + /** @var PropertyBagCollection $collection */ + foreach ($propertyBag->collections() as $collectionName => $collection) { + $collection->loadFrom($this); + } + } + + /** + * @param CollectionOwnerInterface $propertyBag + */ + private function saveCollections($propertyBag) + { + /** @var PropertyBagCollection $collection */ + foreach ($propertyBag->collections() as $collectionName => $collection) { + $collection->putIn($this); + } + } + private function foreignKeys($references) { $keys = array(); diff --git a/lib/Magomogo/Persisted/Container/SqlDb/NamesInterface.php b/lib/Magomogo/Persisted/Container/SqlDb/NamesInterface.php index 0b88533..131e36a 100644 --- a/lib/Magomogo/Persisted/Container/SqlDb/NamesInterface.php +++ b/lib/Magomogo/Persisted/Container/SqlDb/NamesInterface.php @@ -17,4 +17,6 @@ public function classToName($propertyBag); * @return PropertyBag */ public function nameToClass($name); + + public function manyToManyRelationName($collectionBag, $ownerPropertyBag); } \ No newline at end of file diff --git a/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php b/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php index 98d3194..5967c0d 100644 --- a/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php +++ b/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php @@ -7,8 +7,10 @@ use Magomogo\Persisted\Container\ContainerInterface; use Magomogo\Persisted\ModelInterface; use Magomogo\Persisted\PossessionInterface; +use Magomogo\Persisted\PropertyBagCollection; use Magomogo\Persisted\PropertyBag; use Magomogo\Persisted\Exception; +use Magomogo\Persisted\CollectionOwnerInterface; class SchemaCreator implements ContainerInterface { @@ -58,6 +60,14 @@ public function saveProperties($propertyBag) $this->manager->createTable( $this->newTableObject($propertyBag, $tableName) ); + + if ($propertyBag instanceof CollectionOwnerInterface) { + /** @var PropertyBagCollection $collection */ + foreach ($propertyBag->collections() as $collectionName => $collection) { + $collection->putIn($this); + } + } + } $propertyBag->persisted($tableName, $this); @@ -74,18 +84,20 @@ public function deleteProperties(array $propertyBags) } /** - * @param string $referenceName - * @param \Magomogo\Persisted\PropertyBag $leftProperties + * @param PropertyBagCollection $collectionBag + * @param \Magomogo\Persisted\PropertyBag $ownerProperties * @param array $connections array of \Magomogo\Model\PropertyBag * @return void */ - public function referToMany($referenceName, $leftProperties, array $connections) + public function referToMany($collectionBag, $ownerProperties, array $connections) { + $referenceName = $this->names->manyToManyRelationName($collectionBag, $ownerProperties); + if (!empty($connections) && !in_array($referenceName, $this->manager->listTableNames())) { $rightProperties = reset($connections); $table = new Table($this->quoteIdentifier($referenceName)); $this->addForeignReferenceColumn( - $table, $this->names->classToName($leftProperties), $leftProperties + $table, $this->names->classToName($ownerProperties), $ownerProperties ); $this->addForeignReferenceColumn( $table, $this->names->classToName($rightProperties), $rightProperties @@ -95,12 +107,11 @@ public function referToMany($referenceName, $leftProperties, array $connections) } /** - * @param string $referenceName - * @param \Magomogo\Persisted\PropertyBag $leftProperties - * @internal param string $rightPropertiesSample + * @param string $collectionBag + * @param \Magomogo\Persisted\PropertyBag $ownerProperties * @return array of \Magomogo\Model\PropertyBag */ - public function listReferences($referenceName, $leftProperties) + public function listReferences($collectionBag, $ownerProperties) { trigger_error('Incorrect usage', E_USER_ERROR); } diff --git a/lib/Magomogo/Persisted/PropertyBagCollection.php b/lib/Magomogo/Persisted/PropertyBagCollection.php new file mode 100644 index 0000000..b0192df --- /dev/null +++ b/lib/Magomogo/Persisted/PropertyBagCollection.php @@ -0,0 +1,94 @@ +listReferences($this, $this->owner) as $properties) { + /** @var PropertyBag $properties */ + $this->items[] = $properties; + } + return $this; + } + + /** + * @param ContainerInterface $container + * @return $this + */ + public function putIn($container) + { + $container->referToMany($this, $this->owner, $this->items); + return $this; + } + + public function appendPropertyBag($propertyBag, $offset) + { + if (is_null($offset)) { + $this->items[] = $propertyBag; + } else { + $this->items[$offset] = $propertyBag; + } + } + + public function count() + { + return count($this->items); + } + + public function offsetExists($offset) + { + return array_key_exists($offset, $this->items); + } + + public function offsetGet($offset) + { + return $this->constructModel($this->items[$offset]); + } + + /** + * @param mixed $offset + * @param CollectableModelInterface $value + */ + public function offsetSet($offset, $value) + { + $value->appendToCollection($this, $offset); + } + + public function offsetUnset($offset) + { + unset($this->items[$offset]); + } + + public function getIterator() + { + return new \ArrayIterator($this->asArray()); + } + + public function asArray() + { + $models = array(); + foreach ($this->items as $offset => $propertyBag) { + $models[$offset] = $this->constructModel($propertyBag); + } + return $models; + } +} \ No newline at end of file diff --git a/test/Persisted/Container/MemoryTest.php b/test/Persisted/Container/MemoryTest.php index e0e2814..26bde57 100644 --- a/test/Persisted/Container/MemoryTest.php +++ b/test/Persisted/Container/MemoryTest.php @@ -13,6 +13,11 @@ class MemoryTest extends \PHPUnit_Framework_TestCase { + protected function setUp() + { + $this->markTestIncomplete(); + } + /** * @dataProvider modelsProvider */ diff --git a/test/Persisted/PropertyBagCollectionTest.php b/test/Persisted/PropertyBagCollectionTest.php new file mode 100644 index 0000000..86dc6bb --- /dev/null +++ b/test/Persisted/PropertyBagCollectionTest.php @@ -0,0 +1,75 @@ +assertCount(0, new TestCollection()); + } + + public function testArrayAccess() + { + $collection = self::loadedCollection(); + $this->assertNotNull($collection[0]); + $this->assertNotNull($collection[1]); + $this->assertArrayNotHasKey(2, $collection); + } + + public function testConstructsModelOnOffsetGet() + { + $collection = self::loadedCollection(); + $this->assertInstanceOf('Magomogo\\Persisted\\Test\\Keymarker\\Model', $collection[0]); + } + + public function testCanBeAppendedByAModelStoringItsProperties() + { + $collection = new TestCollection; + $collection[] = Test\ObjectMother\Keymarker::IT(); + + $this->assertEquals(Test\ObjectMother\Keymarker::IT(), $collection[0]); + + $container = m::mock(); + $container + ->shouldReceive('referToMany') + ->with( + anything(), + anything(), + m::on(function($arg) { + return (count($arg) == 1) && ($arg[0] instanceof Keymarker\Properties); + })) + ->once(); + $collection->putIn($container); + } + + /** + * @return TestCollection + */ + private static function loadedCollection() + { + $collection = new TestCollection(); + $collection->loadFrom( + m::mock( + array( + 'listReferences' => array(new Keymarker\Properties, new Keymarker\Properties) + ) + ) + ); + return $collection; + } +} + +//====================================================================================================================== + +class TestCollection extends PropertyBagCollection { + + protected function constructModel($propertyBag) + { + return new Keymarker\Model($propertyBag); + } +} \ No newline at end of file diff --git a/test/Person/ModelTest.php b/test/Person/ModelTest.php index b3b242b..1d0fec4 100644 --- a/test/Person/ModelTest.php +++ b/test/Person/ModelTest.php @@ -43,6 +43,7 @@ public function testCanBeSavedIntoAPropertyContainer() $container = m::mock(); $container->shouldReceive('saveProperties') ->with(m::on(function($p) use ($container) {$p->persisted(15, $container); return true;})) + ->andReturnUsing(function($p) {return $p;}) ->once(); $container->shouldIgnoreMissing(); diff --git a/test/_classes/Magomogo/Persisted/Test/DbNames.php b/test/_classes/Magomogo/Persisted/Test/DbNames.php index 72d2f37..030cdb9 100644 --- a/test/_classes/Magomogo/Persisted/Test/DbNames.php +++ b/test/_classes/Magomogo/Persisted/Test/DbNames.php @@ -27,6 +27,11 @@ public function nameToClass($name) return new $className; } + public function manyToManyRelationName($collectionBag, $ownerPropertyBag) + { + return 'person2keymarker'; + } + //---------------------------------------------------------------------------------------------------------------------- /** diff --git a/test/_classes/Magomogo/Persisted/Test/Employee/Model.php b/test/_classes/Magomogo/Persisted/Test/Employee/Model.php index b5d210f..a61cf02 100644 --- a/test/_classes/Magomogo/Persisted/Test/Employee/Model.php +++ b/test/_classes/Magomogo/Persisted/Test/Employee/Model.php @@ -26,7 +26,7 @@ public static function load($container, $id) { $p = new Properties(); $p->loadFrom($container, $id); - return new self(new Company\Model($p->foreign()->company), $p, $p->tags); + return new self(new Company\Model($p->foreign()->company), $p, $p->tags->asArray()); } /** diff --git a/test/_classes/Magomogo/Persisted/Test/Employee/Properties.php b/test/_classes/Magomogo/Persisted/Test/Employee/Properties.php index ed66578..7e56650 100644 --- a/test/_classes/Magomogo/Persisted/Test/Employee/Properties.php +++ b/test/_classes/Magomogo/Persisted/Test/Employee/Properties.php @@ -18,8 +18,9 @@ class Properties extends Person\Properties implements PossessionInterface { private $ownerCompanyProperties; - public function init() + protected function init() { + parent::init(); $this->ownerCompanyProperties = new Company\Properties; } diff --git a/test/_classes/Magomogo/Persisted/Test/JobRecord/Properties.php b/test/_classes/Magomogo/Persisted/Test/JobRecord/Properties.php index e920978..694f257 100644 --- a/test/_classes/Magomogo/Persisted/Test/JobRecord/Properties.php +++ b/test/_classes/Magomogo/Persisted/Test/JobRecord/Properties.php @@ -25,7 +25,7 @@ protected function properties() return array(); } - public function init() + protected function init() { $this->currentCompanyProps = new Company\Properties; $this->previousCompanyProps = new Company\Properties; diff --git a/test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php b/test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php new file mode 100644 index 0000000..394f918 --- /dev/null +++ b/test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php @@ -0,0 +1,22 @@ +owner = $owner; + } + + /** + * @param Properties $propertyBag + * @return Model + */ + protected function constructModel($propertyBag) + { + return new Model($propertyBag); + } +} \ No newline at end of file diff --git a/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php b/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php index 39b7ec5..33436a5 100644 --- a/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php +++ b/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php @@ -1,11 +1,12 @@ properties; + $collection->appendPropertyBag($this->properties, $offset); } } diff --git a/test/_classes/Magomogo/Persisted/Test/Person/Model.php b/test/_classes/Magomogo/Persisted/Test/Person/Model.php index 8d1e955..1ba6b7a 100644 --- a/test/_classes/Magomogo/Persisted/Test/Person/Model.php +++ b/test/_classes/Magomogo/Persisted/Test/Person/Model.php @@ -21,7 +21,7 @@ public static function load($container, $id) { $p = new Properties(); $p->loadFrom($container, $id); - return new self($p, $p->tags); + return new self($p, $p->tags->asArray()); } public function save($container) @@ -81,7 +81,7 @@ public function tag(Keymarker $keymarker) public function taggedAs() { - return join(', ', $this->properties->tags); + return join(', ', $this->properties->tags->asArray()); } } diff --git a/test/_classes/Magomogo/Persisted/Test/Person/Properties.php b/test/_classes/Magomogo/Persisted/Test/Person/Properties.php index dfb0c71..93189bc 100644 --- a/test/_classes/Magomogo/Persisted/Test/Person/Properties.php +++ b/test/_classes/Magomogo/Persisted/Test/Person/Properties.php @@ -1,6 +1,7 @@ persisted($id, $container); - $container->loadProperties($this); - - $this->tags = array(); - foreach ($container->listReferences('person2keymarker', $this) - as $keymarkerProperties) { - /** @var Keymarker\Properties $keymarkerProperties */ - $this->tags[$keymarkerProperties->id] = new Keymarker\Model($keymarkerProperties); - } - return $this; + $this->tags = new Keymarker\Collection($this); } - /** - * @param \Magomogo\Persisted\Container\ContainerInterface $container - * @return string - */ - public function putIn($container) + public function collections() { - $container->saveProperties($this); - - $list = array(); - /** @var Keymarker\Model $keymarker */ - foreach ($this->tags as $keymarker) { - $list[] = $keymarker->propertiesToBeConnectedWith($this); - } - $container->referToMany('person2keymarker', $this, $list); - - return $this->id($container); + $collections = new \stdClass(); + $collections->tags = $this->tags; + return $collections; } - }