Commit 072008b6 authored by romanb's avatar romanb

moved managed record/entity handling to the UnitOfWork. identity maps are the...

moved managed record/entity handling to the UnitOfWork. identity maps are the next. started to remove obsolete table stuff.
parent 2739ed84
......@@ -31,12 +31,21 @@
class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializable
{
/**
* The name of the domain class that is mapped to the database with this metadata.
* The name of the entity class that is mapped to the database with this metadata.
*
* @var string
*/
protected $_entityName;
/**
* The name of the entity class that is at the root of the entity inheritance
* hierarchy. If the entity is not part of an inheritance hierarchy this is the same
* as the $_entityName.
*
* @var string
*/
protected $_rootEntityName;
/**
* The name of the custom mapper class used for the entity class.
*
......@@ -259,6 +268,7 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
public function __construct($entityName, Doctrine_Connection $conn)
{
$this->_entityName = $entityName;
$this->_rootEntityName = $entityName;
$this->_conn = $conn;
$this->_parser = new Doctrine_Relation_Parser($this);
$this->_filters[] = new Doctrine_Record_Filter_Standard();
......@@ -283,6 +293,11 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
return $this->_entityName;
}
public function getRootClassName()
{
return $this->_rootEntityName;
}
/**
* @deprecated
*/
......@@ -648,12 +663,23 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
* Gets the identifier (primary key) field(s) of the mapped class.
*
* @return mixed
* @deprecated Use getIdentifierFieldNames()
*/
public function getIdentifier()
{
return $this->_identifier;
}
/**
* Gets the identifier (primary key) field(s) of the mapped class.
*
* @return mixed
*/
public function getIdentifierFieldNames()
{
return $this->_identifier;
}
public function setIdentifier(array $identifier)
{
$this->_identifier = $identifier;
......@@ -1107,6 +1133,7 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
public function setParentClasses(array $classNames)
{
$this->_options['parents'] = $classNames;
$this->_rootEntityName = array_pop($classNames);
}
/**
......
......@@ -482,7 +482,12 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
*/
public function set($key, $record)
{
if( ! $record instanceOf Doctrine_Record) {
if ( ! $record instanceOf Doctrine_Record) {
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString() . "<br/><br/>";
}
throw new Doctrine_Record_Exception('Value variable in set is not an instance of Doctrine_Record');
}
......
......@@ -664,7 +664,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$query .= implode(', ', $a) . ')';
// prepare and execute the statement
return $this->exec($query, array_values($data));
}
......@@ -1264,7 +1264,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
public function flush()
{
$this->beginInternalTransaction();
$this->unitOfWork->saveAll();
$this->unitOfWork->flush();
$this->commit();
}
......@@ -1277,9 +1277,9 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
*/
public function clear()
{
$this->unitOfWork->detachAllManagedEntities();
foreach ($this->_mappers as $mapper) {
$mapper->getRepository()->evictAll();
$mapper->clear();
$mapper->clear(); // clear identity map of each mapper
}
}
......@@ -1292,6 +1292,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
*/
public function evictTables()
{
$this->clear();
$this->tables = array();
$this->_mappers = array();
$this->exported = array();
......
......@@ -88,20 +88,27 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
{
// 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 $name) {
$mapper = $this->conn->getMapper($name);
foreach ($mapper->getRepository() as $record) {
$mapper->saveSingleRecord($record);
foreach ($tree as $className => $entities) {
$mapper = $this->conn->getMapper($className);
foreach ($entities as $entity) {
$mapper->saveSingleRecord($entity);
}
}
// save all associations
foreach ($tree as $name) {
$mapper = $this->conn->getMapper($name);
foreach ($mapper->getRepository() as $record) {
$mapper->saveAssociations($record);
foreach ($tree as $className => $entities) {
$mapper = $this->conn->getMapper($className);
foreach ($entities as $entity) {
$mapper->saveAssociations($entity);
}
}
}
......@@ -142,7 +149,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
}
$nm = $mapper->getComponentName();
$index = array_search($nm, $tree);
$index = array_search($nm, $tree);
if ($index === false) {
$tree[] = $nm;
......@@ -162,7 +169,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
foreach ($rels as $rel) {
$name = $rel->getTable()->getComponentName();
$index2 = array_search($name,$tree);
$index2 = array_search($name, $tree);
$type = $rel->getType();
// skip self-referenced relations
......@@ -187,7 +194,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
continue;
unset($tree[$index2]);
array_splice($tree,$index,0,$name);
array_splice($tree, $index, 0, $name);
} else {
array_unshift($tree,$name);
$index++;
......@@ -196,8 +203,9 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
$t = $rel->getAssociationFactory();
$n = $t->getComponentName();
if ($index2 !== false)
if ($index2 !== false) {
unset($tree[$index2]);
}
array_splice($tree, $index, 0, $name);
$index++;
......@@ -218,7 +226,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
}
}
return array_values($tree);
return $tree;
}
/**
......@@ -234,4 +242,83 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
return $this->flush();
}
/**
* Adds an entity to the pool of managed entities.
*
*/
public function addManagedEntity(Doctrine_Record $entity)
{
$oid = $entity->getOid();
if ( ! isset($this->_managedEntities[$oid])) {
$this->_managedEntities[$oid] = $entity;
return true;
}
return false;
}
/**
* get
* @param integer $oid
* @throws Doctrine_Table_Repository_Exception
*/
public function getManagedEntity($oid)
{
if ( ! isset($this->_managedEntities[$oid])) {
throw new Doctrine_Connection_UnitOfWork_Exception("Unknown object identifier '$oid'.");
}
return $this->_managedEntities[$oid];
}
/**
* @param integer $oid object identifier
* @return boolean whether ot not the operation was successful
*/
public function detachManagedEntity(Doctrine_Record $entity)
{
$oid = $entity->getOid();
if ( ! isset($this->_managedEntities[$oid])) {
return false;
}
unset($this->_managedEntities[$oid]);
return true;
}
/**
* @return integer number of records evicted
*/
public function detachAllManagedEntities()
{
$evicted = 0;
foreach ($this->_managedEntities as $entity) {
if ($this->detachManagedEntity($entity)) {
$evicted++;
}
}
return $evicted;
}
/**
* contains
* @param integer $oid object identifier
*/
public function isManagedEntity($oid)
{
return isset($this->_managedEntities[$oid]);
}
/**
* Adds an entity to the identity map.
*
*/
public function addToIdentityMap(Doctrine_Record $entity)
{
$id = implode(' ', $entity->identifier());
$className = $entity->getClassMetadata()->getRootClassName();
if (isset($this->_identityMap[$className][$id])) {
return false;
}
$this->_identityMap[$className][$id] = $entity;
return true;
}
}
......@@ -58,15 +58,15 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
/**
* @var array $identityMap first level cache
* @todo Proper identity map implementation & move elsewhere?
* @todo Move to UnitOfWork.
*/
protected $_identityMap = array();
/**
* @var Doctrine_Table_Repository $repository record repository
* @todo Needed? What is it used for? Does the identity map not suffice?
* @todo Move to UnifOfWork together with identity map.
*/
protected $_repository;
//protected $_repository;
/**
......@@ -78,11 +78,19 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
*/
public function __construct($name, Doctrine_ClassMetadata $classMetadata)
{
if ($name != $classMetadata->getClassName()) {
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString() . "<br/><br/>";
}
}
$this->_domainClassName = $name;
$this->_conn = $classMetadata->getConnection();
$this->_classMetadata = $classMetadata;
$this->setParent($this->_conn);
$this->_repository = new Doctrine_Table_Repository($this);
//$this->_repository = new Doctrine_Table_Repository($this);
if ($classMetadata->getInheritanceType() == Doctrine::INHERITANCETYPE_JOINED) {
$this->_mappingStrategy = new Doctrine_Mapper_JoinedStrategy($this);
} else {
......@@ -141,10 +149,10 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
* @return Doctrine_Table_Repository
* @todo refactor
*/
public function getRepository()
/*public function getRepository()
{
return $this->_repository;
}
}*/
/**
* sets the connection for this class
......@@ -184,6 +192,11 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
return $record;
}
public function detach(Doctrine_Record $entity)
{
return $this->_conn->unitOfWork->detachManagedEntity($entity);
}
/**
* Finds an entity by its primary key.
......@@ -310,7 +323,7 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
*/
public function manage(Doctrine_Record $record)
{
return $this->getRepository()->add($record);
return $this->_conn->unitOfWork->addManagedEntity($record);
}
/**
......@@ -864,17 +877,6 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
return true;
}
/**
* Updates an entity.
*/
/*protected function _doUpdate(Doctrine_Record $record)
{
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $this->_classMetadata);
$data = $this->_convertFieldToColumnNames($record->getPrepared(), $this->_classMetadata);
$this->_conn->update($this->_classMetadata->getTableName(), $data, $identifier);
$record->assignIdentifier(true);
}*/
/**
* Inserts an entity.
*
......@@ -900,60 +902,6 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
return true;
}
/**
* Inserts a single entity into the database, without any related entities.
*
* @param Doctrine_Record $record The entity to insert.
*/
/*protected function _doInsert(Doctrine_Record $record)
{
$fields = $record->getPrepared();
if (empty($fields)) {
return false;
}
if ($record->getClassMetadata() !== $this->_classMetadata) {
echo $record->getClassMetadata()->getClassname() . ' != ' . $this->_classMetadata->getClassName() . "<br /><br />";
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString() . "<br /><br />";
}
}
//$class = $record->getClassMetadata();
$class = $this->_classMetadata;
$identifier = (array) $class->getIdentifier();
$fields = $this->_convertFieldToColumnNames($fields, $class);
$seq = $class->getTableOption('sequenceName');
if ( ! empty($seq)) {
$id = $this->_conn->sequence->nextId($seq);
$seqName = $class->getIdentifier();
$fields[$seqName] = $id;
$record->assignIdentifier($id);
}
$this->_conn->insert($class->getTableName(), $fields);
if (empty($seq) && count($identifier) == 1 && $identifier[0] == $class->getIdentifier() &&
$class->getIdentifierType() != Doctrine::IDENTIFIER_NATURAL) {
if (strtolower($this->_conn->getName()) == 'pgsql') {
$seq = $class->getTableName() . '_' . $identifier[0];
}
$id = $this->_conn->sequence->lastInsertId($seq);
if ( ! $id) {
throw new Doctrine_Mapper_Exception("Couldn't get last insert identifier.");
}
$record->assignIdentifier($id);
} else {
$record->assignIdentifier(true);
}
}*/
/**
* Deletes given entity and all it's related entities.
*
......@@ -999,50 +947,6 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
return true;
}
/**
* Deletes an entity.
*/
/*protected function _doDelete(Doctrine_Record $record)
{
try {
$this->_conn->beginInternalTransaction();
$this->_deleteComposites($record);
$record->state(Doctrine_Record::STATE_TDIRTY);
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $this->_classMetadata);
$this->_conn->delete($this->_classMetadata->getTableName(), $identifier);
$record->state(Doctrine_Record::STATE_TCLEAN);
$this->removeRecord($record);
$this->_conn->commit();
} catch (Exception $e) {
$this->_conn->rollback();
throw $e;
}
}*/
/**
* deletes all related composites
* this method is always called internally when a record is deleted
*
* @throws PDOException if something went wrong at database level
* @return void
*/
/*protected function _deleteComposites(Doctrine_Record $record)
{
foreach ($this->_classMetadata->getRelations() as $fk) {
if ($fk->isComposite()) {
$obj = $record->get($fk->getAlias());
if ($obj instanceof Doctrine_Record &&
$obj->state() != Doctrine_Record::STATE_LOCKED) {
$obj->delete($this->_conn);
}
}
}
}*/
public function executeQuery(Doctrine_Query $query)
{
......@@ -1073,16 +977,6 @@ class Doctrine_Mapper extends Doctrine_Configurable implements Countable
$this->_mappingStrategy = null;
}
/*public function addToWhere($componentAlias, array &$sqlWhereParts, Doctrine_Query $query)
{
}
public function addToFrom($sqlString, Doctrine_Query $query)
{
}*/
public function getFieldName($columnName)
{
return $this->_mappingStrategy->getFieldName($columnName);
......
......@@ -81,7 +81,9 @@ class Doctrine_Mapper_DefaultStrategy extends Doctrine_Mapper_Strategy
$fields[$seqName] = $id;
$record->assignIdentifier($id);
}
//echo $class->getTableName() . "--" . $class->getClassName() . '---' . get_class($record) . "<br/>";
$this->_insertRow($class->getTableName(), $fields);
if (empty($seq) && count($identifier) == 1 &&
......
......@@ -656,7 +656,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
}
}
$this->_mapper->getRepository()->add($this);
$this->_mapper->manage($this);
$this->cleanData($this->_data);
$this->_extractIdentifier($this->exists());
......@@ -928,6 +928,11 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
{
$this->_values[$name] = $value;
}
public function getClassName()
{
return $this->_entityName;
}
/**
* set
......@@ -1897,7 +1902,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count
*/
public function free()
{
$this->_mapper->getRepository()->evict($this->_oid);
$this->_mapper->detach($this);
$this->_mapper->removeRecord($this);
$this->_data = array();
$this->_id = array();
......
......@@ -76,9 +76,6 @@ abstract class Doctrine_Relation implements ArrayAccess
'equal' => false,
'refClass' => false, // the name of the association class (many-many)
'refTable' => false, // the association table object (many-many)
'refRelationName' => false,
'refReverseRelationName' => false,
);
/**
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Exception');
/**
* thrown when user tries to initialize a new instance of Doctrine_Table,
* while there already exists an instance of that table
*
* @package Doctrine
* @subpackage Table
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_Table_Exception extends Doctrine_Exception
{
public function __construct($message = "Couldn't initialize table. One instance of this
table already exists. Always use Doctrine_Session::getTable(\$name)
to get on instance of a Doctrine_Table.") {
parent::__construct($message);
}
}
\ No newline at end of file
This diff is collapsed.
<?php
class Doctrine_Table_Factory_Exception extends Doctrine_Table_Exception {}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
/**
* Doctrine_Repository
* each record is added into Doctrine_Repository at the same time they are created,
* loaded from the database or retrieved from the cache
*
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @package Doctrine
* @subpackage Table
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
*/
class Doctrine_Table_Repository implements Countable, IteratorAggregate
{
/**
* @var object Doctrine_Table $table
*/
private $table;
/**
* @var array $registry
* an array of all records
* keys representing record object identifiers
*/
private $registry = array();
/**
* constructor
*
* @param Doctrine_Table $table
*/
public function __construct($mapper)
{
$this->table = $mapper;
}
/**
* getTable
*
* @return object Doctrine_Table
*/
public function getTable()
{
return $this->table;
}
/**
* add
*
* @param Doctrine_Record $record record to be added into registry
* @return boolean
*/
public function add(Doctrine_Record $record)
{
$oid = $record->getOID();
if (isset($this->registry[$oid])) {
return false;
}
$this->registry[$oid] = $record;
return true;
}
/**
* get
* @param integer $oid
* @throws Doctrine_Table_Repository_Exception
*/
public function get($oid)
{
if ( ! isset($this->registry[$oid])) {
throw new Doctrine_Table_Repository_Exception("Unknown object identifier");
}
return $this->registry[$oid];
}
/**
* count
* Doctrine_Registry implements interface Countable
* @return integer the number of records this registry has
*/
public function count()
{
return count($this->registry);
}
/**
* @param integer $oid object identifier
* @return boolean whether ot not the operation was successful
*/
public function evict($oid)
{
if ( ! isset($this->registry[$oid])) {
return false;
}
unset($this->registry[$oid]);
return true;
}
/**
* @return integer number of records evicted
*/
public function evictAll()
{
$evicted = 0;
foreach ($this->registry as $oid => $record) {
if ($this->evict($oid)) {
$evicted++;
}
}
return $evicted;
}
/**
* getIterator
* @return ArrayIterator
*/
public function getIterator()
{
return new ArrayIterator($this->registry);
}
/**
* contains
* @param integer $oid object identifier
*/
public function contains($oid)
{
return isset($this->registry[$oid]);
}
/**
* loadAll
* @return void
*/
public function loadAll()
{
$this->table->findAll();
}
}
\ No newline at end of file
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Exception');
/**
* Doctrine_Table_Repository_Exception
*
* @package Doctrine
* @subpackage Table
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_Table_Repository_Exception extends Doctrine_Exception
{ }
\ No newline at end of file
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