From 7119471b48feb98bcdc0c7b8e312aeaf33e4ce61 Mon Sep 17 00:00:00 2001 From: doctrine Date: Thu, 27 Jul 2006 17:51:19 +0000 Subject: [PATCH] Doctrine_Collection::loadRelated() added --- Doctrine/Access.php | 19 ++++++ Doctrine/Collection.php | 103 ++++++++++++++++++++++++++++++- Doctrine/Configurable.php | 19 ++++++ Doctrine/DB.php | 19 ++++++ Doctrine/Hydrate.php | 9 +++ Doctrine/Lib.php | 28 +++++++++ Doctrine/Manager.php | 19 ++++++ Doctrine/Query.php | 20 +++++- Doctrine/RawSql.php | 27 ++++++++ Doctrine/Record.php | 29 ++++++--- Doctrine/Relation.php | 20 ++++++ Doctrine/Session.php | 20 +++++- tests/CollectionTestCase.php | 116 +++++++++++++++++++++++++++++++++++ tests/classes.php | 14 +++++ tests/run.php | 3 + 15 files changed, 453 insertions(+), 12 deletions(-) diff --git a/Doctrine/Access.php b/Doctrine/Access.php index 080fd0c98..3a284aed1 100644 --- a/Doctrine/Access.php +++ b/Doctrine/Access.php @@ -1,4 +1,23 @@ . + */ /** * Doctrine_Access * diff --git a/Doctrine/Collection.php b/Doctrine/Collection.php index d30b9ea56..11308c6b0 100644 --- a/Doctrine/Collection.php +++ b/Doctrine/Collection.php @@ -1,5 +1,5 @@ getTableName()." WHERE ".$local."=".$this->getIncremented(); $table = $fk->getTable(); - $graph = new Doctrine_DQL_Parser($table->getSession()); + $graph = new Doctrine_Query($table->getSession()); $q = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$table->getIdentifier()." IN ($query)"; @@ -485,6 +485,105 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator } } } + /** + * loadRelated + * + * @param string $name + */ + public function loadRelated($name) { + $rel = $this->table->getForeignKey($name); + $table = $rel->getTable(); + $query = new Doctrine_Query($this->table->getSession()); + $foreign = $rel->getForeign(); + $local = $rel->getLocal(); + + $list = array(); + if($rel instanceof Doctrine_LocalKey || $rel instanceof Doctrine_ForeignKey) { + foreach($this->data as $record): + $list[] = $record[$local]; + endforeach; + } else { + foreach($this->data as $record): + $value = $record->getIncremented(); + if($value !== null) + $list[] = $value; + endforeach; + } + $paramStr = "(".substr(str_repeat("?, ", count($list)),0,-2).")"; + $multi = true; + + if($rel instanceof Doctrine_LocalKey || + $rel instanceof Doctrine_ForeignKey) + $dql = "FROM ".$table->getComponentName(). + " WHERE ".$table->getComponentName().".".$rel->getForeign(). + " IN ".$paramStr; + + + if($rel instanceof Doctrine_LocalKey) { + $multi = false; + } elseif($rel instanceof Doctrine_Association) { + $asf = $rel->getAssociationFactory(); + $sub = "SELECT ".$foreign. + " FROM ".$asf->getTableName(). + " WHERE ".$local. + " IN ".$paramStr; + + $dql = "FROM ".$table->getComponentName().":".$asf->getComponentName()." WHERE ".$table->getComponentName().".".$table->getIdentifier()." IN ($sub)"; + //$query->parseQuery($dql); + //print Doctrine_Lib::formatSql($query->getQuery()); + } + $coll = $query->query($dql, $list); + + + + if($rel instanceof Doctrine_LocalKey) { + foreach($this->data as $key => $record) { + foreach($coll as $k => $related) { + if($related[$foreign] == $record[$local]) { + $this->data[$key]->setRelated($name, $related); + } + } + } + } elseif($rel instanceof Doctrine_ForeignKey) { + foreach($this->data as $key => $record) { + if($record->getState() == Doctrine_Record::STATE_TCLEAN || + $record->getState() == Doctrine_Record::STATE_TDIRTY) + continue; + + $sub = new Doctrine_Collection($table); + + foreach($coll as $k => $related) { + if($related[$foreign] == $record[$local]) { + $sub->add($related); + $coll->remove($k); + } + } + + $this->data[$key]->setRelated($name, $sub); + } + } elseif($rel instanceof Doctrine_Association) { + $identifier = $this->table->getIdentifier(); + + foreach($this->data as $key => $record) { + if($record->getState() == Doctrine_Record::STATE_TCLEAN || + $record->getState() == Doctrine_Record::STATE_TDIRTY) + continue; + + $sub = new Doctrine_Collection($table); + $association = $asf->getComponentName(); + + foreach($coll as $k => $related) { + if($related[$association][0]->get($local) == $record[$identifier]) { + $sub->add($related); + $coll->remove($k); + } + } + + $this->data[$key]->setRelated($name, $sub); + } + } + + } /** * getNormalIterator * returns normal iterator - an iterator that will not expand this collection diff --git a/Doctrine/Configurable.php b/Doctrine/Configurable.php index 07d96468e..0731814f7 100644 --- a/Doctrine/Configurable.php +++ b/Doctrine/Configurable.php @@ -1,4 +1,23 @@ . + */ /** * Doctrine_Configurable * the base for Doctrine_Table, Doctrine_Manager and Doctrine_Session diff --git a/Doctrine/DB.php b/Doctrine/DB.php index c081bbd34..ad4d27f56 100644 --- a/Doctrine/DB.php +++ b/Doctrine/DB.php @@ -1,4 +1,23 @@ . + */ class Doctrine_DB extends PDO implements Countable, IteratorAggregate { /** * default DSN diff --git a/Doctrine/Hydrate.php b/Doctrine/Hydrate.php index fa70a21a5..676c28922 100644 --- a/Doctrine/Hydrate.php +++ b/Doctrine/Hydrate.php @@ -65,6 +65,15 @@ class Doctrine_Hydrate extends Doctrine_Access { public function __construct(Doctrine_Session $session) { $this->session = $session; } + public function remove($name) { + if(isset($this->parts[$name])) { + if($name == "limit" || $name == "offset") + $this->parts[$name] = false; + else + $this->parts[$name] = array(); + } + return $this; + } /** * clear * resets all the variables diff --git a/Doctrine/Lib.php b/Doctrine/Lib.php index d58b65a9f..e22ea1f76 100644 --- a/Doctrine/Lib.php +++ b/Doctrine/Lib.php @@ -1,4 +1,31 @@ . + */ + +/** + * @package Doctrine ORM + * @url www.phpdoctrine.com + * @license LGPL + * + * Doctrine_Lib has not commonly used static functions, mostly for debugging purposes + */ class Doctrine_Lib { /** * @param integer $state the state of record @@ -131,6 +158,7 @@ class Doctrine_Lib { $l = str_replace("SELECT","SELECT
",$l); $l = str_replace("FROM","FROM
",$l); $l = str_replace("LEFT JOIN","
LEFT JOIN",$l); + $l = str_replace("INNER JOIN","
INNER JOIN",$l); $l = str_replace("WHERE","
WHERE",$l); $l = str_replace("GROUP BY","
GROUP BY",$l); $l = str_replace("HAVING","
HAVING",$l); diff --git a/Doctrine/Manager.php b/Doctrine/Manager.php index e7de0d37b..ddec5a6c8 100644 --- a/Doctrine/Manager.php +++ b/Doctrine/Manager.php @@ -1,4 +1,23 @@ . + */ require_once("Configurable.php"); require_once("EventListener.php"); /** diff --git a/Doctrine/Query.php b/Doctrine/Query.php index 61a2b4f06..41c2724ac 100644 --- a/Doctrine/Query.php +++ b/Doctrine/Query.php @@ -1,4 +1,23 @@ . + */ require_once("Access.php"); /** * Doctrine_Query @@ -6,7 +25,6 @@ require_once("Access.php"); * @package Doctrine ORM * @url www.phpdoctrine.com * @license LGPL - * @version 1.0 alpha */ class Doctrine_Query extends Doctrine_Hydrate { diff --git a/Doctrine/RawSql.php b/Doctrine/RawSql.php index ac824c8c3..36630b18e 100644 --- a/Doctrine/RawSql.php +++ b/Doctrine/RawSql.php @@ -1,4 +1,31 @@ . + */ +require_once("Hydrate.php"); +/** + * Doctrine_RawSql + * + * @package Doctrine ORM + * @url www.phpdoctrine.com + * @license LGPL + */ class Doctrine_RawSql extends Doctrine_Hydrate { /** * @var array $fields diff --git a/Doctrine/Record.php b/Doctrine/Record.php index 9174dde77..342aeb4e3 100644 --- a/Doctrine/Record.php +++ b/Doctrine/Record.php @@ -615,8 +615,9 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite * @return boolean */ public function has($name) { - if(isset($this->data[$name]) OR isset($this->id[$name])) + if(isset($this->data[$name]) || isset($this->id[$name])) return true; + return $this->table->hasForeignKey($name); } /** @@ -1036,10 +1037,22 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite public function getReferences() { return $this->references; } - /** + * setRelated + * + * @param string $alias + * @param Doctrine_Access $coll + */ + final public function setRelated($alias, Doctrine_Access $coll) { + $this->references[$alias] = $coll; + $this->originals[$alias] = $coll; + } + /** + * loadReference + * loads a related component + * * @throws InvalidKeyException - * @param name + * @param string $name * @return void */ final public function loadReference($name) { @@ -1152,15 +1165,15 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite * filterRelated * lazy initializes a new filter instance for given related component * - * @param $componentName name of the related component + * @param $componentAlias alias of the related component * @return Doctrine_Filter */ - final public function filterRelated($componentName) { - if( ! isset($this->filters[$componentName])) { - $this->filters[$componentName] = new Doctrine_Filter($componentName); + final public function filterRelated($componentAlias) { + if( ! isset($this->filters[$componentAlias])) { + $this->filters[$componentAlias] = new Doctrine_Filter($componentAlias); } - return $this->filters[$componentName]; + return $this->filters[$componentAlias]; } /** * sets enumerated value array for given field diff --git a/Doctrine/Relation.php b/Doctrine/Relation.php index d7c13c100..f29bd1641 100644 --- a/Doctrine/Relation.php +++ b/Doctrine/Relation.php @@ -1,6 +1,26 @@ . + */ /** * Doctrine_Relation + * This class represents a relation between components * * @package Doctrine ORM * @url www.phpdoctrine.com diff --git a/Doctrine/Session.php b/Doctrine/Session.php index 87196edac..3f19bf196 100644 --- a/Doctrine/Session.php +++ b/Doctrine/Session.php @@ -1,4 +1,23 @@ . + */ require_once("Configurable.php"); require_once("Record.php"); /** @@ -7,7 +26,6 @@ require_once("Record.php"); * @package Doctrine ORM * @url www.phpdoctrine.com * @license LGPL - * @version 1.0 alpha */ abstract class Doctrine_Session extends Doctrine_Configurable implements Countable, IteratorAggregate { /** diff --git a/tests/CollectionTestCase.php b/tests/CollectionTestCase.php index 57318de82..c7f393a06 100644 --- a/tests/CollectionTestCase.php +++ b/tests/CollectionTestCase.php @@ -14,7 +14,123 @@ class Doctrine_CollectionTestCase extends Doctrine_UnitTestCase { $this->assertTrue($coll->count(),3); $this->assertEqual($coll->getKeys(), array(0,1,2)); } + public function testLoadRelatedForAssociation() { + $coll = $this->session->query("FROM User"); + $this->assertEqual($coll->count(), 8); + + $coll[0]->Group[1]->name = "Actors House 2"; + + $coll[0]->Group[2]->name = "Actors House 3"; + + $coll[2]->Group[0]->name = "Actors House 4"; + $coll[2]->Group[1]->name = "Actors House 5"; + $coll[2]->Group[2]->name = "Actors House 6"; + + $coll[5]->Group[0]->name = "Actors House 7"; + $coll[5]->Group[1]->name = "Actors House 8"; + $coll[5]->Group[2]->name = "Actors House 9"; + + $coll->save(); + + $this->session->clear(); + + $coll = $this->session->query("FROM User"); + + $this->assertEqual($coll->count(), 8); + $this->assertEqual($coll[0]->Group->count(), 2); + $this->assertEqual($coll[1]->Group->count(), 1); + $this->assertEqual($coll[2]->Group->count(), 3); + $this->assertEqual($coll[5]->Group->count(), 3); + + $this->session->clear(); + + $coll = $this->session->query("FROM User"); + + $this->assertEqual($coll->count(), 8); + + $count = $this->dbh->count(); + + $coll->loadRelated("Group"); + $this->assertEqual(($count + 1), $this->dbh->count()); + $this->assertEqual($coll[0]->Group->count(), 2); + $this->assertEqual(($count + 1), $this->dbh->count()); + $this->assertEqual($coll[1]->Group->count(), 1); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->assertEqual($coll[2]->Group->count(), 3); + + $this->assertEqual(($count + 1), $this->dbh->count()); + $this->assertEqual($coll[5]->Group->count(), 3); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->session->clear(); + } + + public function testLoadRelatedForLocalKeyRelation() { + $coll = $this->session->query("FROM User"); + + $this->assertEqual($coll->count(), 8); + + $count = $this->dbh->count(); + $coll->loadRelated("Email"); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->assertEqual($coll[0]->Email->address, "zYne@example.com"); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->assertEqual($coll[2]->Email->address, "caine@example.com"); + + $this->assertEqual($coll[3]->Email->address, "kitano@example.com"); + + $this->assertEqual($coll[4]->Email->address, "stallone@example.com"); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->session->clear(); + } + public function testLoadRelatedForForeignKey() { + $coll = $this->session->query("FROM User"); + $this->assertEqual($coll->count(), 8); + + $count = $this->dbh->count(); + $coll->loadRelated("Phonenumber"); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->assertEqual($coll[0]->Phonenumber[0]->phonenumber, "123 123"); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $coll[0]->Phonenumber[1]->phonenumber; + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->assertEqual($coll[4]->Phonenumber[0]->phonenumber, "111 555 333"); + $this->assertEqual($coll[4]["Phonenumber"][1]->phonenumber, "123 213"); + $this->assertEqual($coll[4]["Phonenumber"][2]->phonenumber, "444 555"); + + $this->assertEqual($coll[5]->Phonenumber[0]->phonenumber, "111 222 333"); + + + $this->assertEqual($coll[6]->Phonenumber[0]->phonenumber, "111 222 333"); + $this->assertEqual($coll[6]["Phonenumber"][1]->phonenumber, "222 123"); + $this->assertEqual($coll[6]["Phonenumber"][2]->phonenumber, "123 456"); + + $this->assertEqual(($count + 1), $this->dbh->count()); + + $this->session->clear(); + } + public function testCount() { + $coll = new Doctrine_Collection($this->session->getTable('User')); + $this->assertEqual($coll->count(), 0); + $coll[0]; + $this->assertEqual($coll->count(), 1); + } public function testExpand() { $users = $this->session->query("FROM User-b.Phonenumber-l WHERE User.Phonenumber.phonenumber LIKE '%123%'"); diff --git a/tests/classes.php b/tests/classes.php index ee43ecde1..1a7230a4e 100644 --- a/tests/classes.php +++ b/tests/classes.php @@ -319,6 +319,20 @@ class EnumTest extends Doctrine_Record { $this->setEnumValues("status", array("open","verified","closed")); } } +class FilterTest extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("name","string",100); + } + public function setUp() { + $this->ownsMany("FilterTest2 as filtered", "FilterTest2.test1_id"); + } +} +class FilterTest2 extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("name","string",100); + $this->hasColumn("test1_id","integer"); + } +} class CustomPK extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn("uid","integer",11,"autoincrement|primary"); diff --git a/tests/run.php b/tests/run.php index 91fc36763..175bd9fe7 100644 --- a/tests/run.php +++ b/tests/run.php @@ -21,6 +21,7 @@ require_once("CacheQuerySqliteTestCase.php"); require_once("ViewTestCase.php"); require_once("RawSqlTestCase.php"); require_once("CustomPrimaryKeyTestCase.php"); +require_once("FilterTestCase.php"); error_reporting(E_ALL); @@ -60,6 +61,8 @@ $test->addTestCase(new Doctrine_RawSql_TestCase()); $test->addTestCase(new Doctrine_CustomPrimaryKeyTestCase()); +$test->addTestCase(new Doctrine_Filter_TestCase()); + //$test->addTestCase(new Doctrine_Cache_FileTestCase()); //$test->addTestCase(new Doctrine_Cache_SqliteTestCase());