From 7e7a0b879c51bc1a3b31b3fbf248679f9c8e1e23 Mon Sep 17 00:00:00 2001 From: zYne Date: Mon, 23 Oct 2006 16:19:47 +0000 Subject: [PATCH] Fixes #185 --- lib/Doctrine/DataDict/Mssql.php | 10 +- lib/Doctrine/DataDict/Mysql.php | 151 ++++++++++++++++++++++++++++++- lib/Doctrine/DataDict/Oracle.php | 1 + lib/Doctrine/DataDict/Pgsql.php | 8 +- lib/Doctrine/DataDict/Sqlite.php | 8 +- lib/Doctrine/Table.php | 5 +- tests/RelationTestCase.php | 46 +++++++++- 7 files changed, 211 insertions(+), 18 deletions(-) diff --git a/lib/Doctrine/DataDict/Mssql.php b/lib/Doctrine/DataDict/Mssql.php index ee3de0e65..a298a3734 100644 --- a/lib/Doctrine/DataDict/Mssql.php +++ b/lib/Doctrine/DataDict/Mssql.php @@ -48,8 +48,9 @@ class Doctrine_DataDict_Mssql extends Doctrine_DataDict { * notnull * Boolean flag that indicates whether this field is constrained * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. + * @author Lukas Smith (PEAR MDB2 library) + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. */ public function getTypeDeclaration($field) { switch ($field['type']) { @@ -96,8 +97,9 @@ class Doctrine_DataDict_Mssql extends Doctrine_DataDict { /** * Maps a native array description of a field to a MDB2 datatype and length * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed + * @param array $field native field description + * @author Lukas Smith (PEAR MDB2 library) + * @return array containing the various possible types, length, sign, fixed */ public function mapNativeDatatype($field) { $db_type = preg_replace('/\d/','', strtolower($field['type']) ); diff --git a/lib/Doctrine/DataDict/Mysql.php b/lib/Doctrine/DataDict/Mysql.php index 2b5f27191..d93b9c20f 100644 --- a/lib/Doctrine/DataDict/Mysql.php +++ b/lib/Doctrine/DataDict/Mysql.php @@ -48,9 +48,9 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict { * notnull * Boolean flag that indicates whether this field is constrained * to not be set to null. + * @author Lukas Smith (PEAR MDB2 library) * @return string DBMS specific SQL code portion that should be used to * declare the specified field. - * @access public */ public function getTypeDeclaration($field) { switch ($field['type']) { @@ -122,6 +122,155 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict { } return ''; } + /** + * Maps a native array description of a field to a MDB2 datatype and length + * + * @param array $field native field description + * @author Lukas Smith (PEAR MDB2 library) + * @return array containing the various possible types, length, sign, fixed + */ + public function mapNativeDatatype($field) { + $db_type = strtolower($field['type']); + $db_type = strtok($db_type, '(), '); + if ($db_type == 'national') { + $db_type = strtok('(), '); + } + if (!empty($field['length'])) { + $length = $field['length']; + $decimal = ''; + } else { + $length = strtok('(), '); + $decimal = strtok('(), '); + } + $type = array(); + $unsigned = $fixed = null; + switch ($db_type) { + case 'tinyint': + $type[] = 'integer'; + $type[] = 'boolean'; + if (preg_match('/^(is|has)/', $field['name'])) { + $type = array_reverse($type); + } + $unsigned = preg_match('/ unsigned/i', $field['type']); + $length = 1; + break; + case 'smallint': + $type[] = 'integer'; + $unsigned = preg_match('/ unsigned/i', $field['type']); + $length = 2; + break; + case 'mediumint': + $type[] = 'integer'; + $unsigned = preg_match('/ unsigned/i', $field['type']); + $length = 3; + break; + case 'int': + case 'integer': + $type[] = 'integer'; + $unsigned = preg_match('/ unsigned/i', $field['type']); + $length = 4; + break; + case 'bigint': + $type[] = 'integer'; + $unsigned = preg_match('/ unsigned/i', $field['type']); + $length = 8; + break; + case 'tinytext': + case 'mediumtext': + case 'longtext': + case 'text': + case 'text': + case 'varchar': + $fixed = false; + case 'string': + case 'char': + $type[] = 'text'; + if ($length == '1') { + $type[] = 'boolean'; + if (preg_match('/^(is|has)/', $field['name'])) { + $type = array_reverse($type); + } + } elseif (strstr($db_type, 'text')) { + $type[] = 'clob'; + if ($decimal == 'binary') { + $type[] = 'blob'; + } + } + if ($fixed !== false) { + $fixed = true; + } + break; + case 'enum': + $type[] = 'text'; + preg_match_all('/\'.+\'/U', $field['type'], $matches); + $length = 0; + $fixed = false; + if (is_array($matches)) { + foreach ($matches[0] as $value) { + $length = max($length, strlen($value)-2); + } + if ($length == '1' && count($matches[0]) == 2) { + $type[] = 'boolean'; + if (preg_match('/^(is|has)/', $field['name'])) { + $type = array_reverse($type); + } + } + } + $type[] = 'integer'; + case 'set': + $fixed = false; + $type[] = 'text'; + $type[] = 'integer'; + break; + case 'date': + $type[] = 'date'; + $length = null; + break; + case 'datetime': + case 'timestamp': + $type[] = 'timestamp'; + $length = null; + break; + case 'time': + $type[] = 'time'; + $length = null; + break; + case 'float': + case 'double': + case 'real': + $type[] = 'float'; + $unsigned = preg_match('/ unsigned/i', $field['type']); + break; + case 'unknown': + case 'decimal': + case 'numeric': + $type[] = 'decimal'; + $unsigned = preg_match('/ unsigned/i', $field['type']); + break; + case 'tinyblob': + case 'mediumblob': + case 'longblob': + case 'blob': + $type[] = 'blob'; + $length = null; + break; + case 'year': + $type[] = 'integer'; + $type[] = 'date'; + $length = null; + break; + default: + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'unknown database attribute type: '.$db_type, __FUNCTION__); + } + + return array($type, $length, $unsigned, $fixed); + } /** * lists all databases * diff --git a/lib/Doctrine/DataDict/Oracle.php b/lib/Doctrine/DataDict/Oracle.php index c9384e873..0ea1e9503 100644 --- a/lib/Doctrine/DataDict/Oracle.php +++ b/lib/Doctrine/DataDict/Oracle.php @@ -86,6 +86,7 @@ class Doctrine_DataDict_Oracle extends Doctrine_DataDict { * * @param array $field native field description * @return array containing the various possible types, length, sign, fixed + * @author Lukas Smith (PEAR MDB2 library) * @throws Doctrine_DataDict_Oracle_Exception */ function mapNativeDatatype($field) { diff --git a/lib/Doctrine/DataDict/Pgsql.php b/lib/Doctrine/DataDict/Pgsql.php index b786439c1..e0569ba4c 100644 --- a/lib/Doctrine/DataDict/Pgsql.php +++ b/lib/Doctrine/DataDict/Pgsql.php @@ -48,10 +48,10 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict { * * notnull * Boolean flag that indicates whether this field is constrained - * to not be set to null. + * to not be set to null. + * @author Lukas Smith (PEAR MDB2 library) * @return string DBMS specific SQL code portion that should be used to * declare the specified field. - * @access public */ public function getTypeDeclaration(array $field) { switch ($field['type']) { @@ -112,10 +112,10 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict { * Maps a native array description of a field to a MDB2 datatype and length * * @param array $field native field description + * @author Lukas Smith (PEAR MDB2 library) * @return array containing the various possible types, length, sign, fixed - * @access public */ - function mapNativeDatatype($field) { + public function mapNativeDatatype($field) { $db_type = preg_replace('/\d/','', strtolower($field['type']) ); $length = $field['length']; if ($length == '-1' && !empty($field['atttypmod'])) { diff --git a/lib/Doctrine/DataDict/Sqlite.php b/lib/Doctrine/DataDict/Sqlite.php index 3faf58751..03ab19418 100644 --- a/lib/Doctrine/DataDict/Sqlite.php +++ b/lib/Doctrine/DataDict/Sqlite.php @@ -48,11 +48,11 @@ class Doctrine_DataDict_Sqlite extends Doctrine_DataDict { * notnull * Boolean flag that indicates whether this field is constrained * to not be set to null. + * @author Lukas Smith (PEAR MDB2 library) * @return string DBMS specific SQL code portion that should be used to * declare the specified field. - * @access public */ - function getTypeDeclaration($field) { + public function getTypeDeclaration($field) { switch ($field['type']) { case 'text': $length = !empty($field['length']) @@ -117,10 +117,10 @@ class Doctrine_DataDict_Sqlite extends Doctrine_DataDict { * Maps a native array description of a field to a MDB2 datatype and length * * @param array $field native field description + * @author Lukas Smith (PEAR MDB2 library) * @return array containing the various possible types, length, sign, fixed - * @access public */ - function mapNativeDatatype($field) { + public function mapNativeDatatype($field) { $db_type = strtolower($field['type']); $length = !empty($field['length']) ? $field['length'] : null; $unsigned = !empty($field['unsigned']) ? $field['unsigned'] : null; diff --git a/lib/Doctrine/Table.php b/lib/Doctrine/Table.php index b9ae97fce..22abf491b 100644 --- a/lib/Doctrine/Table.php +++ b/lib/Doctrine/Table.php @@ -606,9 +606,10 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable { if( ! isset($local)) $local = $table->getIdentifier(); - $relation = new Doctrine_Relation_LocalKey($table,$foreign,$local,$type, $alias); + $relation = new Doctrine_Relation_LocalKey($table, $foreign, $local, $type, $alias); } else - throw new Doctrine_Table_Exception("Only one-to-one relations are possible when local reference key is used."); + $relation = new Doctrine_Relation_ForeignKey($table, $foreign, $local, $type, $alias); + } elseif($component == $name || ($component == $alias)) { // && ($name == $this->name || in_array($name,$this->parents)) diff --git a/tests/RelationTestCase.php b/tests/RelationTestCase.php index 6e28eb25d..ecdc0bd2d 100644 --- a/tests/RelationTestCase.php +++ b/tests/RelationTestCase.php @@ -1,13 +1,21 @@ hasColumn("child_id", "integer"); } public function setUp() { $this->ownsMany('OwnsOneToManyWithAlias as AliasO2M', 'AliasO2M.component_id'); $this->hasMany('HasManyToManyWithAlias as AliasM2M', 'JoinTable.c1_id'); } } +class RelationTestChild extends RelationTest { + public function setUp() { + $this->hasOne('RelationTest as Parent', 'RelationTestChild.child_id'); + + $this->ownsMany('RelationTestChild as Children', 'RelationTestChild.child_id'); + } +} + class HasOneToOne extends Doctrine_Record { } @@ -39,10 +47,36 @@ class HasManyToManyWithAlias extends Doctrine_Record { } class Doctrine_Relation_TestCase extends Doctrine_UnitTestCase { public function prepareData() { } - public function prepareTables() { + public function prepareTables() { $this->tables = array(); } + public function testOneToManyTreeRelationWithConcreteInheritance() { + $component = new RelationTestChild(); + + try { + $rel = $component->getTable()->getRelation('Children'); + $this->pass(); + } catch(Doctrine_Exception $e) { + $this->fail(); + } + $this->assertTrue($rel instanceof Doctrine_Relation_ForeignKey); + + $this->assertTrue($component->Children instanceof Doctrine_Collection); + $this->assertTrue($component->Children[0] instanceof RelationTestChild); + } + + public function testOneToOneTreeRelationWithConcreteInheritance() { + $component = new RelationTestChild(); + + try { + $rel = $component->getTable()->getRelation('Parent'); + $this->pass(); + } catch(Doctrine_Exception $e) { + $this->fail(); + } + $this->assertTrue($rel instanceof Doctrine_Relation_LocalKey); + } public function testOneToManyOwnsRelationWithAliases() { $this->manager->setAttribute(Doctrine::ATTR_CREATE_TABLES, false); @@ -67,10 +101,15 @@ class Doctrine_Relation_TestCase extends Doctrine_UnitTestCase { $this->fail(); } $this->assertTrue($rel instanceof Doctrine_Relation_Association); + + $this->assertTrue($component->AliasM2M instanceof Doctrine_Collection); + } + + public function testManyToManyRelation() { $user = new User(); - + // test that join table relations can be initialized even before the association have been initialized try { $user->Groupuser; @@ -98,4 +137,5 @@ class Doctrine_Relation_TestCase extends Doctrine_UnitTestCase { $this->manager->setAttribute(Doctrine::ATTR_CREATE_TABLES, true); } + }