diff --git a/Doctrine/Lib.php b/Doctrine/Lib.php index e8a9ba91b..cee9e4052 100644 --- a/Doctrine/Lib.php +++ b/Doctrine/Lib.php @@ -121,6 +121,26 @@ class Doctrine_Lib { $r[] = ""; return implode("\n",$r)."
"; } + /** + * @return string + */ + public function formatSql($sql) { + $e = explode("\n",$sql); + $color = "367FAC"; + $l = $sql; + $l = str_replace("SELECT","SELECT
",$l); + $l = str_replace("FROM","FROM
",$l); + $l = str_replace("LEFT JOIN","
LEFT JOIN",$l); + $l = str_replace("WHERE","WHERE",$l); + $l = str_replace("AS","AS
",$l); + $l = str_replace("ON","ON",$l); + $l = str_replace("ORDER BY","ORDER BY
",$l); + $l = str_replace("LIMIT","LIMIT
",$l); + $l = str_replace("OFFSET","OFFSET
",$l); + $l = str_replace(" ","
",$l); + + return $l; + } /** * returns a string representation of Doctrine_Collection object * @param Doctrine_Collection $collection diff --git a/Doctrine/Manager.php b/Doctrine/Manager.php index 3704853d8..e3390792e 100644 --- a/Doctrine/Manager.php +++ b/Doctrine/Manager.php @@ -61,7 +61,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera $init = true; $attributes = array( Doctrine::ATTR_CACHE_DIR => "%ROOT%".DIRECTORY_SEPARATOR."cachedir", - Doctrine::ATTR_FETCHMODE => Doctrine::FETCH_LAZY, + Doctrine::ATTR_FETCHMODE => Doctrine::FETCH_IMMEDIATE, Doctrine::ATTR_CACHE_TTL => 100, Doctrine::ATTR_CACHE_SIZE => 100, Doctrine::ATTR_CACHE => Doctrine::CACHE_NONE, diff --git a/Doctrine/Query.php b/Doctrine/Query.php index 8175681eb..b002006bd 100644 --- a/Doctrine/Query.php +++ b/Doctrine/Query.php @@ -154,7 +154,7 @@ class Doctrine_Query extends Doctrine_Access { $this->fetchModes[$component] = $fetchmode; $tablename = $this->tableAliases[$component]; $count = count($this->tables); - + foreach($names as $name) { if($count == 0) { $this->parts["columns"][] = $tablename.".".$name; @@ -436,6 +436,7 @@ class Doctrine_Query extends Doctrine_Access { $colls = array(); + foreach($array as $data) { /** * remove duplicated data rows and map data into objects @@ -443,25 +444,50 @@ class Doctrine_Query extends Doctrine_Access { foreach($data as $key => $row) { if(empty($row)) continue; + $ids = $this->tables[$key]->getIdentifier(); - + + $emptyID = false; if(is_array($ids)) { - $emptyID = false; - foreach($ids as $id) { - if($row[$id] == null) { - $emptyID = true; - break; - } + foreach($ids as $id) { + if($row[$id] == null) { + $emptyID = true; + break; } - if($emptyID) - continue; + } } else { if($row[$ids] === null) - continue; + $emptyID = true; + } + + + $name = $this->tables[$key]->getComponentName(); + + if($emptyID) { + + $pointer = $this->joins[$name]; + $alias = $this->tables[$pointer]->getAlias($name); + $fk = $this->tables[$pointer]->getForeignKey($alias); + $last = $prev[$pointer]->getLast(); + + switch($fk->getType()): + case Doctrine_Relation::ONE_COMPOSITE: + case Doctrine_Relation::ONE_AGGREGATE: + + break; + default: + if($last instanceof Doctrine_Record) { + if( ! $last->hasReference($alias)) { + $prev[$name] = $this->getCollection($name); + $last->initReference($prev[$name],$this->connectors[$name]); + } + } + endswitch; + + continue; } - $name = $this->tables[$key]->getComponentName(); if( ! isset($previd[$name])) $previd[$name] = array(); @@ -478,19 +504,16 @@ class Doctrine_Query extends Doctrine_Access { // add record into root collection $coll->add($record); } else { + $pointer = $this->joins[$name]; $alias = $this->tables[$pointer]->getAlias($name); - - //print "fetching data : ".$pointer." ".$alias."
"; - - $fk = $this->tables[$pointer]->getForeignKey($alias); - - $last = $prev[$pointer]->getLast(); + $fk = $this->tables[$pointer]->getForeignKey($alias); + $last = $prev[$pointer]->getLast(); switch($fk->getType()): case Doctrine_Relation::ONE_COMPOSITE: case Doctrine_Relation::ONE_AGGREGATE: - $last->rawSet($this->connectors[$name]->getLocal(), $record->getID()); + $last->internalSet($this->connectors[$name]->getLocal(), $record->getID()); $last->initSingleReference($record); @@ -500,14 +523,12 @@ class Doctrine_Query extends Doctrine_Access { // one-to-many relation or many-to-many relation if( ! $last->hasReference($alias)) { - //print "initializing reference : ".$name." ".$alias; $prev[$name] = $this->getCollection($name); $last->initReference($prev[$name],$this->connectors[$name]); } else { // previous entry found from identityMap $prev[$name] = $last->get($alias); } - //print "adding reference : ".$pointer." -> ".$name." as ".$alias."
"; $last->addReference($record); endswitch; diff --git a/Doctrine/Record.php b/Doctrine/Record.php index e0bed285f..40db6347a 100644 --- a/Doctrine/Record.php +++ b/Doctrine/Record.php @@ -523,6 +523,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite return $this->references[$name]; } + /** + * internalSet + */ + final public function internalSet($name, $value) { + $this->data[$name] = $value; + } /** * rawSet * doctrine uses this function internally, not recommended for developers @@ -713,10 +719,6 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite final public function getPrepared() { $a = array(); - foreach($this->table->getInheritanceMap() as $k => $v) { - $this->set($k,$v); - } - foreach($this->modified as $k => $v) { $type = $this->table->getTypeOf($v); @@ -733,6 +735,15 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite $a[$v] = $this->data[$v]; } + foreach($this->table->getInheritanceMap() as $k => $v) { + $old = $this->get($k); + + if((string) $old !== (string) $v || $old === null) { + $a[$k] = $v; + $this->data[$k] = $v; + } + } + return $a; } /** diff --git a/Doctrine/Session.php b/Doctrine/Session.php index c80fdb640..64c403e72 100644 --- a/Doctrine/Session.php +++ b/Doctrine/Session.php @@ -404,6 +404,11 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab $table->getRepository()->evictAll(); $table->clear(); } + } + /** + * @return void + */ + public function evictTables() { $this->tables = array(); } /** @@ -503,6 +508,10 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab /** * rollback * rolls back all transactions + * + * this method also listens to onPreTransactionRollback and onTransactionRollback + * eventlisteners + * * @return void */ public function rollback() { @@ -748,6 +757,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab */ private function update(Doctrine_Record $record) { $array = $record->getPrepared(); + if(empty($array)) return false; diff --git a/Doctrine/Validator/Country.class.php b/Doctrine/Validator/Country.class.php deleted file mode 100644 index e3bffa041..000000000 --- a/Doctrine/Validator/Country.class.php +++ /dev/null @@ -1,265 +0,0 @@ - "Andorra", - "ae" => "United Arab Emirates", - "af" => "Afghanistan", - "ag" => "Antigua and Barbuda", - "ai" => "Anguilla", - "al" => "Albania", - "am" => "Armenia", - "an" => "Netherlands Antilles", - "ao" => "Angola", - "aq" => "Antarctica", - "ar" => "Argentina", - "as" => "American Samoa", - "at" => "Austria", - "au" => "Australia", - "aw" => "Aruba", - "az" => "Azerbaijan", - "ba" => "Bosnia Hercegovina", - "bb" => "Barbados", - "bd" => "Bangladesh", - "be" => "Belgium", - "bf" => "Burkina Faso", - "bg" => "Bulgaria", - "bh" => "Bahrain", - "bi" => "Burundi", - "bj" => "Benin", - "bm" => "Bermuda", - "bn" => "Brunei Darussalam", - "bo" => "Bolivia", - "br" => "Brazil", - "bs" => "Bahamas", - "bt" => "Bhutan", - "bv" => "Bouvet Island", - "bw" => "Botswana", - "by" => "Belarus (Byelorussia)", - "bz" => "Belize", - "ca" => "Canada", - "cc" => "Cocos Islands", - "cd" => 'Congo, The Democratic Republic of the', - "cf" => "Central African Republic", - "cg" => "Congo", - "ch" => "Switzerland", - "ci" => "Ivory Coast", - "ck" => "Cook Islands", - "cl" => "Chile", - "cm" => "Cameroon", - "cn" => "China", - "co" => "Colombia", - "cr" => "Costa Rica", - "cs" => "Czechoslovakia", - "cu" => "Cuba", - "cv" => "Cape Verde", - "cx" => "Christmas Island", - "cy" => "Cyprus", - "cz" => 'Czech Republic', - "de" => "Germany", - "dj" => "Djibouti", - "dk" => 'Denmark', - "dm" => "Dominica", - "do" => "Dominican Republic", - "dz" => "Algeria", - "ec" => "Ecuador", - "ee" => "Estonia", - "eg" => "Egypt", - "eh" => "Western Sahara", - "er" => 'Eritrea', - "es" => "Spain", - "et" => "Ethiopia", - "fi" => "Finland", - "fj" => "Fiji", - "fk" => "Falkland Islands", - "fm" => "Micronesia", - "fo" => "Faroe Islands", - "fr" => "France", - "fx" => 'France, Metropolitan FX', - "ga" => "Gabon", - "gb" => 'United Kingdom (Great Britain)', - "gd" => "Grenada", - "ge" => "Georgia", - "gf" => "French Guiana", - "gh" => "Ghana", - "gi" => "Gibraltar", - "gl" => "Greenland", - "gm" => "Gambia", - "gn" => "Guinea", - "gp" => "Guadeloupe", - "gq" => "Equatorial Guinea", - "gr" => "Greece", - "gs" => 'South Georgia and the South Sandwich Islands', - "gt" => "Guatemala", - "gu" => "Guam", - "gw" => "Guinea-bissau", - "gy" => "Guyana", - "hk" => "Hong Kong", - "hm" => "Heard and McDonald Islands", - "hn" => "Honduras", - "hr" => "Croatia", - "ht" => "Haiti", - "hu" => "Hungary", - "id" => "Indonesia", - "ie" => "Ireland", - "il" => "Israel", - "in" => "India", - "io" => "British Indian Ocean Territory", - "iq" => "Iraq", - "ir" => "Iran", - "is" => "Iceland", - "it" => "Italy", - "jm" => "Jamaica", - "jo" => "Jordan", - "jp" => "Japan", - "ke" => "Kenya", - "kg" => "Kyrgyzstan", - "kh" => "Cambodia", - "ki" => "Kiribati", - "km" => "Comoros", - "kn" => "Saint Kitts and Nevis", - "kp" => "North Korea", - "kr" => "South Korea", - "kw" => "Kuwait", - "ky" => "Cayman Islands", - "kz" => "Kazakhstan", - "la" => "Laos", - "lb" => "Lebanon", - "lc" => "Saint Lucia", - "li" => "Lichtenstein", - "lk" => "Sri Lanka", - "lr" => "Liberia", - "ls" => "Lesotho", - "lt" => "Lithuania", - "lu" => "Luxembourg", - "lv" => "Latvia", - "ly" => "Libya", - "ma" => "Morocco", - "mc" => "Monaco", - "md" => "Moldova Republic", - "mg" => "Madagascar", - "mh" => "Marshall Islands", - "mk" => 'Macedonia, The Former Yugoslav Republic of', - "ml" => "Mali", - "mm" => "Myanmar", - "mn" => "Mongolia", - "mo" => "Macau", - "mp" => "Northern Mariana Islands", - "mq" => "Martinique", - "mr" => "Mauritania", - "ms" => "Montserrat", - "mt" => "Malta", - "mu" => "Mauritius", - "mv" => "Maldives", - "mw" => "Malawi", - "mx" => "Mexico", - "my" => "Malaysia", - "mz" => "Mozambique", - "na" => "Namibia", - "nc" => "New Caledonia", - "ne" => "Niger", - "nf" => "Norfolk Island", - "ng" => "Nigeria", - "ni" => "Nicaragua", - "nl" => "Netherlands", - "no" => "Norway", - "np" => "Nepal", - "nr" => "Nauru", - "nt" => "Neutral Zone", - "nu" => "Niue", - "nz" => "New Zealand", - "om" => "Oman", - "pa" => "Panama", - "pe" => "Peru", - "pf" => "French Polynesia", - "pg" => "Papua New Guinea", - "ph" => "Philippines", - "pk" => "Pakistan", - "pl" => "Poland", - "pm" => "St. Pierre and Miquelon", - "pn" => "Pitcairn", - "pr" => "Puerto Rico", - "pt" => "Portugal", - "pw" => "Palau", - "py" => "Paraguay", - "qa" => 'Qatar', - "re" => "Reunion", - "ro" => "Romania", - "ru" => "Russia", - "rw" => "Rwanda", - "sa" => "Saudi Arabia", - "sb" => "Solomon Islands", - "sc" => "Seychelles", - "sd" => "Sudan", - "se" => "Sweden", - "sg" => "Singapore", - "sh" => "St. Helena", - "si" => "Slovenia", - "sj" => "Svalbard and Jan Mayen Islands", - "sk" => 'Slovakia (Slovak Republic)', - "sl" => "Sierra Leone", - "sm" => "San Marino", - "sn" => "Senegal", - "so" => "Somalia", - "sr" => "Suriname", - "st" => "Sao Tome and Principe", - "sv" => "El Salvador", - "sy" => "Syria", - "sz" => "Swaziland", - "tc" => "Turks and Caicos Islands", - "td" => "Chad", - "tf" => "French Southern Territories", - "tg" => "Togo", - "th" => "Thailand", - "tj" => "Tajikistan", - "tk" => "Tokelau", - "tm" => "Turkmenistan", - "tn" => "Tunisia", - "to" => "Tonga", - "tp" => "East Timor", - "tr" => "Turkey", - "tt" => "Trinidad, Tobago", - "tv" => "Tuvalu", - "tw" => "Taiwan", - "tz" => "Tanzania", - "ua" => "Ukraine", - "ug" => "Uganda", - "uk" => "United Kingdom", - "um" => "United States Minor Islands", - "us" => "United States of America", - "uy" => "Uruguay", - "uz" => "Uzbekistan", - "va" => "Vatican City", - "vc" => "Saint Vincent, Grenadines", - "ve" => "Venezuela", - "vg" => "Virgin Islands (British)", - "vi" => "Virgin Islands (USA)", - "vn" => "Viet Nam", - "vu" => "Vanuatu", - "wf" => 'Wallis and Futuna Islands', - "ws" => "Samoa", - "ye" => 'Yemen', - "yt" => 'Mayotte', - "yu" => "Yugoslavia", - "za" => "South Africa", - "zm" => "Zambia", - "zr" => "Zaire", - "zw" => "Zimbabwe"); - /** - * @return array - */ - public static function getCountries() { - return self::$countries; - } - /** - * @param Doctrine_Record $record - * @param string $key - * @param mixed $value - * @param string $args - * @return boolean - */ - public function validate(Doctrine_Record $record, $key, $value, $args) { - return isset(self::$countries[$value]); - } - -} -?> diff --git a/tests/QueryTestCase.php b/tests/QueryTestCase.php index e9368dca3..310c3c85d 100644 --- a/tests/QueryTestCase.php +++ b/tests/QueryTestCase.php @@ -29,21 +29,41 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { $this->assertEqual($users[0]->Group->count(), 0); $this->assertEqual($users[1]->Group->count(), 1); $this->assertEqual($users[2]->Group->count(), 0); + + $this->assertEqual($users[0]->getState(), Doctrine_Record::STATE_PROXY); + $this->assertEqual($users[1]->getState(), Doctrine_Record::STATE_PROXY); + $this->assertEqual($users[2]->getState(), Doctrine_Record::STATE_PROXY); + + $this->assertEqual($users[0]->getModified(), array()); + $this->assertEqual($users[1]->getModified(), array()); + $this->assertEqual($users[2]->getModified(), array()); + $this->assertEqual($users[6]->getModified(), array()); + + $this->assertEqual($users[0]->type, 0); + $this->assertEqual($users[1]->type, 0); + $this->assertEqual($users[2]->type, 0); + + $this->session->flush(); } - public function testManyToManyFetchingWithColonOperator() { - $query = new Doctrine_Query($this->session); + public function testNestedManyToManyRelations() { $task = new Task(); $task->name = "T1"; $task->ResourceAlias[0]->name = "R1"; $task->ResourceAlias[1]->name = "R2"; - + $task->ResourceAlias[0]->Type[0]->type = 'TY1'; + //$task->ResourceAlias[1]->Type[0]->type = 'TY2'; + $task = new Task(); $task->name = "T2"; $task->ResourceAlias[0]->name = "R3"; + $task->ResourceAlias[0]->Type[0]->type = 'TY2'; + $task->ResourceAlias[0]->Type[0]->type = 'TY3'; $task->ResourceAlias[1]->name = "R4"; $task->ResourceAlias[2]->name = "R5"; + $task->ResourceAlias[2]->Type[0]->type = 'TY4'; + $task->ResourceAlias[2]->Type[1]->type = 'TY5'; $task->ResourceAlias[3]->name = "R6"; $this->assertEqual($task->ResourceAlias[0]->name, "R3"); @@ -54,14 +74,39 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { $task = new Task(); $task->name = "T3"; $task->ResourceAlias[0]->name = "R7"; - + $task = new Task(); $task->name = "T4"; $this->session->flush(); - + + $this->session->clear(); + + $query = new Doctrine_Query($this->session); + $query->from("Task.ResourceAlias.Type"); + $tasks = $query->execute(); + + $this->assertEqual($tasks->count(), 4); + + $this->assertEqual($tasks[0]->ResourceAlias->count(), 2); + $this->assertEqual($tasks[1]->ResourceAlias->count(), 4); + $this->assertEqual($tasks[2]->ResourceAlias->count(), 1); + $this->assertEqual($tasks[3]->ResourceAlias->count(), 0); + + $this->assertEqual($tasks[0]->ResourceAlias[0]->Type->count(), 1); + $this->assertEqual($tasks[0]->ResourceAlias[1]->Type->count(), 0); + + $this->assertEqual($tasks[1]->ResourceAlias->count(), 4); + } + + + public function testManyToManyFetchingWithColonOperator() { + $query = new Doctrine_Query($this->session); + + $task = new Task(); + // clear identity maps - $task->getTable()->clear(); + $this->session->getTable('Task')->clear(); $this->session->getTable('Assignment')->clear(); $this->session->getTable('Resource')->clear(); @@ -146,6 +191,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { $this->assertEqual($tasks[3]->ResourceAlias->count(), 0); $this->assertTrue($tasks[3]->ResourceAlias instanceof Doctrine_Collection); } + public function testManyToManyFetchingWithDotOperatorAndLoadedIdentityMaps() { $query = new Doctrine_Query($this->session); @@ -182,6 +228,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { $this->assertEqual($tasks[3]->ResourceAlias->count(), 0); $this->assertTrue($tasks[3]->ResourceAlias instanceof Doctrine_Collection); } + public function testOneToOneSharedRelations() { $status = new Log_Status(); $status->name = 'success'; @@ -279,7 +326,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { $this->assertEqual(($count + 1), $this->dbh->count()); } - public function testImmediateFetching() { $count = $this->dbh->count(); $this->session->getTable('User')->clear(); diff --git a/tests/SessionTestCase.php b/tests/SessionTestCase.php index 4f07175fe..9d6cb0923 100644 --- a/tests/SessionTestCase.php +++ b/tests/SessionTestCase.php @@ -3,7 +3,7 @@ require_once("UnitTestCase.php"); class Doctrine_SessionTestCase extends Doctrine_UnitTestCase { public function testBuildFlushTree() { - $correct = array("Task","Resource","Assignment"); + $correct = array("Task","ResourceType","Resource","Assignment","ResourceReference"); $task = new Task(); @@ -352,10 +352,5 @@ class Doctrine_SessionTestCase extends Doctrine_UnitTestCase { $this->assertEqual($this->session->getState(),Doctrine_Session::STATE_OPEN); $this->assertEqual($this->session->getTransactionLevel(),0); } - public function testClear() { - $this->session->clear(); - $this->assertEqual($this->session->getTables(), array()); - } - } ?> diff --git a/tests/UnitTestCase.php b/tests/UnitTestCase.php index 40087354f..7b1a227f9 100644 --- a/tests/UnitTestCase.php +++ b/tests/UnitTestCase.php @@ -34,13 +34,31 @@ class Doctrine_UnitTestCase extends UnitTestCase { $this->manager->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_IMMEDIATE); - $this->tables = array_merge($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", + "resourceType", + "resourceReference") + ); if($this->manager->count() > 0) { $this->session = $this->manager->getSession(0); - $this->session->clear(); + $this->session->evictTables(); $this->dbh = $this->session->getDBH(); $this->listener = $this->manager->getAttribute(Doctrine::ATTR_LISTENER); diff --git a/tests/classes.php b/tests/classes.php index 791bcec13..e79a4026c 100644 --- a/tests/classes.php +++ b/tests/classes.php @@ -139,18 +139,32 @@ class Task extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn("name","string",100); $this->hasColumn("parent_id","integer"); - } + } } class Resource extends Doctrine_Record { public function setUp() { $this->hasMany("Task as TaskAlias","Assignment.task_id"); - } - public function setTableDefinition() { - $this->hasColumn("name","string",100); + $this->hasMany("ResourceType as Type", "ResourceReference.type_id"); } -} - + public function setTableDefinition() { + $this->hasColumn("name","string",100); + } +} +class ResourceReference extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("type_id","integer"); + $this->hasColumn("resource_id","integer"); + } +} +class ResourceType extends Doctrine_Record { + public function setUp() { + $this->hasMany("Resource as ResourceAlias", "ResourceReference.resource_id"); + } + public function setTableDefinition() { + $this->hasColumn("type","string",100); + } +} class Assignment extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn("task_id","integer");