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
|
* @param integer $type type of relation
|
||||||
* @see Doctrine_Table constants
|
* @see Doctrine_Table constants
|
||||||
*/
|
*/
|
||||||
public function __construct(Doctrine_Table $table, Doctrine_Table $associationTable, $local, $foreign, $type) {
|
public function __construct(Doctrine_Table $table, Doctrine_Table $associationTable, $local, $foreign, $type, $alias) {
|
||||||
parent::__construct($table, $local, $foreign, $type);
|
parent::__construct($table, $local, $foreign, $type, $alias);
|
||||||
$this->associationTable = $associationTable;
|
$this->associationTable = $associationTable;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -280,14 +280,14 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
|
|||||||
if(isset($this->reference_field))
|
if(isset($this->reference_field))
|
||||||
$record->rawSet($this->reference_field,$this->reference);
|
$record->rawSet($this->reference_field,$this->reference);
|
||||||
|
|
||||||
$this->reference->addReference($record);
|
$this->reference->addReference($record, $this->relation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$i = $offset;
|
$i = $offset;
|
||||||
|
|
||||||
foreach($coll as $record) {
|
foreach($coll as $record) {
|
||||||
if(isset($this->reference)) {
|
if(isset($this->reference)) {
|
||||||
$this->reference->addReference($record,$i);
|
$this->reference->addReference($record, $this->relation, $i);
|
||||||
} else
|
} else
|
||||||
$this->data[$i] = $record;
|
$this->data[$i] = $record;
|
||||||
|
|
||||||
|
@ -138,9 +138,9 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
* fields of the tables become: [tablename].[fieldname] as [tablename]__[fieldname]
|
* fields of the tables become: [tablename].[fieldname] as [tablename]__[fieldname]
|
||||||
*
|
*
|
||||||
* @access private
|
* @access private
|
||||||
* @param object Doctrine_Table $table a Doctrine_Table object
|
* @param object Doctrine_Table $table a Doctrine_Table object
|
||||||
* @param integer $fetchmode fetchmode the table is using eg. Doctrine::FETCH_LAZY
|
* @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 array $names fields to be loaded (only used in lazy property loading)
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function loadFields(Doctrine_Table $table, $fetchmode, array $names, $cpath) {
|
private function loadFields(Doctrine_Table $table, $fetchmode, array $names, $cpath) {
|
||||||
@ -296,9 +296,17 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->applyInheritance();
|
$string = $this->applyInheritance();
|
||||||
if( ! empty($this->parts["where"]))
|
|
||||||
|
if( ! empty($this->parts["where"])) {
|
||||||
$q .= " WHERE ".implode(" ",$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"]))
|
if( ! empty($this->parts["groupby"]))
|
||||||
$q .= " GROUP BY ".implode(", ",$this->parts["groupby"]);
|
$q .= " GROUP BY ".implode(", ",$this->parts["groupby"]);
|
||||||
@ -319,12 +327,9 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
* applyInheritance
|
* applyInheritance
|
||||||
* applies column aggregation inheritance to DQL query
|
* applies column aggregation inheritance to DQL query
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return string
|
||||||
*/
|
*/
|
||||||
final public function applyInheritance() {
|
final public function applyInheritance() {
|
||||||
if($this->inheritanceApplied)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// get the inheritance maps
|
// get the inheritance maps
|
||||||
$array = array();
|
$array = array();
|
||||||
|
|
||||||
@ -355,9 +360,7 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
|
|
||||||
$str .= implode(" AND ",$c);
|
$str .= implode(" AND ",$c);
|
||||||
|
|
||||||
$this->addWhere($str);
|
return $str;
|
||||||
$this->inheritanceApplied = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param string $where
|
* @param string $where
|
||||||
@ -490,7 +493,9 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
|
|
||||||
$pointer = $this->joins[$name];
|
$pointer = $this->joins[$name];
|
||||||
$path = array_search($name, $this->tableAliases);
|
$path = array_search($name, $this->tableAliases);
|
||||||
$alias = end( explode(".", $path));
|
$tmp = explode(".", $path);
|
||||||
|
$alias = end($tmp);
|
||||||
|
unset($tmp);
|
||||||
$fk = $this->tables[$pointer]->getForeignKey($alias);
|
$fk = $this->tables[$pointer]->getForeignKey($alias);
|
||||||
|
|
||||||
if( ! isset($prev[$pointer]) )
|
if( ! isset($prev[$pointer]) )
|
||||||
@ -535,7 +540,9 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
|
|
||||||
$pointer = $this->joins[$name];
|
$pointer = $this->joins[$name];
|
||||||
$path = array_search($name, $this->tableAliases);
|
$path = array_search($name, $this->tableAliases);
|
||||||
$alias = end( explode(".", $path));
|
$tmp = explode(".", $path);
|
||||||
|
$alias = end($tmp);
|
||||||
|
unset($tmp);
|
||||||
$fk = $this->tables[$pointer]->getForeignKey($alias);
|
$fk = $this->tables[$pointer]->getForeignKey($alias);
|
||||||
$last = $prev[$pointer]->getLast();
|
$last = $prev[$pointer]->getLast();
|
||||||
|
|
||||||
@ -561,7 +568,7 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
$prev[$name] = $last->get($alias);
|
$prev[$name] = $last->get($alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
$last->addReference($record);
|
$last->addReference($record, $fk);
|
||||||
endswitch;
|
endswitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1147,7 +1154,7 @@ class Doctrine_Query extends Doctrine_Access {
|
|||||||
if($fk instanceof Doctrine_ForeignKey ||
|
if($fk instanceof Doctrine_ForeignKey ||
|
||||||
$fk instanceof Doctrine_LocalKey) {
|
$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) {
|
} elseif($fk instanceof Doctrine_Association) {
|
||||||
$asf = $fk->getAssociationFactory();
|
$asf = $fk->getAssociationFactory();
|
||||||
|
@ -1003,13 +1003,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function initReference(Doctrine_Collection $coll, Doctrine_Relation $connector) {
|
public function initReference(Doctrine_Collection $coll, Doctrine_Relation $connector) {
|
||||||
$name = $this->table->getAlias($coll->getTable()->getComponentName());
|
$alias = $connector->getAlias();
|
||||||
|
|
||||||
if( ! ($connector instanceof Doctrine_Association))
|
if( ! ($connector instanceof Doctrine_Association))
|
||||||
$coll->setReference($this, $connector);
|
$coll->setReference($this, $connector);
|
||||||
|
|
||||||
$this->references[$name] = $coll;
|
$this->references[$alias] = $coll;
|
||||||
$this->originals[$name] = clone $coll;
|
$this->originals[$alias] = clone $coll;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* addReference
|
* addReference
|
||||||
@ -1017,11 +1017,11 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
|
|||||||
* @param mixed $key
|
* @param mixed $key
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function addReference(Doctrine_Record $record, $key = null) {
|
public function addReference(Doctrine_Record $record, Doctrine_Relation $connector, $key = null) {
|
||||||
$name = $this->table->getAlias($record->getTable()->getComponentName());
|
$alias = $connector->getAlias();
|
||||||
|
|
||||||
$this->references[$name]->add($record, $key);
|
$this->references[$alias]->add($record, $key);
|
||||||
$this->originals[$name]->add($record, $key);
|
$this->originals[$alias]->add($record, $key);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* getReferences
|
* getReferences
|
||||||
|
@ -57,11 +57,12 @@ class Doctrine_Relation {
|
|||||||
* @param integer $type
|
* @param integer $type
|
||||||
* @param string $alias
|
* @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->table = $table;
|
||||||
$this->local = $local;
|
$this->local = $local;
|
||||||
$this->foreign = $foreign;
|
$this->foreign = $foreign;
|
||||||
$this->type = $type;
|
$this->type = $type;
|
||||||
|
$this->alias = $alias;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return string the relation alias
|
* @return string the relation alias
|
||||||
|
@ -538,7 +538,7 @@ class Doctrine_Table extends Doctrine_Configurable {
|
|||||||
if( ! isset($local))
|
if( ! isset($local))
|
||||||
$local = $table->getIdentifier();
|
$local = $table->getIdentifier();
|
||||||
|
|
||||||
$relation = new Doctrine_LocalKey($table,$foreign,$local,$type);
|
$relation = new Doctrine_LocalKey($table,$foreign,$local,$type, $alias);
|
||||||
} else
|
} else
|
||||||
throw new Doctrine_Mapping_Exception("Only one-to-one relations are possible when local reference key is used.");
|
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;
|
$local = $this->identifier;
|
||||||
|
|
||||||
// ONE-TO-MANY or ONE-TO-ONE
|
// 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 {
|
} else {
|
||||||
// MANY-TO-MANY
|
// MANY-TO-MANY
|
||||||
@ -578,14 +578,14 @@ class Doctrine_Table extends Doctrine_Configurable {
|
|||||||
|
|
||||||
if(count($fields) > 1) {
|
if(count($fields) > 1) {
|
||||||
// SELF-REFERENCING THROUGH JOIN TABLE
|
// 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 {
|
} else {
|
||||||
// NORMAL MANY-TO-MANY RELATIONSHIP
|
// 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_Entry";
|
||||||
$this->tables[] = "Forum_Board";
|
$this->tables[] = "Forum_Board";
|
||||||
$this->tables[] = "Forum_Thread";
|
$this->tables[] = "Forum_Thread";
|
||||||
|
|
||||||
$this->tables[] = "ORM_TestEntry";
|
$this->tables[] = "ORM_TestEntry";
|
||||||
$this->tables[] = "ORM_TestItem";
|
$this->tables[] = "ORM_TestItem";
|
||||||
$this->tables[] = "Log_Status";
|
$this->tables[] = "Log_Status";
|
||||||
@ -13,48 +14,17 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
|
|||||||
try {
|
try {
|
||||||
$this->dbh->query("DROP TABLE test_items");
|
$this->dbh->query("DROP TABLE test_items");
|
||||||
} catch(PDOException $e) {
|
} catch(PDOException $e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$this->dbh->query("DROP TABLE test_entries");
|
$this->dbh->query("DROP TABLE test_entries");
|
||||||
} catch(PDOException $e) {
|
} catch(PDOException $e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
parent::prepareTables();
|
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() {
|
public function testSelfReferencing() {
|
||||||
$category = new Forum_Category();
|
$category = new Forum_Category();
|
||||||
|
|
||||||
@ -81,6 +51,56 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
|
|||||||
$this->session->clear();
|
$this->session->clear();
|
||||||
|
|
||||||
$query = new Doctrine_Query($this->session);
|
$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() {
|
public function testHaving() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user