From fe882581685c5a1434915972a0d92939a647ed90 Mon Sep 17 00:00:00 2001 From: zYne Date: Wed, 29 Nov 2006 21:09:02 +0000 Subject: [PATCH] Updated classes to use new Transaction module --- lib/Doctrine/Connection.php | 6 +- lib/Doctrine/Connection/Transaction.php | 46 +---------- lib/Doctrine/Connection/UnitOfWork.php | 96 ++++++++++++++++++++++ lib/Doctrine/DataDict/Sqlite.php | 5 +- lib/Doctrine/Transaction.php | 101 +++++++++++++++++++++--- lib/Doctrine/Validator.php | 14 +--- tests/ConnectionTestCase.php | 18 ++--- tests/ConnectionTransactionTestCase.php | 2 +- tests/DataDict/SqliteTestCase.php | 2 +- tests/DriverTestCase.php | 2 +- tests/ExportFirebirdTestCase.php | 29 +++++++ tests/run.php | 23 +++--- 12 files changed, 249 insertions(+), 95 deletions(-) diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index a2b27ca7b..8362a58b6 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -102,7 +102,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun $this->dbh = $adapter; - $this->modules['transaction'] = new Doctrine_Connection_Transaction($this); + //$this->modules['transaction'] = new Doctrine_Connection_Transaction($this); $this->modules['unitOfWork'] = new Doctrine_Connection_UnitOfWork($this); $this->setParent($manager); @@ -782,11 +782,11 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun switch($record->getState()): case Doctrine_Record::STATE_TDIRTY: - $this->transaction->insert($record); + $this->unitOfWork->insert($record); break; case Doctrine_Record::STATE_DIRTY: case Doctrine_Record::STATE_PROXY: - $this->transaction->update($record); + $this->unitOfWork->update($record); break; case Doctrine_Record::STATE_CLEAN: case Doctrine_Record::STATE_TCLEAN: diff --git a/lib/Doctrine/Connection/Transaction.php b/lib/Doctrine/Connection/Transaction.php index 3a4eaf22d..8522ebf4a 100644 --- a/lib/Doctrine/Connection/Transaction.php +++ b/lib/Doctrine/Connection/Transaction.php @@ -63,16 +63,6 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { * @var array $invalid an array containing all invalid records within this transaction */ protected $invalid = array(); - /** - * @var array $update two dimensional pending update list, the records in - * this list will be updated when transaction is committed - */ - protected $update = array(); - /** - * @var array $insert two dimensional pending insert list, the records in - * this list will be inserted when transaction is committed - */ - protected $insert = array(); /** * @var array $delete two dimensional pending delete list, the records in * this list will be deleted when transaction is committed @@ -164,6 +154,7 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { $this->rollback(); $tmp = $this->invalid; + $this->invalid = array(); throw new Doctrine_Validator_Exception($tmp); @@ -326,22 +317,6 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { return true; } - /** - * adds record into pending insert list - * @param Doctrine_Record $record - */ - public function addInsert(Doctrine_Record $record) { - $name = $record->getTable()->getComponentName(); - $this->insert[$name][] = $record; - } - /** - * adds record into penging update list - * @param Doctrine_Record $record - */ - public function addUpdate(Doctrine_Record $record) { - $name = $record->getTable()->getComponentName(); - $this->update[$name][] = $record; - } /** * adds record into pending delete list * @param Doctrine_Record $record @@ -349,7 +324,7 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { public function addDelete(Doctrine_Record $record) { $name = $record->getTable()->getComponentName(); $this->delete[$name][] = $record; - } + } /** * addInvalid * adds record into invalid records list @@ -365,22 +340,7 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { $this->invalid[] = $record; return true; } - /** - * 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 * diff --git a/lib/Doctrine/Connection/UnitOfWork.php b/lib/Doctrine/Connection/UnitOfWork.php index 0e78c9b22..553dae870 100644 --- a/lib/Doctrine/Connection/UnitOfWork.php +++ b/lib/Doctrine/Connection/UnitOfWork.php @@ -235,6 +235,102 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module implemen } } } + /** + * updates the given record + * + * @param Doctrine_Record $record + * @return boolean + */ + public function update(Doctrine_Record $record) { + $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreUpdate($record); + + $array = $record->getPrepared(); + + if(empty($array)) + return false; + + $set = array(); + foreach($array as $name => $value): + $set[] = $name." = ?"; + + if($value instanceof Doctrine_Record) { + switch($value->getState()): + case Doctrine_Record::STATE_TCLEAN: + case Doctrine_Record::STATE_TDIRTY: + $record->save(); + default: + $array[$name] = $value->getIncremented(); + $record->set($name, $value->getIncremented()); + endswitch; + } + endforeach; + + $params = array_values($array); + $id = $record->obtainIdentifier(); + + + if( ! is_array($id)) + $id = array($id); + + $id = array_values($id); + $params = array_merge($params, $id); + + + $sql = "UPDATE ".$record->getTable()->getTableName()." SET ".implode(", ",$set)." WHERE ".implode(" = ? AND ",$record->getTable()->getPrimaryKeys())." = ?"; + + $stmt = $this->conn->getDBH()->prepare($sql); + $stmt->execute($params); + + $record->assignIdentifier(true); + + $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onUpdate($record); + + return true; + } + /** + * inserts a record into database + * + * @param Doctrine_Record $record record to be inserted + * @return boolean + */ + public function insert(Doctrine_Record $record) { + // listen the onPreInsert event + $record->getTable()->getAttribute(Doctrine::ATTR_LISTENER)->onPreInsert($record); + + $array = $record->getPrepared(); + + if(empty($array)) + return false; + + $table = $record->getTable(); + $keys = $table->getPrimaryKeys(); + + + $seq = $record->getTable()->getSequenceName(); + + if( ! empty($seq)) { + $id = $this->nextId($seq); + $name = $record->getTable()->getIdentifier(); + $array[$name] = $id; + } + + $this->conn->insert($table->getTableName(), $array); + + if(count($keys) == 1 && $keys[0] == $table->getIdentifier()) { + $id = $this->conn->getDBH()->lastInsertID(); + + if( ! $id) + $id = $table->getMaxIdentifier(); + + $record->assignIdentifier($id); + } else + $record->assignIdentifier(true); + + // listen the onInsert event + $table->getAttribute(Doctrine::ATTR_LISTENER)->onInsert($record); + + return true; + } public function getIterator() { } public function count() { } diff --git a/lib/Doctrine/DataDict/Sqlite.php b/lib/Doctrine/DataDict/Sqlite.php index 630606de2..ca19ce671 100644 --- a/lib/Doctrine/DataDict/Sqlite.php +++ b/lib/Doctrine/DataDict/Sqlite.php @@ -115,13 +115,12 @@ class Doctrine_DataDict_Sqlite extends Doctrine_Connection_Module { return ''; } /** - * Maps a native array description of a field to a MDB2 datatype and length + * Maps a native array description of a field to Doctrine datatype and length * * @param array $field native field description - * @author Lukas Smith (PEAR MDB2 library) * @return array containing the various possible types, length, sign, fixed */ - public function getDoctrineDeclaration($field) { + public function getPortableDeclaration($field) { $db_type = strtolower($field['type']); $length = !empty($field['length']) ? $field['length'] : null; $unsigned = !empty($field['unsigned']) ? $field['unsigned'] : null; diff --git a/lib/Doctrine/Transaction.php b/lib/Doctrine/Transaction.php index 7190094db..6795379bb 100644 --- a/lib/Doctrine/Transaction.php +++ b/lib/Doctrine/Transaction.php @@ -46,6 +46,15 @@ class Doctrine_Transaction extends Doctrine_Connection_Module { * @var integer $transaction_level the nesting level of transactions, used by transaction methods */ protected $transactionLevel = 0; + /** + * @var array $invalid an array containing all invalid records within this transaction + */ + protected $invalid = array(); + /** + * @var array $delete two dimensional pending delete list, the records in + * this list will be deleted when transaction is committed + */ + protected $delete = array(); /** * getState * returns the state of this connection @@ -65,6 +74,67 @@ class Doctrine_Transaction extends Doctrine_Connection_Module { return Doctrine_Transaction::STATE_BUSY; } } + /** + * adds record into pending delete list + * @param Doctrine_Record $record + */ + public function addDelete(Doctrine_Record $record) { + $name = $record->getTable()->getComponentName(); + $this->delete[$name][] = $record; + } + /** + * addInvalid + * adds record into invalid records list + * + * @param Doctrine_Record $record + * @return boolean false if record already existed in invalid records list, + * otherwise true + */ + public function addInvalid(Doctrine_Record $record) { + if(in_array($record, $this->invalid)) + return false; + + $this->invalid[] = $record; + return true; + } + + /** + * returns the pending delete list + * + * @return array + */ + public function getDeletes() { + return $this->delete; + } + /** + * bulkDelete + * deletes all records from the pending delete list + * + * @return void + */ + public function bulkDelete() { + foreach($this->delete as $name => $deletes) { + $record = false; + $ids = array(); + foreach($deletes as $k => $record) { + $ids[] = $record->getIncremented(); + $record->assignIdentifier(false); + } + if($record instanceof Doctrine_Record) { + $params = substr(str_repeat("?, ",count($ids)),0,-2); + + $query = 'DELETE FROM ' + . $record->getTable()->getTableName() + . ' WHERE ' + . $record->getTable()->getIdentifier() + . ' IN(' . $params . ')'; + + $this->conn->execute($query, $ids); + } + + } + $this->delete = array(); + } /** * getTransactionLevel * get the current transaction nesting level @@ -87,7 +157,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module { * @return integer current transaction nesting level */ public function beginTransaction($savepoint = null) { - $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionBegin($this->conn); + if( ! is_null($savepoint)) { if($this->transactionLevel == 0) @@ -95,13 +165,17 @@ class Doctrine_Transaction extends Doctrine_Connection_Module { $this->createSavePoint($savepoint); } else { - if($this->transactionLevel == 0) - $this->conn->getDbh()->beginTransaction(); + if($this->transactionLevel == 0) { + $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionBegin($this->conn); + + $this->conn->getDbh()->beginTransaction(); + + $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionBegin($this->conn); + } } $level = ++$this->transactionLevel; - $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionBegin($this->conn); return $level; } @@ -131,7 +205,7 @@ class Doctrine_Transaction extends Doctrine_Connection_Module { if($this->transactionLevel == 0) { $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionCommit($this->conn); - /** + try { $this->bulkDelete(); @@ -140,15 +214,15 @@ class Doctrine_Transaction extends Doctrine_Connection_Module { throw new Doctrine_Connection_Transaction_Exception($e->__toString()); } - */ - /** - if($tmp = $this->conn->unitOfWork->getInvalid()) { + if( ! empty($this->invalid)) { $this->rollback(); + + $tmp = $this->invalid; + $this->invalid = array(); throw new Doctrine_Validator_Exception($tmp); } - */ - + $this->conn->getDbh()->commit(); //$this->conn->unitOfWork->reset(); @@ -172,15 +246,16 @@ class Doctrine_Transaction extends Doctrine_Connection_Module { * @return void */ public function rollback($savepoint = null) { - if($this->transactionLevel == 0) - throw new Doctrine_Transaction_Exception('Rollback cannot be done. There is no active transaction.'); + //if($this->transactionLevel == 0) + // throw new Doctrine_Transaction_Exception('Rollback cannot be done. There is no active transaction.'); $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionRollback($this->conn); if ( ! is_null($savepoint)) { $this->rollbackSavePoint($savepoint); } else { - $this->unitOfWork->reset(); + //$this->conn->unitOfWork->reset(); + $this->deteles = array(); $this->transactionLevel = 0; diff --git a/lib/Doctrine/Validator.php b/lib/Doctrine/Validator.php index cf3a56fea..68a3ebe83 100644 --- a/lib/Doctrine/Validator.php +++ b/lib/Doctrine/Validator.php @@ -80,16 +80,10 @@ class Doctrine_Validator { $errorStack = $record->getErrorStack(); - switch($record->getState()): - case Doctrine_Record::STATE_TDIRTY: - case Doctrine_Record::STATE_TCLEAN: - // all fields will be validated - $data = $record->getData(); - break; - default: - // only the modified fields will be validated - $data = $record->getModified(); - endswitch; + + // if record is transient all fields will be validated + // if record is persistent only the modified fields will be validated + $data = ($record->exists()) ? $record->getModified() : $record->getData(); $err = array(); foreach($data as $key => $value) { diff --git a/tests/ConnectionTestCase.php b/tests/ConnectionTestCase.php index 9d030d634..1ed167988 100644 --- a/tests/ConnectionTestCase.php +++ b/tests/ConnectionTestCase.php @@ -224,7 +224,7 @@ class Doctrine_ConnectionTestCase extends Doctrine_UnitTestCase { $this->assertTrue($this->connection->getIterator() instanceof ArrayIterator); } public function testGetState() { - $this->assertEqual($this->connection->transaction->getState(),Doctrine_Connection_Transaction::STATE_OPEN); + $this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_SLEEP); $this->assertEqual(Doctrine_Lib::getConnectionStateAsString($this->connection->transaction->getState()), "open"); } public function testGetTables() { @@ -234,9 +234,9 @@ class Doctrine_ConnectionTestCase extends Doctrine_UnitTestCase { public function testTransactions() { $this->connection->beginTransaction(); - $this->assertEqual($this->connection->transaction->getState(),Doctrine_Connection_Transaction::STATE_ACTIVE); + $this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_ACTIVE); $this->connection->commit(); - $this->assertEqual($this->connection->transaction->getState(),Doctrine_Connection_Transaction::STATE_OPEN); + $this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_SLEEP); $this->connection->beginTransaction(); @@ -254,24 +254,24 @@ class Doctrine_ConnectionTestCase extends Doctrine_UnitTestCase { public function testRollback() { $this->connection->beginTransaction(); $this->assertEqual($this->connection->transaction->getTransactionLevel(),1); - $this->assertEqual($this->connection->transaction->getState(), Doctrine_Connection_Transaction::STATE_ACTIVE); + $this->assertEqual($this->connection->transaction->getState(), Doctrine_Transaction::STATE_ACTIVE); $this->connection->rollback(); - $this->assertEqual($this->connection->transaction->getState(), Doctrine_Connection_Transaction::STATE_OPEN); + $this->assertEqual($this->connection->transaction->getState(), Doctrine_Transaction::STATE_SLEEP); $this->assertEqual($this->connection->transaction->getTransactionLevel(),0); } public function testNestedTransactions() { $this->assertEqual($this->connection->transaction->getTransactionLevel(),0); $this->connection->beginTransaction(); $this->assertEqual($this->connection->transaction->getTransactionLevel(),1); - $this->assertEqual($this->connection->transaction->getState(),Doctrine_Connection_Transaction::STATE_ACTIVE); + $this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_ACTIVE); $this->connection->beginTransaction(); - $this->assertEqual($this->connection->transaction->getState(),Doctrine_Connection_Transaction::STATE_BUSY); + $this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_BUSY); $this->assertEqual($this->connection->transaction->getTransactionLevel(),2); $this->connection->commit(); - $this->assertEqual($this->connection->transaction->getState(),Doctrine_Connection_Transaction::STATE_ACTIVE); + $this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_ACTIVE); $this->assertEqual($this->connection->transaction->getTransactionLevel(),1); $this->connection->commit(); - $this->assertEqual($this->connection->transaction->getState(),Doctrine_Connection_Transaction::STATE_OPEN); + $this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_SLEEP); $this->assertEqual($this->connection->transaction->getTransactionLevel(),0); } } diff --git a/tests/ConnectionTransactionTestCase.php b/tests/ConnectionTransactionTestCase.php index 3d01eabb4..4032f56d1 100644 --- a/tests/ConnectionTransactionTestCase.php +++ b/tests/ConnectionTransactionTestCase.php @@ -168,7 +168,7 @@ class Doctrine_Connection_Transaction_TestCase extends Doctrine_UnitTestCase { $users->delete(); - $this->assertEqual($listener->pop(), 'onPreDelete'); + $this->assertEqual($listener->pop(), 'onDelete'); $this->assertTrue($count, count($this->dbh)); diff --git a/tests/DataDict/SqliteTestCase.php b/tests/DataDict/SqliteTestCase.php index fa88af253..3372184fb 100644 --- a/tests/DataDict/SqliteTestCase.php +++ b/tests/DataDict/SqliteTestCase.php @@ -35,7 +35,7 @@ class Doctrine_DataDict_Sqlite_TestCase extends Doctrine_Driver_UnitTestCase { public function testYearMapsToIntegerAndDate() { $this->assertDeclarationType('year', array('integer','date')); } - public function testSomething( ){ + public function testSomething() { /** $this->assertEqual($this->getDeclaration('clob'), array(array('integer', 'boolean'), 1, false, null)); diff --git a/tests/DriverTestCase.php b/tests/DriverTestCase.php index 8dda4cdef..e93b89036 100644 --- a/tests/DriverTestCase.php +++ b/tests/DriverTestCase.php @@ -79,7 +79,7 @@ class Doctrine_Driver_UnitTestCase extends UnitTestCase { $this->assertEqual($dec[0], $type2); } public function getDeclaration($type) { - return $this->dataDict->getDoctrineDeclaration(array('type' => $type, 'name' => 'colname', 'length' => 1, 'fixed' => true)); + return $this->dataDict->getPortableDeclaration(array('type' => $type, 'name' => 'colname', 'length' => 1, 'fixed' => true)); } public function init() { $this->adapter = new AdapterMock($this->driverName); diff --git a/tests/ExportFirebirdTestCase.php b/tests/ExportFirebirdTestCase.php index f13508a14..cbe165b07 100644 --- a/tests/ExportFirebirdTestCase.php +++ b/tests/ExportFirebirdTestCase.php @@ -19,6 +19,35 @@ class Doctrine_Export_Firebird_TestCase extends Doctrine_Export_TestCase { $this->pass(); } } + public function testCreateTableSupportsAutoincPks() { + $name = 'mytable'; + + $fields = array('id' => array('type' => 'integer', 'unsigned' => 1, 'autoincrement' => true)); + $this->export->createTable($name, $fields); + + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mytable (id SERIAL PRIMARY KEY)'); + } + public function testCreateTableSupportsDefaultAttribute() { + $name = 'mytable'; + $fields = array('name' => array('type' => 'char', 'length' => 10, 'default' => 'def'), + 'type' => array('type' => 'integer', 'length' => 3, 'default' => 12) + ); + + $options = array('primary' => array('name', 'type')); + $this->export->createTable($name, $fields, $options); + + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mytable (name CHAR(10) DEFAULT \'def\', type INT DEFAULT 12, PRIMARY KEY(name, type))'); + } + public function testCreateTableSupportsMultiplePks() { + $name = 'mytable'; + $fields = array('name' => array('type' => 'char', 'length' => 10), + 'type' => array('type' => 'integer', 'length' => 3)); + + $options = array('primary' => array('name', 'type')); + $this->export->createTable($name, $fields, $options); + + $this->assertEqual($this->adapter->pop(), 'CREATE TABLE mytable (name CHAR(10), type INT, PRIMARY KEY(name, type))'); + } } ?> diff --git a/tests/run.php b/tests/run.php index 1236fd0e6..f873f20dc 100644 --- a/tests/run.php +++ b/tests/run.php @@ -122,28 +122,29 @@ print '
';
 
 $test = new GroupTest('Doctrine Framework Unit Tests');
 
