Commit 7ef869ee authored by zYne's avatar zYne

Refactored Doctrine_Connection and Doctrine_Record, fixes #212

parent d8dddffc
...@@ -645,7 +645,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator ...@@ -645,7 +645,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
} }
/** /**
* save * save
* saves all records * saves all records of this collection
* *
* @return void * @return void
*/ */
...@@ -653,19 +653,34 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator ...@@ -653,19 +653,34 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
if ($conn == null) { if ($conn == null) {
$conn = $this->table->getConnection(); $conn = $this->table->getConnection();
} }
$conn->saveCollection($this); $conn->beginTransaction();
foreach($this as $key => $record):
$record->save();
endforeach;
$conn->commit();
} }
/** /**
* single shot delete * single shot delete
* deletes all records from this collection * deletes all records from this collection
* uses only one database query to perform this operation * and uses only one database query to perform this operation
*
* @return boolean * @return boolean
*/ */
public function delete(Doctrine_Connection $conn = null) { public function delete(Doctrine_Connection $conn = null) {
if ($conn == null) { if ($conn == null) {
$conn = $this->table->getConnection(); $conn = $this->table->getConnection();
} }
$ids = $conn->deleteCollection($this);
$conn->beginTransaction();
foreach($this as $key => $record) {
$record->delete();
}
$conn->commit();
$this->data = array(); $this->data = array();
} }
/** /**
......
...@@ -48,13 +48,30 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -48,13 +48,30 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
* @var Doctrine_DataDict $dataDict * @var Doctrine_DataDict $dataDict
*/ */
private $dataDict; private $dataDict;
private static $availibleDrivers = array(
"Mysql",
"Pgsql",
"Oracle",
"Informix",
"Mssql",
"Sqlite",
"Firebird"
);
private static $driverMap = array('oracle' => 'oci8',
'postgres' => 'pgsql',
'oci' => 'oci8',
'sqlite2' => 'sqlite',
'sqlite3' => 'sqlite');
/** /**
* the constructor * the constructor
* *
* @param Doctrine_Manager $manager the manager object * @param Doctrine_Manager $manager the manager object
* @param PDO $pdo the database handler * @param PDO $pdo the database handler
*/ */
public function __construct(Doctrine_Manager $manager,PDO $pdo) { public function __construct(Doctrine_Manager $manager, PDO $pdo) {
$this->dbh = $pdo; $this->dbh = $pdo;
$this->transaction = new Doctrine_Connection_Transaction($this); $this->transaction = new Doctrine_Connection_Transaction($this);
...@@ -112,6 +129,13 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -112,6 +129,13 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
public function getDBH() { public function getDBH() {
return $this->dbh; return $this->dbh;
} }
/**
* converts given driver name
*
* @param
*/
public function driverName($name) {
}
/** /**
* returns a datadict object * returns a datadict object
* *
...@@ -202,7 +226,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -202,7 +226,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
*/ */
public function select($query,$limit = 0,$offset = 0) { public function select($query,$limit = 0,$offset = 0) {
if($limit > 0 || $offset > 0) if($limit > 0 || $offset > 0)
$query = $this->modifyLimitQuery($query,$limit,$offset); $query = $this->modifyLimitQuery($query, $limit, $offset);
return $this->dbh->query($query); return $this->dbh->query($query);
} }
...@@ -332,7 +356,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -332,7 +356,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
foreach($tree as $name) { foreach($tree as $name) {
$table = $this->tables[$name]; $table = $this->tables[$name];
foreach($table->getRepository() as $record) { foreach($table->getRepository() as $record) {
$record->saveAssociations(); $this->unitOfWork->saveAssociations($record);
} }
} }
} }
...@@ -409,60 +433,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -409,60 +433,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
public function rollback() { public function rollback() {
$this->transaction->rollback(); $this->transaction->rollback();
} }
/**
* returns maximum identifier values
*
* @param array $names an array of component names
* @return array
*/
public function getMaximumValues(array $names) {
$values = array();
foreach($names as $name) {
$table = $this->tables[$name];
$keys = $table->getPrimaryKeys();
$tablename = $table->getTableName();
if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) {
// record uses auto_increment column
$sql = "SELECT MAX(".$table->getIdentifier().") FROM ".$tablename;
$stmt = $this->dbh->query($sql);
$data = $stmt->fetch(PDO::FETCH_NUM);
$values[$tablename] = $data[0];
$stmt->closeCursor();
}
}
return $values;
}
/**
* saves a collection
*
* @param Doctrine_Collection $coll
* @return void
*/
public function saveCollection(Doctrine_Collection $coll) {
$this->beginTransaction();
foreach($coll as $key=>$record):
$record->save();
endforeach;
$this->commit();
}
/**
* deletes all records from collection
*
* @param Doctrine_Collection $coll
* @return void
*/
public function deleteCollection(Doctrine_Collection $coll) {
$this->beginTransaction();
foreach($coll as $k=>$record) {
$record->delete();
}
$this->commit();
}
/** /**
* saves the given record * saves the given record
* *
...@@ -489,125 +459,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -489,125 +459,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record); $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onSave($record);
} }
/**
* saves all related records to $record
*
* @param Doctrine_Record $record
*/
public function saveRelated(Doctrine_Record $record) {
$saveLater = array();
foreach($record->getReferences() as $k=>$v) {
$fk = $record->getTable()->getRelation($k);
if($fk instanceof Doctrine_Relation_ForeignKey ||
$fk instanceof Doctrine_Relation_LocalKey) {
if($fk->isComposite()) {
$local = $fk->getLocal();
$foreign = $fk->getForeign();
if($record->getTable()->hasPrimaryKey($fk->getLocal())) {
if( ! $record->exists())
$saveLater[$k] = $fk;
else
$v->save();
} else {
// ONE-TO-ONE relationship
$obj = $record->get($fk->getTable()->getComponentName());
if($obj->getState() != Doctrine_Record::STATE_TCLEAN)
$obj->save();
}
}
} elseif($fk instanceof Doctrine_Relation_Association) {
$v->save();
}
}
return $saveLater;
}
/**
* deletes all related composites
* this method is always called internally when a record is deleted
*
* @return void
*/
final public function deleteComposites(Doctrine_Record $record) {
foreach($record->getTable()->getRelations() as $fk) {
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::MANY_COMPOSITE:
$obj = $record->get($fk->getAlias());
$obj->delete();
break;
endswitch;
}
}
/**
* saveAssociations
* save the associations of many-to-many relations
* this method also deletes associations that do not exist anymore
* @return void
*/
final public function saveAssociations(Doctrine_Record $record) {
foreach($record->getTable()->table->getRelations() as $rel):
$table = $rel->getTable();
$name = $table->getComponentName();
$alias = $this->table->getAlias($name);
if($rel instanceof Doctrine_Relation_Association) {
$asf = $rel->getAssociationFactory();
if($record->hasReference($alias)) {
$new = $record->getReference($alias);
if( ! $this->hasOriginalsFor($alias))
$record->loadReference($alias);
$operations = Doctrine_Relation::getDeleteOperations($this->originals[$alias],$new);
foreach($operations as $r) {
$query = "DELETE FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." = ?"
." AND ".$fk->getLocal()." = ?";
$this->table->getConnection()->execute($query, array($r->getIncremented(),$record->getIncremented()));
}
$operations = Doctrine_Relation::getInsertOperations($record->obtainOriginals($alias),$new);
foreach($operations as $r) {
$reldao = $asf->create();
$reldao->set($fk->getForeign(),$r);
$reldao->set($fk->getLocal(),$this);
$reldao->save();
}
$record->assignOriginals($alias, clone $this->references[$alias]);
}
} elseif($fk instanceof Doctrine_Relation_ForeignKey ||
$fk instanceof Doctrine_Relation_LocalKey) {
if($fk->isOneToOne()) {
if($record->obtainOriginals($alias) && $record->obtainOriginals($alias)->obtainIdentifier() != $this->references[$alias]->obtainIdentifier())
$record->obtainOriginals($alias)->delete();
} else {
if(isset($this->references[$alias])) {
$new = $this->references[$alias];
if( ! isset($this->originals[$alias]))
$record->loadReference($alias);
$operations = Doctrine_Relation::getDeleteOperations($this->originals[$alias], $new);
foreach($operations as $r) {
$r->delete();
}
$record->assignOriginals($alias, clone $this->references[$alias]);
}
}
}
endforeach;
}
/** /**
* deletes this data access object and all the related composites * deletes this data access object and all the related composites
* this operation is isolated by a transaction * this operation is isolated by a transaction
...@@ -616,7 +467,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -616,7 +467,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
* *
* @return boolean true on success, false on failure * @return boolean true on success, false on failure
*/ */
final public function delete(Doctrine_Record $record) { public function delete(Doctrine_Record $record) {
if( ! $record->exists()) if( ! $record->exists())
return false; return false;
...@@ -624,7 +475,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun ...@@ -624,7 +475,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$record->getTable()->getListener()->onPreDelete($record); $record->getTable()->getListener()->onPreDelete($record);
$this->deleteComposites($record); $this->unitOfWork->deleteComposites($record);
$this->transaction->addDelete($record); $this->transaction->addDelete($record);
......
...@@ -35,6 +35,28 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common { ...@@ -35,6 +35,28 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common {
public function __construct(Doctrine_Manager $manager,PDO $pdo) { public function __construct(Doctrine_Manager $manager,PDO $pdo) {
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$this->setAttribute(Doctrine::ATTR_QUERY_LIMIT, Doctrine::LIMIT_ROWS); $this->setAttribute(Doctrine::ATTR_QUERY_LIMIT, Doctrine::LIMIT_ROWS);
$this->supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => false,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => true
);
parent::__construct($manager,$pdo); parent::__construct($manager,$pdo);
} }
/** /**
......
...@@ -45,6 +45,11 @@ class Doctrine_Connection_UnitOfWork implements IteratorAggregate, Countable { ...@@ -45,6 +45,11 @@ class Doctrine_Connection_UnitOfWork implements IteratorAggregate, Countable {
* buildFlushTree * buildFlushTree
* builds a flush tree that is used in transactions * builds a flush tree that is used in transactions
* *
* The returned array has all the initialized components in
* 'correct' order. Basically this means that the records of those
* components can be saved safely in the order specified by the returned array.
*
* @param array $tables
* @return array * @return array
*/ */
public function buildFlushTree(array $tables) { public function buildFlushTree(array $tables) {
...@@ -133,7 +138,81 @@ class Doctrine_Connection_UnitOfWork implements IteratorAggregate, Countable { ...@@ -133,7 +138,81 @@ class Doctrine_Connection_UnitOfWork implements IteratorAggregate, Countable {
} }
return array_values($tree); return array_values($tree);
} }
/**
* saveRelated
* saves all related records to $record
*
* @param Doctrine_Record $record
*/
public function saveRelated(Doctrine_Record $record) {
$saveLater = array();
foreach($record->getReferences() as $k=>$v) {
$fk = $record->getTable()->getRelation($k);
if($fk instanceof Doctrine_Relation_ForeignKey ||
$fk instanceof Doctrine_Relation_LocalKey) {
if($fk->isComposite()) {
$local = $fk->getLocal();
$foreign = $fk->getForeign();
if($record->getTable()->hasPrimaryKey($fk->getLocal())) {
if( ! $record->exists())
$saveLater[$k] = $fk;
else
$v->save();
} else {
// ONE-TO-ONE relationship
$obj = $record->get($fk->getTable()->getComponentName());
if($obj->getState() != Doctrine_Record::STATE_TCLEAN)
$obj->save();
}
}
} elseif($fk instanceof Doctrine_Relation_Association) {
$v->save();
}
}
return $saveLater;
}
/**
* saveAssociations
*
* this method takes a diff of one-to-many / many-to-many original and
* current collections and applies the changes
*
* for example if original many-to-many related collection has records with
* primary keys 1,2 and 3 and the new collection has records with primary keys
* 3, 4 and 5, this method would first destroy the associations to 1 and 2 and then
* save new associations to 4 and 5
*
* @param Doctrine_Record $record
* @return void
*/
public function saveAssociations(Doctrine_Record $record) {
foreach($record->getTable()->getRelations() as $rel) {
$table = $rel->getTable();
$alias = $rel->getAlias();
$rel->processDiff($record);
}
}
/**
* deletes all related composites
* this method is always called internally when a record is deleted
*
* @return void
*/
public function deleteComposites(Doctrine_Record $record) {
foreach($record->getTable()->getRelations() as $fk) {
switch($fk->getType()):
case Doctrine_Relation::ONE_COMPOSITE:
case Doctrine_Relation::MANY_COMPOSITE:
$obj = $record->get($fk->getAlias());
$obj->delete();
break;
endswitch;
}
}
public function getIterator() { } public function getIterator() { }
public function count() { } public function count() { }
......
...@@ -598,25 +598,26 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { ...@@ -598,25 +598,26 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable {
} }
} }
/** /**
* DQL PARSER * splitQuery
* parses a DQL query * splits the given dql query into an array where keys
* first splits the query in parts and then uses individual * represent different query part names and values are
* parsers for each part * arrays splitted using sqlExplode method
*
* example:
*
* parameter:
* $query = "SELECT u.* FROM User u WHERE u.name LIKE ?"
* returns:
* array('select' => array('u.*'),
* 'from' => array('User', 'u'),
* 'where' => array('u.name', 'LIKE', '?'))
* *
* @param string $query DQL query * @param string $query DQL query
* @param boolean $clear whether or not to clear the aliases
* @throws Doctrine_Query_Exception if some generic parsing error occurs * @throws Doctrine_Query_Exception if some generic parsing error occurs
* @return Doctrine_Query * @return array an array containing the query string parts
*/ */
public function parseQuery($query, $clear = true) { public function splitQuery($query) {
if($clear) $e = self::sqlExplode($query, ' ');
$this->clear();
$query = trim($query);
$query = str_replace("\n"," ",$query);
$query = str_replace("\r"," ",$query);
$e = self::sqlExplode($query," ","(",")");
foreach($e as $k=>$part) { foreach($e as $k=>$part) {
$part = trim($part); $part = trim($part);
...@@ -651,6 +652,28 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { ...@@ -651,6 +652,28 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable {
$parts[$p][] = $part; $parts[$p][] = $part;
} }
} }
return $parts;
}
/**
* DQL PARSER
* parses a DQL query
* first splits the query in parts and then uses individual
* parsers for each part
*
* @param string $query DQL query
* @param boolean $clear whether or not to clear the aliases
* @throws Doctrine_Query_Exception if some generic parsing error occurs
* @return Doctrine_Query
*/
public function parseQuery($query, $clear = true) {
if($clear)
$this->clear();
$query = trim($query);
$query = str_replace("\n"," ",$query);
$query = str_replace("\r"," ",$query);
$parts = $this->splitQuery($query);
foreach($parts as $k => $part) { foreach($parts as $k => $part) {
$part = implode(" ",$part); $part = implode(" ",$part);
...@@ -753,11 +776,18 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { ...@@ -753,11 +776,18 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable {
} }
/** /**
* bracketExplode * bracketExplode
* usage: *
* example:
*
* parameters:
* $str = (age < 20 AND age > 18) AND email LIKE 'John@example.com' * $str = (age < 20 AND age > 18) AND email LIKE 'John@example.com'
* now exploding $str with parameters $d = ' AND ', $e1 = '(' and $e2 = ')' * $d = ' AND '
* $e1 = '('
* $e2 = ')'
*
* would return an array: * would return an array:
* array("(age < 20 AND age > 18)", "email LIKE 'John@example.com'") * array("(age < 20 AND age > 18)",
* "email LIKE 'John@example.com'")
* *
* @param string $str * @param string $str
* @param string $d the delimeter which explodes the string * @param string $d the delimeter which explodes the string
...@@ -765,7 +795,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { ...@@ -765,7 +795,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable {
* @param string $e2 the second bracket, usually ')' * @param string $e2 the second bracket, usually ')'
* *
*/ */
public static function bracketExplode($str,$d,$e1 = '(',$e2 = ')') { public static function bracketExplode($str, $d = ' ', $e1 = '(', $e2 = ')') {
if(is_array($d)) { if(is_array($d)) {
$a = preg_split('/('.implode('|', $d).')/', $str); $a = preg_split('/('.implode('|', $d).')/', $str);
$d = stripslashes($d[0]); $d = stripslashes($d[0]);
...@@ -777,13 +807,13 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { ...@@ -777,13 +807,13 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable {
foreach($a as $key=>$val) { foreach($a as $key=>$val) {
if (empty($term[$i])) { if (empty($term[$i])) {
$term[$i] = trim($val); $term[$i] = trim($val);
$s1 = substr_count($term[$i],"$e1"); $s1 = substr_count($term[$i], "$e1");
$s2 = substr_count($term[$i],"$e2"); $s2 = substr_count($term[$i], "$e2");
if($s1 == $s2) $i++; if($s1 == $s2) $i++;
} else { } else {
$term[$i] .= "$d".trim($val); $term[$i] .= "$d".trim($val);
$c1 = substr_count($term[$i],"$e1"); $c1 = substr_count($term[$i], "$e1");
$c2 = substr_count($term[$i],"$e2"); $c2 = substr_count($term[$i], "$e2");
if($c1 == $c2) $i++; if($c1 == $c2) $i++;
} }
} }
...@@ -795,6 +825,21 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { ...@@ -795,6 +825,21 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable {
* explodes a string into array using custom brackets and * explodes a string into array using custom brackets and
* quote delimeters * quote delimeters
* *
*
* example:
*
* parameters:
* $str = "(age < 20 AND age > 18) AND name LIKE 'John Doe'"
* $d = ' '
* $e1 = '('
* $e2 = ')'
*
* would return an array:
* array('(age < 20 AND age > 18)',
* 'name',
* 'LIKE',
* 'John Doe')
*
* @param string $str * @param string $str
* @param string $d the delimeter which explodes the string * @param string $d the delimeter which explodes the string
* @param string $e1 the first bracket, usually '(' * @param string $e1 the first bracket, usually '('
...@@ -802,7 +847,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { ...@@ -802,7 +847,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable {
* *
* @return array * @return array
*/ */
public static function sqlExplode($str,$d = " ",$e1 = '(',$e2 = ')') { public static function sqlExplode($str, $d = ' ', $e1 = '(', $e2 = ')') {
if(is_array($d)) { if(is_array($d)) {
$str = preg_split('/('.implode('|', $d).')/', $str); $str = preg_split('/('.implode('|', $d).')/', $str);
$d = stripslashes($d[0]); $d = stripslashes($d[0]);
......
...@@ -858,7 +858,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -858,7 +858,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
} }
$conn->beginTransaction(); $conn->beginTransaction();
$saveLater = $conn->saveRelated($this);
$saveLater = $conn->getUnitOfWork()->saveRelated($this);
if ($this->isValid()) { if ($this->isValid()) {
$conn->save($this); $conn->save($this);
...@@ -878,7 +879,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -878,7 +879,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
// save the MANY-TO-MANY associations // save the MANY-TO-MANY associations
$this->saveAssociations(); $conn->getUnitOfWork()->saveAssociations($this);
//$this->saveAssociations();
$conn->commit(); $conn->commit();
} }
...@@ -1012,98 +1014,17 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite ...@@ -1012,98 +1014,17 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
public function getIterator() { public function getIterator() {
return new Doctrine_Record_Iterator($this); return new Doctrine_Record_Iterator($this);
} }
public function obtainOriginals($name) {
if(isset($this->originals[$name]))
return $this->originals[$name];
return false;
}
/**
* saveAssociations
*
* save the associations of many-to-many relations
* this method also deletes associations that do not exist anymore
*
* @return void
*/
final public function saveAssociations() {
foreach($this->_table->getRelations() as $fk) {
$table = $fk->getTable();
$name = $table->getComponentName();
$alias = $this->_table->getAlias($name);
if($fk instanceof Doctrine_Relation_Association) {
switch($fk->getType()):
case Doctrine_Relation::MANY_AGGREGATE:
$asf = $fk->getAssociationFactory();
if(isset($this->references[$alias])) {
$new = $this->references[$alias];
if( ! isset($this->originals[$alias])) {
$this->loadReference($alias);
}
$r = Doctrine_Relation::getDeleteOperations($this->originals[$alias],$new);
foreach($r as $record) {
$query = "DELETE FROM ".$asf->getTableName()." WHERE ".$fk->getForeign()." = ?"
." AND ".$fk->getLocal()." = ?";
$this->_table->getConnection()->execute($query, array($record->getIncremented(),$this->getIncremented()));
}
$r = Doctrine_Relation::getInsertOperations($this->originals[$alias],$new);
foreach($r as $record) {
$reldao = $asf->create();
$reldao->set($fk->getForeign(),$record);
$reldao->set($fk->getLocal(),$this);
$reldao->save();
}
$this->originals[$alias] = clone $this->references[$alias];
}
break;
endswitch;
} elseif($fk instanceof Doctrine_Relation_ForeignKey ||
$fk instanceof Doctrine_Relation_LocalKey) {
if($fk->isOneToOne()) {
if(isset($this->originals[$alias]) && $this->originals[$alias]->obtainIdentifier() != $this->references[$alias]->obtainIdentifier())
$this->originals[$alias]->delete();
} else {
if(isset($this->references[$alias])) {
$new = $this->references[$alias];
if( ! isset($this->originals[$alias]))
$this->loadReference($alias);
$r = Doctrine_Relation::getDeleteOperations($this->originals[$alias], $new);
foreach($r as $record) {
$record->delete();
}
$this->originals[$alias] = clone $this->references[$alias];
}
}
}
}
}
/** /**
* getOriginals * getOriginals
* returns an original collection of related component * returns an original collection of related component
* *
* @return Doctrine_Collection * @return Doctrine_Collection|false
*/ */
final public function getOriginals($name) { public function obtainOriginals($name) {
if( ! isset($this->originals[$name])) if(isset($this->originals[$name]))
throw new InvalidKeyException();
return $this->originals[$name]; return $this->originals[$name];
return false;
} }
/** /**
* deletes this data access object and all the related composites * deletes this data access object and all the related composites
......
...@@ -52,6 +52,45 @@ class Doctrine_Relation_Association extends Doctrine_Relation { ...@@ -52,6 +52,45 @@ class Doctrine_Relation_Association extends Doctrine_Relation {
public function getAssociationFactory() { public function getAssociationFactory() {
return $this->associationTable; return $this->associationTable;
} }
/**
* processDiff
*
* @param Doctrine_Record
*/
public function processDiff(Doctrine_Record $record) {
$asf = $this->getAssociationFactory();
$alias = $this->getAlias();
if($record->hasReference($alias)) {
$new = $record->obtainReference($alias);
if( ! $record->obtainOriginals($alias))
$record->loadReference($alias);
$operations = Doctrine_Relation::getDeleteOperations($record->obtainOriginals($alias), $new);
foreach($operations as $r) {
$query = 'DELETE FROM ' . $asf->getTableName()
. ' WHERE ' . $this->getForeign() . ' = ?'
. ' AND ' . $this->getLocal() . ' = ?';
$this->getTable()->getConnection()->execute($query, array($r->getIncremented(),$record->getIncremented()));
}
$operations = Doctrine_Relation::getInsertOperations($record->obtainOriginals($alias),$new);
foreach($operations as $r) {
$reldao = $asf->create();
$reldao->set($this->getForeign(), $r);
$reldao->set($this->getLocal(), $record);
$reldao->save();
}
$record->assignOriginals($alias, clone $record->get($alias));
}
}
/** /**
* getRelationDql * getRelationDql
* *
......
...@@ -28,6 +28,35 @@ Doctrine::autoload('Doctrine_Relation'); ...@@ -28,6 +28,35 @@ Doctrine::autoload('Doctrine_Relation');
* @package Doctrine * @package Doctrine
*/ */
class Doctrine_Relation_ForeignKey extends Doctrine_Relation { class Doctrine_Relation_ForeignKey extends Doctrine_Relation {
/**
* processDiff
*
* @param Doctrine_Record $record
*/
public function processDiff(Doctrine_Record $record) {
$alias = $this->getAlias();
if($this->isOneToOne()) {
if($record->obtainOriginals($alias) &&
$record->obtainOriginals($alias)->obtainIdentifier() != $this->obtainReference($alias)->obtainIdentifier())
$record->obtainOriginals($alias)->delete();
} else {
if($record->hasReference($alias)) {
$new = $record->obtainReference($alias);
if( ! $record->obtainOriginals($alias))
$record->loadReference($alias);
$operations = Doctrine_Relation::getDeleteOperations($record->obtainOriginals($alias), $new);
foreach($operations as $r) {
$r->delete();
}
$record->assignOriginals($alias, clone $record->get($alias));
}
}
}
/** /**
* fetchRelatedFor * fetchRelatedFor
* *
......
...@@ -28,6 +28,18 @@ Doctrine::autoload('Doctrine_Relation'); ...@@ -28,6 +28,18 @@ Doctrine::autoload('Doctrine_Relation');
* @package Doctrine * @package Doctrine
*/ */
class Doctrine_Relation_LocalKey extends Doctrine_Relation { class Doctrine_Relation_LocalKey extends Doctrine_Relation {
/**
* processDiff
*
* @param Doctrine_Record $record
*/
public function processDiff(Doctrine_Record $record) {
$alias = $this->getAlias();
if($record->obtainOriginals($alias) &&
$record->obtainOriginals($alias)->obtainIdentifier() != $this->references[$alias]->obtainIdentifier())
$record->obtainOriginals($alias)->delete();
}
/** /**
* fetchRelatedFor * fetchRelatedFor
* *
......
...@@ -64,16 +64,14 @@ print '<pre>'; ...@@ -64,16 +64,14 @@ print '<pre>';
$test = new GroupTest('Doctrine Framework Unit Tests'); $test = new GroupTest('Doctrine Framework Unit Tests');
$test->addTestCase(new Doctrine_DataDict_Pgsql_TestCase()); $test->addTestCase(new Doctrine_Record_TestCase());
$test->addTestCase(new Doctrine_DataDict_Pgsql_TestCase());
$test->addTestCase(new Doctrine_Relation_ManyToMany_TestCase()); $test->addTestCase(new Doctrine_Relation_ManyToMany_TestCase());
$test->addTestCase(new Doctrine_Relation_TestCase()); $test->addTestCase(new Doctrine_Relation_TestCase());
$test->addTestCase(new Doctrine_Record_TestCase());
$test->addTestCase(new Doctrine_Record_State_TestCase()); $test->addTestCase(new Doctrine_Record_State_TestCase());
$test->addTestCase(new Doctrine_Import_TestCase()); $test->addTestCase(new Doctrine_Import_TestCase());
......
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