diff --git a/Doctrine/Collection.php b/Doctrine/Collection.php
index 67213640f..43f8bb077 100644
--- a/Doctrine/Collection.php
+++ b/Doctrine/Collection.php
@@ -180,6 +180,8 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$record->rawSet($this->reference_field, $this->reference);
}
}
+ } elseif($relation instanceof Doctrine_Association) {
+
}
}
/**
@@ -249,7 +251,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
} elseif($this->relation instanceof Doctrine_Association) {
- $asf = $fk->getAssociationFactory();
+ $asf = $this->relation->getAssociationFactory();
$query = "SELECT ".$foreign." FROM ".$asf->getTableName()." WHERE ".$local."=".$this->getID();
$table = $fk->getTable();
@@ -411,6 +413,10 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
$this->data[$key] = $record;
return true;
}
+
+ if(in_array($record,$this->data)) {
+ return false;
+ } else
if(isset($this->generator)) {
$key = $this->generator->getIndex($record);
diff --git a/Doctrine/Query.php b/Doctrine/Query.php
index e2afe5727..d26ea17ec 100644
--- a/Doctrine/Query.php
+++ b/Doctrine/Query.php
@@ -467,28 +467,36 @@ class Doctrine_Query extends Doctrine_Access {
$coll->add($record);
} else {
$pointer = $this->joins[$name];
+ $alias = $this->tables[$pointer]->getAlias($name);
+
+ //print "fetching data : ".$pointer." ".$alias."
";
- $fk = $this->tables[$pointer]->getForeignKey($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:
- $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)) {
+
+ 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;
}
@@ -930,37 +938,35 @@ class Doctrine_Query extends Doctrine_Access {
$this->connectors[$name] = $fk;
+ switch($mark):
+ case ":":
+ $join = 'INNER JOIN ';
+ break;
+ case ".":
+ $join = 'LEFT JOIN ';
+ break;
+ default:
+ throw new Doctrine_Exception("Unknown operator '$mark'");
+ endswitch;
+
+
if($fk instanceof Doctrine_ForeignKey ||
$fk instanceof Doctrine_LocalKey) {
- switch($mark):
- case ":":
- $this->parts["join"][$tname][$tname2] = "INNER JOIN ".$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
- break;
- case ".":
- $this->parts["join"][$tname][$tname2] = "LEFT JOIN ".$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
- break;
- endswitch;
+ $this->parts["join"][$tname][$tname2] = $join.$tname2." ON ".$tname.".".$fk->getLocal()." = ".$tname2.".".$fk->getForeign();
- $c = $table->getComponentName();
- $this->joins[$name] = $c;
} elseif($fk instanceof Doctrine_Association) {
$asf = $fk->getAssociationFactory();
- switch($fk->getType()):
- case Doctrine_Relation::ONE_AGGREGATE:
- case Doctrine_Relation::ONE_COMPOSITE:
+ $assocTableName = $asf->getTableName();
- break;
- case Doctrine_Relation::MANY_AGGREGATE:
- case Doctrine_Relation::MANY_COMPOSITE:
-
- //$this->addWhere("SELECT ".$fk->getLocal()." FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." IN (SELECT ".$fk->getTable()->getComponentName().")");
- $this->parts["from"][$tname] = true;
- break;
- endswitch;
+ $this->parts["join"][$tname][$assocTableName] = $join.$assocTableName." ON ".$tname.".id = ".$assocTableName.".".$fk->getLocal();
+ $this->parts["join"][$tname][$tname2] = $join.$tname2." ON ".$tname2.".id = ".$assocTableName.".".$fk->getForeign();
}
+ $c = $table->getComponentName();
+ $this->joins[$name] = $c;
+
$table = $fk->getTable();
}
@@ -992,7 +998,7 @@ class Doctrine_Query extends Doctrine_Access {
}
} catch(Exception $e) {
- throw new DQLException($e->getMessage(),$e->getCode());
+ throw new DQLException($e->__toString());
}
}
}
diff --git a/Doctrine/Record.php b/Doctrine/Record.php
index 42ec0d7ad..9cc9af3ec 100644
--- a/Doctrine/Record.php
+++ b/Doctrine/Record.php
@@ -98,7 +98,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
*/
private static $index = 1;
/**
- * @var Doctrine_Null $null a Doctrine_Null object used for extremely fast
+ * @var Doctrine_Null $null a Doctrine_Null object used for extremely fast
* null value testing
*/
private static $null;
@@ -153,7 +153,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->prepareIdentifiers($exists);
if( ! $exists) {
-
+
if($count > 0)
$this->state = Doctrine_Record::STATE_TDIRTY;
else
@@ -169,7 +169,6 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->state = Doctrine_Record::STATE_PROXY;
}
-
// listen the onLoad event
$this->table->getAttribute(Doctrine::ATTR_LISTENER)->onLoad($this);
}
@@ -219,6 +218,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$tmp = $this->data;
$this->data = array();
+
+ $count = 0;
foreach($this->table->getColumnNames() as $name) {
$type = $this->table->getTypeOf($name);
@@ -239,9 +240,11 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
break;
default:
$this->data[$name] = $tmp[$name];
+ $count++;
endswitch;
}
}
+ return $count;
}
/**
* prepares identifiers for later use
@@ -973,7 +976,10 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
*/
public function initReference(Doctrine_Collection $coll, Doctrine_Relation $connector) {
$name = $this->table->getAlias($coll->getTable()->getComponentName());
- $coll->setReference($this, $connector);
+
+ if( ! ($connector instanceof Doctrine_Association))
+ $coll->setReference($this, $connector);
+
$this->references[$name] = $coll;
$this->originals[$name] = clone $coll;
}
diff --git a/Doctrine/Table.php b/Doctrine/Table.php
index 4b9253afc..971c7ba41 100644
--- a/Doctrine/Table.php
+++ b/Doctrine/Table.php
@@ -159,6 +159,7 @@ class Doctrine_Table extends Doctrine_Configurable {
$this->primaryKeys[] = "id";
$this->identifier = "id";
$this->identifierType = Doctrine_Identifier::AUTO_INCREMENT;
+ $this->columnCount++;
break;
default:
if(count($this->primaryKeys) > 1) {
@@ -804,7 +805,7 @@ class Doctrine_Table extends Doctrine_Configurable {
* @return integer
*/
final public function getColumnCount() {
- return $this->columnCount;
+ return $this->columnCount;
}
/**
* returns all columns and their definitions
diff --git a/Doctrine/Validator.php b/Doctrine/Validator.php
index 75488537b..579563fdb 100644
--- a/Doctrine/Validator.php
+++ b/Doctrine/Validator.php
@@ -120,11 +120,12 @@ class Doctrine_Validator {
$column = $columns[$key];
- if($column[0] == 'array' || $column[0] == 'object') {
- $value = serialize($value);
- }
+ if($column[0] == 'array' || $column[0] == 'object')
+ $length = strlen(serialize($value));
+ else
+ $length = strlen($value);
- if(strlen($value) > $column[1]) {
+ if($length > $column[1]) {
$err[$key] = Doctrine_Validator::ERR_LENGTH;
continue;
}
diff --git a/Doctrine/Validator/Exception.php b/Doctrine/Validator/Exception.php
index 61a4f842b..25bc88996 100644
--- a/Doctrine/Validator/Exception.php
+++ b/Doctrine/Validator/Exception.php
@@ -2,12 +2,32 @@
Doctrine::autoload('Doctrine_Exception');
class Doctrine_Validator_Exception extends Doctrine_Exception {
+ /**
+ * @var Doctrine_Validator $validator
+ */
private $validator;
+ /**
+ * @param Doctrine_Validator $validator
+ */
public function __construct(Doctrine_Validator $validator) {
$this->validator = $validator;
}
+ /**
+ * returns the error stack
+ *
+ * @return array
+ */
public function getErrorStack() {
return $this->validator->getErrorStack();
}
+ /**
+ * __toString
+ *
+ * @return string
+ */
+ public function __toString() {
+ $string = "Error stack : ".print_r($this->validator->getErrorStack(), true);
+ return $string.parent::__toString();
+ }
}
?>
diff --git a/tests/QueryTestCase.php b/tests/QueryTestCase.php
index 4ec5808cd..95687a8b5 100644
--- a/tests/QueryTestCase.php
+++ b/tests/QueryTestCase.php
@@ -14,6 +14,158 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->dbh->query("DROP TABLE IF EXISTS test_entries");
parent::prepareTables();
}
+ //public function prepareData() { }
+
+ public function testManyToManyFetchingWithColonOperator() {
+ $query = new Doctrine_Query($this->session);
+
+ $task = new Task();
+ $task->name = "T1";
+ $task->ResourceAlias[0]->name = "R1";
+ $task->ResourceAlias[1]->name = "R2";
+
+ $task = new Task();
+ $task->name = "T2";
+ $task->ResourceAlias[0]->name = "R3";
+ $task->ResourceAlias[1]->name = "R4";
+ $task->ResourceAlias[2]->name = "R5";
+ $task->ResourceAlias[3]->name = "R6";
+
+ $this->assertEqual($task->ResourceAlias[0]->name, "R3");
+ $this->assertEqual($task->ResourceAlias[1]->name, "R4");
+ $this->assertEqual($task->ResourceAlias[2]->name, "R5");
+ $this->assertEqual($task->ResourceAlias[3]->name, "R6");
+
+ $task = new Task();
+ $task->name = "T3";
+ $task->ResourceAlias[0]->name = "R7";
+
+ $task = new Task();
+ $task->name = "T4";
+
+ $this->session->flush();
+
+ // clear identity maps
+ $task->getTable()->clear();
+ $this->session->getTable('Assignment')->clear();
+ $this->session->getTable('Resource')->clear();
+
+ $tasks[1] = $task->getTable()->find(2);
+ $this->assertEqual($tasks[1]->ResourceAlias[0]->name, "R3");
+ $this->assertEqual($tasks[1]->ResourceAlias[1]->name, "R4");
+ $this->assertEqual($tasks[1]->ResourceAlias[2]->name, "R5");
+ $this->assertEqual($tasks[1]->ResourceAlias[3]->name, "R6");
+
+ // clear identity maps
+ $task->getTable()->clear();
+ $this->session->getTable('Assignment')->clear();
+ $this->session->getTable('Resource')->clear();
+
+ $query->from("Task-l:ResourceAlias-l");
+ $tasks = $query->execute();
+ $this->assertEqual($tasks->count(), 3);
+ $this->assertTrue($tasks instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[0]->ResourceAlias->count(), 2);
+ $this->assertTrue($tasks[0]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+
+
+ $this->assertEqual($tasks[1]->ResourceAlias->count(), 4);
+ $this->assertTrue($tasks[1]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+ // sanity checking
+ $this->assertEqual($tasks[1]->ResourceAlias[0]->getState(), Doctrine_Record::STATE_PROXY);
+ $this->assertEqual($tasks[1]->ResourceAlias[1]->getState(), Doctrine_Record::STATE_PROXY);
+ $this->assertEqual($tasks[1]->ResourceAlias[2]->getState(), Doctrine_Record::STATE_PROXY);
+ $this->assertEqual($tasks[1]->ResourceAlias[3]->getState(), Doctrine_Record::STATE_PROXY);
+
+ $count = count($this->dbh);
+
+ $this->assertEqual($tasks[1]->ResourceAlias[0]->name, "R3");
+ $this->assertEqual($tasks[1]->ResourceAlias[1]->name, "R4");
+ $this->assertEqual($tasks[1]->ResourceAlias[2]->name, "R5");
+ $this->assertEqual($tasks[1]->ResourceAlias[3]->name, "R6");
+
+ $this->assertEqual(count($this->dbh), ($count + 4));
+
+ $this->assertEqual($tasks[2]->ResourceAlias->count(), 1);
+ $this->assertTrue($tasks[2]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+ }
+ public function testManyToManyFetchingWithDotOperator() {
+ $query = new Doctrine_Query($this->session);
+
+ $this->session->getTable('Task')->clear();
+ $this->session->getTable('Assignment')->clear();
+ $this->session->getTable('Resource')->clear();
+
+ $tasks = $query->query("FROM Task-l.ResourceAlias-l");
+ $this->assertEqual($tasks->count(), 4);
+ $this->assertTrue($tasks instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[0]->ResourceAlias->count(), 2);
+ $this->assertTrue($tasks[0]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[1]->ResourceAlias->count(), 4);
+ $this->assertTrue($tasks[1]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[1]->ResourceAlias->count(), 4);
+ $this->assertTrue($tasks[1]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+ // sanity checking
+ $this->assertEqual($tasks[1]->ResourceAlias[0]->getState(), Doctrine_Record::STATE_PROXY);
+ $this->assertEqual($tasks[1]->ResourceAlias[1]->getState(), Doctrine_Record::STATE_PROXY);
+ $this->assertEqual($tasks[1]->ResourceAlias[2]->getState(), Doctrine_Record::STATE_PROXY);
+ $this->assertEqual($tasks[1]->ResourceAlias[3]->getState(), Doctrine_Record::STATE_PROXY);
+
+ $count = count($this->dbh);
+
+ $this->assertEqual($tasks[1]->ResourceAlias[0]->name, "R3");
+ $this->assertEqual($tasks[1]->ResourceAlias[1]->name, "R4");
+ $this->assertEqual($tasks[1]->ResourceAlias[2]->name, "R5");
+ $this->assertEqual($tasks[1]->ResourceAlias[3]->name, "R6");
+
+ $this->assertEqual(count($this->dbh), ($count + 4));
+
+ $this->assertEqual($tasks[2]->ResourceAlias->count(), 1);
+ $this->assertTrue($tasks[2]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[3]->ResourceAlias->count(), 0);
+ $this->assertTrue($tasks[3]->ResourceAlias instanceof Doctrine_Collection);
+ }
+ public function testManyToManyFetchingWithDotOperatorAndLoadedIdentityMaps() {
+ $query = new Doctrine_Query($this->session);
+
+ $tasks = $query->query("FROM Task-l.ResourceAlias-l");
+ $this->assertEqual($tasks->count(), 4);
+ $this->assertTrue($tasks instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[0]->ResourceAlias->count(), 2);
+ $this->assertTrue($tasks[0]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[1]->ResourceAlias->count(), 4);
+ $this->assertTrue($tasks[1]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+
+ $this->assertEqual($tasks[1]->ResourceAlias->count(), 4);
+ $this->assertTrue($tasks[1]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+ // sanity checking
+ $this->assertEqual($tasks[1]->ResourceAlias[0]->getState(), Doctrine_Record::STATE_CLEAN);
+ $this->assertEqual($tasks[1]->ResourceAlias[1]->getState(), Doctrine_Record::STATE_CLEAN);
+ $this->assertEqual($tasks[1]->ResourceAlias[2]->getState(), Doctrine_Record::STATE_CLEAN);
+ $this->assertEqual($tasks[1]->ResourceAlias[3]->getState(), Doctrine_Record::STATE_CLEAN);
+
+ $count = count($this->dbh);
+
+ $this->assertEqual($tasks[1]->ResourceAlias[0]->name, "R3");
+ $this->assertEqual($tasks[1]->ResourceAlias[1]->name, "R4");
+ $this->assertEqual($tasks[1]->ResourceAlias[2]->name, "R5");
+ $this->assertEqual($tasks[1]->ResourceAlias[3]->name, "R6");
+
+ $this->assertEqual(count($this->dbh), $count);
+
+ $this->assertEqual($tasks[2]->ResourceAlias->count(), 1);
+ $this->assertTrue($tasks[2]->ResourceAlias instanceof Doctrine_Collection_Lazy);
+
+ $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';
@@ -330,7 +482,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertTrue(is_numeric($users[2]->email_id));
$this->assertEqual($count + 1, count($this->dbh));
}
-
public function testQueryWithComplexAliases() {
$q = new Doctrine_Query($this->session);
@@ -373,7 +524,7 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($board->Category->getState(), Doctrine_Record::STATE_CLEAN);
$this->assertEqual($board->Threads[0]->getState(), Doctrine_Record::STATE_CLEAN);
$this->assertTrue($board->Threads[0] instanceof Forum_Thread);
-
+ $this->assertEqual($board->Threads[0]->Entries->count(), 2);
$q->from("Forum_Board");
@@ -393,21 +544,25 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
$q->from("Forum_Board-l.Threads-l");
$this->assertEqual($q->getQuery(), "SELECT forum_board.id AS Forum_Board__id, forum_thread.id AS Forum_Thread__id FROM forum_board LEFT JOIN forum_thread ON forum_board.id = forum_thread.board_id");
- $q->from("Forum_Board.Threads.Entries-l");
+ //$this->session->clear();
+
+ $q->from("Forum_Board-l.Threads-l.Entries-l");
$this->assertEqual($q->getQuery(), "SELECT forum_board.id AS Forum_Board__id, forum_thread.id AS Forum_Thread__id, forum_entry.id AS Forum_Entry__id FROM forum_board LEFT JOIN forum_thread ON forum_board.id = forum_thread.board_id LEFT JOIN forum_entry ON forum_thread.id = forum_entry.thread_id");
$boards = $q->execute();
$this->assertEqual($boards->count(), 1);
$count = count($this->dbh);
$this->assertEqual($boards[0]->Threads->count(), 1);
$this->assertEqual(count($this->dbh), $count);
- $this->assertEqual($boards[0]->Threads[0]->Entries->count(), 1);
-
+ $this->assertEqual($boards[0]->Threads[0]->Entries->count(), 2);
+
+
$q->from("Forum_Board-l.Threads-l.Entries-i");
$this->assertEqual($boards->count(), 1);
$count = count($this->dbh);
$this->assertEqual($boards[0]->Threads->count(), 1);
$this->assertEqual(count($this->dbh), $count);
- $this->assertEqual($boards[0]->Threads[0]->Entries->count(), 1);
+ $this->assertEqual($boards[0]->Threads[0]->Entries->count(), 2);
+
}
public function testQueryWithAliases() {
@@ -693,5 +848,6 @@ class Doctrine_QueryTestCase extends Doctrine_UnitTestCase {
}
+
}
?>
diff --git a/tests/run.php b/tests/run.php
index bc486415e..508391713 100644
--- a/tests/run.php
+++ b/tests/run.php
@@ -46,7 +46,7 @@ $test->addTestCase(new Doctrine_CollectionTestCase());
$test->addTestCase(new Doctrine_QueryTestCase());
-$test->addTestCase(new Doctrine_PessimisticLockingTestCase());
+//$test->addTestCase(new Doctrine_PessimisticLockingTestCase());
//$test->addTestCase(new Doctrine_Cache_FileTestCase());
//$test->addTestCase(new Doctrine_Cache_SqliteTestCase());