-
-
+ /**
 $test->addTestCase(new Doctrine_Connection_Mysql_TestCase());
 
 $test->addTestCase(new Doctrine_Export_Mysql_TestCase());
 
+$test->addTestCase(new Doctrine_Export_Oracle_TestCase());
+
+$test->addTestCase(new Doctrine_Export_Pgsql_TestCase());
+
+$test->addTestCase(new Doctrine_Export_Firebird_TestCase());
+
 foreach($drivers as $driver) {
     $class = 'Doctrine_DataDict_' . $driver . '_TestCase'; 
     
     $test->addTestCase(new $class());
 }
 
- /**
-$test->addTestCase(new Doctrine_DataDict_Sqlite_TestCase());
+
+
 $test->addTestCase(new Doctrine_Configurable_TestCase());
 
 
-$test->addTestCase(new Doctrine_Export_Firebird_TestCase());
 
-$test->addTestCase(new Doctrine_Export_Pgsql_TestCase());
-
-$test->addTestCase(new Doctrine_Export_Oracle_TestCase());
 
 
 $test->addTestCase(new Doctrine_Transaction_TestCase());
@@ -158,8 +159,8 @@ $test->addTestCase(new Doctrine_Transaction_Firebird_TestCase());
 
 $test->addTestCase(new Doctrine_Transaction_Sqlite_TestCase());
 
-$test->addTestCase(new Doctrine_Transaction_Mssql_TestCase());
-/**
+$test->addTestCase(new Doctrine_Transaction_Mssql_TestCase());  */
+
 $test->addTestCase(new Doctrine_Relation_ManyToMany_TestCase());
 
 $test->addTestCase(new Doctrine_UnitOfWork_TestCase());
@@ -250,7 +251,7 @@ $test->addTestCase(new Doctrine_Query_Where_TestCase());
 $test->addTestCase(new Doctrine_Query_Limit_TestCase());
 
 $test->addTestCase(new Doctrine_Query_Select_TestCase());
-*/
+
 
 
 //$test->addTestCase(new Doctrine_Cache_Query_SqliteTestCase());