DQL: self-referencing support
This commit is contained in:
parent
0062d9c3ff
commit
8c4d8293e5
@ -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,48 +14,17 @@ 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 testGetPath() {
|
||||
$this->query->from("User.Group.Email");
|
||||
|
||||
$this->assertEqual($this->query->getTableAlias("User"), "entity");
|
||||
$this->assertEqual($this->query->getTableAlias("User.Group"), "entity2");
|
||||
|
||||
|
||||
$this->query->from("Task.Subtask.Subtask");
|
||||
$this->assertEqual($this->query->getTableAlias("Task"), "task");
|
||||
$this->assertEqual($this->query->getTableAlias("Task.Subtask"), "task2");
|
||||
$this->assertEqual($this->query->getTableAlias("Task.Subtask.Subtask"), "task3");
|
||||
}
|
||||
|
||||
public function testMultiComponentFetching2() {
|
||||
$this->session->clear();
|
||||
|
||||
$query = new Doctrine_Query($this->session);
|
||||
|
||||
$query->from("User.Email, User.Phonenumber");
|
||||
|
||||
|
||||
$users = $query->execute();
|
||||
|
||||
$count = count($this->dbh);
|
||||
|
||||
$this->assertEqual($users->count(), 8);
|
||||
$this->assertTrue($users[0]->Email instanceof Email);
|
||||
$this->assertEqual($users[0]->Phonenumber->count(), 1);
|
||||
$this->assertEqual($count, count($this->dbh));
|
||||
}
|
||||
|
||||
|
||||
public function testSelfReferencing() {
|
||||
$category = new Forum_Category();
|
||||
|
||||
@ -81,6 +51,56 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
|
||||
$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() {
|
||||
$this->query->from("User.Group.Email");
|
||||
|
||||
$this->assertEqual($this->query->getTableAlias("User"), "entity");
|
||||
$this->assertEqual($this->query->getTableAlias("User.Group"), "entity2");
|
||||
|
||||
|
||||
$this->query->from("Task.Subtask.Subtask");
|
||||
$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() {
|
||||
$this->session->clear();
|
||||
|
||||
$query = new Doctrine_Query($this->session);
|
||||
|
||||
$query->from("User.Email, User.Phonenumber");
|
||||
|
||||
|
||||
$users = $query->execute();
|
||||
|
||||
$count = count($this->dbh);
|
||||
|
||||
$this->assertEqual($users->count(), 8);
|
||||
$this->assertTrue($users[0]->Email instanceof Email);
|
||||
$this->assertEqual($users[0]->Phonenumber->count(), 1);
|
||||
$this->assertEqual($count, count($this->dbh));
|
||||
}
|
||||
|
||||
public function testHaving() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user