1
0
mirror of synced 2025-01-30 20:11:49 +03:00

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

This commit is contained in:
doctrine 2006-05-29 08:43:21 +00:00
parent e15cfd70b2
commit 20990ed204
13 changed files with 197 additions and 87 deletions

View File

@ -28,6 +28,7 @@ class Doctrine_Collection_Batch extends Doctrine_Collection {
/**
* @param integer $batchSize batch size
* @return boolean
*/
public function setBatchSize($batchSize) {
$batchSize = (int) $batchSize;
@ -38,15 +39,19 @@ class Doctrine_Collection_Batch extends Doctrine_Collection {
return true;
}
/**
* returns the batch size of this collection
*
* @return integer
*/
public function getBatchSize() {
return $this->batchSize;
}
/**
* load load a specified element, by loading the batch the element is part of
* @param Doctrine_Record $record data access object
* @return boolean whether or not the load operation was successful
* load
* 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
*/
public function load(Doctrine_Record $record) {
if(empty($this->data))

View File

@ -22,4 +22,4 @@ class Doctrine_IndexGenerator {
return $value;
}
}
?>
?>

View File

@ -419,8 +419,7 @@ class Doctrine_Query extends Doctrine_Access {
$array = $this->parseData($stmt);
$colls = array();
$colls = array();
foreach($array as $data) {
/**
@ -465,14 +464,30 @@ class Doctrine_Query extends Doctrine_Access {
$coll->add($record);
} else {
$pointer = $this->joins[$name];
$last = $prev[$pointer]->getLast();
if( ! $last->hasReference($name)) {
$prev[$name] = $this->getCollection($name);
$last->initReference($prev[$name],$this->connectors[$name]);
}
$last->addReference($record);
$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();
if( ! $last->hasReference($name)) {
$prev[$name] = $this->getCollection($name);
$last->initReference($prev[$name],$this->connectors[$name]);
}
$last->addReference($record);
endswitch;
}
}

View File

@ -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
*/
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
*/
@ -157,6 +161,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->table->getRepository()->add($this);
}
}
/**
* initNullObject
*/
public static function initNullObject() {
self::$nullObject = new Doctrine_Null;
}
/**
* setUp
* implemented by child classes
@ -402,7 +412,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
if(is_array($this->data[$name])) {
// no use trying to load the data from database if the Doctrine_Record is not a proxy
if($this->state == Doctrine_Record::STATE_PROXY) {
if($this->state == Doctrine_Record::STATE_PROXY) {
if( ! empty($this->collections)) {
foreach($this->collections as $collection) {
$collection->load($this);
@ -582,11 +592,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->table->getSession()->save($this);
foreach($saveLater as $fk) {
$table = $fk->getTable();
$foreign = $fk->getForeign();
$local = $fk->getLocal();
$table = $fk->getTable();
$alias = $this->table->getAlias($table->getComponentName());
if(isset($this->references[$alias])) {
@ -836,6 +842,17 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
final public function getID() {
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
* @param string $name
@ -845,8 +862,22 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
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 string $connectorField
* @param Doctrine_Relation $connector
* @return void
*/
public function initReference(Doctrine_Collection $coll, Doctrine_Relation $connector) {
$name = $this->table->getAlias($coll->getTable()->getComponentName());

View File

@ -1,10 +1,8 @@
<?php
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_Customer extends Sensei_User { }
class Sensei_Customer extends Sensei_User { }
class Sensei_Entity extends Doctrine_Record {
/**
* setTableDefinition
@ -65,10 +63,7 @@ class Sensei_Session extends Doctrine_Record {
$this->hasColumn("created","integer");
}
}
class Sensei_Exception extends Exception { }
class Sensei extends Doctrine_Access {
const ATTR_LIFESPAN = 0;
/**

View File

@ -246,46 +246,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
public function create($name) {
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
@ -573,7 +534,6 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
$increment = true;
}
foreach($inserts as $k => $record) {
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreSave($record);
// listen the onPreInsert event

View File

@ -81,6 +81,10 @@ class Doctrine_Table extends Doctrine_Configurable {
* @var array $boundAliases bound relation aliases
*/
private $boundAliases = array();
/**
* @var integer $columnCount cached column count
*/
private $columnCount;
/**
@ -135,6 +139,8 @@ class Doctrine_Table extends Doctrine_Configurable {
if(method_exists($record,"setTableDefinition")) {
$record->setTableDefinition();
$this->columnCount = count($this->columns);
if(isset($this->columns)) {
$method = new ReflectionMethod($this->name,"setTableDefinition");
$class = $method->getDeclaringClass();
@ -784,7 +790,7 @@ class Doctrine_Table extends Doctrine_Configurable {
* @return integer
*/
final public function getColumnCount() {
return count($this->columns);
return $this->columnCount;
}
/**
* returns all columns and their definitions

View File

@ -8,7 +8,7 @@ class Doctrine_Validator_NoSpace {
* @return boolean
*/
public function validate(Doctrine_Record $record, $key, $value, $args) {
if(preg_match("/[\s\r\t\n]/", $value))
if(trim($value) === '')
return false;
return true;

View File

@ -7,6 +7,46 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->tables[] = "Forum_Thread";
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() {
$q = new Doctrine_Query($this->session);
@ -49,7 +89,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($count + 1, count($this->dbh));
}
public function testQueryWithComplexAliases() {
$q = new Doctrine_Query($this->session);
@ -209,7 +248,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($query->offset, 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"));
$this->assertEqual($coll->count(), 1);
}
@ -223,6 +262,25 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($users->count(),8);
$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() {
@ -326,20 +384,8 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$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();
@ -403,5 +449,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
//$this->assertTrue(isset($values['max']));
}
}
?>

View File

@ -1,5 +1,6 @@
<?php
require_once("../classes/Doctrine.class.php");
Doctrine::loadAll();
class Sensei_UnitTestCase extends UnitTestCase {
@ -13,6 +14,9 @@ class Sensei_UnitTestCase extends UnitTestCase {
private $init = false;
public function init() {
if(headers_sent())
throw new Exception("'".ob_end_flush()."'");
$this->manager = Doctrine_Manager::getInstance();
$this->manager->setAttribute(Doctrine::ATTR_CACHE, Doctrine::CACHE_NONE);
@ -40,7 +44,7 @@ class Sensei_UnitTestCase extends UnitTestCase {
$entity->loginname = "Chuck Norris";
$entity->password = "toughguy";
$entity->save();
$this->init = true;
@ -109,6 +113,5 @@ class Sensei_UnitTestCase extends UnitTestCase {
$this->assertEqual($this->record->entity_id, 0);
}
}
?>

View File

@ -49,6 +49,7 @@ class Doctrine_UnitTestCase extends UnitTestCase {
$this->manager->setAttribute(Doctrine::ATTR_LISTENER, $this->listener);
}
$this->query = new Doctrine_Query($this->session);
$this->prepareTables();
$this->prepareData();
}

View File

@ -207,4 +207,53 @@ class Forum_Thread extends Doctrine_Record {
$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>';
}
}
*/
?>

View File

@ -52,8 +52,6 @@ $test->addTestCase(new Doctrine_QueryTestCase());
//$test->addTestCase(new Doctrine_Cache_SqliteTestCase());
print "<pre>";
$test->run(new HtmlReporter());
$cache = Doctrine_Manager::getInstance()->getCurrentSession()->getCacheHandler();