diff --git a/core/Base/Assert.class.php b/core/Base/Assert.class.php index 1c41da0ffc..08aee64de6 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) + ); + } public static function isObject($object, $message = null) { diff --git a/core/DB/PgSQL.class.php b/core/DB/PgSQL.class.php index 7a450f7c2b..d4e22a63ed 100644 --- a/core/DB/PgSQL.class.php +++ b/core/DB/PgSQL.class.php @@ -77,6 +77,9 @@ public function isConnected() public function obtainSequence($sequence) { + if(UuidUtils::isUuidSequence($sequence)) + return UuidUtils::make(); + $res = $this->queryRaw("select nextval('{$sequence}') as seq"); $row = pg_fetch_assoc($res); pg_free_result($res); @@ -192,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, 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..e64b45b637 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 **/ @@ -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/PrimitiveUuid.class.php b/core/Form/Primitives/PrimitiveUuid.class.php new file mode 100644 index 0000000000..18b46af359 --- /dev/null +++ b/core/Form/Primitives/PrimitiveUuid.class.php @@ -0,0 +1,43 @@ + '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 78bf621ef3..1d8c77cd29 100644 --- a/main/Base/LightMetaProperty.class.php +++ b/main/Base/LightMetaProperty.class.php @@ -138,6 +138,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..ac82d5fa8d --- /dev/null +++ b/main/Utils/UuidUtils.class.php @@ -0,0 +1,56 @@ +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 b8572961ca..b40744fa53 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(); @@ -350,6 +353,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 ba98dc7840..89b57bd263 100644 --- a/test/meta/config.meta.xml +++ b/test/meta/config.meta.xml @@ -257,4 +257,14 @@ + + + + + + + + + + diff --git a/test/misc/DAOTest.class.php b/test/misc/DAOTest.class.php index e0e2baaf21..787723ebd7 100644 --- a/test/misc/DAOTest.class.php +++ b/test/misc/DAOTest.class.php @@ -358,8 +358,18 @@ public function fill($assertions = true) $this->getListByIdsTest(); $this->getListByIdsTest(); } + + $testUuidObj = TestUuidObject::create()->setName('test-uuid-name'); + TestUuidObject::dao()->add($testUuidObj); + + $uuid = UuidUtils::make(); + $testUuidObj2 = TestUuidObject::create()->setId( + $uuid + )->setName('test-uuid-name2'); + TestUuidObject::dao()->import($testUuidObj2); + } - + public function criteriaResult() { $queryResult = Criteria::create(TestCity::dao())->getResult(); @@ -538,6 +548,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 @@ -735,7 +763,7 @@ public function nonIntegerIdentifier() { $id = 'non-integer-one'; $binaryData = "\0!bbq!\0"; - + $bin = TestBinaryStuff::create()-> setId($id)-> @@ -1019,5 +1047,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