From 6c48eca1426971819479b81feca7d7567e86169d Mon Sep 17 00:00:00 2001 From: Magomogo Date: Fri, 27 Sep 2013 15:25:16 +0700 Subject: [PATCH] more natural way to have natural keys: can be stored in any field --- lib/Magomogo/Persisted/AbstractProperties.php | 2 +- lib/Magomogo/Persisted/Container/CouchDb.php | 4 +- lib/Magomogo/Persisted/Container/Memory.php | 7 +++- lib/Magomogo/Persisted/Container/SqlDb.php | 16 +++++++- .../Container/SqlDb/SchemaCreator.php | 37 ++++++++++--------- .../Persisted/PropertiesInterface.php | 8 ++-- test/Keymarker/PropertiesTest.php | 8 +++- test/ModelsPersistencyTest.php | 2 +- .../Persisted/Test/Keymarker/Collection.php | 3 +- .../Persisted/Test/Keymarker/Model.php | 2 +- .../Persisted/Test/Keymarker/Properties.php | 6 +-- .../Persisted/Test/ObjectMother/Keymarker.php | 4 +- 12 files changed, 61 insertions(+), 38 deletions(-) diff --git a/lib/Magomogo/Persisted/AbstractProperties.php b/lib/Magomogo/Persisted/AbstractProperties.php index 13b6f5b..ec34084 100644 --- a/lib/Magomogo/Persisted/AbstractProperties.php +++ b/lib/Magomogo/Persisted/AbstractProperties.php @@ -42,7 +42,7 @@ public function id($container) $this->idInContainer[get_class($container)] : null; } - public function naturalKey() + public function naturalKeyFieldName() { return null; } diff --git a/lib/Magomogo/Persisted/Container/CouchDb.php b/lib/Magomogo/Persisted/Container/CouchDb.php index f5effe3..bf5cbf9 100644 --- a/lib/Magomogo/Persisted/Container/CouchDb.php +++ b/lib/Magomogo/Persisted/Container/CouchDb.php @@ -67,8 +67,8 @@ public function saveProperties($properties) $doc = array_merge_recursive($doc, $existingDoc); $this->client->putDocument($doc, $properties->id($this)); } else { - if (!is_null($properties->naturalKey())) { - $doc['_id'] = $properties->naturalKey(); + if (!is_null($properties->naturalKeyFieldName())) { + $doc['_id'] = $properties->{$properties->naturalKeyFieldName()}; } list($id, $rev) = $this->client->postDocument($doc); $properties->persisted($id, $this); diff --git a/lib/Magomogo/Persisted/Container/Memory.php b/lib/Magomogo/Persisted/Container/Memory.php index 579ebe3..f713b87 100644 --- a/lib/Magomogo/Persisted/Container/Memory.php +++ b/lib/Magomogo/Persisted/Container/Memory.php @@ -95,8 +95,13 @@ public function deleteProperties($properties) */ private function notifyOnPersistence($properties) { - $id = $properties->id($this) ?: $properties->naturalKey() ?: self::$autoincrement++; + if (is_null($properties->naturalKeyFieldName())) { + $id = $properties->id($this) ?: self::$autoincrement++; + } else { + $id = $properties->{$properties->naturalKeyFieldName()}; + } $properties->persisted($id, $this); + return $properties; } diff --git a/lib/Magomogo/Persisted/Container/SqlDb.php b/lib/Magomogo/Persisted/Container/SqlDb.php index 1c3a7ae..616a63f 100644 --- a/lib/Magomogo/Persisted/Container/SqlDb.php +++ b/lib/Magomogo/Persisted/Container/SqlDb.php @@ -8,6 +8,7 @@ use Magomogo\Persisted\PossessionInterface; use Magomogo\Persisted\AbstractProperties; use Magomogo\Persisted\Exception; +use Magomogo\Persisted\PropertiesInterface; class SqlDb implements ContainerInterface { @@ -130,7 +131,7 @@ private function begin($properties) $row = $this->db->fetchAssoc( 'SELECT * FROM ' . $this->db->quoteIdentifier($this->names->propertiesToName($properties)) - . ' WHERE id=?', + . ' WHERE ' . $this->db->quoteIdentifier(($properties->naturalKeyFieldName() ?: 'id')) . '=?', array($properties->id($this)) ); @@ -153,7 +154,7 @@ private function commit(array $row, $properties) if (!$properties->id($this)) { $this->db->insert($this->db->quoteIdentifier($tableName), $row); - $properties->persisted($properties->naturalKey() ?: $this->db->lastInsertId($tableName . '_id_seq'), $this); + $properties->persisted($this->defineNewId($properties, $tableName), $this); } else { $this->db->update($this->db->quoteIdentifier($tableName), $row, array('id' => $properties->id($this))); } @@ -265,4 +266,15 @@ private function foreignKeys($references) return $keys; } + + /** + * @param PropertiesInterface $properties + * @param string $tableName + * @return string + */ + private function defineNewId($properties, $tableName) + { + return $properties->naturalKeyFieldName() ? + $properties->{$properties->naturalKeyFieldName()} : $this->db->lastInsertId($tableName . '_id_seq'); + } } diff --git a/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php b/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php index 5844157..20b09ae 100644 --- a/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php +++ b/lib/Magomogo/Persisted/Container/SqlDb/SchemaCreator.php @@ -72,7 +72,7 @@ function($items) use ($properties, $collection, $creator) { } - $properties->persisted($tableName, $this); + $properties->persisted($properties, $this); return $properties; } @@ -99,10 +99,12 @@ public function many2manySchema($collection, $leftProperties, array $manyPropert $rightProperties = reset($manyProperties); $table = new Table($this->quoteIdentifier($referenceName)); $this->addForeignReferenceColumn( - $table, $this->names->propertiesToName($leftProperties), $leftProperties + $table, $this->names->propertiesToName($leftProperties), $leftProperties, + array('onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE') ); $this->addForeignReferenceColumn( - $table, $this->names->propertiesToName($rightProperties), $rightProperties + $table, $this->names->propertiesToName($rightProperties), $rightProperties, + array('onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE') ); $this->manager->createTable($table); } @@ -126,12 +128,10 @@ private function defineSchemaForField($table, $fieldName, $fieldValue) { if (is_string($fieldValue)) { $table->addColumn($this->quoteIdentifier($fieldName), 'text', array('notNull' => false)); } elseif ($fieldValue instanceof ModelInterface) { - $table->addColumn($this->quoteIdentifier($fieldName), 'integer', array('unsigned' => true, 'notNull' => false)); - $relatedTable = $fieldValue->save($this); - $table->addForeignKeyConstraint( - $this->quoteIdentifier($relatedTable), - array($this->quoteIdentifier($fieldName)), - array('id'), + $this->addForeignReferenceColumn( + $table, + $fieldName, + $fieldValue->save($this), array('onUpdate' => 'RESTRICT', 'onDelete' => 'SET NULL') ); } elseif ($fieldValue instanceof \DateTime) { @@ -150,23 +150,24 @@ private function newTableObject($properties, $tableName) { $table = new Table($this->quoteIdentifier($tableName)); - if (!isset($properties->id)) { + if (is_null($properties->naturalKeyFieldName())) { $table->addColumn('id', 'integer', array('unsigned' => true, 'autoincrement' => true)); } foreach ($properties as $name => $value) { - if (($name === 'id') && is_string($value)) { - $table->addColumn('id', 'string', array('length' => 255, 'notnull' => true)); + if ($properties->naturalKeyFieldName() === $name) { + $table->addColumn($name, 'string', array('length' => 255, 'notnull' => true)); } else { $this->defineSchemaForField($table, $name, $value); } } - $table->setPrimaryKey(array('id')); + $table->setPrimaryKey(array($properties->naturalKeyFieldName() ?: 'id')); if ($properties instanceof PossessionInterface) { foreach ($properties->foreign() as $propertyName => $foreignProperties) { - $this->addForeignReferenceColumn($table, $propertyName, $foreignProperties); + $this->addForeignReferenceColumn($table, $propertyName, $foreignProperties, + array('onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE')); } } @@ -178,9 +179,9 @@ private function newTableObject($properties, $tableName) * @param string $columnName * @param AbstractProperties $leftProperties */ - private function addForeignReferenceColumn($table, $columnName, $leftProperties) + private function addForeignReferenceColumn($table, $columnName, $leftProperties, $options) { - if ($leftProperties->naturalKey() && is_string($leftProperties->naturalKey())) { + if ($leftProperties->naturalKeyFieldName()) { $table->addColumn($this->quoteIdentifier($columnName), 'string', array('length' => 255, 'notnull' => false)); } else { $table->addColumn( @@ -192,8 +193,8 @@ private function addForeignReferenceColumn($table, $columnName, $leftProperties) $table->addForeignKeyConstraint( $this->quoteIdentifier($this->names->propertiesToName($leftProperties)), array($this->quoteIdentifier($columnName)), - array('id'), - array('onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE') + array($leftProperties->naturalKeyFieldName() ?: 'id'), + $options ); } diff --git a/lib/Magomogo/Persisted/PropertiesInterface.php b/lib/Magomogo/Persisted/PropertiesInterface.php index 72b7187..9cf02a4 100644 --- a/lib/Magomogo/Persisted/PropertiesInterface.php +++ b/lib/Magomogo/Persisted/PropertiesInterface.php @@ -14,12 +14,12 @@ interface PropertiesInterface public function id($container); /** - * Optionally defines natural key value - * null value forces container to set its artificial identifier + * Optionally defines natural key + * null value forces container to use its specific artificial identifier * - * @return mixed + * @return string|null */ - public function naturalKey(); + public function naturalKeyFieldName(); /** * The message. A container stored properties giving particular identifier diff --git a/test/Keymarker/PropertiesTest.php b/test/Keymarker/PropertiesTest.php index 67058ce..53f9d4b 100644 --- a/test/Keymarker/PropertiesTest.php +++ b/test/Keymarker/PropertiesTest.php @@ -1,11 +1,15 @@ 'Natural')); - $this->assertEquals('Natural', $properties->naturalKey()); + $properties = new Properties(array('name' => 'Natural')); + $container = new Memory(); + $container->saveProperties($properties); + $this->assertEquals('Natural', $properties->id($container)); } } diff --git a/test/ModelsPersistencyTest.php b/test/ModelsPersistencyTest.php index 75d120b..072e085 100644 --- a/test/ModelsPersistencyTest.php +++ b/test/ModelsPersistencyTest.php @@ -157,7 +157,7 @@ private static function employeeModel($container) $company = ObjectMother\Company::xiag(); $company->save($container); - $keymarker = new Keymarker\Model(new Keymarker\Properties(array('id' => 'test'))); + $keymarker = new Keymarker\Model(new Keymarker\Properties(array('name' => 'test'))); $keymarker->save($container); return new Employee\Model( diff --git a/test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php b/test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php index 207e355..9670a2a 100644 --- a/test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php +++ b/test/_classes/Magomogo/Persisted/Test/Keymarker/Collection.php @@ -25,8 +25,9 @@ public function propertiesOperation($function) parent::propertiesOperation($function); $indexedItems = array(); + /** @var Properties $property */ foreach ($this->items as $property) { - $indexedItems[$property->id] = $property; + $indexedItems[$property->name] = $property; } $this->items = $indexedItems; } diff --git a/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php b/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php index de397ed..6ba1a1f 100644 --- a/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php +++ b/test/_classes/Magomogo/Persisted/Test/Keymarker/Model.php @@ -41,7 +41,7 @@ public function __construct($properties) public function __toString() { - return $this->properties->id; + return $this->properties->name; } /** diff --git a/test/_classes/Magomogo/Persisted/Test/Keymarker/Properties.php b/test/_classes/Magomogo/Persisted/Test/Keymarker/Properties.php index d54ce4c..32a184e 100644 --- a/test/_classes/Magomogo/Persisted/Test/Keymarker/Properties.php +++ b/test/_classes/Magomogo/Persisted/Test/Keymarker/Properties.php @@ -12,13 +12,13 @@ class Properties extends AbstractProperties protected function properties() { return array( - 'id' => '', + 'name' => '', 'created' => new \DateTime(date('c')) ); } - public function naturalKey() + public function naturalKeyFieldName() { - return $this->id; + return 'name'; } } diff --git a/test/_classes/Magomogo/Persisted/Test/ObjectMother/Keymarker.php b/test/_classes/Magomogo/Persisted/Test/ObjectMother/Keymarker.php index 0d20706..6014665 100644 --- a/test/_classes/Magomogo/Persisted/Test/ObjectMother/Keymarker.php +++ b/test/_classes/Magomogo/Persisted/Test/ObjectMother/Keymarker.php @@ -9,14 +9,14 @@ class Keymarker public static function friend() { return new Model( - new Properties(array('id' => 'Friend', 'created' => new \DateTime('2012-12-08T10:16+07:00'))) + new Properties(array('name' => 'Friend', 'created' => new \DateTime('2012-12-08T10:16+07:00'))) ); } public static function IT() { return new Model( - new Properties(array('id' => 'IT', 'created' => new \DateTime('2012-12-08T10:36+07:00'))) + new Properties(array('name' => 'IT', 'created' => new \DateTime('2012-12-08T10:36+07:00'))) ); }