Commit 3d8a37b2 authored by romanb's avatar romanb

Refactorings along with a speed improvement on the Hydrator when processing...

Refactorings along with a speed improvement on the Hydrator when processing joined resultsets. Other minor tweaks.
parent 42ec3c94
......@@ -389,6 +389,11 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
}
if ( ! isset($this->modules[$name])) {
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString() . "<br/><br/>";
}
throw new Doctrine_Connection_Exception('Unknown module / property ' . $name);
}
if ($this->modules[$name] === false) {
......@@ -1211,7 +1216,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
*/
public function getIterator()
{
return new ArrayIterator($this->tables);
return new ArrayIterator($this->_mappers);
}
/**
......
......@@ -38,6 +38,8 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
* A map of all currently managed entities.
*
* @var array
* @deprecated Only here to keep the saveAll() functionality working. We don't need
* this in the future.
*/
protected $_managedEntities = array();
......@@ -57,78 +59,95 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
protected $_autoflush = true;
/**
* A list of all postponed inserts.
* A list of all new entities.
*/
protected $_inserts = array();
protected $_newEntities = array();
/**
* A list of all postponed updates.
* A list of all dirty entities.
*/
protected $_updates = array();
protected $_dirtyEntities = array();
/**
* A list of all postponed deletes.
* A list of all removed entities.
*/
protected $_deletes = array();
protected $_removedEntities = array();
/**
* The EntityManager the unit of work belongs to.
*/
protected $_em;
/**
* The dbal connection used by the unit of work.
*
* @var Doctrine_Connection
* @todo Allow multiple connections for transparent master-slave replication.
* @todo Not needed in the future. Remove.
*/
protected $_conn;
/**
* Flushes the unit of work, executing all operations that have been postponed
* Commits the unit of work, executing all operations that have been postponed
* up to this point.
*
*/
public function flush()
public function commit()
{
// get the flush tree
$tree = $this->buildFlushTree($this->conn->getMappers());
$tree = array_combine($tree, array_fill(0, count($tree), array()));
foreach ($this->_managedEntities as $oid => $entity) {
$className = $entity->getClassName();
$tree[$className][] = $entity;
}
// save all records
foreach ($tree as $className => $entities) {
$mapper = $this->conn->getMapper($className);
foreach ($entities as $entity) {
$mapper->saveSingleRecord($entity);
}
}
$this->_orderCommits();
// save all associations
foreach ($tree as $className => $entities) {
$mapper = $this->conn->getMapper($className);
foreach ($entities as $entity) {
$mapper->saveAssociations($entity);
}
}
$this->_insertNew();
$this->_updateDirty();
$this->_deleteRemoved();
}
public function addInsert()
private function _orderCommits()
{
}
public function addUpdate()
/**
* Register a new entity.
*/
public function registerNew(Doctrine_Record $entity)
{
if (isset($this->_dirtyEntities[$entity->getOid()])) {
throw new Doctrine_Connection_Exception("Dirty object can't be registered as new.");
} else if (isset($this->_removedEntities[$entity->getOid()])) {
throw new Doctrine_Connection_Exception("Removed object can't be registered as new.");
}
$this->_newEntities[$entity->getOid()] = $entity;
}
public function addDelete()
/**
* Registers a clean entity.
*/
public function registerClean(Doctrine_Record $entity)
{
$this->registerIdentity($entity);
}
/**
* Registers a dirty entity.
*/
public function registerDirty(Doctrine_Record $entity)
{
if (isset($this->_removedEntities[$entity->getOid()])) {
throw new Doctrine_Connection_Exception("Removed object can't be registered as dirty.");
} else if (isset($this->_newEntities[$entity->getOid()])) {
throw new Doctrine_Connection_Exception("");
}
$this->_dirtyEntities[$entity->getOid()] = $entity;
}
/**
* Registers a deleted entity.
*/
public function registerDeleted(Doctrine_Record $entity)
{
$this->unregisterIdentity($entity);
$this->_removedEntities[$entity->getOid()] = $entity;
}
/**
* buildFlushTree
* builds a flush tree that is used in transactions
......@@ -239,7 +258,33 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
*/
public function saveAll()
{
return $this->flush();
$this->conn->beginInternalTransaction();
// get the flush tree
$tree = $this->buildFlushTree($this->conn->getMappers());
$tree = array_combine($tree, array_fill(0, count($tree), array()));
foreach ($this->_managedEntities as $oid => $entity) {
$className = $entity->getClassName();
$tree[$className][] = $entity;
}
// save all records
foreach ($tree as $className => $entities) {
$mapper = $this->conn->getMapper($className);
foreach ($entities as $entity) {
$mapper->saveSingleRecord($entity);
}
}
// save all associations
foreach ($tree as $className => $entities) {
$mapper = $this->conn->getMapper($className);
foreach ($entities as $entity) {
$mapper->saveAssociations($entity);
}
}
$this->conn->commit();
}
/**
......@@ -329,6 +374,11 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
return true;
}
public function clearIdentitiesForEntity($entityName)
{
$this->_identityMap[$entityName] = array();
}
public function unregisterIdentity(Doctrine_Record $entity)
{
$id = implode(' ', $entity->identifier());
......@@ -345,9 +395,14 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
return false;
}
public function containsIdentity(Doctrine_Record $entity)
public function getByIdentity($id, $rootClassName)
{
return $this->_identityMap[$rootClassName][$id];
}
public function containsIdentity($id, $rootClassName)
{
return isset($this->_identityMap[$rootClassName][$id]);
}
}
......@@ -78,15 +78,14 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$event = new Doctrine_Event(null, Doctrine_Event::HYDRATE, null);
//$s = microtime(true);
// Used variables during hydration
reset($this->_queryComponents);
$rootAlias = key($this->_queryComponents);
$rootComponentName = $this->_queryComponents[$rootAlias]['mapper']->getComponentName();
// if only one component is involved we can make our lives easier
$isSimpleQuery = count($this->_queryComponents) <= 1;
// Holds the resulting hydrated data structure
$result = array();
// Holds hydration listeners that get called during hydration
$listeners = array();
// Lookup map to quickly discover/lookup existing records in the result
......@@ -97,6 +96,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
// separated by a pipe '|' and grouped by component alias (r, u, i, ... whatever)
$id = array();
// Holds the resulting hydrated data structure
$result = $driver->getElementCollection($rootComponentName);
if ($stmt === false || $stmt === 0) {
......@@ -126,15 +126,21 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$table = $this->_queryComponents[$rootAlias]['table'];
$mapper = $this->_queryComponents[$rootAlias]['mapper'];
$componentName = $mapper->getComponentName();
// just event stuff
$event->set('data', $rowData[$rootAlias]);
$listeners[$componentName]->preHydrate($event);
$element = $driver->getElement($rowData[$rootAlias], $componentName);
$index = false;
//--
// Check for an existing element
$index = false;
if ($isSimpleQuery || ! isset($identifierMap[$rootAlias][$id[$rootAlias]])) {
$element = $driver->getElement($rowData[$rootAlias], $componentName);
// just event stuff
$event->set('data', $element);
$listeners[$componentName]->postHydrate($event);
//--
// do we need to index by a custom field?
if ($field = $this->_getCustomIndexField($rootAlias)) {
......@@ -164,16 +170,19 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
// (related) components.
foreach ($rowData as $dqlAlias => $data) {
$index = false;
$map = $this->_queryComponents[$dqlAlias];
$map = $this->_queryComponents[$dqlAlias];
$table = $map['table'];
$mapper = $map['mapper'];
$componentName = $mapper->getComponentName();
// just event stuff
$event->set('data', $data);
$listeners[$componentName]->preHydrate($event);
//--
$element = $driver->getElement($data, $componentName);
$parent = $map['parent'];
$parent = $map['parent'];
$relation = $map['relation'];
$relationAlias = $map['relation']->getAlias();
......@@ -188,15 +197,18 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$oneToOne = false;
// append element
if (isset($nonemptyComponents[$dqlAlias])) {
if ($isSimpleQuery || ! isset($identifierMap[$path][$id[$parent]][$id[$dqlAlias]])) {
if ( ! isset($identifierMap[$path][$id[$parent]][$id[$dqlAlias]])) {
// just event stuff
$event->set('data', $element);
$listeners[$componentName]->postHydrate($event);
//--
if ($field = $this->_getCustomIndexField($dqlAlias)) {
// TODO: we should check this earlier. Fields used in INDEXBY
// must be unique. Then this can be removed here.
if (isset($prev[$parent][$relationAlias][$field])) {
throw new Doctrine_Hydrator_Exception("Hydration failed. Found non-unique key mapping.");
throw Doctrine_Hydrator_Exception::nonUniqueKeyMapping();
} else if ( ! isset($element[$field])) {
throw new Doctrine_Hydrator_Exception("Hydration failed. Found a non-existent field '$field'.");
throw Doctrine_Hydrator_Exception::nonExistantFieldUsedAsIndex($field);
}
$prev[$parent][$relationAlias][$element[$field]] = $element;
} else {
......@@ -247,7 +259,11 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
* sets the last element of given data array / collection
* as previous element
*
* @param boolean|integer $index
* @param array $prev The array that contains the pointers to the latest element of each class.
* @param array|Collection The object collection.
* @param boolean|integer $index Index of the element in the collection.
* @param string $dqlAlias
* @param boolean $oneToOne Whether it is a single-valued association or not.
* @return void
* @todo Detailed documentation
*/
......
......@@ -31,4 +31,14 @@ Doctrine::autoload('Doctrine_Exception');
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_Hydrator_Exception extends Doctrine_Exception
{ }
\ No newline at end of file
{
public static function nonUniqueKeyMapping()
{
return new self("Hydration failed. Found non-unique key mapping.");
}
public static function nonExistantFieldUsedAsIndex($field)
{
return new self("Hydration failed. Found a non-existent field '$field'.");
}
}
\ No newline at end of file
......@@ -21,7 +21,7 @@
/**
* Doctrine_Hydrate_RecordDriver
* Hydration strategy used for creating collections of entity objects.
* Hydration strategy used for creating graphs of entity objects.
*
* @package Doctrine
* @subpackage Hydrate
......@@ -122,7 +122,7 @@ class Doctrine_Hydrator_RecordDriver
public function flush()
{
// take snapshots from all initialized collections
foreach ($this->_collections as $key => $coll) {
foreach ($this->_collections as $coll) {
$coll->takeSnapshot();
}
$this->_collections = array();
......
......@@ -29,7 +29,9 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision: 3406 $
* @link www.phpdoctrine.org
* @since 1.0
* @since 2.0
* @todo Move all finder stuff to EntityRepository.
* @todo Rename to "EntityPersister" or similar.
*/
class Doctrine_Mapper
{
......@@ -188,6 +190,7 @@ class Doctrine_Mapper
* @param $id database row id
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return mixed Array or Doctrine_Record or false if no result
* @todo Remove. Move to EntityRepository.
*/
public function find($id, $hydrationMode = null)
{
......@@ -208,6 +211,7 @@ class Doctrine_Mapper
*
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return Doctrine_Collection
* @todo Remove. Move to EntityRepository.
*/
public function findAll($hydrationMode = null)
{
......@@ -226,6 +230,7 @@ class Doctrine_Mapper
*
* @todo This actually takes DQL, not SQL, but it requires column names
* instead of field names. This should be fixed to use raw SQL instead.
* @todo Remove. Move to EntityRepository.
*/
public function findBySql($dql, array $params = array(), $hydrationMode = null)
{
......@@ -241,6 +246,7 @@ class Doctrine_Mapper
* @param array $params query parameters
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @return Doctrine_Collection
* @todo Remove. Move to EntityRepository.
*/
public function findByDql($dql, array $params = array(), $hydrationMode = null)
{
......@@ -276,6 +282,7 @@ class Doctrine_Mapper
public function clear()
{
$this->_identityMap = array();
//$this->_conn->unitOfWork->clearIdentitiesForEntity($this->_classMetadata->getRootClassName());
}
/**
......@@ -289,11 +296,15 @@ class Doctrine_Mapper
public function addRecord(Doctrine_Record $record)
{
$id = implode(' ', $record->identifier());
if (isset($this->_identityMap[$id])) {
return false;
}
/*if ($this->_conn->unitOfWork->containsIdentity($id, $record->getClassMetadata()->getRootClassname())) {
return false;
}*/
//$this->_conn->unitOfWork->registerIdentity($record);
$this->_identityMap[$id] = $record;
return true;
......@@ -327,6 +338,10 @@ class Doctrine_Mapper
unset($this->_identityMap[$id]);
return true;
}
/*if ($this->_conn->unitOfWork->containsIdentity($id, $record->getClassMetadata()->getRootClassName())) {
$this->_conn->unitOfWork->unregisterIdentity($record);
return true;
}*/
return false;
}
......@@ -363,10 +378,13 @@ class Doctrine_Mapper
$id = implode(' ', $id);
if (isset($this->_identityMap[$id])) {
//if ($this->_conn->unitOfWork->containsIdentity($id, $this->_classMetadata->getRootClassName())) {
$record = $this->_identityMap[$id];
//$record = $this->_conn->unitOfWork->getByIdentity($id, $this->_classMetadata->getRootClassName());
$record->hydrate($data);
} else {
$record = new $this->_domainClassName($this, false, $data);
//$this->_conn->unitOfWork->registerIdentity($record);
$this->_identityMap[$id] = $record;
}
$data = array();
......@@ -567,6 +585,7 @@ class Doctrine_Mapper
* @param string $value
* @param string $hydrationMode
* @return void
* @todo Remove. Move to EntityRepository.
*/
protected function findBy($fieldName, $value, $hydrationMode = null)
{
......@@ -580,6 +599,7 @@ class Doctrine_Mapper
* @param string $value
* @param string $hydrationMode
* @return void
* @todo Remove. Move to EntityRepository.
*/
protected function findOneBy($fieldName, $value, $hydrationMode = null)
{
......@@ -599,6 +619,7 @@ class Doctrine_Mapper
* @throws Doctrine_Mapper_Exception If the method called is an invalid find* method
* or no find* method at all and therefore an invalid
* method call.
* @todo Remove. Move to EntityRepository.
*/
public function __call($method, $arguments)
{
......
......@@ -31,6 +31,8 @@ Doctrine::autoload('Doctrine_Record_Abstract');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @todo Rename to "Entity". Split up into "Entity" and "ActiveRecord"???
* @todo Remove as many methods as possible.
*/
abstract class Doctrine_Record extends Doctrine_Access implements Countable, IteratorAggregate, Serializable
{
......@@ -242,6 +244,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
// set the default values for this record
$this->assignDefaultValues();
} else {
// TODO: registerClean() on UnitOfWork
$this->_state = Doctrine_Record::STATE_CLEAN;
if ($count < $this->_class->getColumnCount()) {
$this->_state = Doctrine_Record::STATE_PROXY;
......@@ -1107,6 +1110,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
*/
public function save(Doctrine_Connection $conn = null)
{
// TODO: Forward to EntityManager. There: registerNew() OR registerDirty() on UnitOfWork.
$this->_mapper->save($this, $conn);
}
......@@ -1467,6 +1471,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
*/
public function delete(Doctrine_Connection $conn = null)
{
// TODO: Forward to EntityManager. There: registerRemoved() on UnitOfWork
return $this->_mapper->delete($this, $conn);
}
......
......@@ -34,6 +34,8 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
{
public function testFlush()
{
$uow = $this->connection->unitOfWork;
$user = $this->connection->getTable('User')->find(4);
$this->assertTrue(is_numeric($user->Phonenumber[0]->entity_id));
......@@ -59,7 +61,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$this->assertTrue($user->Phonenumber[0]->entity_id instanceof User);
$this->assertTrue($user->Phonenumber[2]->entity_id instanceof User);
$this->connection->flush();
$uow->saveAll();
$this->assertTrue(is_numeric($user->Phonenumber[0]->entity_id));
......@@ -90,7 +92,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$user->Phonenumber = $coll;
$this->assertTrue($user->Phonenumber->count() == 0);
$this->connection->flush();
$uow->saveAll();
unset($user);
$user = $this->objTable->find(5);
......@@ -102,7 +104,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$this->assertTrue(is_numeric($user->Phonenumber[0]->entity_id));
$user->Phonenumber[1]->phonenumber = '123 123';
$this->connection->flush();
$uow->saveAll();
$this->assertEqual($user->Phonenumber->count(), 2);
......@@ -112,7 +114,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($user->Phonenumber->count(), 2);
$user->Phonenumber[3]->phonenumber = '123 123';
$this->connection->flush();
$uow->saveAll();
$this->assertEqual($user->Phonenumber->count(), 3);
unset($user);
......@@ -134,7 +136,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$user->Phonenumber['work']->phonenumber = '444 444';
$this->assertEqual($user->Phonenumber->count(), 2);
$this->connection->flush();
$uow->saveAll();
$this->assertEqual($user->Phonenumber->count(), 2);
unset($user);
......@@ -153,7 +155,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$user->Phonenumber = $coll;
$this->connection->flush();
$uow->saveAll();
$this->assertEqual($user->Phonenumber->count(), 3);
$user = $this->objTable->find(5);
$this->assertEqual($user->Phonenumber->count(), 3);
......@@ -163,7 +165,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$user->Email->address = 'drinker@drinkmore.info';
$this->assertTrue($user->Email instanceof Email);
$this->connection->flush();
$uow->saveAll();
$this->assertTrue($user->Email instanceof Email);
$user = $this->objTable->find(5);
$this->assertEqual($user->Email->address, 'drinker@drinkmore.info');
......@@ -177,7 +179,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$this->assertTrue($user->Email instanceof Email);
$this->assertEqual($user->Email->address, 'absolutist@nottodrink.com');
$this->connection->flush();
$uow->saveAll();
unset($user);
$user = $this->objTable->find(5);
......@@ -190,7 +192,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
public function testTransactions()
{
$uow = $this->connection->unitOfWork;
$this->connection->beginTransaction();
$this->assertEqual($this->connection->transaction->getState(),Doctrine_Transaction::STATE_ACTIVE);
$this->connection->commit();
......@@ -201,7 +203,7 @@ class Doctrine_Connection_UnitOfWork_TestCase extends Doctrine_UnitTestCase
$user = $this->objTable->find(6);
$user->name = 'Jack Daniels';
$this->connection->flush();
$uow->saveAll();
$this->connection->commit();
$user = $this->objTable->find(6);
......
......@@ -73,7 +73,7 @@ class Doctrine_CustomResultSetOrder_TestCase extends Doctrine_UnitTestCase {
// The second category gets 1 board!
$cat2->Boards[0] = $board4;
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
}
/**
......
......@@ -223,7 +223,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($user->Group[0]->name, "Action Actors");
$this->assertEqual(count($user->Group), 3);
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$this->assertEqual($user->Group[0]->name, "Action Actors");
$this->assertEqual(count($user->Group), 3);
......@@ -280,7 +280,7 @@ class Doctrine_Query_Limit_TestCase extends Doctrine_UnitTestCase
$coll[2]->name = "photo 3";
$coll[3]->Tag[0]->tag = "Other tag";
$coll[3]->name = "photo 4";
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$q = new Doctrine_Query();
$q->from('Photo')->where('Photo.Tag.id = ?')->orderby('Photo.id DESC')->limit(100);
......
......@@ -57,7 +57,7 @@ class Doctrine_Query_ReferenceModel_TestCase extends Doctrine_UnitTestCase {
$category->Subcategory[1]->Subcategory[0]->name = 'Sub 2 Sub 1';
$category->Subcategory[1]->Subcategory[1]->name = 'Sub 2 Sub 2';
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$this->connection->clear();
$category = $category->getMapper()->find($category->id);
......
......@@ -79,7 +79,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$account->amount = 2000;
$this->assertEqual($account->getTable()->getColumnNames(), array('id', 'entity_id', 'amount'));
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$this->assertEqual($user->state(), Doctrine_Record::STATE_CLEAN);
$this->assertTrue($account instanceof Account);
......@@ -342,7 +342,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$task->name = "Task 1";
$task->ResourceAlias[0]->name = "Resource 1";
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$this->assertTrue($task->ResourceAlias[0] instanceof Resource);
$this->assertEqual($task->ResourceAlias[0]->name, "Resource 1");
......@@ -366,7 +366,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($task->ResourceAlias->count(), 1);
$this->assertEqual($task->Subtask[0]->name, "Subtask 1");
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$task = $task->getMapper()->find($task->identifier());
......@@ -436,7 +436,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$elements = $this->connection->query("FROM Element");
$this->assertEqual($elements->count(), 5);
......
......@@ -19,7 +19,7 @@ class Doctrine_Relation_Access_TestCase extends Doctrine_UnitTestCase {
$us = array();
$us[1] = new MyUser();
$us[1]->name = "user1";
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
// OneThings
$onethings_gs = array(
array(6,1)
......@@ -65,7 +65,7 @@ class Doctrine_Relation_Access_TestCase extends Doctrine_UnitTestCase {
}
}
*/
$this->connection->flush();
$this->connection->unitOfWork->saveAll();
$this->connection->clear();
}
......
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