Commit 8c4d8293 authored by doctrine's avatar doctrine

DQL: self-referencing support

parent 0062d9c3
......@@ -24,8 +24,8 @@ class Doctrine_Association extends Doctrine_Relation {
* @param integer $type type of relation
* @see Doctrine_Table constants
*/
public function __construct(Doctrine_Table $table, Doctrine_Table $associationTable, $local, $foreign, $type) {
parent::__construct($table, $local, $foreign, $type);
public function __construct(Doctrine_Table $table, Doctrine_Table $associationTable, $local, $foreign, $type, $alias) {
parent::__construct($table, $local, $foreign, $type, $alias);
$this->associationTable = $associationTable;
}
/**
......
......@@ -280,14 +280,14 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
if(isset($this->reference_field))
$record->rawSet($this->reference_field,$this->reference);
$this->reference->addReference($record);
$this->reference->addReference($record, $this->relation);
}
} else {
$i = $offset;
foreach($coll as $record) {
if(isset($this->reference)) {
$this->reference->addReference($record,$i);
$this->reference->addReference($record, $this->relation, $i);
} else
$this->data[$i] = $record;
......
......@@ -138,9 +138,9 @@ class Doctrine_Query extends Doctrine_Access {
* fields of the tables become: [tablename].[fieldname] as [tablename]__[fieldname]
*
* @access private
* @param object Doctrine_Table $table a Doctrine_Table object
* @param integer $fetchmode fetchmode the table is using eg. Doctrine::FETCH_LAZY
* @param array $names fields to be loaded (only used in lazy property loading)
* @param object Doctrine_Table $table a Doctrine_Table object
* @param integer $fetchmode fetchmode the table is using eg. Doctrine::FETCH_LAZY
* @param array $names fields to be loaded (only used in lazy property loading)
* @return void
*/
private function loadFields(Doctrine_Table $table, $fetchmode, array $names, $cpath) {
......@@ -296,9 +296,17 @@ class Doctrine_Query extends Doctrine_Access {
}
}
$this->applyInheritance();
if( ! empty($this->parts["where"]))
$string = $this->applyInheritance();
if( ! empty($this->parts["where"])) {
$q .= " WHERE ".implode(" ",$this->parts["where"]);
if( ! empty($string))
$q .= " AND (".$string.")";
} else {
if( ! empty($string))
$q .= " WHERE (".$string.")";
}
if( ! empty($this->parts["groupby"]))
$q .= " GROUP BY ".implode(", ",$this->parts["groupby"]);
......@@ -319,12 +327,9 @@ class Doctrine_Query extends Doctrine_Access {
* applyInheritance
* applies column aggregation inheritance to DQL query
*
* @return boolean
* @return string
*/
final public function applyInheritance() {
if($this->inheritanceApplied)
return false;
// get the inheritance maps
$array = array();
......@@ -355,9 +360,7 @@ class Doctrine_Query extends Doctrine_Access {
$str .= implode(" AND ",$c);
$this->addWhere($str);
$this->inheritanceApplied = true;
return true;
return $str;
}
/**
* @param string $where
......@@ -490,7 +493,9 @@ class Doctrine_Query extends Doctrine_Access {
$pointer = $this->joins[$name];
$path = array_search($name, $this->tableAliases);
$alias = end( explode(".", $path));
$tmp = explode(".", $path);
$alias = end($tmp);
unset($tmp);
$fk = $this->tables[$pointer]->getForeignKey($alias);
if( ! isset($prev[$pointer]) )
......@@ -535,7 +540,9 @@ class Doctrine_Query extends Doctrine_Access {
$pointer = $this->joins[$name];
$path = array_search($name, $this->tableAliases);
$alias = end( explode(".", $path));
$tmp = explode(".", $path);
$alias = end($tmp);
unset($tmp);
$fk = $this->tables[$pointer]->getForeignKey($alias);
$last = $prev[$pointer]->getLast();
......@@ -561,7 +568,7 @@ class Doctrine_Query extends Doctrine_Access {
$prev[$name] = $last->get($alias);
}
$last->addReference($record);
$last->addReference($record, $fk);
endswitch;
}
}
......@@ -1147,7 +1154,7 @@ class Doctrine_Query extends Doctrine_Access {
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
$this->parts["join"][$tname][$tname2] = $join.$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
$this->parts["join"][$tname][$tname2] = $join.$aliasString." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
} elseif($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
......
......@@ -1003,13 +1003,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* @return void
*/
public function initReference(Doctrine_Collection $coll, Doctrine_Relation $connector) {
$name = $this->table->getAlias($coll->getTable()->getComponentName());
$alias = $connector->getAlias();
if( ! ($connector instanceof Doctrine_Association))
$coll->setReference($this, $connector);
$this->references[$name] = $coll;
$this->originals[$name] = clone $coll;
$this->references[$alias] = $coll;
$this->originals[$alias] = clone $coll;
}
/**
* addReference
......@@ -1017,11 +1017,11 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* @param mixed $key
* @return void
*/
public function addReference(Doctrine_Record $record, $key = null) {
$name = $this->table->getAlias($record->getTable()->getComponentName());
public function addReference(Doctrine_Record $record, Doctrine_Relation $connector, $key = null) {
$alias = $connector->getAlias();
$this->references[$name]->add($record, $key);
$this->originals[$name]->add($record, $key);
$this->references[$alias]->add($record, $key);
$this->originals[$alias]->add($record, $key);
}
/**
* getReferences
......
......@@ -57,11 +57,12 @@ class Doctrine_Relation {
* @param integer $type
* @param string $alias
*/
public function __construct(Doctrine_Table $table, $local, $foreign, $type) {
public function __construct(Doctrine_Table $table, $local, $foreign, $type, $alias) {
$this->table = $table;
$this->local = $local;
$this->foreign = $foreign;
$this->type = $type;
$this->alias = $alias;
}
/**
* @return string the relation alias
......
......@@ -538,7 +538,7 @@ class Doctrine_Table extends Doctrine_Configurable {
if( ! isset($local))
$local = $table->getIdentifier();
$relation = new Doctrine_LocalKey($table,$foreign,$local,$type);
$relation = new Doctrine_LocalKey($table,$foreign,$local,$type, $alias);
} else
throw new Doctrine_Mapping_Exception("Only one-to-one relations are possible when local reference key is used.");
......@@ -547,7 +547,7 @@ class Doctrine_Table extends Doctrine_Configurable {
$local = $this->identifier;
// ONE-TO-MANY or ONE-TO-ONE
$relation = new Doctrine_ForeignKey($table,$local,$foreign,$type);
$relation = new Doctrine_ForeignKey($table, $local, $foreign, $type, $alias);
} else {
// MANY-TO-MANY
......@@ -578,14 +578,14 @@ class Doctrine_Table extends Doctrine_Configurable {
if(count($fields) > 1) {
// SELF-REFERENCING THROUGH JOIN TABLE
$this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$fields[0],Doctrine_Relation::MANY_COMPOSITE);
$this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$fields[0],Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
$relation = new Doctrine_Association($table,$associationTable,$fields[0],$fields[1],$type);
$relation = new Doctrine_Association($table,$associationTable,$fields[0],$fields[1], $type, $alias);
} else {
// NORMAL MANY-TO-MANY RELATIONSHIP
$this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE);
$this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE, $e2[0]);
$relation = new Doctrine_Association($table,$associationTable,$e2[1],$foreign,$type);
$relation = new Doctrine_Association($table, $associationTable, $e2[1], $foreign, $type, $alias);
}
}
......
......@@ -5,6 +5,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->tables[] = "Forum_Entry";
$this->tables[] = "Forum_Board";
$this->tables[] = "Forum_Thread";
$this->tables[] = "ORM_TestEntry";
$this->tables[] = "ORM_TestItem";
$this->tables[] = "Log_Status";
......@@ -13,14 +14,58 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
try {
$this->dbh->query("DROP TABLE test_items");
} catch(PDOException $e) {
}
try {
$this->dbh->query("DROP TABLE test_entries");
} catch(PDOException $e) {
}
}
parent::prepareTables();
}
public function testSelfReferencing() {
$category = new Forum_Category();
$category->name = "Root";
$category->Subcategory[0]->name = "Sub 1";
$category->Subcategory[1]->name = "Sub 2";
$category->Subcategory[0]->Subcategory[0]->name = "Sub 1 Sub 1";
$category->Subcategory[0]->Subcategory[1]->name = "Sub 1 Sub 2";
$category->Subcategory[1]->Subcategory[0]->name = "Sub 2 Sub 1";
$category->Subcategory[1]->Subcategory[1]->name = "Sub 2 Sub 2";
$this->session->flush();
$this->session->clear();
$category = $category->getTable()->find($category->id);
$this->assertEqual($category->name, "Root");
$this->assertEqual($category->Subcategory[0]->name, "Sub 1");
$this->assertEqual($category->Subcategory[1]->name, "Sub 2");
$this->assertEqual($category->Subcategory[0]->Subcategory[0]->name, "Sub 1 Sub 1");
$this->assertEqual($category->Subcategory[0]->Subcategory[1]->name, "Sub 1 Sub 2");
$this->assertEqual($category->Subcategory[1]->Subcategory[0]->name, "Sub 2 Sub 1");
$this->assertEqual($category->Subcategory[1]->Subcategory[1]->name, "Sub 2 Sub 2");
$this->session->clear();
$query = new Doctrine_Query($this->session);
$count = count($this->dbh);
$query->from("Forum_Category.Subcategory.Subcategory");
$coll = $query->execute();
$category = $coll[0];
$this->assertEqual($category->name, "Root");
$this->assertEqual($category->Subcategory[0]->name, "Sub 1");
$this->assertEqual($category->Subcategory[1]->name, "Sub 2");
$this->assertEqual($category->Subcategory[0]->Subcategory[0]->name, "Sub 1 Sub 1");
$this->assertEqual($category->Subcategory[0]->Subcategory[1]->name, "Sub 1 Sub 2");
$this->assertEqual($category->Subcategory[1]->Subcategory[0]->name, "Sub 2 Sub 1");
$this->assertEqual($category->Subcategory[1]->Subcategory[1]->name, "Sub 2 Sub 2");
$this->assertEqual(($count + 1), count($this->dbh));
}
public function testGetPath() {
......@@ -34,6 +79,10 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($this->query->getTableAlias("Task"), "task");
$this->assertEqual($this->query->getTableAlias("Task.Subtask"), "task2");
$this->assertEqual($this->query->getTableAlias("Task.Subtask.Subtask"), "task3");
$this->assertEqual($this->query->getQuery(),
"SELECT task.id AS task__id, task.name AS task__name, task.parent_id AS task__parent_id, task2.id AS task2__id, task2.name AS task2__name, task2.parent_id AS task2__parent_id, task3.id AS task3__id, task3.name AS task3__name, task3.parent_id AS task3__parent_id FROM task LEFT JOIN task AS task2 ON task.id = task2.parent_id LEFT JOIN task AS task3 ON task2.id = task3.parent_id");
}
public function testMultiComponentFetching2() {
......@@ -54,35 +103,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($count, count($this->dbh));
}
public function testSelfReferencing() {
$category = new Forum_Category();
$category->name = "Root";
$category->Subcategory[0]->name = "Sub 1";
$category->Subcategory[1]->name = "Sub 2";
$category->Subcategory[0]->Subcategory[0]->name = "Sub 1 Sub 1";
$category->Subcategory[0]->Subcategory[1]->name = "Sub 1 Sub 2";
$category->Subcategory[1]->Subcategory[0]->name = "Sub 2 Sub 1";
$category->Subcategory[1]->Subcategory[1]->name = "Sub 2 Sub 2";
$this->session->flush();
$this->session->clear();
$category = $category->getTable()->find($category->id);
$this->assertEqual($category->name, "Root");
$this->assertEqual($category->Subcategory[0]->name, "Sub 1");
$this->assertEqual($category->Subcategory[1]->name, "Sub 2");
$this->assertEqual($category->Subcategory[0]->Subcategory[0]->name, "Sub 1 Sub 1");
$this->assertEqual($category->Subcategory[0]->Subcategory[1]->name, "Sub 1 Sub 2");
$this->assertEqual($category->Subcategory[1]->Subcategory[0]->name, "Sub 2 Sub 1");
$this->assertEqual($category->Subcategory[1]->Subcategory[1]->name, "Sub 2 Sub 2");
$this->session->clear();
$query = new Doctrine_Query($this->session);
}
public function testHaving() {
$this->session->clear();
......
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