Commit 048d7788 authored by zYne's avatar zYne

Many-to-Many relation handling fixed, fixes #193

parent 7e4e5924
......@@ -260,13 +260,7 @@ class Doctrine_DataDict_Mysql extends Doctrine_DataDict {
$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__);
throw new Doctrine_DataDict_Mysql_Exception('unknown database attribute type: '.$db_type);
}
return array($type, $length, $unsigned, $fixed);
......
......@@ -126,7 +126,7 @@ class Doctrine_DataDict_Pgsql extends Doctrine_DataDict {
}
$type = array();
$unsigned = $fixed = null;
switch ($field['type']) {
switch (strtolower($field['type'])) {
case 'smallint':
case 'int2':
$type[] = 'integer';
......
......@@ -847,11 +847,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* this method is smart enough to know if any changes are made
* and whether to use INSERT or UPDATE statement
*
* this method also saves the related composites
* this method also saves the related components
*
* @param Doctrine_Connection $conn
* @return void
*/
final public function save(Doctrine_Connection $conn = null) {
public function save(Doctrine_Connection $conn = null) {
if ($conn === null) {
$conn = $this->_table->getConnection();
}
......@@ -885,7 +886,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* returns an array of modified fields and associated values
* @return array
*/
final public function getModified() {
public function getModified() {
$a = array();
foreach($this->_modified as $k => $v) {
......@@ -1301,8 +1302,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* @param string $fkField
* @return void
*/
final public function ownsOne($componentName,$foreignKey, $localKey = null) {
$this->_table->bind($componentName,$foreignKey,Doctrine_Relation::ONE_COMPOSITE, $localKey);
final public function ownsOne($componentName, $foreignKey, $localKey = null) {
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::ONE_COMPOSITE, $localKey);
}
/**
* binds One-to-Many composite relation
......@@ -1312,7 +1313,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* @return void
*/
final public function ownsMany($componentName,$foreignKey, $localKey = null) {
$this->_table->bind($componentName,$foreignKey,Doctrine_Relation::MANY_COMPOSITE, $localKey);
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::MANY_COMPOSITE, $localKey);
}
/**
* binds One-to-One aggregate relation
......@@ -1322,7 +1323,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* @return void
*/
final public function hasOne($componentName,$foreignKey, $localKey = null) {
$this->_table->bind($componentName,$foreignKey,Doctrine_Relation::ONE_AGGREGATE, $localKey);
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::ONE_AGGREGATE, $localKey);
}
/**
* binds One-to-Many aggregate relation
......@@ -1332,7 +1333,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* @return void
*/
final public function hasMany($componentName,$foreignKey, $localKey = null) {
$this->_table->bind($componentName,$foreignKey,Doctrine_Relation::MANY_AGGREGATE, $localKey);
$this->_table->bind($componentName, $foreignKey, Doctrine_Relation::MANY_AGGREGATE, $localKey);
}
/**
* setPrimaryKey
......
......@@ -482,6 +482,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable {
* @return array
*/
public function getBoundForName($name, $component) {
foreach($this->bound as $k => $bound) {
$e = explode('.', $bound[0]);
......@@ -553,7 +554,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable {
* @param string $field
* @return void
*/
final public function bind($name, $field, $type, $localKey) {
public function bind($name, $field, $type, $localKey) {
if(isset($this->relations[$name]))
unset($this->relations[$name]);
......@@ -567,7 +568,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable {
$alias = $name;
$this->bound[$alias] = array($field,$type,$localKey,$name);
$this->bound[$alias] = array($field, $type, $localKey, $name);
}
/**
* getComponentName
......@@ -661,8 +662,12 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable {
$bound = $table->getBoundForName($class, $component);
break;
} catch(Doctrine_Table_Exception $exc) { }
}
if( ! isset($bound))
throw new Doctrine_Table_Exception("Couldn't map many-to-many relation for "
. $this->options['name'] . " and $name. Components use different join tables.");
if( ! isset($local))
$local = $this->identifier;
......@@ -676,17 +681,17 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable {
if(count($fields) > 1) {
// SELF-REFERENCING THROUGH JOIN TABLE
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable,$local,$fields[0],Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable, $local, $fields[0],Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
$relation = new Doctrine_Relation_Association_Self($table,$associationTable,$fields[0],$fields[1], $type, $alias);
$relation = new Doctrine_Relation_Association_Self($table, $associationTable, $fields[0], $fields[1], $type, $alias);
} else {
// auto initialize a new one-to-one relationship for association table
$associationTable->bind($this->getComponentName(), $associationTable->getComponentName(). '.' .$e2[1], Doctrine_Relation::ONE_AGGREGATE, 'id');
$associationTable->bind($table->getComponentName(), $associationTable->getComponentName(). '.' .$foreign, Doctrine_Relation::ONE_AGGREGATE, 'id');
$associationTable->bind($this->getComponentName(), $associationTable->getComponentName(). '.' .$e2[1], Doctrine_Relation::ONE_AGGREGATE, $this->getIdentifier());
$associationTable->bind($table->getComponentName(), $associationTable->getComponentName(). '.' .$foreign, Doctrine_Relation::ONE_AGGREGATE, $table->getIdentifier());
// NORMAL MANY-TO-MANY RELATIONSHIP
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
$this->relations[$e2[0]] = new Doctrine_Relation_ForeignKey($associationTable, $local, $e2[1], Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
$relation = new Doctrine_Relation_Association($table, $associationTable, $e2[1], $foreign, $type, $alias);
}
......
......@@ -83,7 +83,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase {
public function testLimitWithOneToManyInnerJoin() {
$this->query->from("User(id):Phonenumber");
$this->query->select('u.id')->from("User u INNER JOIN u.Phonenumber");
$this->query->limit(5);
......@@ -177,7 +177,8 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase {
$q = new Doctrine_Query();
$q->from("User")->where("User.Group.id = ?")->orderby("User.id DESC")->limit(5);
$q->from("User")->where("User.Group.id = ?")->orderby("User.id ASC")->limit(5);
$users = $q->execute(array($user->Group[1]->id));
$this->assertEqual($users->count(), 3);
......@@ -222,7 +223,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase {
$photos = $q->execute(array(1));
$this->assertEqual($photos->count(), 3);
$this->assertEqual($q->getQuery(),
"SELECT photo.id AS photo__id, photo.name AS photo__name FROM photo LEFT JOIN phototag ON photo.id = phototag.photo_id LEFT JOIN tag ON tag.id = phototag.tag_id WHERE photo.id IN (SELECT DISTINCT photo.id FROM photo LEFT JOIN phototag ON photo.id = phototag.photo_id LEFT JOIN tag ON tag.id = phototag.tag_id WHERE tag.id = ? LIMIT 100) AND tag.id = ? ORDER BY photo.id DESC");
"SELECT photo.id AS photo__id, photo.name AS photo__name FROM photo LEFT JOIN phototag ON photo.id = phototag.photo_id LEFT JOIN tag ON tag.id = phototag.tag_id WHERE photo.id IN (SELECT DISTINCT photo.id FROM photo LEFT JOIN phototag ON photo.id = phototag.photo_id LEFT JOIN tag ON tag.id = phototag.tag_id WHERE tag.id = ? ORDER BY photo.id DESC LIMIT 100) AND tag.id = ? ORDER BY photo.id DESC");
}
}
?>
......@@ -10,9 +10,40 @@ class M2MTest extends Doctrine_Record {
$this->hasMany('RTC2 as RTC2', 'JC1.c1_id');
$this->hasMany('RTC3 as RTC3', 'JC2.c1_id');
$this->hasMany('RTC3 as RTC4', 'JC1.c1_id');
}
}
class RelationErrorTest extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn('name', 'string', 200);
}
public function setUp() {
$this->hasMany('RTCUnknown', 'JC1.c1_id');
}
}
class M2MTest2 extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn('oid', 'integer', 11, array('autoincrement', 'primary'));
$this->hasColumn('name', 'string', 20);
}
public function setUp() {
$this->hasMany('RTC4 as RTC5', 'JC3.c1_id');
}
}
class RTCUnknown extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn('name', 'string', 200);
}
public function setUp() {
$this->hasMany('M2MTest', 'JC2.c2_id');
}
}
class JC3 extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn('c1_id', 'integer');
$this->hasColumn('c2_id', 'integer');
}
}
class JC1 extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn('c1_id', 'integer');
......@@ -50,12 +81,105 @@ class RTC3 extends Doctrine_Record {
$this->hasMany('M2MTest as RTC4', 'JC1.c2_id');
}
}
class RTC4 extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn('oid', 'integer', 11, array('autoincrement', 'primary'));
$this->hasColumn('name', 'string', 20);
}
public function setUp() {
$this->hasMany('M2MTest2', 'JC3.c2_id');
}
}
class Doctrine_Relation_ManyToMany_TestCase extends Doctrine_UnitTestCase {
public function prepareData() { }
public function prepareTables() {
parent::prepareTables();
}
public function testManyToManyRelationWithAliasesAndCustomPKs() {
$component = new M2MTest2();
try {
$rel = $component->getTable()->getRelation('RTC5');
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
$this->assertTrue($rel instanceof Doctrine_Relation_Association);
$this->assertTrue($component->RTC5 instanceof Doctrine_Collection);
try {
$rel = $component->getTable()->getRelation('JC3');
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
$this->assertEqual($rel->getLocal(), 'oid');
}
public function testJoinComponent() {
$component = new JC3();
try {
$rel = $component->getTable()->getRelation('M2MTest2');
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
$this->assertEqual($rel->getForeign(), 'oid');
try {
$rel = $component->getTable()->getRelation('RTC4');
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
$this->assertEqual($rel->getForeign(), 'oid');
}
public function testManyToManyRelationFetchingWithAliasesAndCustomPKs() {
$q = new Doctrine_Query();
try {
$q->from('M2MTest2 m LEFT JOIN m.RTC5');
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
try {
$q->execute();
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
}
public function testUnknownManyToManyRelation() {
$component = new RelationErrorTest();
try {
$rel = $component->getTable()->getRelation('RTCUnknown');
$this->fail();
} catch(Doctrine_Table_Exception $e) {
$this->pass();
}
}
public function testManyToManyRelationFetchingWithAliasesAndCustomPKs2() {
$q = new Doctrine_Query();
try {
$q->from('M2MTest2 m INNER JOIN m.JC3');
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
try {
$q->execute();
$this->pass();
} catch(Doctrine_Exception $e) {
$this->fail();
}
}
public function testManyToManyHasRelationWithAliases4() {
$component = new M2MTest();
......
......@@ -66,10 +66,12 @@ $test = new GroupTest('Doctrine Framework Unit Tests');
$test->addTestCase(new Doctrine_DataDict_Pgsql_TestCase());
$test->addTestCase(new Doctrine_Relation_TestCase());
$test->addTestCase(new Doctrine_Relation_ManyToMany_TestCase());
$test->addTestCase(new Doctrine_Relation_TestCase());
$test->addTestCase(new Doctrine_Record_TestCase());
$test->addTestCase(new Doctrine_Record_State_TestCase());
......@@ -148,7 +150,6 @@ $test->addTestCase(new Doctrine_Query_Delete_TestCase());
$test->addTestCase(new Doctrine_Query_Update_TestCase());
$test->addTestCase(new Doctrine_Query_Limit_TestCase());
$test->addTestCase(new Doctrine_EnumTestCase());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment