From 469567bceeb028a59fefcfab2f2d9455c6988ff8 Mon Sep 17 00:00:00 2001 From: Georgy Kutsurua Date: Mon, 12 Mar 2012 00:31:55 +0400 Subject: [PATCH 1/6] #75 Add Uuid support --- core/Base/Assert.class.php | 24 +++++++ core/DB/PgSQL.class.php | 12 ++++ .../UnsupportedExtensionException.class.php | 16 +++++ core/Form/Primitive.class.php | 30 +++++++++ .../PrimitiveIdentifierList.class.php | 4 +- core/Form/Primitives/PrimitiveUuid.class.php | 33 ++++++++++ .../PrimitiveUuidIdentifier.class.php | 28 +++++++++ .../PrimitiveUuidIdentifierList.class.php | 27 ++++++++ core/OSQL/DataType.class.php | 2 + main/Base/LightMetaProperty.class.php | 1 + main/Utils/UuidUtils.class.php | 41 ++++++++++++ meta/builders/BaseBuilder.class.php | 7 ++- meta/classes/MetaClassProperty.class.php | 5 ++ meta/types/UuidType.class.php | 57 +++++++++++++++++ test/core/AssertTest.class.php | 19 ++++++ .../PrimitiveUuidIdentifierTest.class.php | 32 ++++++++++ test/core/PrimitiveUuidTest.class.php | 35 +++++++++++ test/main/Utils/UuidUtilsTest.class.php | 35 +++++++++++ test/meta/config.meta.xml | 10 +++ test/misc/DAOTest.class.php | 63 ++++++++++++++++++- 20 files changed, 477 insertions(+), 4 deletions(-) create mode 100644 core/Exceptions/UnsupportedExtensionException.class.php create mode 100644 core/Form/Primitives/PrimitiveUuid.class.php create mode 100644 core/Form/Primitives/PrimitiveUuidIdentifier.class.php create mode 100644 core/Form/Primitives/PrimitiveUuidIdentifierList.class.php create mode 100644 main/Utils/UuidUtils.class.php create mode 100644 meta/types/UuidType.class.php create mode 100644 test/core/PrimitiveUuidIdentifierTest.class.php create mode 100644 test/core/PrimitiveUuidTest.class.php create mode 100644 test/main/Utils/UuidUtilsTest.class.php diff --git a/core/Base/Assert.class.php b/core/Base/Assert.class.php index ea375b18d2..38812e8c9b 100644 --- a/core/Base/Assert.class.php +++ b/core/Base/Assert.class.php @@ -276,6 +276,30 @@ public static function isUnreachable($message = 'unreachable code reached') { throw new WrongArgumentException($message); } + + /** + * Checking UUID + * @see http://tools.ietf.org/html/rfc4122 + * @param string $value + * @return boolean + */ + public static function checkUuid($value) + { + return ( + is_string($value) && + preg_match(PrimitiveUuid::UUID_PATTERN, $value) + ); + } + + public static function isUuid($variable, $message = null) + { + if( + !self::checkUuid($variable) + ) + throw new WrongArgumentException( + $message.', '.self::dumpArgument($variable) + ); + } /// exceptionless methods //@{ diff --git a/core/DB/PgSQL.class.php b/core/DB/PgSQL.class.php index 7a450f7c2b..648b544d5a 100644 --- a/core/DB/PgSQL.class.php +++ b/core/DB/PgSQL.class.php @@ -77,11 +77,23 @@ public function isConnected() public function obtainSequence($sequence) { + if($sequence === 'uuid') + return $this->obtainUuid(); + $res = $this->queryRaw("select nextval('{$sequence}') as seq"); $row = pg_fetch_assoc($res); pg_free_result($res); return $row['seq']; } + + + /** + * @return string + */ + public function obtainUuid() + { + return UuidUtils::make(); + } /** * @return PgSQL diff --git a/core/Exceptions/UnsupportedExtensionException.class.php b/core/Exceptions/UnsupportedExtensionException.class.php new file mode 100644 index 0000000000..950cfab735 --- /dev/null +++ b/core/Exceptions/UnsupportedExtensionException.class.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/core/Form/Primitives/PrimitiveIdentifierList.class.php b/core/Form/Primitives/PrimitiveIdentifierList.class.php index 726349fc31..0a8cfbb480 100644 --- a/core/Form/Primitives/PrimitiveIdentifierList.class.php +++ b/core/Form/Primitives/PrimitiveIdentifierList.class.php @@ -12,11 +12,11 @@ /** * @ingroup Primitives **/ - final class PrimitiveIdentifierList extends PrimitiveIdentifier + class PrimitiveIdentifierList extends PrimitiveIdentifier { protected $value = array(); private $ignoreEmpty = false; - + /** * @return PrimitiveIdentifierList **/ diff --git a/core/Form/Primitives/PrimitiveUuid.class.php b/core/Form/Primitives/PrimitiveUuid.class.php new file mode 100644 index 0000000000..07076a0f6f --- /dev/null +++ b/core/Form/Primitives/PrimitiveUuid.class.php @@ -0,0 +1,33 @@ +setAllowedPattern(self::UUID_PATTERN); + } + } \ No newline at end of file diff --git a/core/Form/Primitives/PrimitiveUuidIdentifier.class.php b/core/Form/Primitives/PrimitiveUuidIdentifier.class.php new file mode 100644 index 0000000000..aefe1426ef --- /dev/null +++ b/core/Form/Primitives/PrimitiveUuidIdentifier.class.php @@ -0,0 +1,28 @@ + 'TIME', self::TIMESTAMP => 'TIMESTAMP', self::INTERVAL => 'INTERVAL', + self::UUID => 'UUID', self::BINARY => 'BINARY', diff --git a/main/Base/LightMetaProperty.class.php b/main/Base/LightMetaProperty.class.php index e3a9225c54..cd83367212 100644 --- a/main/Base/LightMetaProperty.class.php +++ b/main/Base/LightMetaProperty.class.php @@ -137,6 +137,7 @@ public static function fill( ($type == 'identifier') // obsoleted || ($type == 'integerIdentifier') || ($type == 'scalarIdentifier') + || ($type == 'uuidIdentifier') ); return $property; diff --git a/main/Utils/UuidUtils.class.php b/main/Utils/UuidUtils.class.php new file mode 100644 index 0000000000..fac3a15115 --- /dev/null +++ b/main/Utils/UuidUtils.class.php @@ -0,0 +1,41 @@ +getPattern() instanceof AbstractClassPattern) { + $sequenceName = $class->getTableName().'_id'; + + if($class->getIdentifier()->getType() instanceof UuidType) + $sequenceName = 'uuid'; + if ( $class->getIdentifier()->getColumnName() !== 'id' ) { @@ -49,7 +54,7 @@ public function getObjectName() public function getSequence() { - return '{$class->getTableName()}_id'; + return '{$sequenceName}'; } EOT; } elseif ($class->getWithInternalProperties()) { diff --git a/meta/classes/MetaClassProperty.class.php b/meta/classes/MetaClassProperty.class.php index dbac6fe23b..0d0eb7594d 100644 --- a/meta/classes/MetaClassProperty.class.php +++ b/meta/classes/MetaClassProperty.class.php @@ -328,6 +328,9 @@ public function toLightProperty(MetaClass $holder) if ($this->getType() instanceof IntegerType) { $primitiveName = 'integerIdentifier'; $className = $holder->getName(); + } elseif ($this->getType() instanceof UuidType) { + $primitiveName = 'uuidIdentifier'; + $className = $holder->getName(); } elseif ($this->getType() instanceof StringType) { $primitiveName = 'scalarIdentifier'; $className = $holder->getName(); @@ -348,6 +351,8 @@ public function toLightProperty(MetaClass $holder) ) { if ($identifier->getType() instanceof IntegerType) { $primitiveName = 'integerIdentifier'; + } elseif ($identifier->getType() instanceof UuidType) { + $primitiveName = 'uuidIdentifier'; } elseif ($identifier->getType() instanceof StringType) { $primitiveName = 'scalarIdentifier'; } else diff --git a/meta/types/UuidType.class.php b/meta/types/UuidType.class.php new file mode 100644 index 0000000000..cdd8ae939d --- /dev/null +++ b/meta/types/UuidType.class.php @@ -0,0 +1,57 @@ +default = $default; + + return $this; + } + + public function getDeclaration() + { + if ($this->hasDefault()) + return $this->default; + + return 'null'; + } + + public function isMeasurable() + { + return false; + } + + public function toColumnType() + { + return 'DataType::create(DataType::UUID)'; + } + } +?> \ No newline at end of file diff --git a/test/core/AssertTest.class.php b/test/core/AssertTest.class.php index 3cfb09f2d5..db9d74b26a 100644 --- a/test/core/AssertTest.class.php +++ b/test/core/AssertTest.class.php @@ -81,5 +81,24 @@ public function testTernaryBase() $this->fail(); } } + + public function testUuid() + { + $exampleUuid = '550e8400-e29b-41d4-a716-446655440000'; + try { + Assert::isUuid($exampleUuid); + Assert::isUuid(strtoupper($exampleUuid)); + } catch (WrongArgumentException $e) { + $this->fail('uuid asserts working uncorrectly!'); + } + + $uncorrectlyUuid = '550j8400-e29b-41d4-a716-446655440000'; + try { + Assert::isUuid($uncorrectlyUuid); + + $this->fail('uuid asserts working uncorrectly!'); + } catch (WrongArgumentException $e) {} + + } } ?> \ No newline at end of file diff --git a/test/core/PrimitiveUuidIdentifierTest.class.php b/test/core/PrimitiveUuidIdentifierTest.class.php new file mode 100644 index 0000000000..dac8e2c9f5 --- /dev/null +++ b/test/core/PrimitiveUuidIdentifierTest.class.php @@ -0,0 +1,32 @@ +of('TestUuidObject'); + + $nullValues = array(null, ''); + foreach ($nullValues as $value) { + $this->assertNull($prm->import(array('name' => $value))); + $this->assertNull($prm->importValue($value)); + } + + $emptyValues = array(0, '0', false, '550j8400-e29b-41d4-a716-446655440000'); + + foreach ($emptyValues as $value) { + $this->assertFalse($prm->import(array('name' => $value))); + $this->assertFalse($prm->importValue($value)); + } + } + } +?> \ No newline at end of file diff --git a/test/core/PrimitiveUuidTest.class.php b/test/core/PrimitiveUuidTest.class.php new file mode 100644 index 0000000000..b51b444099 --- /dev/null +++ b/test/core/PrimitiveUuidTest.class.php @@ -0,0 +1,35 @@ +assertNull($prm->importValue($value)); + + $falseValues = array('550j8400-e29b-41d4-a716-446655440000', $prm); + + foreach ($falseValues as $value) + $this->assertFalse($prm->importValue($value)); + + $trueValues = array('550e8400-e29b-41d4-a716-446655440000', '550f8400-e29b-41d4-A716-446155440000'); + + foreach ($trueValues as $value) + $this->assertTrue($prm->importValue($value)); + } + + } +?> \ No newline at end of file diff --git a/test/main/Utils/UuidUtilsTest.class.php b/test/main/Utils/UuidUtilsTest.class.php new file mode 100644 index 0000000000..52e13a51e4 --- /dev/null +++ b/test/main/Utils/UuidUtilsTest.class.php @@ -0,0 +1,35 @@ +markTestSkipped('uuid module is not supported, skipped!'); + else { + + /* + * time based uuid + */ + $uuid = UuidUtils::make(); + + try{ + Assert::isUuid($uuid); + } catch(WrongArgumentException $e) { + $this->fail('UuidUtils::make generate uncorrectly id "'.$uuid.'"'); + } + + } + + } + } +?> \ No newline at end of file diff --git a/test/meta/config.meta.xml b/test/meta/config.meta.xml index e4341b477b..d889fbae89 100644 --- a/test/meta/config.meta.xml +++ b/test/meta/config.meta.xml @@ -249,4 +249,14 @@ + + + + + + + + + + diff --git a/test/misc/DAOTest.class.php b/test/misc/DAOTest.class.php index 14f8dacb8a..177a19d77a 100644 --- a/test/misc/DAOTest.class.php +++ b/test/misc/DAOTest.class.php @@ -321,6 +321,22 @@ public function fill($assertions = true) $this->getListByIdsTest(); $this->getListByIdsTest(); } + + $testUuidObj = TestUuidObject::create()->setName('test-uuid-name'); + TestUuidObject::dao()->add($testUuidObj); + $uuid1 = $testUuidObj->getId(); + + $uuid2 = UuidUtils::make(); + $testUuidObj2 = TestUuidObject::create()->setId( + $uuid2 + )->setName('test-uuid-name2'); + TestUuidObject::dao()->import($testUuidObj2); + + if($assertions) + { + $this->uuidTest(); + } + } public function criteriaResult() @@ -698,7 +714,7 @@ public function nonIntegerIdentifier() { $id = 'non-integer-one'; $binaryData = "\0!bbq!\0"; - + $bin = TestBinaryStuff::create()-> setId($id)-> @@ -979,5 +995,50 @@ private function getByEmptyIdTest($id) // pass } } + + private function uuidTest() + { + $count = TestUuidObject::dao()->getTotalCount(); + $list = TestUuidObject::dao()->getPlainList(); + + $this->assertEquals(2, $count); + $this->assertEquals(2, count($list)); + + try{ + Assert::isUuid($list[0]->getId() ); + } catch(WrongArgumentException $e) { + $this->fail('object::id must be uuid, but is not it!'); + } + + $ids = ArrayUtils::getIdsArray($list); + + unset($list); + $list = TestUuidObject::dao()->getListByIds($ids); + + $this->assertEquals(2, count($list) ); + + $prm = Primitive::uuidIdentifierList('ids')->of('TestUuidObject'); + $prm->import( + array( + 'ids' => $ids, + ) + ); + + $this->assertEquals(2, count($prm->getValue() ) ); + $this->assertEquals($list, $prm->getValue() ); + + unset($prm); + $firstId = reset($ids); + + $prm = Primitive::uuidIdentifier('id')->of('TestUuidObject'); + $prm->import( + array( + 'id'=> $firstId + ) + ); + + $this->assertEquals(reset($list), $prm->getValue() ); + + } } ?> \ No newline at end of file From e2ac63f043c847df058f78c9b2ece4cc91342587 Mon Sep 17 00:00:00 2001 From: Georgy Kutsurua Date: Wed, 14 Mar 2012 22:39:18 +0400 Subject: [PATCH 2/6] #73 fix --- core/Form/Primitives/PrimitiveUuid.class.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/Form/Primitives/PrimitiveUuid.class.php b/core/Form/Primitives/PrimitiveUuid.class.php index 07076a0f6f..18b46af359 100644 --- a/core/Form/Primitives/PrimitiveUuid.class.php +++ b/core/Form/Primitives/PrimitiveUuid.class.php @@ -28,6 +28,16 @@ public static function create($name) public function __construct($name) { parent::__construct($name); - $this->setAllowedPattern(self::UUID_PATTERN); + parent::setAllowedPattern(self::UUID_PATTERN); } + + /** + * @param $pattern + * @throws UnsupportedMethodException + */ + public function setAllowedPattern($pattern) + { + throw new UnsupportedMethodException('this method not supported yet!'); + } + } \ No newline at end of file From 8f0fceb1b86cee2a6b96d52f1c29da233bb5c990 Mon Sep 17 00:00:00 2001 From: Georgy Kutsurua Date: Wed, 14 Mar 2012 22:49:05 +0400 Subject: [PATCH 3/6] #75 fix --- core/DB/PgSQL.class.php | 13 ++----------- main/Utils/UuidUtils.class.php | 12 ++++++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/core/DB/PgSQL.class.php b/core/DB/PgSQL.class.php index 648b544d5a..bc0df5a43f 100644 --- a/core/DB/PgSQL.class.php +++ b/core/DB/PgSQL.class.php @@ -77,23 +77,14 @@ public function isConnected() public function obtainSequence($sequence) { - if($sequence === 'uuid') - return $this->obtainUuid(); + if(UuidUtils::isUuidSequence($sequence)) + return UuidUtils::make(); $res = $this->queryRaw("select nextval('{$sequence}') as seq"); $row = pg_fetch_assoc($res); pg_free_result($res); return $row['seq']; } - - - /** - * @return string - */ - public function obtainUuid() - { - return UuidUtils::make(); - } /** * @return PgSQL diff --git a/main/Utils/UuidUtils.class.php b/main/Utils/UuidUtils.class.php index fac3a15115..83ceeb8ae2 100644 --- a/main/Utils/UuidUtils.class.php +++ b/main/Utils/UuidUtils.class.php @@ -15,6 +15,18 @@ class UuidUtils extends StaticFactory { + const SEQUENCE_NAME = 'uuid'; + + /** + * @static + * @param $sequence + * @return bool + */ + public static function isUuidSequence($sequence) + { + return ($sequence === self::SEQUENCE_NAME); + } + /** * @static * @return bool From 1d0dedd23e5e7a2cdbf677883f1251b7ac546197 Mon Sep 17 00:00:00 2001 From: Georgy Kutsurua Date: Tue, 20 Mar 2012 22:24:51 +0400 Subject: [PATCH 4/6] #75 fix --- main/Utils/UuidUtils.class.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main/Utils/UuidUtils.class.php b/main/Utils/UuidUtils.class.php index 83ceeb8ae2..ac82d5fa8d 100644 --- a/main/Utils/UuidUtils.class.php +++ b/main/Utils/UuidUtils.class.php @@ -42,11 +42,14 @@ public static function isExtensionLoaded() * @return string * @throws UnsupportedExtensionException */ - public static function make($type=UUID_TYPE_TIME) + public static function make($type=null) { if(!static::isExtensionLoaded() ) throw new UnsupportedExtensionException('uuid is unloaded, but it needed!'); + if($type===null) + $type=UUID_TYPE_TIME; + return uuid_create($type); } From 4dee5448f6b159169810a60a8ad2c25179910ccc Mon Sep 17 00:00:00 2001 From: Georgy Kutsurua Date: Wed, 28 Mar 2012 00:28:15 +0400 Subject: [PATCH 5/6] fix --- .../PrimitiveIdentifierList.class.php | 18 +++++++++-- .../PrimitiveUuidIdentifierList.class.php | 10 +++++++ test/misc/DAOTest.class.php | 30 +++++++++++++------ 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/core/Form/Primitives/PrimitiveIdentifierList.class.php b/core/Form/Primitives/PrimitiveIdentifierList.class.php index 0a8cfbb480..e64b45b637 100644 --- a/core/Form/Primitives/PrimitiveIdentifierList.class.php +++ b/core/Form/Primitives/PrimitiveIdentifierList.class.php @@ -83,7 +83,20 @@ public function importValue($value) return parent::importValue($value); } - + + /** + * Here we check a identifier + * @param $id + * @return bool + */ + protected function checkIdentifier($id) + { + return ( + ($this->scalar && Assert::checkScalar($id)) + || (!$this->scalar && Assert::checkInteger($id)) + ); + } + public function import($scope) { if (!$this->className) @@ -106,8 +119,7 @@ public function import($scope) continue; if ( - ($this->scalar && !Assert::checkScalar($id)) - || (!$this->scalar && !Assert::checkInteger($id)) + !$this->checkIdentifier($id) ) return false; diff --git a/core/Form/Primitives/PrimitiveUuidIdentifierList.class.php b/core/Form/Primitives/PrimitiveUuidIdentifierList.class.php index 045d8251eb..1ae16f138e 100644 --- a/core/Form/Primitives/PrimitiveUuidIdentifierList.class.php +++ b/core/Form/Primitives/PrimitiveUuidIdentifierList.class.php @@ -14,6 +14,16 @@ **/ class PrimitiveUuidIdentifierList extends PrimitiveIdentifierList { + /** + * @param $id + * @return bool + */ + protected function checkIdentifier($id) + { + return ( + Assert::checkUuid($id) + ); + } protected function checkNumber($number) { diff --git a/test/misc/DAOTest.class.php b/test/misc/DAOTest.class.php index 177a19d77a..46b710ec11 100644 --- a/test/misc/DAOTest.class.php +++ b/test/misc/DAOTest.class.php @@ -324,21 +324,15 @@ public function fill($assertions = true) $testUuidObj = TestUuidObject::create()->setName('test-uuid-name'); TestUuidObject::dao()->add($testUuidObj); - $uuid1 = $testUuidObj->getId(); - $uuid2 = UuidUtils::make(); + $uuid = UuidUtils::make(); $testUuidObj2 = TestUuidObject::create()->setId( - $uuid2 + $uuid )->setName('test-uuid-name2'); TestUuidObject::dao()->import($testUuidObj2); - if($assertions) - { - $this->uuidTest(); - } - } - + public function criteriaResult() { $queryResult = Criteria::create(TestCity::dao())->getResult(); @@ -517,6 +511,24 @@ public function testWorkingWithCache() $this->drop(); } + + public function testUuid() + { + $this->create(); + + foreach (DBTestPool::me()->getPool() as $connector => $db) { + DBPool::me()->setDefault($db); + $this->fill(); + + $this->uuidTest(); + + Cache::me()->clean(); + } + + $this->deletedCount(); + + $this->drop(); + } /** * Install hstore From 03c5ca908c7c2ebf32cc1a18eb2f356f1a2f2f0f Mon Sep 17 00:00:00 2001 From: Georgy Kutsurua Date: Thu, 19 Apr 2012 21:04:12 +0400 Subject: [PATCH 6/6] fix PgSQL->getTableInfo support new uuid type --- core/DB/PgSQL.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/core/DB/PgSQL.class.php b/core/DB/PgSQL.class.php index bc0df5a43f..d4e22a63ed 100644 --- a/core/DB/PgSQL.class.php +++ b/core/DB/PgSQL.class.php @@ -195,6 +195,7 @@ public function getTableInfo($table) 'int4' => DataType::INTEGER, 'int8' => DataType::BIGINT, 'numeric' => DataType::NUMERIC, + 'uuid' => DataType::UUID, 'float4' => DataType::REAL, 'float8' => DataType::DOUBLE,