From 7ef869ee4050be133bf89806a492c3341dd275e8 Mon Sep 17 00:00:00 2001 From: zYne Date: Mon, 30 Oct 2006 23:00:09 +0000 Subject: [PATCH] Refactored Doctrine_Connection and Doctrine_Record, fixes #212 --- lib/Doctrine/Collection.php | 23 ++- lib/Doctrine/Connection.php | 207 ++++--------------------- lib/Doctrine/Connection/Mysql.php | 22 +++ lib/Doctrine/Connection/UnitOfWork.php | 79 ++++++++++ lib/Doctrine/Query.php | 95 +++++++++--- lib/Doctrine/Record.php | 101 ++---------- lib/Doctrine/Relation/Association.php | 39 +++++ lib/Doctrine/Relation/ForeignKey.php | 29 ++++ lib/Doctrine/Relation/LocalKey.php | 12 ++ tests/run.php | 6 +- 10 files changed, 312 insertions(+), 301 deletions(-) diff --git a/lib/Doctrine/Collection.php b/lib/Doctrine/Collection.php index 8a6f731d5..4da243232 100644 --- a/lib/Doctrine/Collection.php +++ b/lib/Doctrine/Collection.php @@ -645,7 +645,7 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator } /** * save - * saves all records + * saves all records of this collection * * @return void */ @@ -653,19 +653,34 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator if ($conn == null) { $conn = $this->table->getConnection(); } - $conn->saveCollection($this); + $conn->beginTransaction(); + + foreach($this as $key => $record): + $record->save(); + endforeach; + + $conn->commit(); } /** * single shot delete * 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 */ public function delete(Doctrine_Connection $conn = null) { if ($conn == null) { $conn = $this->table->getConnection(); } - $ids = $conn->deleteCollection($this); + + $conn->beginTransaction(); + + foreach($this as $key => $record) { + $record->delete(); + } + + $conn->commit(); + $this->data = array(); } /** diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index ff8013a6f..cf652c704 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -48,13 +48,30 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * @var Doctrine_DataDict $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 * * @param Doctrine_Manager $manager the manager object * @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->transaction = new Doctrine_Connection_Transaction($this); @@ -112,6 +129,13 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun public function getDBH() { return $this->dbh; } + /** + * converts given driver name + * + * @param + */ + public function driverName($name) { + } /** * returns a datadict object * @@ -202,7 +226,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun */ public function select($query,$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); } @@ -332,7 +356,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun foreach($tree as $name) { $table = $this->tables[$name]; foreach($table->getRepository() as $record) { - $record->saveAssociations(); + $this->unitOfWork->saveAssociations($record); } } } @@ -409,60 +433,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun public function 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 * @@ -489,125 +459,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun $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 * this operation is isolated by a transaction @@ -616,7 +467,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun * * @return boolean true on success, false on failure */ - final public function delete(Doctrine_Record $record) { + public function delete(Doctrine_Record $record) { if( ! $record->exists()) return false; @@ -624,7 +475,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun $record->getTable()->getListener()->onPreDelete($record); - $this->deleteComposites($record); + $this->unitOfWork->deleteComposites($record); $this->transaction->addDelete($record); diff --git a/lib/Doctrine/Connection/Mysql.php b/lib/Doctrine/Connection/Mysql.php index fe2d04f29..2ec1b5be6 100644 --- a/lib/Doctrine/Connection/Mysql.php +++ b/lib/Doctrine/Connection/Mysql.php @@ -35,6 +35,28 @@ class Doctrine_Connection_Mysql extends Doctrine_Connection_Common { public function __construct(Doctrine_Manager $manager,PDO $pdo) { $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $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); } /** diff --git a/lib/Doctrine/Connection/UnitOfWork.php b/lib/Doctrine/Connection/UnitOfWork.php index 92941c66b..92d777438 100644 --- a/lib/Doctrine/Connection/UnitOfWork.php +++ b/lib/Doctrine/Connection/UnitOfWork.php @@ -44,7 +44,12 @@ class Doctrine_Connection_UnitOfWork implements IteratorAggregate, Countable { /** * buildFlushTree * 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 */ public function buildFlushTree(array $tables) { @@ -133,7 +138,81 @@ class Doctrine_Connection_UnitOfWork implements IteratorAggregate, Countable { } 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 count() { } diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 9a0ef926d..1a4e683b6 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -598,25 +598,26 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { } } /** - * DQL PARSER - * parses a DQL query - * first splits the query in parts and then uses individual - * parsers for each part + * splitQuery + * splits the given dql query into an array where keys + * represent different query part names and values are + * 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 boolean $clear whether or not to clear the aliases * @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) { - if($clear) - $this->clear(); - - $query = trim($query); - $query = str_replace("\n"," ",$query); - $query = str_replace("\r"," ",$query); - - $e = self::sqlExplode($query," ","(",")"); + public function splitQuery($query) { + $e = self::sqlExplode($query, ' '); foreach($e as $k=>$part) { $part = trim($part); @@ -651,6 +652,28 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { $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) { $part = implode(" ",$part); @@ -753,11 +776,18 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { } /** * bracketExplode - * usage: - * $str = (age < 20 AND age > 18) AND email LIKE 'John@example.com' - * now exploding $str with parameters $d = ' AND ', $e1 = '(' and $e2 = ')' + * + * example: + * + * parameters: + * $str = (age < 20 AND age > 18) AND email LIKE 'John@example.com' + * $d = ' AND ' + * $e1 = '(' + * $e2 = ')' + * * 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 $d the delimeter which explodes the string @@ -765,7 +795,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * @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)) { $a = preg_split('/('.implode('|', $d).')/', $str); $d = stripslashes($d[0]); @@ -777,13 +807,13 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { foreach($a as $key=>$val) { if (empty($term[$i])) { $term[$i] = trim($val); - $s1 = substr_count($term[$i],"$e1"); - $s2 = substr_count($term[$i],"$e2"); + $s1 = substr_count($term[$i], "$e1"); + $s2 = substr_count($term[$i], "$e2"); if($s1 == $s2) $i++; } else { $term[$i] .= "$d".trim($val); - $c1 = substr_count($term[$i],"$e1"); - $c2 = substr_count($term[$i],"$e2"); + $c1 = substr_count($term[$i], "$e1"); + $c2 = substr_count($term[$i], "$e2"); if($c1 == $c2) $i++; } } @@ -795,6 +825,21 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * explodes a string into array using custom brackets and * 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 $d the delimeter which explodes the string * @param string $e1 the first bracket, usually '(' @@ -802,7 +847,7 @@ class Doctrine_Query extends Doctrine_Hydrate implements Countable { * * @return array */ - public static function sqlExplode($str,$d = " ",$e1 = '(',$e2 = ')') { + public static function sqlExplode($str, $d = ' ', $e1 = '(', $e2 = ')') { if(is_array($d)) { $str = preg_split('/('.implode('|', $d).')/', $str); $d = stripslashes($d[0]); diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index ebb247733..955cd2b45 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -857,8 +857,9 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite $conn = $this->_table->getConnection(); } $conn->beginTransaction(); - - $saveLater = $conn->saveRelated($this); + + + $saveLater = $conn->getUnitOfWork()->saveRelated($this); if ($this->isValid()) { $conn->save($this); @@ -878,7 +879,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite // save the MANY-TO-MANY associations - $this->saveAssociations(); + $conn->getUnitOfWork()->saveAssociations($this); + //$this->saveAssociations(); $conn->commit(); } @@ -1012,99 +1014,18 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite public function getIterator() { return new Doctrine_Record_Iterator($this); } - + /** + * getOriginals + * returns an original collection of related component + * + * @return Doctrine_Collection|false + */ 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 - * returns an original collection of related component - * - * @return Doctrine_Collection - */ - final public function getOriginals($name) { - if( ! isset($this->originals[$name])) - throw new InvalidKeyException(); - - return $this->originals[$name]; - } /** * deletes this data access object and all the related composites * this operation is isolated by a transaction diff --git a/lib/Doctrine/Relation/Association.php b/lib/Doctrine/Relation/Association.php index bfce9664e..a351bd89e 100644 --- a/lib/Doctrine/Relation/Association.php +++ b/lib/Doctrine/Relation/Association.php @@ -52,6 +52,45 @@ class Doctrine_Relation_Association extends Doctrine_Relation { public function getAssociationFactory() { 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 * diff --git a/lib/Doctrine/Relation/ForeignKey.php b/lib/Doctrine/Relation/ForeignKey.php index 1de724a61..eb137f5cf 100644 --- a/lib/Doctrine/Relation/ForeignKey.php +++ b/lib/Doctrine/Relation/ForeignKey.php @@ -28,6 +28,35 @@ Doctrine::autoload('Doctrine_Relation'); * @package Doctrine */ 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 * diff --git a/lib/Doctrine/Relation/LocalKey.php b/lib/Doctrine/Relation/LocalKey.php index f3403709e..aa20d36a6 100644 --- a/lib/Doctrine/Relation/LocalKey.php +++ b/lib/Doctrine/Relation/LocalKey.php @@ -28,6 +28,18 @@ Doctrine::autoload('Doctrine_Relation'); * @package Doctrine */ 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 * diff --git a/tests/run.php b/tests/run.php index b96639fb2..4cc648530 100644 --- a/tests/run.php +++ b/tests/run.php @@ -64,16 +64,14 @@ print '
';
 
 $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_TestCase());
 
-$test->addTestCase(new Doctrine_Record_TestCase());
-
 $test->addTestCase(new Doctrine_Record_State_TestCase());
 
 $test->addTestCase(new Doctrine_Import_TestCase());