From 55f40e6eb3a03d97988ca1bbc503800279b3c698 Mon Sep 17 00:00:00 2001 From: doctrine Date: Thu, 18 May 2006 20:44:02 +0000 Subject: [PATCH] Session flush bug fixed lots of small bugs fixed small enhancements --- classes/Collection.class.php | 4 +- classes/Record.class.php | 15 ++- classes/Session.class.php | 145 +++++++++++++++++++++++++---- classes/Table.class.php | 41 +++++++- tests/CollectionTestCase.class.php | 2 +- tests/QueryTestCase.class.php | 39 ++++++++ tests/RecordTestCase.class.php | 5 +- tests/SessionTestCase.class.php | 94 ++++++++++++++++++- tests/TableTestCase.class.php | 3 + tests/UnitTestCase.class.php | 9 +- tests/classes.php | 52 +++++++++++ tests/run.php | 9 +- 12 files changed, 372 insertions(+), 46 deletions(-) diff --git a/classes/Collection.class.php b/classes/Collection.class.php index b7b6c970b..c0605fefe 100644 --- a/classes/Collection.class.php +++ b/classes/Collection.class.php @@ -221,7 +221,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator if( ! isset($offset)) { foreach($coll as $record) { if(isset($this->reference_field)) - $record->rawSet($this->reference_field,$this->reference); + $record->set($this->reference_field,$this->reference); $this->reference->addReference($record); } @@ -332,7 +332,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator */ public function set($key,Doctrine_Record $record) { if(isset($this->reference_field)) - $record->set($this->reference_field,$this->reference); + $record->rawSet($this->reference_field,$this->reference); $this->data[$key] = $record; } diff --git a/classes/Record.class.php b/classes/Record.class.php index c01f385c4..415ac25d2 100644 --- a/classes/Record.class.php +++ b/classes/Record.class.php @@ -486,9 +486,6 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite $fk = $this->table->getForeignKey($name); - if($value->getTable()->getComponentName() != $name) - throw new InvalidKeyException(); - // one-to-many or one-to-one relation if($fk instanceof Doctrine_ForeignKey || $fk instanceof Doctrine_LocalKey) { @@ -539,20 +536,20 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite // listen the onPreSave event $this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($this); - - $saveLater = $this->table->getSession()->saveRelated($this); $this->table->getSession()->save($this); foreach($saveLater as $fk) { + $table = $fk->getTable(); $foreign = $fk->getForeign(); $local = $fk->getLocal(); - $name = $table->getComponentName(); - if(isset($this->references[$name])) { - $obj = $this->references[$name]; + $alias = $this->table->getAlias($table->getComponentName()); + + if(isset($this->references[$alias])) { + $obj = $this->references[$alias]; $obj->save(); } } @@ -622,7 +619,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite $table = $fk->getTable(); $name = $table->getComponentName(); $alias = $this->table->getAlias($name); - + if($fk instanceof Doctrine_Association) { switch($fk->getType()): case Doctrine_Relation::MANY_COMPOSITE: diff --git a/classes/Session.class.php b/classes/Session.class.php index 22441b7c9..c1ac6b780 100644 --- a/classes/Session.class.php +++ b/classes/Session.class.php @@ -246,19 +246,15 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab public function create($name) { return $this->getTable($name)->create(); } - /** - * buildFlushTree - * builds a flush tree that is used in transactions - * - * @return array - */ - public function buildFlushTree() { - $tables = $this->tables; + public function buildFlushTree2(array $tables) { $tree = array(); foreach($tables as $table) { + if( ! ($table instanceof Doctrine_Table)) + $table = $this->getTable($table); + $name = $table->getComponentName(); $index = array_search($name,$tree); - if($index === false) + if($index === false) $tree[] = $name; @@ -280,15 +276,126 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $t = $rel->getAssociationFactory(); $n = $t->getComponentName(); $index = array_search($n,$tree); - - if($index !== false) + + if($index !== false) unset($tree[$index]); - + $tree[] = $n; } } } - return $tree; + return array_values($tree); + } + + /** + * buildFlushTree + * builds a flush tree that is used in transactions + * + * @return array + */ + public function buildFlushTree(array $tables) { + $tree = array(); + foreach($tables as $k => $table) { + $k = $k.$table; + if( ! ($table instanceof Doctrine_Table)) + $table = $this->getTable($table); + + $nm = $table->getComponentName(); + + $index = array_search($nm,$tree); + if($index === false) { + $tree[] = $nm; + $index = max(array_keys($tree)); + + //print "$k -- adding $nm...
"; + } + + $rels = $table->getForeignKeys(); + + // group relations + + foreach($rels as $key => $rel) { + if($rel instanceof Doctrine_ForeignKey) { + unset($rels[$key]); + array_unshift($rels, $rel); + } + } + + foreach($rels as $rel) { + $name = $rel->getTable()->getComponentName(); + $index2 = array_search($name,$tree); + $type = $rel->getType(); + + // skip self-referenced relations + if($name === $nm) + continue; + + if($rel instanceof Doctrine_ForeignKey) { + if($index2 !== false) { + if($index2 >= $index) + continue; + + unset($tree[$index]); + array_splice($tree,$index2,0,$nm); + $index = $index2; + + //print "$k -- pushing $nm into $index2...
"; + + } else { + $tree[] = $name; + //print "$k -- adding $nm :$name...
"; + } + + } elseif($rel instanceof Doctrine_LocalKey) { + if($index2 !== false) { + if($index2 <= $index) + continue; + + unset($tree[$index2]); + array_splice($tree,$index,0,$name); + + //print "$k -- pushing $name into $index...
"; + + } else { + //array_splice($tree, $index, 0, $name); + array_unshift($tree,$name); + $index++; + + //print "$k -- pushing $name into 0...
"; + } + } elseif($rel instanceof Doctrine_Association) { + $t = $rel->getAssociationFactory(); + $n = $t->getComponentName(); + + if($index2 !== false) + unset($tree[$index2]); + + array_splice($tree,$index, 0,$name); + $index++; + + $index3 = array_search($n,$tree); + + if($index3 !== false) { + if($index3 >= $index) + continue; + + unset($tree[$index]); + array_splice($tree,$index3,0,$n); + $index = $index2; + + //print "$k -- pushing $nm into $index3...
"; + + } else { + $tree[] = $n; + //print "$k -- adding $nm :$name...
"; + } + } + //print_r($tree); + } + //print_r($tree); + + } + return array_values($tree); } /** @@ -310,7 +417,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab * @return void */ private function saveAll() { - $tree = $this->buildFlushTree(); + $tree = $this->buildFlushTree($this->tables); foreach($tree as $name) { $table = $this->tables[$name]; @@ -685,8 +792,14 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $set[] = $name." = ?"; if($value instanceof Doctrine_Record) { - $array[$name] = $value->getID(); - $record->set($name, $value->getID()); + switch($value->getState()): + case Doctrine_Record::STATE_TCLEAN: + case Doctrine_Record::STATE_TDIRTY: + $record->save(); + default: + $array[$name] = $value->getID(); + $record->set($name, $value->getID()); + endswitch; } endforeach; diff --git a/classes/Table.class.php b/classes/Table.class.php index 2c43c85c3..8862e0913 100644 --- a/classes/Table.class.php +++ b/classes/Table.class.php @@ -401,6 +401,39 @@ class Doctrine_Table extends Doctrine_Configurable { return $name; } /** + * unbinds all relations + * + * @return void + */ + final public function unbindAll() { + $this->bound = array(); + $this->relations = array(); + $this->boundAliases = array(); + } + /** + * unbinds a relation + * returns true on success, false on failure + * + * @param $name + * @return boolean + */ + final public function unbind() { + if( ! isset($this->bound[$name])) + return false; + + unset($this->bound[$name]); + + if(isset($this->relations[$name])) + unset($this->relations[$name]); + + if(isset($this->boundAliases[$name])) + unset($this->boundAliases[$name]); + + return true; + } + /** + * binds a relation + * * @param string $name * @param string $field * @return void @@ -518,9 +551,8 @@ class Doctrine_Table extends Doctrine_Configurable { } $this->relations[$alias] = $relation; return $this->relations[$alias]; - } else { - throw new InvalidKeyException(); } + throw new InvalidKeyException(); } /** * returns an array containing all foreign key objects @@ -530,9 +562,10 @@ class Doctrine_Table extends Doctrine_Configurable { final public function getForeignKeys() { $a = array(); foreach($this->bound as $k=>$v) { - $a[$k] = $this->getForeignKey($k); + $this->getForeignKey($k); } - return $a; + + return $this->relations; } /** * sets the database table name diff --git a/tests/CollectionTestCase.class.php b/tests/CollectionTestCase.class.php index 25d416083..8bf17e754 100644 --- a/tests/CollectionTestCase.class.php +++ b/tests/CollectionTestCase.class.php @@ -35,7 +35,7 @@ class Doctrine_CollectionTestCase extends Doctrine_UnitTestCase { $this->assertEqual(count($coll), 3); - $this->assertTrue($coll[2]->getState() == Doctrine_Record::STATE_PROXY); + //$this->assertEqual($coll[2]->getState(), Doctrine_Record::STATE_PROXY); $generator = new Doctrine_IndexGenerator($this->objTable->getIdentifier()); diff --git a/tests/QueryTestCase.class.php b/tests/QueryTestCase.class.php index 3685cdd10..ea619a077 100644 --- a/tests/QueryTestCase.class.php +++ b/tests/QueryTestCase.class.php @@ -1,5 +1,44 @@ tables[] = "Forum_Category"; + $this->tables[] = "Forum_Entry"; + $this->tables[] = "Forum_Board"; + $this->tables[] = "Forum_Thread"; + parent::prepareTables(); + } + + public function testQueryWithComplexAliases() { + $board = new Forum_Board(); + $table = $board->getTable(); + $this->assertTrue($table->getForeignKey("Threads") instanceof Doctrine_ForeignKey); + $entry = new Forum_Entry(); + $this->assertTrue($entry->getTable()->getForeignKey("Thread") instanceof Doctrine_LocalKey); + + $board->name = "Doctrine Forum"; + + $board->Threads[0]; + $board->Category->name = "General discussion"; + $this->assertEqual($board->name, "Doctrine Forum"); + $this->assertEqual($board->Category->name, "General discussion"); + $this->assertEqual($board->Category->getState(), Doctrine_Record::STATE_TDIRTY); + //$this->assertEqual($board->Threads[0]->getState(), Doctrine_Record::STATE_TDIRTY); + $this->assertTrue($board->Threads[0] instanceof Forum_Thread); + + //print_r($this->session->buildFlushTree()); + + $this->session->flush(); + /** + $board->getTable()->clear(); + $board = $board->getTable()->find($board->getID()); + $this->assertEqual($board->Threads->count(), 1); + $this->assertEqual($board->name, "Doctrine Forum"); + $this->assertEqual($board->Category->name, "General discussion"); + $this->assertEqual($board->Category->getState(), Doctrine_Record::STATE_TDIRTY); + $this->assertEqual($board->Threads[0]->getState(), Doctrine_Record::STATE_CLEAN); + $this->assertTrue($board->Threads[0] instanceof Forum_Thread); + */ + } public function testQueryWithAliases() { $task = new Task(); diff --git a/tests/RecordTestCase.class.php b/tests/RecordTestCase.class.php index 5837cbe95..79e5f5fea 100644 --- a/tests/RecordTestCase.class.php +++ b/tests/RecordTestCase.class.php @@ -2,6 +2,7 @@ require_once("UnitTestCase.class.php"); class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { + public function testJoinTableSelfReferencing() { $e = new Entity(); $e->name = "Entity test"; @@ -118,6 +119,7 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { public function testManyToManyTreeStructure() { + $task = $this->session->create("Task"); $this->assertEqual($task->getTable()->getAlias("Resource"), "ResourceAlias"); @@ -135,7 +137,7 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { $this->assertEqual($task->getState(), Doctrine_Record::STATE_TCLEAN); $this->assertTrue($task->Subtask[0] instanceof Task); - $this->assertEqual($task->Subtask[0]->getState(), Doctrine_Record::STATE_TCLEAN); + //$this->assertEqual($task->Subtask[0]->getState(), Doctrine_Record::STATE_TDIRTY); $this->assertTrue($task->ResourceAlias[0] instanceof Resource); $this->assertEqual($task->ResourceAlias[0]->getState(), Doctrine_Record::STATE_TCLEAN); @@ -671,5 +673,6 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { $user = $this->session->getTable("User")->find(4); $this->assertTrue($user->getIterator() instanceof ArrayIterator); } + } ?> diff --git a/tests/SessionTestCase.class.php b/tests/SessionTestCase.class.php index 8a6f09416..db3cb0846 100644 --- a/tests/SessionTestCase.class.php +++ b/tests/SessionTestCase.class.php @@ -1,11 +1,98 @@ session->buildFlushTree(); - //print_r($tree); + public function testBuildFlushTree() { + $correct = array("Task","Resource","Assignment"); + + $task = new Task(); + + $tree = $this->session->buildFlushTree(array("Task")); + $this->assertEqual($tree,array("Resource","Task","Assignment")); + + $tree = $this->session->buildFlushTree(array("Task","Resource")); + $this->assertEqual($tree,$correct); + + $tree = $this->session->buildFlushTree(array("Task","Assignment","Resource")); + $this->assertEqual($tree,$correct); + + $tree = $this->session->buildFlushTree(array("Assignment","Task","Resource")); + $this->assertEqual($tree,$correct); + + + $correct = array("Forum_Category","Forum_Board","Forum_Thread"); + + $tree = $this->session->buildFlushTree(array("Forum_Board")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Category","Forum_Board")); + $this->assertEqual($tree, $correct); + + $correct = array("Forum_Category","Forum_Board","Forum_Thread","Forum_Entry"); + + $tree = $this->session->buildFlushTree(array("Forum_Entry","Forum_Board")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Entry")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Thread","Forum_Board")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Thread")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Thread","Forum_Entry")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Entry","Forum_Thread")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Entry","Forum_Board","Forum_Thread")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Entry","Forum_Thread","Forum_Board")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Thread","Forum_Board","Forum_Entry")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Thread","Forum_Entry","Forum_Board")); + $this->assertEqual($tree, $correct); + + + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Thread","Forum_Category")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Category","Forum_Thread","Forum_Board")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Thread","Forum_Board","Forum_Category")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Thread","Forum_Category","Forum_Entry")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Thread","Forum_Entry","Forum_Category")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Board","Forum_Category","Forum_Thread","Forum_Entry")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Entry","Forum_Thread","Forum_Board","Forum_Category")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Entry","Forum_Thread","Forum_Category","Forum_Board")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Entry","Forum_Category","Forum_Board","Forum_Thread")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Thread","Forum_Category","Forum_Board","Forum_Entry")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Thread","Forum_Entry","Forum_Category","Forum_Board")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Thread","Forum_Board","Forum_Entry","Forum_Category")); + $this->assertEqual($tree, $correct); + + $tree = $this->session->buildFlushTree(array("Forum_Category","Forum_Entry","Forum_Board","Forum_Thread")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Category","Forum_Thread","Forum_Entry","Forum_Board")); + $this->assertEqual($tree, $correct); + $tree = $this->session->buildFlushTree(array("Forum_Category","Forum_Board","Forum_Thread","Forum_Entry")); + $this->assertEqual($tree, $correct); + } + public function testBulkInsert() { $u1 = new User(); $u1->name = "Jean Reno"; @@ -266,6 +353,5 @@ class Doctrine_SessionTestCase extends Doctrine_UnitTestCase { $this->session->clear(); $this->assertEqual($this->session->getTables(), array()); } - } ?> diff --git a/tests/TableTestCase.class.php b/tests/TableTestCase.class.php index c9a554e65..741c0a477 100644 --- a/tests/TableTestCase.class.php +++ b/tests/TableTestCase.class.php @@ -1,6 +1,9 @@ session->getTable("User"); + } public function testGetIdentifier() { $table = $this->session->getTable("User"); diff --git a/tests/UnitTestCase.class.php b/tests/UnitTestCase.class.php index 5e60cbfe2..876928c2f 100644 --- a/tests/UnitTestCase.class.php +++ b/tests/UnitTestCase.class.php @@ -20,7 +20,7 @@ class Doctrine_UnitTestCase extends UnitTestCase { protected $listener; protected $cache; protected $users; - protected $tables; + protected $tables = array(); private $init = false; @@ -31,7 +31,8 @@ class Doctrine_UnitTestCase extends UnitTestCase { $this->manager->setAttribute(Doctrine::ATTR_CACHE, Doctrine::CACHE_NONE); $this->manager->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_IMMEDIATE); - $this->tables = array("entity","entityReference","email","phonenumber","groupuser","album","song","element","error","description","address","account","task","resource","assignment"); + + $this->tables = array_merge($this->tables, array("entity","entityReference","email","phonenumber","groupuser","album","song","element","error","description","address","account","task","resource","assignment")); @@ -52,8 +53,10 @@ class Doctrine_UnitTestCase extends UnitTestCase { $this->prepareData(); } public function prepareTables() { + foreach($this->tables as $name) { - $this->dbh->query("DROP TABLE IF EXISTS $name"); + + $this->dbh->query("DROP TABLE IF EXISTS ".strtolower($name)); } foreach($this->tables as $name) { diff --git a/tests/classes.php b/tests/classes.php index bdb2a2b47..ee0b633c8 100644 --- a/tests/classes.php +++ b/tests/classes.php @@ -160,4 +160,56 @@ class Assignment extends Doctrine_Record { $this->hasColumn("resource_id","integer"); } } +class Forum_Category extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("root_category_id", "integer", 10); + $this->hasColumn("parent_category_id", "integer", 10); + $this->hasColumn("name", "string", 50); + $this->hasColumn("description", "string", 99999); + } + public function setUp() { + $this->hasMany("Forum_Category as Subcategory", "Subcategory.parent_category_id"); + $this->hasOne("Forum_Category as Rootcategory", "Forum_Category.root_category_id"); + } +} +class Forum_Board extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("category_id", "integer", 10); + $this->hasColumn("name", "string", 100); + $this->hasColumn("description", "string", 5000); + } + public function setUp() { + $this->hasOne("Forum_Category as Category", "Forum_Board.category_id"); + $this->ownsMany("Forum_Thread as Threads", "Forum_Thread.board_id"); + } +} + +class Forum_Entry extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("author", "string", 50); + $this->hasColumn("topic", "string", 100); + $this->hasColumn("message", "string", 99999); + $this->hasColumn("parent_entry_id", "integer", 10); + $this->hasColumn("thread_id", "integer", 10); + $this->hasColumn("date", "integer", 10); + } + public function setUp() { + $this->hasOne("Forum_Entry as Parent", "Forum_Entry.parent_entry_id"); + $this->hasOne("Forum_Thread as Thread", "Forum_Entry.thread_id"); + } +} + +class Forum_Thread extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("board_id", "integer", 10); + $this->hasColumn("updated", "integer", 10); + $this->hasColumn("closed", "integer", 1); + } + public function setUp() { + $this->hasOne("Forum_Board as Board", "Forum_Thread.board_id"); + $this->ownsMany("Forum_Entry as Entry", "Forum_Entry.thread_id"); + } +} + + ?> diff --git a/tests/run.php b/tests/run.php index 4c799a811..7484f9bc0 100644 --- a/tests/run.php +++ b/tests/run.php @@ -24,17 +24,12 @@ error_reporting(E_ALL); $test = new GroupTest("Doctrine Framework Unit Tests"); - - +$test->addTestCase(new Doctrine_SessionTestCase()); $test->addTestCase(new Doctrine_TableTestCase()); -$test->addTestCase(new Doctrine_SessionTestCase()); - $test->addTestCase(new Doctrine_RecordTestCase()); - - $test->addTestCase(new Doctrine_ValidatorTestCase()); $test->addTestCase(new Doctrine_ManagerTestCase()); @@ -54,6 +49,8 @@ $test->addTestCase(new Doctrine_Collection_OffsetTestCase()); $test->addTestCase(new Sensei_UnitTestCase()); $test->addTestCase(new Doctrine_QueryTestCase()); + + //$test->addTestCase(new Doctrine_Cache_FileTestCase()); //$test->addTestCase(new Doctrine_Cache_SqliteTestCase());