diff --git a/classes/Access.class.php b/classes/Access.class.php index 594801697..7d4510ff5 100644 --- a/classes/Access.class.php +++ b/classes/Access.class.php @@ -1,8 +1,9 @@ get($name); } /** + * @param mixed $offset * @return boolean -- whether or not the data has a field $offset */ public function offsetExists($offset) { diff --git a/classes/Manager.class.php b/classes/Manager.class.php index a070e96e7..47b5953ad 100644 --- a/classes/Manager.class.php +++ b/classes/Manager.class.php @@ -70,6 +70,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera } /** * returns the root directory of Doctrine + * * @return string */ final public function getRoot() { @@ -77,7 +78,9 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera } /** * getInstance - * this class uses the singleton pattern + * returns an instance of this class + * (this class uses the singleton pattern) + * * @return Doctrine_Manager */ final public static function getInstance() { @@ -171,6 +174,8 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera } /** * setCurrentSession + * sets the current session to $key + * * @param mixed $key the session key * @throws InvalidKeyException * @return void @@ -217,6 +222,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera /** * __toString * returns a string representation of this object + * * @return string */ public function __toString() { diff --git a/classes/Record.class.php b/classes/Record.class.php index 6d7477a2f..64649d58c 100644 --- a/classes/Record.class.php +++ b/classes/Record.class.php @@ -815,7 +815,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite final public function loadReference($name) { $fk = $this->table->getForeignKey($name); $table = $fk->getTable(); - $name = $table->getComponentName(); + $local = $fk->getLocal(); $foreign = $fk->getForeign(); $graph = $table->getQueryObject(); @@ -825,7 +825,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite case Doctrine_Record::STATE_TDIRTY: case Doctrine_Record::STATE_TCLEAN: - if($type == Doctrine_Relation::ONE_COMPOSITE || + if($type == Doctrine_Relation::ONE_COMPOSITE || $type == Doctrine_Relation::ONE_AGGREGATE) { // ONE-TO-ONE @@ -837,7 +837,6 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite $this->set($fk->getLocal(),$this->references[$name]); } } else { - $this->references[$name] = new Doctrine_Collection($table); if($fk instanceof Doctrine_ForeignKey) { // ONE-TO-MANY @@ -849,13 +848,16 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite case Doctrine_Record::STATE_DIRTY: case Doctrine_Record::STATE_CLEAN: case Doctrine_Record::STATE_PROXY: + switch($fk->getType()): case Doctrine_Relation::ONE_COMPOSITE: case Doctrine_Relation::ONE_AGGREGATE: + // ONE-TO-ONE $id = $this->get($local); if($fk instanceof Doctrine_LocalKey) { + if(empty($id)) { $this->references[$name] = $table->create(); $this->set($fk->getLocal(),$this->references[$name]); @@ -868,11 +870,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite } } elseif ($fk instanceof Doctrine_ForeignKey) { + if(empty($id)) { $this->references[$name] = $table->create(); $this->references[$name]->set($fk->getForeign(), $this); } else { - $dql = "FROM ".$name." WHERE ".$name.".".$fk->getForeign()." = ?"; + $dql = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$fk->getForeign()." = ?"; $coll = $graph->query($dql, array($id)); $this->references[$name] = $coll[0]; $this->references[$name]->set($fk->getForeign(), $this); @@ -883,7 +886,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite // ONE-TO-MANY if($fk instanceof Doctrine_ForeignKey) { $id = $this->get($local); - $query = "FROM ".$name." WHERE ".$name.".".$fk->getForeign()." = ?"; + $query = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$fk->getForeign()." = ?"; $coll = $graph->query($query,array($id)); $this->references[$name] = $coll; diff --git a/classes/Session.class.php b/classes/Session.class.php index 37e23e14c..484bc699e 100644 --- a/classes/Session.class.php +++ b/classes/Session.class.php @@ -131,6 +131,9 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab /** * query * queries the database with Doctrine Query Language + * + * @param string $query DQL query + * @param array $params query parameters */ final public function query($query,array $params = array()) { $parser = new Doctrine_Query($this); @@ -149,7 +152,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab public function select($query,$limit = 0,$offset = 0) { if($limit > 0 || $offset > 0) $query = $this->modifyLimitQuery($query,$limit,$offset); - + return $this->dbh->query($query); } /** @@ -177,12 +180,13 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab return isset($this->tables[$name]); } /** + * returns a table object for given component name + * * @param string $name component name - * @throws Doctrine_Table_Exception * @return object Doctrine_Table */ public function getTable($name) { - $name = ucwords(strtolower($name)); + // $name = ucwords(strtolower($name)); if(isset($this->tables[$name])) return $this->tables[$name]; @@ -197,25 +201,32 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab } } /** - * @return array -- an array of all initialized tables + * returns an array of all initialized tables + * + * @return array */ public function getTables() { return $this->tables; } /** + * returns an iterator that iterators through all + * initialized table objects + * * @return ArrayIterator */ public function getIterator() { return new ArrayIterator($this->tables); } /** + * returns the count of initialized table objects + * * @return integer */ public function count() { return count($this->tables); } /** - * @param $objTable -- a Doctrine_Table object to be added into factory registry + * @param $objTable a Doctrine_Table object to be added into registry * @return boolean */ public function addTable(Doctrine_Table $objTable) { @@ -228,6 +239,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab return true; } /** + * creates a record + * * create creates a record * @param string $name component name * @return Doctrine_Record Doctrine_Record object @@ -237,6 +250,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab } /** * buildFlushTree + * builds a flush tree that is used in transactions + * * @return array */ public function buildFlushTree() { @@ -293,6 +308,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab /** * saveAll * saves all the records from all tables + * + * @return void */ private function saveAll() { $tree = $this->buildFlushTree(); @@ -312,8 +329,9 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab } } /** - * clear + * clear * clears the whole registry + * * @return void */ public function clear() { @@ -408,7 +426,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab } /** * rollback - * rolls back all the transactions + * rolls back all transactions * @return void */ public function rollback() { @@ -501,6 +519,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab /** * bulkUpdate * updates all objects in the pending update list + * * @return void */ public function bulkUpdate() { @@ -527,6 +546,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab } /** * bulkDelete + * deletes all records from the pending delete list + * * @return void */ public function bulkDelete() { @@ -549,10 +570,9 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab } $this->delete = array(); } - - - /** + * saves a collection + * * @param Doctrine_Collection $coll * @return void */ @@ -566,6 +586,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $this->commit(); } /** + * deletes all records from collection + * * @param Doctrine_Collection $coll * @return void */ @@ -577,6 +599,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $this->commit(); } /** + * saves the given record + * * @param Doctrine_Record $record * @return void */ @@ -596,6 +620,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab endswitch; } /** + * saves all related records to $record + * * @param Doctrine_Record $record */ final public function saveRelated(Doctrine_Record $record) { @@ -638,6 +664,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab return $saveLater; } /** + * updates the given record + * * @param Doctrine_Record $record * @return boolean */ @@ -676,6 +704,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab return true; } /** + * inserts a record into database + * * @param Doctrine_Record $record * @return boolean */ @@ -711,7 +741,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab } /** * deletes all related composites - * this method is always called internally when this data access object is deleted + * this method is always called internally when a record is deleted * * @return void */ @@ -752,7 +782,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab endswitch; } /** - * adds data access object into pending insert list + * adds record into pending insert list * @param Doctrine_Record $record */ public function addInsert(Doctrine_Record $record) { @@ -760,7 +790,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $this->insert[$name][] = $record; } /** - * adds data access object into penging update list + * adds record into penging update list * @param Doctrine_Record $record */ public function addUpdate(Doctrine_Record $record) { @@ -768,7 +798,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $this->update[$name][] = $record; } /** - * adds data access object into pending delete list + * adds record into pending delete list * @param Doctrine_Record $record */ public function addDelete(Doctrine_Record $record) { @@ -776,18 +806,24 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $this->delete[$name][] = $record; } /** + * returns the pending insert list + * * @return array */ public function getInserts() { return $this->insert; } /** + * returns the pending update list + * * @return array */ public function getUpdates() { return $this->update; } /** + * returns the pending delete list + * * @return array */ public function getDeletes() { diff --git a/classes/Table.class.php b/classes/Table.class.php index 0376fe914..4a685002c 100644 --- a/classes/Table.class.php +++ b/classes/Table.class.php @@ -21,9 +21,9 @@ class Doctrine_Table extends Doctrine_Configurable { */ private $data = array(); /** - * @var array $foreignKeys an array containing all the Doctrine_ForeignKey objects for this table + * @var array $relations an array containing all the Doctrine_Relation objects for this table */ - private $foreignKeys = array(); + private $relations = array(); /** * @var array $primaryKeys an array containing all primary key column names */ @@ -337,25 +337,14 @@ class Doctrine_Table extends Doctrine_Configurable { return $this->bound[$name]; } /** - * @param string $objTableName + * @param string $name * @param string $field * @return void */ - final public function bind($objTableName,$field,$type,$localKey) { - $name = (string) $objTableName; - $field = (string) $field; - - if(isset($this->foreignKeys[$name])) + final public function bind($name,$field,$type,$localKey) { + if(isset($this->relations[$name])) throw new InvalidKeyException(); - $e = explode(".", $field); - - // is reference table used? - if($e[0] != $name && $e[0] == $this->name) - $this->bound[$name] = array($field,Doctrine_Relation::MANY_COMPOSITE); - - - $this->bound[$name] = array($field,$type,$localKey); } /** @@ -388,77 +377,80 @@ class Doctrine_Table extends Doctrine_Configurable { * @return Doctrine_Relation */ final public function getForeignKey($name) { - if(isset($this->foreignKeys[$name])) - return $this->foreignKeys[$name]; + if(isset($this->relations[$name])) + return $this->relations[$name]; if(isset($this->bound[$name])) { - $field = $this->bound[$name][0]; - $type = $this->bound[$name][1]; - $local = $this->bound[$name][2]; - $e = explode(".",$field); - $objTable = $this->session->getTable($name); + $type = $this->bound[$name][1]; + $local = $this->bound[$name][2]; + $e = explode(".",$this->bound[$name][0]); + $component = $e[0]; + $foreign = $e[1]; - switch($e[0]): - case $name: + $e = explode(" as ",$name); + $name = $e[0]; + + if(isset($e[1])) + $alias = $e[1]; + else + $alias = $name; + + $table = $this->session->getTable($name); + + if($component == $this->name || in_array($component, $this->parents)) { + + // ONE-TO-ONE + if($type == Doctrine_Relation::ONE_COMPOSITE || + $type == Doctrine_Relation::ONE_AGGREGATE) { if( ! isset($local)) - $local = $this->identifier; + $local = $table->getIdentifier(); - // ONE-TO-MANY or ONE-TO-ONE - $foreignKey = new Doctrine_ForeignKey($objTable,$local,$e[1],$type); - break; - case $this->name: - // ONE-TO-ONE + $relation = new Doctrine_LocalKey($table,$foreign,$local,$type); + } else + throw new Doctrine_Mapping_Exception(); - if($type <= Doctrine_Relation::ONE_COMPOSITE) { - if( ! isset($local)) - $local = $objTable->getIdentifier(); + } elseif($component == $name || ($component == $alias && $name == $this->name)) { + if( ! isset($local)) + $local = $this->identifier; - $foreignKey = new Doctrine_LocalKey($objTable,$e[1],$local,$type); - } else - throw new Doctrine_Mapping_Exception(); - break; - default: - if(in_array($e[0], $this->parents)) { - // ONE-TO-ONE + // ONE-TO-MANY or ONE-TO-ONE + $relation = new Doctrine_ForeignKey($table,$local,$foreign,$type); - if($type <= Doctrine_Relation::ONE_COMPOSITE) { - if( ! isset($local)) - $local = $objTable->getIdentifier(); + } else { + // MANY-TO-MANY + // only aggregate relations allowed - $foreignKey = new Doctrine_LocalKey($objTable,$e[1],$local,$type); - } else - throw new Doctrine_Mapping_Exception(); - } else { - // POSSIBLY MANY-TO-MANY + if($type != Doctrine_Relation::MANY_AGGREGATE) + throw new Doctrine_Mapping_Exception(); - $classes = array_merge($this->parents, array($this->name)); + $classes = array_merge($this->parents, array($this->name)); - foreach($classes as $class) { - try { - $bound = $objTable->getBound($class); - break; - } catch(InvalidKeyException $exc) { + foreach($classes as $class) { + try { + $bound = $table->getBound($class); + break; + } catch(InvalidKeyException $exc) { - } - } - if( ! isset($local)) - $local = $this->identifier; - - $e2 = explode(".",$bound[0]); - - if($e2[0] != $e[0]) - throw new Doctrine_Mapping_Exception(); - - $associationTable = $this->session->getTable($e2[0]); - - $this->foreignKeys[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE); - - $foreignKey = new Doctrine_Association($objTable,$associationTable,$e2[1],$e[1],$type); } - endswitch; - $this->foreignKeys[$name] = $foreignKey; - return $this->foreignKeys[$name]; + } + if( ! isset($local)) + $local = $this->identifier; + + $e2 = explode(".",$bound[0]); + + if($e2[0] != $component) + throw new Doctrine_Mapping_Exception(); + + $associationTable = $this->session->getTable($e2[0]); + + $this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE); + + $relation = new Doctrine_Association($table,$associationTable,$e2[1],$foreign,$type); + + } + $this->relations[$alias] = $relation; + return $this->relations[$alias]; } else { throw new InvalidKeyException(); } diff --git a/classes/Validator.class.php b/classes/Validator.class.php index a17fab008..ec563b9d4 100644 --- a/classes/Validator.class.php +++ b/classes/Validator.class.php @@ -29,11 +29,14 @@ class Doctrine_Validator { */ private $stack = array(); /** - * @var array $validators + * @var array $validators an array of validator objects */ private static $validators = array(); /** + * returns a validator object + * * @param string $name + * @return Doctrine_Validator_Interface */ public static function getValidator($name) { if( ! isset(self::$validators[$name])) { @@ -48,6 +51,9 @@ class Doctrine_Validator { return self::$validators[$name]; } /** + * validates a given record and saves possible errors + * in Doctrine_Validator::$stack + * * @param Doctrine_Record $record * @return void */ @@ -101,12 +107,15 @@ class Doctrine_Validator { } /** * whether or not this validator has errors + * * @return boolean */ public function hasErrors() { return (count($this->stack) > 0); } /** + * returns the error stack + * * @return array */ public function getErrorStack() { @@ -114,7 +123,9 @@ class Doctrine_Validator { } /** * returns the type of loosely typed variable + * * @param mixed $var + * @return string */ public static function gettype($var) { $type = gettype($var); diff --git a/tests/RecordTestCase.class.php b/tests/RecordTestCase.class.php index 5be32d83d..aba445aa3 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 testManyToManyTreeStructure() { $task = $this->session->create("Task"); @@ -14,20 +15,20 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { $task = new Task(); $this->assertTrue($task instanceof Task); $this->assertEqual($task->getState(), Doctrine_Record::STATE_TCLEAN); - $this->assertTrue($task->Task[0] instanceof Task); + $this->assertTrue($task->Subtask[0] instanceof Task); - $this->assertEqual($task->Task[0]->getState(), Doctrine_Record::STATE_TCLEAN); + $this->assertEqual($task->Subtask[0]->getState(), Doctrine_Record::STATE_TCLEAN); $this->assertTrue($task->Resource[0] instanceof Resource); $this->assertEqual($task->Resource[0]->getState(), Doctrine_Record::STATE_TCLEAN); $task->name = "Task 1"; $task->Resource[0]->name = "Resource 1"; - $task->Task[0]->name = "Subtask 1"; + $task->Subtask[0]->name = "Subtask 1"; $this->assertEqual($task->name, "Task 1"); $this->assertEqual($task->Resource[0]->name, "Resource 1"); $this->assertEqual($task->Resource->count(), 1); - $this->assertEqual($task->Task[0]->name, "Subtask 1"); + $this->assertEqual($task->Subtask[0]->name, "Subtask 1"); $this->session->flush(); @@ -36,7 +37,7 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { $this->assertEqual($task->name, "Task 1"); $this->assertEqual($task->Resource[0]->name, "Resource 1"); $this->assertEqual($task->Resource->count(), 1); - $this->assertEqual($task->Task[0]->name, "Subtask 1"); + $this->assertEqual($task->Subtask[0]->name, "Subtask 1"); } @@ -119,43 +120,53 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { $this->assertTrue($user->getState() == Doctrine_Record::STATE_CLEAN); $this->assertTrue($user->name,"John Locke"); } + public function testTreeStructure() { $e = new Element(); - $e->name = "parent"; - $e->Element[0]->name = "child 1"; - $e->Element[1]->name = "child 2"; - $e->Element[1]->Element[0]->name = "child 1's child 1"; - $e->Element[1]->Element[1]->name = "child 1's child 1"; + $fk = $e->getTable()->getForeignKey("Child"); + $this->assertTrue($fk instanceof Doctrine_ForeignKey); + $this->assertEqual($fk->getType(), Doctrine_Relation::MANY_AGGREGATE); + $this->assertEqual($fk->getForeign(), "parent_id"); + $this->assertEqual($fk->getLocal(), "id"); + + + + $e->name = "parent"; + $e->Child[0]->name = "child 1"; + $e->Child[1]->name = "child 2"; + + $e->Child[1]->Child[0]->name = "child 1's child 1"; + $e->Child[1]->Child[1]->name = "child 1's child 1"; $this->assertEqual($e->name,"parent"); - $this->assertEqual($e->Element[0]->name,"child 1"); - $this->assertEqual($e->Element[1]->name,"child 2"); - $this->assertEqual($e->Element[1]->Element[0]->name,"child 1's child 1"); - $this->assertEqual($e->Element[1]->Element[1]->name,"child 1's child 1"); + + $this->assertEqual($e->Child[0]->name,"child 1"); + $this->assertEqual($e->Child[1]->name,"child 2"); + $this->assertEqual($e->Child[1]->Child[0]->name,"child 1's child 1"); + $this->assertEqual($e->Child[1]->Child[1]->name,"child 1's child 1"); + $this->session->flush(); - - - $e = $e->getTable()->find(1); $this->assertEqual($e->name,"parent"); - $this->assertEqual($e->Element[0]->name,"child 1"); + $this->assertEqual($e->Child[0]->name,"child 1"); $c = $e->getTable()->find(2); $this->assertEqual($c->name, "child 1"); - + $this->assertEqual($e->Child[0]->parent_id, 1); + $this->assertEqual($e->Child[0]->Parent->getID(), $e->getID()); - $this->assertEqual($e->Element[0]->parent_id, 1); - $this->assertEqual($e->Element[1]->parent_id, 1); - $this->assertEqual($e->Element[1]->Element[0]->name,"child 1's child 1"); - $this->assertEqual($e->Element[1]->Element[1]->name,"child 1's child 1"); - $this->assertEqual($e->Element[1]->Element[0]->parent_id, 3); - $this->assertEqual($e->Element[1]->Element[1]->parent_id, 3); + + $this->assertEqual($e->Child[1]->parent_id, 1); + $this->assertEqual($e->Child[1]->Child[0]->name,"child 1's child 1"); + $this->assertEqual($e->Child[1]->Child[1]->name,"child 1's child 1"); + $this->assertEqual($e->Child[1]->Child[0]->parent_id, 3); + $this->assertEqual($e->Child[1]->Child[1]->parent_id, 3); } diff --git a/tests/TableTestCase.class.php b/tests/TableTestCase.class.php index 3929ae279..756d4c8b5 100644 --- a/tests/TableTestCase.class.php +++ b/tests/TableTestCase.class.php @@ -26,6 +26,8 @@ class Doctrine_TableTestCase extends Doctrine_UnitTestCase { $this->assertTrue($fk->getType() == Doctrine_Relation::MANY_COMPOSITE); $this->assertTrue($fk->getLocal() == $this->objTable->getIdentifier()); $this->assertTrue($fk->getForeign() == "entity_id"); + + } public function testGetComponentName() { $this->assertTrue($this->objTable->getComponentName() == "User"); diff --git a/tests/UnitTestCase.class.php b/tests/UnitTestCase.class.php index f2690f6ea..c2e64fb06 100644 --- a/tests/UnitTestCase.class.php +++ b/tests/UnitTestCase.class.php @@ -55,6 +55,7 @@ class Doctrine_UnitTestCase extends UnitTestCase { } foreach($tables as $name) { + $name = ucwords($name); $table = $this->session->getTable($name); $table->getCache()->deleteAll(); } diff --git a/tests/classes.php b/tests/classes.php index 7820593d7..5f06b2ec5 100644 --- a/tests/classes.php +++ b/tests/classes.php @@ -97,7 +97,8 @@ class Element extends Doctrine_Record { $this->hasColumn("parent_id", "integer"); } public function setUp() { - $this->hasMany("Element","Element.parent_id"); + $this->hasMany("Element as Child","Child.parent_id"); + $this->hasOne("Element as Parent","Element.parent_id"); } } class Email extends Doctrine_Record { @@ -127,8 +128,8 @@ class Song extends Doctrine_Record { class Task extends Doctrine_Record { public function setUp() { - $this->hasMany("Resource","Assignment.resource_id"); - $this->hasMany("Task","Task.parent_id"); + $this->hasMany("Resource","Assignment.resource_id"); + $this->hasMany("Task as Subtask","Subtask.parent_id"); } public function setTableDefinition() { $this->hasColumn("name","string",100);