From 96177e3e22153f0ec7431ae859dd1ef0da967e38 Mon Sep 17 00:00:00 2001 From: zYne Date: Sun, 24 Sep 2006 19:38:45 +0000 Subject: [PATCH] Added unit tests to cover all eventlistener events, fixed fatal transaction bug --- Doctrine/Configurable.php | 60 +++++-- Doctrine/Connection/Transaction.php | 41 +++-- Doctrine/EventListener.php | 5 +- Doctrine/Record.php | 2 + Doctrine/Table.php | 2 +- ...ase.php => EventListenerChainTestCase.php} | 4 +- tests/EventListenerTestCase.php | 149 +++++++++++++++++- tests/RecordTestCase.php | 14 ++ tests/classes.php | 6 + 9 files changed, 241 insertions(+), 42 deletions(-) rename tests/{EventListenerTestChainCase.php => EventListenerChainTestCase.php} (91%) diff --git a/Doctrine/Configurable.php b/Doctrine/Configurable.php index 07ea6dcb2..b0dd831c4 100644 --- a/Doctrine/Configurable.php +++ b/Doctrine/Configurable.php @@ -45,7 +45,7 @@ abstract class Doctrine_Configurable { * @param mixed $value * @return void */ - final public function setAttribute($attribute,$value) { + public function setAttribute($attribute,$value) { switch($attribute): case Doctrine::ATTR_BATCH_SIZE: if($value < 0) @@ -126,13 +126,51 @@ abstract class Doctrine_Configurable { * @param Doctrine_EventListener $listener * @return void */ - final public function setEventListener($listener) { - $i = Doctrine::ATTR_LISTENER; - if( ! ($listener instanceof Doctrine_EventListener) && - ! ($listener instanceof Doctrine_EventListener_Chain)) - throw new Doctrine_Exception("EventListener must extend Doctrine_EventListener or Doctrine_EventListener_Chain"); + public function setEventListener($listener) { + return $this->setListener($listener); + } + /** + * addListener + * + * @param Doctrine_DB_EventListener_Interface|Doctrine_Overloadable $listener + * @return Doctrine_DB + */ + public function addListener($listener, $name = null) { + if( ! ($this->attributes[Doctrine::ATTR_LISTENER] instanceof Doctrine_EventListener_Chain)) + $this->attributes[Doctrine::ATTR_LISTENER] = new Doctrine_EventListener_Chain(); - $this->attributes[$i] = $listener; + $this->attributes[Doctrine::ATTR_LISTENER]->add($listener, $name); + + return $this; + } + /** + * getListener + * + * @return Doctrine_DB_EventListener_Interface|Doctrine_Overloadable + */ + public function getListener() { + if( ! isset($this->attributes[Doctrine::ATTR_LISTENER])) { + if(isset($this->parent)) + return $this->parent->getListener(); + + return null; + } + return $this->attributes[Doctrine::ATTR_LISTENER]; + } + /** + * setListener + * + * @param Doctrine_DB_EventListener_Interface|Doctrine_Overloadable $listener + * @return Doctrine_DB + */ + public function setListener($listener) { + if( ! ($listener instanceof Doctrine_EventListener_Interface) && + ! ($listener instanceof Doctrine_Overloadable)) + throw new Doctrine_DB_Exception("Couldn't set eventlistener. EventListeners should implement either Doctrine_EventListener_Interface or Doctrine_Overloadable"); + + $this->attributes[Doctrine::ATTR_LISTENER] = $listener; + + return $this; } /** * returns the value of an attribute @@ -140,7 +178,7 @@ abstract class Doctrine_Configurable { * @param integer $attribute * @return mixed */ - final public function getAttribute($attribute) { + public function getAttribute($attribute) { $attribute = (int) $attribute; if($attribute < 1 || $attribute > 17) @@ -160,7 +198,7 @@ abstract class Doctrine_Configurable { * * @return array */ - final public function getAttributes() { + public function getAttributes() { return $this->attributes; } /** @@ -170,7 +208,7 @@ abstract class Doctrine_Configurable { * @param Doctrine_Configurable $component * @return void */ - final public function setParent(Doctrine_Configurable $component) { + public function setParent(Doctrine_Configurable $component) { $this->parent = $component; } /** @@ -179,7 +217,7 @@ abstract class Doctrine_Configurable { * * @return Doctrine_Configurable */ - final public function getParent() { + public function getParent() { return $this->parent; } } diff --git a/Doctrine/Connection/Transaction.php b/Doctrine/Connection/Transaction.php index 8363c607f..1ac06711b 100644 --- a/Doctrine/Connection/Transaction.php +++ b/Doctrine/Connection/Transaction.php @@ -150,34 +150,31 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { $this->validator = new Doctrine_Validator(); try { - + $this->bulkInsert(); $this->bulkUpdate(); $this->bulkDelete(); - if($this->conn->getAttribute(Doctrine::ATTR_VLD)) { - - if($this->validator->hasErrors()) { - $this->rollback(); - throw new Doctrine_Validator_Exception($this->validator); - } - } - - $this->conn->getDBH()->commit(); - - } catch(PDOException $e) { + } catch(Exception $e) { $this->rollback(); throw new Doctrine_Exception($e->__toString()); } - + + if($this->conn->getAttribute(Doctrine::ATTR_VLD)) { + if($this->validator->hasErrors()) { + $this->rollback(); + throw new Doctrine_Validator_Exception($this->validator); + } + } + + $this->conn->getDBH()->commit(); + $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onTransactionCommit($this->conn); - $this->delete = array(); - $this->state = Doctrine_Connection_Transaction::STATE_OPEN; - + $this->state = Doctrine_Connection_Transaction::STATE_OPEN; $this->validator = null; - + } elseif($this->transaction_level == 1) $this->state = Doctrine_Connection_Transaction::STATE_ACTIVE; } @@ -192,6 +189,10 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { */ public function rollback() { $this->conn->getAttribute(Doctrine::ATTR_LISTENER)->onPreTransactionRollback($this->conn); + + $this->delete = array(); + $this->insert = array(); + $this->update = array(); $this->transaction_level = 0; $this->conn->getDBH()->rollback(); @@ -295,12 +296,18 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate { $record->assignIdentifier(false); } if($record instanceof Doctrine_Record) { + $table = $record->getTable(); + $table->getListener()->onPreDelete($record); + $params = substr(str_repeat("?, ",count($ids)),0,-2); $query = "DELETE FROM ".$record->getTable()->getTableName()." WHERE ".$table->getIdentifier()." IN(".$params.")"; $this->conn->execute($query,$ids); + + $table->getListener()->onDelete($record); } + } $this->delete = array(); } diff --git a/Doctrine/EventListener.php b/Doctrine/EventListener.php index 22341fa38..b71c4c9cb 100644 --- a/Doctrine/EventListener.php +++ b/Doctrine/EventListener.php @@ -79,7 +79,4 @@ abstract class Doctrine_EventListener implements Doctrine_EventListener_Interfac public function onCollectionDelete(Doctrine_Collection $collection) { } public function onPreCollectionDelete(Doctrine_Collection $collection) { } -} - - - +} diff --git a/Doctrine/Record.php b/Doctrine/Record.php index 652267f4d..c06240268 100644 --- a/Doctrine/Record.php +++ b/Doctrine/Record.php @@ -167,12 +167,14 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite // listen the onPreCreate event $this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreCreate($this); } else { + // listen the onPreLoad event $this->table->getAttribute(Doctrine::ATTR_LISTENER)->onPreLoad($this); } // get the data array $this->data = $this->table->getData(); + // get the column count $count = count($this->data); diff --git a/Doctrine/Table.php b/Doctrine/Table.php index 5153f5f99..c57b3db41 100644 --- a/Doctrine/Table.php +++ b/Doctrine/Table.php @@ -831,7 +831,7 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable { if(isset($this->identityMap[$id])) $record = $this->identityMap[$id]; - else { + else { $record = new $this->name($this); $this->identityMap[$id] = $record; } diff --git a/tests/EventListenerTestChainCase.php b/tests/EventListenerChainTestCase.php similarity index 91% rename from tests/EventListenerTestChainCase.php rename to tests/EventListenerChainTestCase.php index 4119d8e98..bf8fa31a1 100644 --- a/tests/EventListenerTestChainCase.php +++ b/tests/EventListenerChainTestCase.php @@ -1,6 +1,6 @@ hasColumn("name", "string", 100); } @@ -23,7 +23,7 @@ class Doctrine_EventListener_TestB extends Doctrine_EventListener { } } -class Doctrine_EventListenerChainTestCase extends Doctrine_UnitTestCase { +class Doctrine_EventListener_Chain_TestCase extends Doctrine_UnitTestCase { public function testEvents() { $connection = $this->manager->openConnection(Doctrine_DB::getConn("sqlite::memory:")); $debug = $this->listener->getMessages(); diff --git a/tests/EventListenerTestCase.php b/tests/EventListenerTestCase.php index cb159a8bd..9c8cf7d6a 100644 --- a/tests/EventListenerTestCase.php +++ b/tests/EventListenerTestCase.php @@ -15,15 +15,30 @@ class EventListenerTest extends Doctrine_Record { return md5($password); } } +class Doctrine_EventListener_TestLogger implements Doctrine_Overloadable, Countable { + private $messages = array(); + + public function __call($m, $a) { + + $this->messages[] = $m; + } + public function pop() { + return array_pop($this->messages); + } + public function clear() { + $this->messages = array(); + } + public function getAll() { + return $this->messages; + } + public function count() { + return count($this->messages); + } +} class Doctrine_EventListenerTestCase extends Doctrine_UnitTestCase { - public function testEvents() { - $connection = $this->manager->openConnection(Doctrine_DB::getConn("sqlite::memory:")); - $debug = $this->listener->getMessages(); - $last = end($debug); - $this->assertTrue($last->getObject() instanceof Doctrine_Connection); - $this->assertTrue($last->getCode() == Doctrine_EventListener_Debugger::EVENT_OPEN); - } + private $logger; + public function testAccessorInvoker() { $e = new EventListenerTest; $e->name = "something"; @@ -61,7 +76,127 @@ class Doctrine_EventListenerTestCase extends Doctrine_UnitTestCase { $this->assertEqual($e->name, 'SOMETHING'); $this->assertEqual($e->rawGet('name'), 'something'); $this->assertEqual($e->password, '202cb962ac59075b964b07152d234b70'); + } + public function testSetListener() { + $this->logger = new Doctrine_EventListener_TestLogger(); + + $e = new EventListenerTest; + + $e->getTable()->setListener($this->logger); + + $this->assertEqual($e->getTable()->getListener(), $this->logger); + } + public function testOnLoad() { + $this->logger->clear(); + $this->assertEqual($this->connection->getTable('EventListenerTest')->getListener(), $this->logger); + $this->connection->clear(); + + $e = $this->connection->getTable('EventListenerTest')->find(1); + + $this->assertEqual($e->getTable()->getListener(), $this->logger); + + $this->assertEqual($this->logger->pop(), 'onLoad'); + $this->assertEqual($this->logger->pop(), 'onPreLoad'); + } + + public function testOnCreate() { + $e = new EventListenerTest; + + + $e->setListener($this->logger); + $this->logger->clear(); + $e = new EventListenerTest; + + $this->assertEqual($this->logger->pop(), 'onCreate'); + $this->assertEqual($this->logger->pop(), 'onPreCreate'); + $this->assertEqual($this->logger->count(), 0); + } + public function testOnSleepAndOnWakeUp() { + $e = new EventListenerTest; + + $this->logger->clear(); + + $s = serialize($e); + + $this->assertEqual($this->logger->pop(), 'onSleep'); + $this->assertEqual($this->logger->count(), 0); + + $e = unserialize($s); + + $this->assertEqual($this->logger->pop(), 'onWakeUp'); + $this->assertEqual($this->logger->count(), 0); + } + public function testTransaction() { + $e = new EventListenerTest(); + $e->name = "test 1"; + + $this->logger->clear(); + + $e->save(); + + $this->assertEqual($this->logger->pop(), 'onSave'); + $this->assertEqual($this->logger->pop(), 'onInsert'); + $this->assertEqual($this->logger->pop(), 'onPreInsert'); + $this->assertEqual($this->logger->pop(), 'onPreSave'); + + $e->name = "test 2"; + + $e->save(); + + $this->assertEqual($this->logger->pop(), 'onSave'); + $this->assertEqual($this->logger->pop(), 'onUpdate'); + $this->assertEqual($this->logger->pop(), 'onPreUpdate'); + $this->assertEqual($this->logger->pop(), 'onPreSave'); + + $this->logger->clear(); + + $e->delete(); + + $this->assertEqual($this->logger->pop(), 'onDelete'); + $this->assertEqual($this->logger->pop(), 'onPreDelete'); + } + public function testTransactionWithConnectionListener() { + $e = new EventListenerTest(); + $e->getTable()->getConnection()->setListener($this->logger); + + $e->name = "test 2"; + + $this->logger->clear(); + + $e->save(); + + $this->assertEqual($this->logger->pop(), 'onTransactionCommit'); + $this->assertEqual($this->logger->pop(), 'onSave'); + $this->assertEqual($this->logger->pop(), 'onInsert'); + $this->assertEqual($this->logger->pop(), 'onPreInsert'); + $this->assertEqual($this->logger->pop(), 'onPreSave'); + $this->assertEqual($this->logger->pop(), 'onTransactionBegin'); + $this->assertEqual($this->logger->pop(), 'onPreTransactionBegin'); + + $e->name = "test 1"; + + $e->save(); + + $this->assertEqual($this->logger->pop(), 'onTransactionCommit'); + $this->assertEqual($this->logger->pop(), 'onSave'); + $this->assertEqual($this->logger->pop(), 'onUpdate'); + $this->assertEqual($this->logger->pop(), 'onPreUpdate'); + $this->assertEqual($this->logger->pop(), 'onPreSave'); + $this->assertEqual($this->logger->pop(), 'onTransactionBegin'); + $this->assertEqual($this->logger->pop(), 'onPreTransactionBegin'); + + $this->logger->clear(); + + $e->delete(); + + $this->assertEqual($this->logger->pop(), 'onTransactionCommit'); + $this->assertEqual($this->logger->pop(), 'onDelete'); + $this->assertEqual($this->logger->pop(), 'onPreDelete'); + $this->assertEqual($this->logger->pop(), 'onTransactionBegin'); + $this->assertEqual($this->logger->pop(), 'onPreTransactionBegin'); + } + public function prepareData() { } public function prepareTables() { $this->tables = array('EventListenerTest'); diff --git a/tests/RecordTestCase.php b/tests/RecordTestCase.php index 5dc8e548d..c6435280a 100644 --- a/tests/RecordTestCase.php +++ b/tests/RecordTestCase.php @@ -9,6 +9,20 @@ class Doctrine_RecordTestCase extends Doctrine_UnitTestCase { $this->tables[] = "GzipTest"; parent::prepareTables(); } + public function testNotNullConstraint() { + $null = new NotNullTest(); + + $null->name = null; + + $null->type = 1; + try { + $null->save(); + $this->fail(); + } catch(Doctrine_Exception $e) { + $this->pass(); + } + + } public function testGzipType() { $gzip = new GzipTest(); $gzip->gzip = "compressed"; diff --git a/tests/classes.php b/tests/classes.php index 42454e3ab..e7de9841a 100644 --- a/tests/classes.php +++ b/tests/classes.php @@ -453,6 +453,12 @@ class Data_File extends Doctrine_Record { $this->hasOne("File_Owner", "Data_File.file_owner_id"); } } +class NotNullTest extends Doctrine_Record { + public function setTableDefinition() { + $this->hasColumn("name", "string", 100, "notnull"); + $this->hasColumn("type", "integer", 11); + } +} class File_Owner extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn("name", "string", 255);