Commit 20990ed2 authored by doctrine's avatar doctrine

DQL: direct one-to-one relation fetching bug fixed

parent e15cfd70
...@@ -28,6 +28,7 @@ class Doctrine_Collection_Batch extends Doctrine_Collection { ...@@ -28,6 +28,7 @@ class Doctrine_Collection_Batch extends Doctrine_Collection {
/** /**
* @param integer $batchSize batch size * @param integer $batchSize batch size
* @return boolean
*/ */
public function setBatchSize($batchSize) { public function setBatchSize($batchSize) {
$batchSize = (int) $batchSize; $batchSize = (int) $batchSize;
...@@ -38,14 +39,18 @@ class Doctrine_Collection_Batch extends Doctrine_Collection { ...@@ -38,14 +39,18 @@ class Doctrine_Collection_Batch extends Doctrine_Collection {
return true; return true;
} }
/** /**
* returns the batch size of this collection
*
* @return integer * @return integer
*/ */
public function getBatchSize() { public function getBatchSize() {
return $this->batchSize; return $this->batchSize;
} }
/** /**
* load load a specified element, by loading the batch the element is part of * load
* @param Doctrine_Record $record data access object * loads a specified element, by loading the batch the element is part of
*
* @param Doctrine_Record $record record to be loaded
* @return boolean whether or not the load operation was successful * @return boolean whether or not the load operation was successful
*/ */
public function load(Doctrine_Record $record) { public function load(Doctrine_Record $record) {
......
...@@ -421,7 +421,6 @@ class Doctrine_Query extends Doctrine_Access { ...@@ -421,7 +421,6 @@ class Doctrine_Query extends Doctrine_Access {
$colls = array(); $colls = array();
foreach($array as $data) { foreach($array as $data) {
/** /**
* remove duplicated data rows and map data into objects * remove duplicated data rows and map data into objects
...@@ -466,6 +465,21 @@ class Doctrine_Query extends Doctrine_Access { ...@@ -466,6 +465,21 @@ class Doctrine_Query extends Doctrine_Access {
} else { } else {
$pointer = $this->joins[$name]; $pointer = $this->joins[$name];
$fk = $this->tables[$pointer]->getForeignKey($this->tables[$pointer]->getAlias($name));
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::ONE_AGGREGATE:
$last = $prev[$pointer]->getLast();
$last->rawSet($this->connectors[$name]->getLocal(), $record->getID());
$last->initSingleReference($record);
$prev[$name] = $record;
break;
default:
// one-to-many relation or many-to-many relation
$last = $prev[$pointer]->getLast(); $last = $prev[$pointer]->getLast();
if( ! $last->hasReference($name)) { if( ! $last->hasReference($name)) {
...@@ -473,6 +487,7 @@ class Doctrine_Query extends Doctrine_Access { ...@@ -473,6 +487,7 @@ class Doctrine_Query extends Doctrine_Access {
$last->initReference($prev[$name],$this->connectors[$name]); $last->initReference($prev[$name],$this->connectors[$name]);
} }
$last->addReference($record); $last->addReference($record);
endswitch;
} }
} }
......
...@@ -83,6 +83,10 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -83,6 +83,10 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* @var integer $index this index is used for creating object identifiers * @var integer $index this index is used for creating object identifiers
*/ */
private static $index = 1; private static $index = 1;
/**
* @var Doctrine_Null $nullObject a Doctrine_Null object used for SQL null value testing
*/
private static $nullObject;
/** /**
* @var integer $oid object identifier * @var integer $oid object identifier
*/ */
...@@ -157,6 +161,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -157,6 +161,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->table->getRepository()->add($this); $this->table->getRepository()->add($this);
} }
} }
/**
* initNullObject
*/
public static function initNullObject() {
self::$nullObject = new Doctrine_Null;
}
/** /**
* setUp * setUp
* implemented by child classes * implemented by child classes
...@@ -582,11 +592,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -582,11 +592,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->table->getSession()->save($this); $this->table->getSession()->save($this);
foreach($saveLater as $fk) { foreach($saveLater as $fk) {
$table = $fk->getTable(); $table = $fk->getTable();
$foreign = $fk->getForeign();
$local = $fk->getLocal();
$alias = $this->table->getAlias($table->getComponentName()); $alias = $this->table->getAlias($table->getComponentName());
if(isset($this->references[$alias])) { if(isset($this->references[$alias])) {
...@@ -836,6 +842,17 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -836,6 +842,17 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
final public function getID() { final public function getID() {
return $this->id; return $this->id;
} }
/**
* getLast
* this method is used internally be Doctrine_Query
* it is needed to provide compatibility between
* records and collections
*
* @return Doctrine_Record
*/
public function getLast() {
return $this;
}
/** /**
* hasRefence * hasRefence
* @param string $name * @param string $name
...@@ -845,8 +862,22 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -845,8 +862,22 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
return isset($this->references[$name]); return isset($this->references[$name]);
} }
/** /**
* initalizes a one-to-one relation
*
* @param Doctrine_Record $record
* @param Doctrine_Relation $connector
* @return void
*/
public function initSingleReference(Doctrine_Record $record) {
$name = $this->table->getAlias($record->getTable()->getComponentName());
$this->references[$name] = $record;
}
/**
* initalizes a one-to-many / many-to-many relation
*
* @param Doctrine_Collection $coll * @param Doctrine_Collection $coll
* @param string $connectorField * @param Doctrine_Relation $connector
* @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()); $name = $this->table->getAlias($coll->getTable()->getComponentName());
......
<?php <?php
class Sensei_Group extends Doctrine_Record { } class Sensei_Group extends Doctrine_Record { }
//class Sensei_Company extends Sensei_Group { } class Sensei_Company extends Sensei_Group { }
class Sensei_User extends Doctrine_Record { } class Sensei_User extends Doctrine_Record { }
//class Sensei_Customer extends Sensei_User { } class Sensei_Customer extends Sensei_User { }
class Sensei_Entity extends Doctrine_Record { class Sensei_Entity extends Doctrine_Record {
/** /**
* setTableDefinition * setTableDefinition
...@@ -65,10 +63,7 @@ class Sensei_Session extends Doctrine_Record { ...@@ -65,10 +63,7 @@ class Sensei_Session extends Doctrine_Record {
$this->hasColumn("created","integer"); $this->hasColumn("created","integer");
} }
} }
class Sensei_Exception extends Exception { } class Sensei_Exception extends Exception { }
class Sensei extends Doctrine_Access { class Sensei extends Doctrine_Access {
const ATTR_LIFESPAN = 0; const ATTR_LIFESPAN = 0;
/** /**
......
...@@ -246,46 +246,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab ...@@ -246,46 +246,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
public function create($name) { public function create($name) {
return $this->getTable($name)->create(); return $this->getTable($name)->create();
} }
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)
$tree[] = $name;
foreach($table->getForeignKeys() as $rel) {
$name = $rel->getTable()->getComponentName();
$index = array_search($name,$tree);
if($rel instanceof Doctrine_ForeignKey) {
if($index !== false)
unset($tree[$index]);
$tree[] = $name;
} elseif($rel instanceof Doctrine_LocalKey) {
if($index !== false)
unset($tree[$index]);
array_unshift($tree, $name);
} elseif($rel instanceof Doctrine_Association) {
$t = $rel->getAssociationFactory();
$n = $t->getComponentName();
$index = array_search($n,$tree);
if($index !== false)
unset($tree[$index]);
$tree[] = $n;
}
}
}
return array_values($tree);
}
/** /**
* buildFlushTree * buildFlushTree
...@@ -573,7 +534,6 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab ...@@ -573,7 +534,6 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
$increment = true; $increment = true;
} }
foreach($inserts as $k => $record) { foreach($inserts as $k => $record) {
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record); $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record);
// listen the onPreInsert event // listen the onPreInsert event
......
...@@ -81,6 +81,10 @@ class Doctrine_Table extends Doctrine_Configurable { ...@@ -81,6 +81,10 @@ class Doctrine_Table extends Doctrine_Configurable {
* @var array $boundAliases bound relation aliases * @var array $boundAliases bound relation aliases
*/ */
private $boundAliases = array(); private $boundAliases = array();
/**
* @var integer $columnCount cached column count
*/
private $columnCount;
/** /**
...@@ -135,6 +139,8 @@ class Doctrine_Table extends Doctrine_Configurable { ...@@ -135,6 +139,8 @@ class Doctrine_Table extends Doctrine_Configurable {
if(method_exists($record,"setTableDefinition")) { if(method_exists($record,"setTableDefinition")) {
$record->setTableDefinition(); $record->setTableDefinition();
$this->columnCount = count($this->columns);
if(isset($this->columns)) { if(isset($this->columns)) {
$method = new ReflectionMethod($this->name,"setTableDefinition"); $method = new ReflectionMethod($this->name,"setTableDefinition");
$class = $method->getDeclaringClass(); $class = $method->getDeclaringClass();
...@@ -784,7 +790,7 @@ class Doctrine_Table extends Doctrine_Configurable { ...@@ -784,7 +790,7 @@ class Doctrine_Table extends Doctrine_Configurable {
* @return integer * @return integer
*/ */
final public function getColumnCount() { final public function getColumnCount() {
return count($this->columns); return $this->columnCount;
} }
/** /**
* returns all columns and their definitions * returns all columns and their definitions
......
...@@ -8,7 +8,7 @@ class Doctrine_Validator_NoSpace { ...@@ -8,7 +8,7 @@ class Doctrine_Validator_NoSpace {
* @return boolean * @return boolean
*/ */
public function validate(Doctrine_Record $record, $key, $value, $args) { public function validate(Doctrine_Record $record, $key, $value, $args) {
if(preg_match("/[\s\r\t\n]/", $value)) if(trim($value) === '')
return false; return false;
return true; return true;
......
...@@ -7,6 +7,46 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { ...@@ -7,6 +7,46 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->tables[] = "Forum_Thread"; $this->tables[] = "Forum_Thread";
parent::prepareTables(); parent::prepareTables();
} }
public function testOneToOneRelationFetching() {
$count = $this->dbh->count();
$users = $this->query->from("User-l:Email-i")->execute();
$this->assertEqual(($count + 1), $this->dbh->count());
$this->assertTrue($users instanceof Doctrine_Collection_Lazy);
$count = $this->dbh->count();
foreach($users as $user) {
// iterate through users and test that no additional queries are needed
$user->Email->address;
$this->assertEqual($count, $this->dbh->count());
}
$users[0]->Account->amount = 3000;
$this->assertEqual($users[0]->Account->amount, 3000);
$this->assertTrue($users[0]->Account instanceof Account);
$this->assertEqual($users[0]->id, $users[0]->Account->entity_id);
$users[0]->Account->save();
$users[0]->refresh();
$this->assertEqual($users[0]->Account->amount, 3000);
$this->assertTrue($users[0]->Account instanceof Account);
$this->assertEqual($users[0]->id, $users[0]->Account->entity_id);
$this->assertEqual($users[0]->Account->getState(), Doctrine_Record::STATE_CLEAN);
$users[0]->getTable()->clear();
$users[0]->Account->getTable()->clear();
$count = $this->dbh->count();
$users = $this->query->from("User-l:Account-i")->execute();
$this->assertEqual(($count + 1), $this->dbh->count());
$this->assertTrue($users instanceof Doctrine_Collection_Lazy);
$this->assertEqual($users->count(), 1);
$this->assertEqual($users[0]->Account->amount,3000);
}
public function testNotValidLazyPropertyFetching() { public function testNotValidLazyPropertyFetching() {
$q = new Doctrine_Query($this->session); $q = new Doctrine_Query($this->session);
...@@ -49,7 +89,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { ...@@ -49,7 +89,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($count + 1, count($this->dbh)); $this->assertEqual($count + 1, count($this->dbh));
} }
public function testQueryWithComplexAliases() { public function testQueryWithComplexAliases() {
$q = new Doctrine_Query($this->session); $q = new Doctrine_Query($this->session);
...@@ -209,7 +248,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { ...@@ -209,7 +248,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($query->offset, 3); $this->assertEqual($query->offset, 3);
$this->assertEqual($coll->count(), 3); $this->assertEqual($coll->count(), 3);
} }
public function testPrepared() { public function testPreparedQuery() {
$coll = $this->session->query("FROM User WHERE User.name = :name", array(":name" => "zYne")); $coll = $this->session->query("FROM User WHERE User.name = :name", array(":name" => "zYne"));
$this->assertEqual($coll->count(), 1); $this->assertEqual($coll->count(), 1);
} }
...@@ -223,6 +262,25 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { ...@@ -223,6 +262,25 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($users->count(),8); $this->assertEqual($users->count(),8);
$this->assertTrue($users[0]->name == "Arnold Schwarzenegger"); $this->assertTrue($users[0]->name == "Arnold Schwarzenegger");
} }
public function testBatchFetching() {
$query = new Doctrine_Query($this->session);
$users = $query->query("FROM User-b");
$this->assertEqual(trim($query->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.type = 0)");
$this->assertEqual($users[0]->name, "zYne");
$this->assertTrue($users instanceof Doctrine_Collection_Batch);
}
public function testLazyFetching() {
$query = new Doctrine_Query($this->session);
$users = $query->query("FROM User-l");
$this->assertEqual(trim($query->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.type = 0)");
$this->assertEqual($users[0]->name, "zYne");
$this->assertTrue($users instanceof Doctrine_Collection_Lazy);
}
public function testQuery() { public function testQuery() {
...@@ -326,21 +384,9 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { ...@@ -326,21 +384,9 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$count2 = $this->session->getDBH()->count(); $count2 = $this->session->getDBH()->count();
$users = $query->query("FROM User-b");
$this->assertEqual(trim($query->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.type = 0)");
$this->assertEqual($users[0]->name, "zYne");
$this->assertTrue($users instanceof Doctrine_Collection_Batch);
$users = $query->query("FROM User-l");
$this->assertEqual(trim($query->getQuery()),
"SELECT entity.id AS User__id FROM entity WHERE (entity.type = 0)");
$this->assertEqual($users[0]->name, "zYne");
$this->assertTrue($users instanceof Doctrine_Collection_Lazy);
//$this->clearCache(); //$this->clearCache();
...@@ -403,5 +449,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase { ...@@ -403,5 +449,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
//$this->assertTrue(isset($values['max'])); //$this->assertTrue(isset($values['max']));
} }
} }
?> ?>
<?php <?php
require_once("../classes/Doctrine.class.php"); require_once("../classes/Doctrine.class.php");
Doctrine::loadAll(); Doctrine::loadAll();
class Sensei_UnitTestCase extends UnitTestCase { class Sensei_UnitTestCase extends UnitTestCase {
...@@ -13,6 +14,9 @@ class Sensei_UnitTestCase extends UnitTestCase { ...@@ -13,6 +14,9 @@ class Sensei_UnitTestCase extends UnitTestCase {
private $init = false; private $init = false;
public function init() { public function init() {
if(headers_sent())
throw new Exception("'".ob_end_flush()."'");
$this->manager = Doctrine_Manager::getInstance(); $this->manager = Doctrine_Manager::getInstance();
$this->manager->setAttribute(Doctrine::ATTR_CACHE, Doctrine::CACHE_NONE); $this->manager->setAttribute(Doctrine::ATTR_CACHE, Doctrine::CACHE_NONE);
...@@ -109,6 +113,5 @@ class Sensei_UnitTestCase extends UnitTestCase { ...@@ -109,6 +113,5 @@ class Sensei_UnitTestCase extends UnitTestCase {
$this->assertEqual($this->record->entity_id, 0); $this->assertEqual($this->record->entity_id, 0);
} }
} }
?> ?>
...@@ -49,6 +49,7 @@ class Doctrine_UnitTestCase extends UnitTestCase { ...@@ -49,6 +49,7 @@ class Doctrine_UnitTestCase extends UnitTestCase {
$this->manager->setAttribute(Doctrine::ATTR_LISTENER, $this->listener); $this->manager->setAttribute(Doctrine::ATTR_LISTENER, $this->listener);
} }
$this->query = new Doctrine_Query($this->session);
$this->prepareTables(); $this->prepareTables();
$this->prepareData(); $this->prepareData();
} }
......
...@@ -207,4 +207,53 @@ class Forum_Thread extends Doctrine_Record { ...@@ -207,4 +207,53 @@ class Forum_Thread extends Doctrine_Record {
$this->ownsMany("Forum_Entry as Entries", "Forum_Entry.thread_id"); $this->ownsMany("Forum_Entry as Entries", "Forum_Entry.thread_id");
} }
} }
class App extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("name", "string", 32);
$this->hasColumn("user_id", "integer", 11);
$this->hasColumn("app_category_id", "integer", 11);
}
public function setUp() {
$this->hasOne("User","User.id");
$this->hasMany("App_Category as Category","App_Category.id");
}
}
class App_User extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("first_name", "string", 32);
$this->hasColumn("last_name", "string", 32);
$this->hasColumn("email", "string", 128, "email");
$this->hasColumn("username", "string", 16, "unique, nospace");
$this->hasColumn("password", "string", 128, "notblank");
$this->hasColumn("country", "string", 2, "country");
$this->hasColumn("zipcode", "string", 9, "nospace");
}
public function setUp() {
$this->hasMany("App","App.user_id");
}
}
class App_Category extends Doctrine_Record {
public function setTableDefinition() {
$this->hasColumn("name", "string", 32);
$this->hasColumn("parent_id","integer");
}
public function setUp() {
$this->hasMany("App","App.app_category_id");
$this->hasMany("App_Category as Parent","App_Category.parent_id");
}
}
/**
$apps = $con->query("FROM App.Category");
if (!empty($apps))
{
foreach ($apps as $app)
{
print '<p>' . $app->Category[0]->name . ' => ' . $app->name . '</p>';
}
}
*/
?> ?>
...@@ -52,8 +52,6 @@ $test->addTestCase(new Doctrine_QueryTestCase()); ...@@ -52,8 +52,6 @@ $test->addTestCase(new Doctrine_QueryTestCase());
//$test->addTestCase(new Doctrine_Cache_SqliteTestCase()); //$test->addTestCase(new Doctrine_Cache_SqliteTestCase());
print "<pre>"; print "<pre>";
$test->run(new HtmlReporter()); $test->run(new HtmlReporter());
$cache = Doctrine_Manager::getInstance()->getCurrentSession()->getCacheHandler(); $cache = Doctrine_Manager::getInstance()->getCurrentSession()->getCacheHandler();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment