1
0
mirror of synced 2024-12-05 03:06:05 +03:00

Preliminary support for relation aliases

This commit is contained in:
doctrine 2006-05-13 08:37:52 +00:00
parent 774f3fb7a1
commit c9877af407
10 changed files with 189 additions and 124 deletions

View File

@ -1,8 +1,9 @@
<?php
/**
* class Doctrine_Access
* Doctrine_Record and Doctrine_Collection classes extend this base class
* the purpose of DAOStrategy is to provice array access and property overload interface for these classes
*
* the purpose of Doctrine_Access is to provice array access
* and property overload interface for subclasses
*/
abstract class Doctrine_Access implements ArrayAccess {
/**
@ -33,6 +34,7 @@ abstract class Doctrine_Access implements ArrayAccess {
return $this->get($name);
}
/**
* @param mixed $offset
* @return boolean -- whether or not the data has a field $offset
*/
public function offsetExists($offset) {

View File

@ -70,6 +70,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
}
/**
* returns the root directory of Doctrine
*
* @return string
*/
final public function getRoot() {
@ -77,7 +78,9 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
}
/**
* getInstance
* this class uses the singleton pattern
* returns an instance of this class
* (this class uses the singleton pattern)
*
* @return Doctrine_Manager
*/
final public static function getInstance() {
@ -171,6 +174,8 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
}
/**
* setCurrentSession
* sets the current session to $key
*
* @param mixed $key the session key
* @throws InvalidKeyException
* @return void
@ -217,6 +222,7 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
/**
* __toString
* returns a string representation of this object
*
* @return string
*/
public function __toString() {

View File

@ -815,7 +815,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
final public function loadReference($name) {
$fk = $this->table->getForeignKey($name);
$table = $fk->getTable();
$name = $table->getComponentName();
$local = $fk->getLocal();
$foreign = $fk->getForeign();
$graph = $table->getQueryObject();
@ -825,7 +825,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
case Doctrine_Record::STATE_TDIRTY:
case Doctrine_Record::STATE_TCLEAN:
if($type == Doctrine_Relation::ONE_COMPOSITE ||
if($type == Doctrine_Relation::ONE_COMPOSITE ||
$type == Doctrine_Relation::ONE_AGGREGATE) {
// ONE-TO-ONE
@ -837,7 +837,6 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->set($fk->getLocal(),$this->references[$name]);
}
} else {
$this->references[$name] = new Doctrine_Collection($table);
if($fk instanceof Doctrine_ForeignKey) {
// ONE-TO-MANY
@ -849,13 +848,16 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
case Doctrine_Record::STATE_DIRTY:
case Doctrine_Record::STATE_CLEAN:
case Doctrine_Record::STATE_PROXY:
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::ONE_AGGREGATE:
// ONE-TO-ONE
$id = $this->get($local);
if($fk instanceof Doctrine_LocalKey) {
if(empty($id)) {
$this->references[$name] = $table->create();
$this->set($fk->getLocal(),$this->references[$name]);
@ -868,11 +870,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
} elseif ($fk instanceof Doctrine_ForeignKey) {
if(empty($id)) {
$this->references[$name] = $table->create();
$this->references[$name]->set($fk->getForeign(), $this);
} else {
$dql = "FROM ".$name." WHERE ".$name.".".$fk->getForeign()." = ?";
$dql = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$fk->getForeign()." = ?";
$coll = $graph->query($dql, array($id));
$this->references[$name] = $coll[0];
$this->references[$name]->set($fk->getForeign(), $this);
@ -883,7 +886,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
// ONE-TO-MANY
if($fk instanceof Doctrine_ForeignKey) {
$id = $this->get($local);
$query = "FROM ".$name." WHERE ".$name.".".$fk->getForeign()." = ?";
$query = "FROM ".$table->getComponentName()." WHERE ".$table->getComponentName().".".$fk->getForeign()." = ?";
$coll = $graph->query($query,array($id));
$this->references[$name] = $coll;

View File

@ -131,6 +131,9 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
/**
* query
* queries the database with Doctrine Query Language
*
* @param string $query DQL query
* @param array $params query parameters
*/
final public function query($query,array $params = array()) {
$parser = new Doctrine_Query($this);
@ -149,7 +152,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
public function select($query,$limit = 0,$offset = 0) {
if($limit > 0 || $offset > 0)
$query = $this->modifyLimitQuery($query,$limit,$offset);
return $this->dbh->query($query);
}
/**
@ -177,12 +180,13 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
return isset($this->tables[$name]);
}
/**
* returns a table object for given component name
*
* @param string $name component name
* @throws Doctrine_Table_Exception
* @return object Doctrine_Table
*/
public function getTable($name) {
$name = ucwords(strtolower($name));
// $name = ucwords(strtolower($name));
if(isset($this->tables[$name]))
return $this->tables[$name];
@ -197,25 +201,32 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
}
}
/**
* @return array -- an array of all initialized tables
* returns an array of all initialized tables
*
* @return array
*/
public function getTables() {
return $this->tables;
}
/**
* returns an iterator that iterators through all
* initialized table objects
*
* @return ArrayIterator
*/
public function getIterator() {
return new ArrayIterator($this->tables);
}
/**
* returns the count of initialized table objects
*
* @return integer
*/
public function count() {
return count($this->tables);
}
/**
* @param $objTable -- a Doctrine_Table object to be added into factory registry
* @param $objTable a Doctrine_Table object to be added into registry
* @return boolean
*/
public function addTable(Doctrine_Table $objTable) {
@ -228,6 +239,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
return true;
}
/**
* creates a record
*
* create creates a record
* @param string $name component name
* @return Doctrine_Record Doctrine_Record object
@ -237,6 +250,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
}
/**
* buildFlushTree
* builds a flush tree that is used in transactions
*
* @return array
*/
public function buildFlushTree() {
@ -293,6 +308,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
/**
* saveAll
* saves all the records from all tables
*
* @return void
*/
private function saveAll() {
$tree = $this->buildFlushTree();
@ -312,8 +329,9 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
}
}
/**
* clear
* clear
* clears the whole registry
*
* @return void
*/
public function clear() {
@ -408,7 +426,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
}
/**
* rollback
* rolls back all the transactions
* rolls back all transactions
* @return void
*/
public function rollback() {
@ -501,6 +519,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
/**
* bulkUpdate
* updates all objects in the pending update list
*
* @return void
*/
public function bulkUpdate() {
@ -527,6 +546,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
}
/**
* bulkDelete
* deletes all records from the pending delete list
*
* @return void
*/
public function bulkDelete() {
@ -549,10 +570,9 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
}
$this->delete = array();
}
/**
* saves a collection
*
* @param Doctrine_Collection $coll
* @return void
*/
@ -566,6 +586,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
$this->commit();
}
/**
* deletes all records from collection
*
* @param Doctrine_Collection $coll
* @return void
*/
@ -577,6 +599,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
$this->commit();
}
/**
* saves the given record
*
* @param Doctrine_Record $record
* @return void
*/
@ -596,6 +620,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
endswitch;
}
/**
* saves all related records to $record
*
* @param Doctrine_Record $record
*/
final public function saveRelated(Doctrine_Record $record) {
@ -638,6 +664,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
return $saveLater;
}
/**
* updates the given record
*
* @param Doctrine_Record $record
* @return boolean
*/
@ -676,6 +704,8 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
return true;
}
/**
* inserts a record into database
*
* @param Doctrine_Record $record
* @return boolean
*/
@ -711,7 +741,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
}
/**
* deletes all related composites
* this method is always called internally when this data access object is deleted
* this method is always called internally when a record is deleted
*
* @return void
*/
@ -752,7 +782,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
endswitch;
}
/**
* adds data access object into pending insert list
* adds record into pending insert list
* @param Doctrine_Record $record
*/
public function addInsert(Doctrine_Record $record) {
@ -760,7 +790,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
$this->insert[$name][] = $record;
}
/**
* adds data access object into penging update list
* adds record into penging update list
* @param Doctrine_Record $record
*/
public function addUpdate(Doctrine_Record $record) {
@ -768,7 +798,7 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
$this->update[$name][] = $record;
}
/**
* adds data access object into pending delete list
* adds record into pending delete list
* @param Doctrine_Record $record
*/
public function addDelete(Doctrine_Record $record) {
@ -776,18 +806,24 @@ abstract class Doctrine_Session extends Doctrine_Configurable implements Countab
$this->delete[$name][] = $record;
}
/**
* returns the pending insert list
*
* @return array
*/
public function getInserts() {
return $this->insert;
}
/**
* returns the pending update list
*
* @return array
*/
public function getUpdates() {
return $this->update;
}
/**
* returns the pending delete list
*
* @return array
*/
public function getDeletes() {

View File

@ -21,9 +21,9 @@ class Doctrine_Table extends Doctrine_Configurable {
*/
private $data = array();
/**
* @var array $foreignKeys an array containing all the Doctrine_ForeignKey objects for this table
* @var array $relations an array containing all the Doctrine_Relation objects for this table
*/
private $foreignKeys = array();
private $relations = array();
/**
* @var array $primaryKeys an array containing all primary key column names
*/
@ -337,25 +337,14 @@ class Doctrine_Table extends Doctrine_Configurable {
return $this->bound[$name];
}
/**
* @param string $objTableName
* @param string $name
* @param string $field
* @return void
*/
final public function bind($objTableName,$field,$type,$localKey) {
$name = (string) $objTableName;
$field = (string) $field;
if(isset($this->foreignKeys[$name]))
final public function bind($name,$field,$type,$localKey) {
if(isset($this->relations[$name]))
throw new InvalidKeyException();
$e = explode(".", $field);
// is reference table used?
if($e[0] != $name && $e[0] == $this->name)
$this->bound[$name] = array($field,Doctrine_Relation::MANY_COMPOSITE);
$this->bound[$name] = array($field,$type,$localKey);
}
/**
@ -388,77 +377,80 @@ class Doctrine_Table extends Doctrine_Configurable {
* @return Doctrine_Relation
*/
final public function getForeignKey($name) {
if(isset($this->foreignKeys[$name]))
return $this->foreignKeys[$name];
if(isset($this->relations[$name]))
return $this->relations[$name];
if(isset($this->bound[$name])) {
$field = $this->bound[$name][0];
$type = $this->bound[$name][1];
$local = $this->bound[$name][2];
$e = explode(".",$field);
$objTable = $this->session->getTable($name);
$type = $this->bound[$name][1];
$local = $this->bound[$name][2];
$e = explode(".",$this->bound[$name][0]);
$component = $e[0];
$foreign = $e[1];
switch($e[0]):
case $name:
$e = explode(" as ",$name);
$name = $e[0];
if(isset($e[1]))
$alias = $e[1];
else
$alias = $name;
$table = $this->session->getTable($name);
if($component == $this->name || in_array($component, $this->parents)) {
// ONE-TO-ONE
if($type == Doctrine_Relation::ONE_COMPOSITE ||
$type == Doctrine_Relation::ONE_AGGREGATE) {
if( ! isset($local))
$local = $this->identifier;
$local = $table->getIdentifier();
// ONE-TO-MANY or ONE-TO-ONE
$foreignKey = new Doctrine_ForeignKey($objTable,$local,$e[1],$type);
break;
case $this->name:
// ONE-TO-ONE
$relation = new Doctrine_LocalKey($table,$foreign,$local,$type);
} else
throw new Doctrine_Mapping_Exception();
if($type <= Doctrine_Relation::ONE_COMPOSITE) {
if( ! isset($local))
$local = $objTable->getIdentifier();
} elseif($component == $name || ($component == $alias && $name == $this->name)) {
if( ! isset($local))
$local = $this->identifier;
$foreignKey = new Doctrine_LocalKey($objTable,$e[1],$local,$type);
} else
throw new Doctrine_Mapping_Exception();
break;
default:
if(in_array($e[0], $this->parents)) {
// ONE-TO-ONE
// ONE-TO-MANY or ONE-TO-ONE
$relation = new Doctrine_ForeignKey($table,$local,$foreign,$type);
if($type <= Doctrine_Relation::ONE_COMPOSITE) {
if( ! isset($local))
$local = $objTable->getIdentifier();
} else {
// MANY-TO-MANY
// only aggregate relations allowed
$foreignKey = new Doctrine_LocalKey($objTable,$e[1],$local,$type);
} else
throw new Doctrine_Mapping_Exception();
} else {
// POSSIBLY MANY-TO-MANY
if($type != Doctrine_Relation::MANY_AGGREGATE)
throw new Doctrine_Mapping_Exception();
$classes = array_merge($this->parents, array($this->name));
$classes = array_merge($this->parents, array($this->name));
foreach($classes as $class) {
try {
$bound = $objTable->getBound($class);
break;
} catch(InvalidKeyException $exc) {
foreach($classes as $class) {
try {
$bound = $table->getBound($class);
break;
} catch(InvalidKeyException $exc) {
}
}
if( ! isset($local))
$local = $this->identifier;
$e2 = explode(".",$bound[0]);
if($e2[0] != $e[0])
throw new Doctrine_Mapping_Exception();
$associationTable = $this->session->getTable($e2[0]);
$this->foreignKeys[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE);
$foreignKey = new Doctrine_Association($objTable,$associationTable,$e2[1],$e[1],$type);
}
endswitch;
$this->foreignKeys[$name] = $foreignKey;
return $this->foreignKeys[$name];
}
if( ! isset($local))
$local = $this->identifier;
$e2 = explode(".",$bound[0]);
if($e2[0] != $component)
throw new Doctrine_Mapping_Exception();
$associationTable = $this->session->getTable($e2[0]);
$this->relations[$e2[0]] = new Doctrine_ForeignKey($associationTable,$local,$e2[1],Doctrine_Relation::MANY_COMPOSITE);
$relation = new Doctrine_Association($table,$associationTable,$e2[1],$foreign,$type);
}
$this->relations[$alias] = $relation;
return $this->relations[$alias];
} else {
throw new InvalidKeyException();
}

View File

@ -29,11 +29,14 @@ class Doctrine_Validator {
*/
private $stack = array();
/**
* @var array $validators
* @var array $validators an array of validator objects
*/
private static $validators = array();
/**
* returns a validator object
*
* @param string $name
* @return Doctrine_Validator_Interface
*/
public static function getValidator($name) {
if( ! isset(self::$validators[$name])) {
@ -48,6 +51,9 @@ class Doctrine_Validator {
return self::$validators[$name];
}
/**
* validates a given record and saves possible errors
* in Doctrine_Validator::$stack
*
* @param Doctrine_Record $record
* @return void
*/
@ -101,12 +107,15 @@ class Doctrine_Validator {
}
/**
* whether or not this validator has errors
*
* @return boolean
*/
public function hasErrors() {
return (count($this->stack) > 0);
}
/**
* returns the error stack
*
* @return array
*/
public function getErrorStack() {
@ -114,7 +123,9 @@ class Doctrine_Validator {
}
/**
* returns the type of loosely typed variable
*
* @param mixed $var
* @return string
*/
public static function gettype($var) {
$type = gettype($var);

View File

@ -2,6 +2,7 @@
require_once("UnitTestCase.class.php");
class Doctrine_RecordTestCase extends Doctrine_UnitTestCase {
public function testManyToManyTreeStructure() {
$task = $this->session->create("Task");
@ -14,20 +15,20 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase {
$task = new Task();
$this->assertTrue($task instanceof Task);
$this->assertEqual($task->getState(), Doctrine_Record::STATE_TCLEAN);
$this->assertTrue($task->Task[0] instanceof Task);
$this->assertTrue($task->Subtask[0] instanceof Task);
$this->assertEqual($task->Task[0]->getState(), Doctrine_Record::STATE_TCLEAN);
$this->assertEqual($task->Subtask[0]->getState(), Doctrine_Record::STATE_TCLEAN);
$this->assertTrue($task->Resource[0] instanceof Resource);
$this->assertEqual($task->Resource[0]->getState(), Doctrine_Record::STATE_TCLEAN);
$task->name = "Task 1";
$task->Resource[0]->name = "Resource 1";
$task->Task[0]->name = "Subtask 1";
$task->Subtask[0]->name = "Subtask 1";
$this->assertEqual($task->name, "Task 1");
$this->assertEqual($task->Resource[0]->name, "Resource 1");
$this->assertEqual($task->Resource->count(), 1);
$this->assertEqual($task->Task[0]->name, "Subtask 1");
$this->assertEqual($task->Subtask[0]->name, "Subtask 1");
$this->session->flush();
@ -36,7 +37,7 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase {
$this->assertEqual($task->name, "Task 1");
$this->assertEqual($task->Resource[0]->name, "Resource 1");
$this->assertEqual($task->Resource->count(), 1);
$this->assertEqual($task->Task[0]->name, "Subtask 1");
$this->assertEqual($task->Subtask[0]->name, "Subtask 1");
}
@ -119,43 +120,53 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase {
$this->assertTrue($user->getState() == Doctrine_Record::STATE_CLEAN);
$this->assertTrue($user->name,"John Locke");
}
public function testTreeStructure() {
$e = new Element();
$e->name = "parent";
$e->Element[0]->name = "child 1";
$e->Element[1]->name = "child 2";
$e->Element[1]->Element[0]->name = "child 1's child 1";
$e->Element[1]->Element[1]->name = "child 1's child 1";
$fk = $e->getTable()->getForeignKey("Child");
$this->assertTrue($fk instanceof Doctrine_ForeignKey);
$this->assertEqual($fk->getType(), Doctrine_Relation::MANY_AGGREGATE);
$this->assertEqual($fk->getForeign(), "parent_id");
$this->assertEqual($fk->getLocal(), "id");
$e->name = "parent";
$e->Child[0]->name = "child 1";
$e->Child[1]->name = "child 2";
$e->Child[1]->Child[0]->name = "child 1's child 1";
$e->Child[1]->Child[1]->name = "child 1's child 1";
$this->assertEqual($e->name,"parent");
$this->assertEqual($e->Element[0]->name,"child 1");
$this->assertEqual($e->Element[1]->name,"child 2");
$this->assertEqual($e->Element[1]->Element[0]->name,"child 1's child 1");
$this->assertEqual($e->Element[1]->Element[1]->name,"child 1's child 1");
$this->assertEqual($e->Child[0]->name,"child 1");
$this->assertEqual($e->Child[1]->name,"child 2");
$this->assertEqual($e->Child[1]->Child[0]->name,"child 1's child 1");
$this->assertEqual($e->Child[1]->Child[1]->name,"child 1's child 1");
$this->session->flush();
$e = $e->getTable()->find(1);
$this->assertEqual($e->name,"parent");
$this->assertEqual($e->Element[0]->name,"child 1");
$this->assertEqual($e->Child[0]->name,"child 1");
$c = $e->getTable()->find(2);
$this->assertEqual($c->name, "child 1");
$this->assertEqual($e->Child[0]->parent_id, 1);
$this->assertEqual($e->Child[0]->Parent->getID(), $e->getID());
$this->assertEqual($e->Element[0]->parent_id, 1);
$this->assertEqual($e->Element[1]->parent_id, 1);
$this->assertEqual($e->Element[1]->Element[0]->name,"child 1's child 1");
$this->assertEqual($e->Element[1]->Element[1]->name,"child 1's child 1");
$this->assertEqual($e->Element[1]->Element[0]->parent_id, 3);
$this->assertEqual($e->Element[1]->Element[1]->parent_id, 3);
$this->assertEqual($e->Child[1]->parent_id, 1);
$this->assertEqual($e->Child[1]->Child[0]->name,"child 1's child 1");
$this->assertEqual($e->Child[1]->Child[1]->name,"child 1's child 1");
$this->assertEqual($e->Child[1]->Child[0]->parent_id, 3);
$this->assertEqual($e->Child[1]->Child[1]->parent_id, 3);
}

View File

@ -26,6 +26,8 @@ class Doctrine_TableTestCase extends Doctrine_UnitTestCase {
$this->assertTrue($fk->getType() == Doctrine_Relation::MANY_COMPOSITE);
$this->assertTrue($fk->getLocal() == $this->objTable->getIdentifier());
$this->assertTrue($fk->getForeign() == "entity_id");
}
public function testGetComponentName() {
$this->assertTrue($this->objTable->getComponentName() == "User");

View File

@ -55,6 +55,7 @@ class Doctrine_UnitTestCase extends UnitTestCase {
}
foreach($tables as $name) {
$name = ucwords($name);
$table = $this->session->getTable($name);
$table->getCache()->deleteAll();
}

View File

@ -97,7 +97,8 @@ class Element extends Doctrine_Record {
$this->hasColumn("parent_id", "integer");
}
public function setUp() {
$this->hasMany("Element","Element.parent_id");
$this->hasMany("Element as Child","Child.parent_id");
$this->hasOne("Element as Parent","Element.parent_id");
}
}
class Email extends Doctrine_Record {
@ -127,8 +128,8 @@ class Song extends Doctrine_Record {
class Task extends Doctrine_Record {
public function setUp() {
$this->hasMany("Resource","Assignment.resource_id");
$this->hasMany("Task","Task.parent_id");
$this->hasMany("Resource","Assignment.resource_id");
$this->hasMany("Task as Subtask","Subtask.parent_id");
}
public function setTableDefinition() {
$this->hasColumn("name","string",100);