General work. Now using spl_object_hash.
This commit is contained in:
parent
6be6f40e84
commit
2395888feb
39 changed files with 665 additions and 1119 deletions
|
@ -1,12 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* A class loader used to load class files on demand.
|
||||
*
|
||||
* Usage recommendation:
|
||||
* 1) Use only 1 class loader instance.
|
||||
* 2) Prepend the base paths to your class libraries (including Doctrine's) to your include path.
|
||||
* 2) Set the base paths to your class libraries (including Doctrine's) through
|
||||
* $classLoader->setBasePath($prefix, $basePath);
|
||||
* Example:
|
||||
* $classLoader->setBasePath('Doctrine', '/usr/local/phplibs/doctrine/lib');
|
||||
* Then, when trying to load the class Doctrine\ORM\EntityManager, for example
|
||||
* the classloader will look for /usr/local/phplibs/doctrine/lib/Doctrine/ORM/EntityManager.php
|
||||
*
|
||||
* 3) DO NOT setCheckFileExists(true). Doing so is expensive in terms of performance.
|
||||
* 4) Use an opcode-cache (i.e. APC) (STRONGLY RECOMMENDED).
|
||||
*
|
||||
* @since 2.0
|
||||
* @author romanb <roman@code-factory.org>
|
||||
|
@ -16,7 +22,7 @@ class Doctrine_Common_ClassLoader
|
|||
private $_namespaceSeparator = '_';
|
||||
private $_fileExtension = '.php';
|
||||
private $_checkFileExists = false;
|
||||
private $_basePath;
|
||||
private $_basePaths = array();
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -38,19 +44,20 @@ class Doctrine_Common_ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets a static base path that is prepended to the path derived from the class itself.
|
||||
* Sets a static base path for classes with a certain prefix that is prepended
|
||||
* to the path derived from the class itself.
|
||||
*
|
||||
* @param string $basePath
|
||||
*/
|
||||
public function setBasePath($basePath)
|
||||
public function setBasePath($classPrefix, $basePath)
|
||||
{
|
||||
$this->_basePath = $basePath;
|
||||
$this->_basePaths[$classPrefix] = $basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $classname The name of the class to load.
|
||||
* @param string $classname The name of the class to load.
|
||||
* @return boolean TRUE if the class has been successfully loaded, FALSE otherwise.
|
||||
*/
|
||||
public function loadClass($className)
|
||||
|
@ -59,9 +66,10 @@ class Doctrine_Common_ClassLoader
|
|||
return false;
|
||||
}
|
||||
|
||||
$prefix = substr($className, 0, strpos($className, $this->_namespaceSeparator));
|
||||
$class = '';
|
||||
if ($this->_basePath) {
|
||||
$class .= $this->_basePath . DIRECTORY_SEPARATOR;
|
||||
if (isset($this->_basePaths[$prefix])) {
|
||||
$class .= $this->_basePaths[$prefix] . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
$class .= str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $className)
|
||||
. $this->_fileExtension;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::Common;
|
||||
#namespace Doctrine\Common;
|
||||
|
||||
/**
|
||||
* The EventManager is the central point of Doctrine's event listener system.
|
||||
|
@ -101,7 +101,7 @@ class Doctrine_Common_EventManager
|
|||
* Adds an EventSubscriber. The subscriber is asked for all the events he is
|
||||
* interested in and added as a listener for these events.
|
||||
*
|
||||
* @param Doctrine::Common::Event::EventSubscriber $subscriber The subscriber.
|
||||
* @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
|
||||
*/
|
||||
public function addEventSubscriber(Doctrine_Common_EventSubscriber $subscriber)
|
||||
{
|
||||
|
|
|
@ -22,8 +22,7 @@
|
|||
#namespace Doctrine\DBAL;
|
||||
|
||||
/**
|
||||
* The Configuration is the container for all configuration options of Doctrine.
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
* Configuration container for the Doctrine DBAL.
|
||||
*
|
||||
* INTERNAL: When adding a new configuration option just write a getter/setter
|
||||
* pair and add the option to the _attributes array with a proper default value.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PDO implementation of the driver Connection interface.
|
||||
* Used by all PDO-based drivers.
|
||||
|
@ -16,5 +15,3 @@ class Doctrine_DBAL_Driver_PDOConnection extends PDO implements Doctrine_DBAL_Dr
|
|||
$this->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
#namespace Doctrine::DBAL::Driver::PDOMySql;
|
||||
#namespace Doctrine\DBAL\Driver\PDOMySql;
|
||||
|
||||
#use Doctrine::DBAL::Driver;
|
||||
#use Doctrine\DBAL\Driver;
|
||||
|
||||
class Doctrine_DBAL_Driver_PDOMySql_Driver implements Doctrine_DBAL_Driver
|
||||
{
|
||||
|
|
|
@ -58,8 +58,8 @@ class Doctrine_DBAL_Driver_PDOSqlite_Driver implements Doctrine_DBAL_Driver
|
|||
/**
|
||||
* Gets the schema manager that is relevant for this driver.
|
||||
*
|
||||
* @param Doctrine::DBAL::Connection $conn
|
||||
* @return Doctrine::DBAL::Schema::AbstractSchemaManager
|
||||
* @param Doctrine\DBAL\Connection $conn
|
||||
* @return Doctrine\DBAL\Schema\AbstractSchemaManager
|
||||
*/
|
||||
public function getSchemaManager(Doctrine_DBAL_Connection $conn)
|
||||
{
|
||||
|
|
|
@ -2,5 +2,3 @@
|
|||
|
||||
class Doctrine_DBAL_Driver_PDOStatement extends PDOStatement implements Doctrine_DBAL_Driver_Statement
|
||||
{}
|
||||
|
||||
?>
|
|
@ -18,16 +18,16 @@
|
|||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::DBAL::Driver;
|
||||
|
||||
#namespace Doctrine\DBAL\Driver;
|
||||
|
||||
/**
|
||||
* Statement interface.
|
||||
* Drivers must implement this interface.
|
||||
*
|
||||
* This resembles the PDOStatement interface.
|
||||
* Statement interface.
|
||||
* Drivers must implement this interface.
|
||||
*
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* This resembles the PDOStatement interface.
|
||||
*
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::DBAL;
|
||||
#namespace Doctrine\DBAL;
|
||||
|
||||
/**
|
||||
* Factory for creating Doctrine::DBAL::Connection instances.
|
||||
* Factory for creating Doctrine\DBAL\Connection instances.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
|
@ -43,12 +43,13 @@ final class Doctrine_DBAL_DriverManager
|
|||
'pdo_firebird' => 'Doctrine_DBAL_Driver_PDOFirebird_Driver',
|
||||
'pdo_informix' => 'Doctrine_DBAL_Driver_PDOInformix_Driver',
|
||||
);
|
||||
|
||||
|
||||
/** Private constructor. This class cannot be instantiated. */
|
||||
private function __construct() {}
|
||||
|
||||
/**
|
||||
* Creates a connection object based on the specified parameters.
|
||||
* This method returns a Doctrine::DBAL::Connection which wraps the underlying
|
||||
* This method returns a Doctrine\DBAL\Connection which wraps the underlying
|
||||
* driver connection.
|
||||
*
|
||||
* $params must contain at least one of the following.
|
||||
|
@ -79,16 +80,16 @@ final class Doctrine_DBAL_DriverManager
|
|||
*
|
||||
* <b>pdo</b>:
|
||||
* You can pass an existing PDO instance through this parameter. The PDO
|
||||
* instance will be wrapped in a Doctrine::DBAL::Connection.
|
||||
* instance will be wrapped in a Doctrine\DBAL\Connection.
|
||||
*
|
||||
* <b>wrapperClass</b>:
|
||||
* You may specify a custom wrapper class through the 'wrapperClass'
|
||||
* parameter but this class MUST inherit from Doctrine::DBAL::Connection.
|
||||
* parameter but this class MUST inherit from Doctrine\DBAL\Connection.
|
||||
*
|
||||
* @param array $params The parameters.
|
||||
* @param Doctrine::Common::Configuration The configuration to use.
|
||||
* @param Doctrine::Common::EventManager The event manager to use.
|
||||
* @return Doctrine::DBAL::Connection
|
||||
* @param Doctrine\DBAL\Configuration The configuration to use.
|
||||
* @param Doctrine\Common\EventManager The event manager to use.
|
||||
* @return Doctrine\DBAL\Connection
|
||||
*/
|
||||
public static function getConnection(array $params,
|
||||
Doctrine_DBAL_Configuration $config = null,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::DBAL::Platforms;
|
||||
#namespace Doctrine\DBAL\Platforms;
|
||||
|
||||
/**
|
||||
* Base class for all DatabasePlatforms. The DatabasePlatforms are the central
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::ORM;
|
||||
#namespace Doctrine\ORM;
|
||||
|
||||
/**
|
||||
* A persistent collection.
|
||||
* A persistent collection wrapper.
|
||||
*
|
||||
* A collection object is strongly typed in the sense that it can only contain
|
||||
* entities of a specific type or one of it's subtypes. A collection object is
|
||||
|
@ -73,7 +73,7 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
protected $_snapshot = array();
|
||||
|
||||
/**
|
||||
* This entity that owns this collection.
|
||||
* The entity that owns this collection.
|
||||
*
|
||||
* @var Doctrine\ORM\Entity
|
||||
*/
|
||||
|
@ -468,7 +468,7 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
public function add($value, $key = null)
|
||||
{
|
||||
if ( ! $value instanceof $this->_entityBaseType) {
|
||||
throw new Doctrine_Record_Exception('Value variable in collection is not an instance of Doctrine_Entity.');
|
||||
throw new Doctrine_Exception('Invalid instance.');
|
||||
}
|
||||
|
||||
// TODO: Really prohibit duplicates?
|
||||
|
@ -511,121 +511,6 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
//TODO: Register collection as dirty with the UoW if necessary
|
||||
//$this->_changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* loadRelated
|
||||
*
|
||||
* @param mixed $name
|
||||
* @return boolean
|
||||
* @todo New implementation & maybe move elsewhere.
|
||||
*/
|
||||
/*public function loadRelated($name = null)
|
||||
{
|
||||
$list = array();
|
||||
$query = new Doctrine_Query($this->_mapper->getConnection());
|
||||
|
||||
if ( ! isset($name)) {
|
||||
foreach ($this->_data as $record) {
|
||||
// FIXME: composite key support
|
||||
$ids = $record->identifier();
|
||||
$value = count($ids) > 0 ? array_pop($ids) : null;
|
||||
if ($value !== null) {
|
||||
$list[] = $value;
|
||||
}
|
||||
}
|
||||
$query->from($this->_mapper->getComponentName()
|
||||
. '(' . implode(", ",$this->_mapper->getTable()->getPrimaryKeys()) . ')');
|
||||
$query->where($this->_mapper->getComponentName()
|
||||
. '.id IN (' . substr(str_repeat("?, ", count($list)),0,-2) . ')');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
$rel = $this->_mapper->getTable()->getRelation($name);
|
||||
|
||||
if ($rel instanceof Doctrine_Relation_LocalKey || $rel instanceof Doctrine_Relation_ForeignKey) {
|
||||
foreach ($this->_data as $record) {
|
||||
$list[] = $record[$rel->getLocal()];
|
||||
}
|
||||
} else {
|
||||
foreach ($this->_data as $record) {
|
||||
$ids = $record->identifier();
|
||||
$value = count($ids) > 0 ? array_pop($ids) : null;
|
||||
if ($value !== null) {
|
||||
$list[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dql = $rel->getRelationDql(count($list), 'collection');
|
||||
$coll = $query->query($dql, $list);
|
||||
|
||||
$this->populateRelated($name, $coll);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* populateRelated
|
||||
*
|
||||
* @param string $name
|
||||
* @param Doctrine_Collection $coll
|
||||
* @return void
|
||||
* @todo New implementation & maybe move elsewhere.
|
||||
*/
|
||||
/*protected function populateRelated($name, Doctrine_Collection $coll)
|
||||
{
|
||||
$rel = $this->_mapper->getTable()->getRelation($name);
|
||||
$table = $rel->getTable();
|
||||
$foreign = $rel->getForeign();
|
||||
$local = $rel->getLocal();
|
||||
|
||||
if ($rel instanceof Doctrine_Relation_LocalKey) {
|
||||
foreach ($this->_data as $key => $record) {
|
||||
foreach ($coll as $k => $related) {
|
||||
if ($related[$foreign] == $record[$local]) {
|
||||
$this->_data[$key]->_setRelated($name, $related);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ($rel instanceof Doctrine_Relation_ForeignKey) {
|
||||
foreach ($this->_data as $key => $record) {
|
||||
if ( ! $record->exists()) {
|
||||
continue;
|
||||
}
|
||||
$sub = new Doctrine_Collection($rel->getForeignComponentName());
|
||||
|
||||
foreach ($coll as $k => $related) {
|
||||
if ($related[$foreign] == $record[$local]) {
|
||||
$sub->add($related);
|
||||
$coll->remove($k);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_data[$key]->_setRelated($name, $sub);
|
||||
}
|
||||
} else if ($rel instanceof Doctrine_Relation_Association) {
|
||||
// @TODO composite key support
|
||||
$identifier = (array)$this->_mapper->getClassMetadata()->getIdentifier();
|
||||
$asf = $rel->getAssociationFactory();
|
||||
$name = $table->getComponentName();
|
||||
|
||||
foreach ($this->_data as $key => $record) {
|
||||
if ( ! $record->exists()) {
|
||||
continue;
|
||||
}
|
||||
$sub = new Doctrine_Collection($rel->getForeignComponentName());
|
||||
foreach ($coll as $k => $related) {
|
||||
$idField = $identifier[0];
|
||||
if ($related->get($local) == $record[$idField]) {
|
||||
$sub->add($related->get($name));
|
||||
}
|
||||
}
|
||||
$this->_data[$key]->_setRelated($name, $sub);
|
||||
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
|
@ -661,7 +546,8 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Returns the data of the last snapshot.
|
||||
* INTERNAL:
|
||||
* Returns the data of the last snapshot.
|
||||
*
|
||||
* @return array returns the data in last snapshot
|
||||
*/
|
||||
|
@ -671,7 +557,8 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Processes the difference of the last snapshot and the current data.
|
||||
* INTERNAL:
|
||||
* Processes the difference of the last snapshot and the current data.
|
||||
*
|
||||
* an example:
|
||||
* Snapshot with the objects 1, 2 and 4
|
||||
|
@ -719,7 +606,7 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
}
|
||||
|
||||
/**
|
||||
* Populate a Doctrine_Collection from an array of data.
|
||||
* Populate a Collection from an array of data.
|
||||
*
|
||||
* @param string $array
|
||||
* @return void
|
||||
|
@ -733,7 +620,7 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
}
|
||||
|
||||
/**
|
||||
* Synchronizes a Doctrine_Collection with data from an array.
|
||||
* Synchronizes a Collection with data from an array.
|
||||
*
|
||||
* it expects an array representation of a Doctrine_Collection similar to the return
|
||||
* value of the toArray() method. It will create Dectrine_Records that don't exist
|
||||
|
@ -760,7 +647,8 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: getDeleteDiff
|
||||
* INTERNAL:
|
||||
* getDeleteDiff
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -786,17 +674,17 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
*/
|
||||
protected function _compareRecords($a, $b)
|
||||
{
|
||||
if ($a->getOid() == $b->getOid()) {
|
||||
if ($a === $b) {
|
||||
return 0;
|
||||
}
|
||||
return ($a->getOid() > $b->getOid()) ? 1 : -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <type> $deep
|
||||
*/
|
||||
public function free($deep = false)
|
||||
/*public function free($deep = false)
|
||||
{
|
||||
foreach ($this->getData() as $key => $record) {
|
||||
if ( ! ($record instanceof Doctrine_Null)) {
|
||||
|
@ -810,8 +698,7 @@ class Doctrine_ORM_Collection implements Countable, IteratorAggregate, Serializa
|
|||
$this->_owner->free($deep);
|
||||
$this->_owner = null;
|
||||
}
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
/**
|
||||
* getIterator
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#use Doctrine\DBAL\Configuration;
|
||||
|
||||
/**
|
||||
* The Configuration is the container for all configuration options of Doctrine.
|
||||
* Configuration container for all configuration options of Doctrine.
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
*
|
||||
* INTERNAL: When adding a new configuration option just write a getter/setter
|
||||
|
@ -72,7 +72,7 @@ class Doctrine_ORM_Configuration extends Doctrine_DBAL_Configuration
|
|||
return $this->_attributes['metadataCacheImpl'];
|
||||
}
|
||||
|
||||
public function setMetadataCacheImpl(Doctrine_Cache_Interface $cacheImpl)
|
||||
public function setMetadataCacheImpl($cacheImpl)
|
||||
{
|
||||
$this->_attributes['metadataCacheImpl'] = $cacheImpl;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#namespace Doctrine\ORM;
|
||||
|
||||
#use \Serializable;
|
||||
|
||||
/**
|
||||
* Entity marker interface.
|
||||
*
|
||||
|
|
|
@ -86,14 +86,14 @@ class Doctrine_ORM_EntityManager
|
|||
/**
|
||||
* The database connection used by the EntityManager.
|
||||
*
|
||||
* @var Doctrine_Connection
|
||||
* @var Connection
|
||||
*/
|
||||
private $_conn;
|
||||
|
||||
/**
|
||||
* The metadata factory, used to retrieve the metadata of entity classes.
|
||||
*
|
||||
* @var Doctrine::ORM::Mapping::ClassMetadataFactory
|
||||
* @var Doctrine\ORM\Mapping\ClassMetadataFactory
|
||||
*/
|
||||
private $_metadataFactory;
|
||||
|
||||
|
@ -131,19 +131,8 @@ class Doctrine_ORM_EntityManager
|
|||
* @var EventManager
|
||||
*/
|
||||
private $_eventManager;
|
||||
|
||||
/**
|
||||
* Container that is used temporarily during hydration.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_tmpEntityData = array();
|
||||
|
||||
private $_idGenerators = array();
|
||||
|
||||
private $_closed = false;
|
||||
|
||||
private $_originalEntityData = array();
|
||||
|
||||
/**
|
||||
* Creates a new EntityManager that operates on the given database connection.
|
||||
|
@ -220,6 +209,7 @@ class Doctrine_ORM_EntityManager
|
|||
* Returns the metadata for a class.
|
||||
*
|
||||
* @return Doctrine_Metadata
|
||||
* @internal Performance-sensitive method.
|
||||
*/
|
||||
public function getClassMetadata($className)
|
||||
{
|
||||
|
@ -262,8 +252,7 @@ class Doctrine_ORM_EntityManager
|
|||
* Creates a new Query object.
|
||||
*
|
||||
* @param string The DQL string.
|
||||
* @return Doctrine::ORM::Query
|
||||
* @todo package:orm
|
||||
* @return Doctrine\ORM\Query
|
||||
*/
|
||||
public function createQuery($dql = "")
|
||||
{
|
||||
|
@ -271,7 +260,6 @@ class Doctrine_ORM_EntityManager
|
|||
if ( ! empty($dql)) {
|
||||
$query->setDql($dql);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
@ -281,16 +269,16 @@ class Doctrine_ORM_EntityManager
|
|||
* This is usually not of interest for users, mainly for internal use.
|
||||
*
|
||||
* @param string $entityName The name of the Entity.
|
||||
* @return Doctrine::ORM::Internal::EntityPersister
|
||||
* @return Doctrine\ORM\Persister\AbstractEntityPersister
|
||||
*/
|
||||
public function getEntityPersister($entityName)
|
||||
{
|
||||
if ( ! isset($this->_persisters[$entityName])) {
|
||||
$class = $this->getClassMetadata($entityName);
|
||||
if ($class->getInheritanceType() == Doctrine::INHERITANCE_TYPE_JOINED) {
|
||||
if ($class->getInheritanceType() == Doctrine_ORM_Mapping_ClassMetadata::INHERITANCE_TYPE_JOINED) {
|
||||
$persister = new Doctrine_EntityPersister_JoinedSubclass($this, $class);
|
||||
} else {
|
||||
$persister = new Doctrine_EntityPersister_Standard($this, $class);
|
||||
$persister = new Doctrine_ORM_Persisters_StandardEntityPersister($this, $class);
|
||||
}
|
||||
$this->_persisters[$entityName] = $persister;
|
||||
}
|
||||
|
@ -444,7 +432,7 @@ class Doctrine_ORM_EntityManager
|
|||
/**
|
||||
* Removes the given entity from the persistent store.
|
||||
*
|
||||
* @param Doctrine::ORM::Entity $entity
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Doctrine_ORM_Entity $entity)
|
||||
|
@ -506,93 +494,6 @@ class Doctrine_ORM_EntityManager
|
|||
return $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity. Used for reconstitution as well as initial creation.
|
||||
*
|
||||
* @param string $className The name of the entity class.
|
||||
* @param array $data The data for the entity.
|
||||
* @return Doctrine\ORM\Entity
|
||||
*/
|
||||
public function createEntity($className, array $data, Doctrine_Query $query = null)
|
||||
{
|
||||
$this->_errorIfNotActiveOrClosed();
|
||||
|
||||
$this->_tmpEntityData = $data;
|
||||
$className = $this->_inferCorrectClassName($data, $className);
|
||||
$classMetadata = $this->getClassMetadata($className);
|
||||
if ( ! empty($data)) {
|
||||
$identifierFieldNames = $classMetadata->getIdentifier();
|
||||
$isNew = false;
|
||||
foreach ($identifierFieldNames as $fieldName) {
|
||||
if ( ! isset($data[$fieldName])) {
|
||||
// id field not found return new entity
|
||||
$isNew = true;
|
||||
break;
|
||||
}
|
||||
$id[] = $data[$fieldName];
|
||||
}
|
||||
|
||||
if ($isNew) {
|
||||
$entity = new $className;
|
||||
} else {
|
||||
$idHash = $this->_unitOfWork->getIdentifierHash($id);
|
||||
$entity = $this->_unitOfWork->tryGetByIdHash($idHash, $classMetadata->getRootClassName());
|
||||
if ($entity) {
|
||||
$this->_mergeData($entity, $data/*, $classMetadata, $query->getHint('doctrine.refresh')*/);
|
||||
return $entity;
|
||||
} else {
|
||||
$entity = new $className;
|
||||
$this->_unitOfWork->addToIdentityMap($entity);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$entity = new $className;
|
||||
}
|
||||
|
||||
//$this->_originalEntityData[$entity->getOid()] = $data;
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the given data into the given entity, optionally overriding
|
||||
* local changes.
|
||||
*
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @param array $data
|
||||
* @param boolean $overrideLocalChanges
|
||||
* @return void
|
||||
*/
|
||||
private function _mergeData(Doctrine_ORM_Entity $entity, /*$class,*/ array $data, $overrideLocalChanges = false) {
|
||||
if ($overrideLocalChanges) {
|
||||
foreach ($data as $field => $value) {
|
||||
$entity->_internalSetField($field, $value);
|
||||
}
|
||||
} else {
|
||||
foreach ($data as $field => $value) {
|
||||
$currentValue = $entity->get($field);
|
||||
if ( ! isset($currentValue) || $entity->_internalGetField($field) === null) {
|
||||
$entity->_internalSetField($field, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NEW
|
||||
/*if ($overrideLocalChanges) {
|
||||
foreach ($data as $field => $value) {
|
||||
$class->getReflectionProperty($field)->setValue($entity, $value);
|
||||
}
|
||||
} else {
|
||||
foreach ($data as $field => $value) {
|
||||
$currentValue = $class->getReflectionProperty($field)->getValue($entity);
|
||||
if ( ! isset($this->_originalEntityData[$entity->getOid()]) ||
|
||||
$currentValue == $this->_originalEntityData[$entity->getOid()]) {
|
||||
$class->getReflectionProperty($field)->setValue($entity, $value);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the instance is managed by the EntityManager.
|
||||
*
|
||||
|
@ -606,51 +507,10 @@ class Doctrine_ORM_EntityManager
|
|||
! $this->_unitOfWork->isRegisteredRemoved($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: For internal hydration purposes only.
|
||||
*
|
||||
* Gets the temporarily stored entity data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function _getTmpEntityData()
|
||||
{
|
||||
$data = $this->_tmpEntityData;
|
||||
$this->_tmpEntityData = array();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the dataset for a discriminator column to determine the correct
|
||||
* class to instantiate. If no discriminator column is found, the given
|
||||
* classname will be returned.
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $className
|
||||
* @return string The name of the class to instantiate.
|
||||
*/
|
||||
private function _inferCorrectClassName(array $data, $className)
|
||||
{
|
||||
$class = $this->getClassMetadata($className);
|
||||
|
||||
$discCol = $class->getInheritanceOption('discriminatorColumn');
|
||||
if ( ! $discCol) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
$discMap = $class->getInheritanceOption('discriminatorMap');
|
||||
|
||||
if (isset($data[$discCol], $discMap[$data[$discCol]])) {
|
||||
return $discMap[$data[$discCol]];
|
||||
} else {
|
||||
return $className;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the EventManager used by the EntityManager.
|
||||
*
|
||||
* @return Doctrine::Common::EventManager
|
||||
* @return Doctrine\Common\EventManager
|
||||
*/
|
||||
public function getEventManager()
|
||||
{
|
||||
|
@ -660,7 +520,7 @@ class Doctrine_ORM_EntityManager
|
|||
/**
|
||||
* Gets the Configuration used by the EntityManager.
|
||||
*
|
||||
* @return Doctrine::Common::Configuration
|
||||
* @return Doctrine\ORM\Configuration
|
||||
*/
|
||||
public function getConfiguration()
|
||||
{
|
||||
|
@ -682,7 +542,7 @@ class Doctrine_ORM_EntityManager
|
|||
/**
|
||||
* Gets the UnitOfWork used by the EntityManager to coordinate operations.
|
||||
*
|
||||
* @return Doctrine::ORM::UnitOfWork
|
||||
* @return Doctrine\ORM\UnitOfWork
|
||||
*/
|
||||
public function getUnitOfWork()
|
||||
{
|
||||
|
@ -747,7 +607,7 @@ class Doctrine_ORM_EntityManager
|
|||
/**
|
||||
* Static lookup to get the currently active EntityManager.
|
||||
*
|
||||
* @return Doctrine::ORM::EntityManager
|
||||
* @return Doctrine\ORM\EntityManager
|
||||
*/
|
||||
public static function getActiveEntityManager()
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::ORM;
|
||||
#namespace Doctrine\ORM;
|
||||
|
||||
/**
|
||||
* A repository provides the illusion of an in-memory Entity store.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
#namespace Doctrine::ORM::Id;
|
||||
#namespace Doctrine\ORM\Id;
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
|
@ -8,17 +8,33 @@
|
|||
* @todo Rename to AbstractIdGenerator
|
||||
*/
|
||||
abstract class Doctrine_ORM_Id_AbstractIdGenerator
|
||||
{
|
||||
const POST_INSERT_INDICATOR = 'POST_INSERT_INDICATOR';
|
||||
|
||||
{
|
||||
protected $_em;
|
||||
|
||||
public function __construct(Doctrine_ORM_EntityManager $em)
|
||||
{
|
||||
$this->_em = $em;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates an identifier for an entity.
|
||||
*
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function generate($entity);
|
||||
|
||||
/**
|
||||
* Gets whether this generator is a post-insert generator which means that
|
||||
* {@link generate()} must be called after the entity has been inserted
|
||||
* into the database.
|
||||
* By default, this method returns FALSE. Generators that have this requirement
|
||||
* must override this method and return TRUE.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isPostInsertGenerator() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -4,23 +4,43 @@
|
|||
* Special generator for application-assigned identifiers (doesnt really generate anything).
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Doctrine_ORM_Id_Assigned extends Doctrine_ORM_Id_AbstractIdGenerator
|
||||
{
|
||||
/**
|
||||
* Enter description here...
|
||||
* Returns the identifier assigned to the given entity.
|
||||
*
|
||||
* @param Doctrine_ORM_Entity $entity
|
||||
* @return unknown
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return mixed
|
||||
* @override
|
||||
*/
|
||||
public function generate($entity)
|
||||
{
|
||||
if ( ! $entity->_identifier()) {
|
||||
throw new Doctrine_Exception("Entity '$entity' is missing an assigned Id");
|
||||
$class = $this->_em->getClassMetadata(get_class($entity));
|
||||
if ($class->isIdentifierComposite()) {
|
||||
$identifier = array();
|
||||
$idFields = $class->getIdentifierFieldNames();
|
||||
foreach ($idFields as $idField) {
|
||||
$identifier[] =
|
||||
$value = $class->getReflectionProperty($idField)->getValue($entity);
|
||||
if (isset($value)) {
|
||||
$identifier[] = $value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$value = $class->getReflectionProperty($class->getSingleIdentifierFieldName())
|
||||
->getValue($entity);
|
||||
if (isset($value)) {
|
||||
$identifier = array($value);
|
||||
}
|
||||
}
|
||||
return $entity->_identifier();
|
||||
|
||||
if ( ! $identifier) {
|
||||
throw new Doctrine_Exception("Entity '$entity' is missing an assigned ID.");
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -10,14 +10,16 @@ class Doctrine_ORM_Id_IdentityGenerator extends Doctrine_ORM_Id_AbstractIdGenera
|
|||
* @override
|
||||
*/
|
||||
public function generate($entity)
|
||||
{
|
||||
return self::POST_INSERT_INDICATOR;
|
||||
}
|
||||
|
||||
public function getPostInsertId()
|
||||
{
|
||||
return $this->_em->getConnection()->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* @override
|
||||
*/
|
||||
public function isPostInsertGenerator() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -19,7 +19,7 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::ORM::Internal;
|
||||
#namespace Doctrine\ORM\Internal;
|
||||
|
||||
/**
|
||||
* The CommitOrderCalculator is used by the UnitOfWork to sort out the
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::ORM::Internal;
|
||||
#namespace Doctrine\ORM\Internal;
|
||||
|
||||
/**
|
||||
* A CommitOrderNode is a temporary wrapper around ClassMetadata instances
|
||||
* that is used to sort the order of commits.
|
||||
* that is used to sort the order of commits in a UnitOfWork.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
|
@ -53,7 +53,7 @@ class Doctrine_ORM_Internal_CommitOrderNode
|
|||
* Creates a new node.
|
||||
*
|
||||
* @param mixed $wrappedObj The object to wrap.
|
||||
* @param Doctrine::ORM::Internal::CommitOrderCalculator $calc The calculator.
|
||||
* @param Doctrine\ORM\Internal\CommitOrderCalculator $calc The calculator.
|
||||
*/
|
||||
public function __construct($wrappedObj, Doctrine_ORM_Internal_CommitOrderCalculator $calc)
|
||||
{
|
||||
|
@ -155,7 +155,7 @@ class Doctrine_ORM_Internal_CommitOrderNode
|
|||
/**
|
||||
* Adds a directed dependency (an edge on the graph). "$this -before-> $other".
|
||||
*
|
||||
* @param Doctrine::ORM::Internal::CommitOrderNode $node
|
||||
* @param Doctrine\ORM\Internal\CommitOrderNode $node
|
||||
*/
|
||||
public function before(Doctrine_ORM_Internal_CommitOrderNode $node)
|
||||
{
|
||||
|
@ -163,4 +163,3 @@ class Doctrine_ORM_Internal_CommitOrderNode
|
|||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -19,7 +19,7 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::ORM::Internal::Hydration;
|
||||
#namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
/**
|
||||
* Defines an array hydration strategy.
|
||||
|
@ -32,8 +32,7 @@
|
|||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Doctrine_ORM_Internal_Hydration_ArrayDriver
|
||||
{
|
||||
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -66,8 +65,7 @@ class Doctrine_ORM_Internal_Hydration_ArrayDriver
|
|||
}
|
||||
}
|
||||
|
||||
public function addRelatedIndexedElement(array &$entity1, $property, array &$entity2,
|
||||
$indexField)
|
||||
public function addRelatedIndexedElement(array &$entity1, $property, array &$entity2, $indexField)
|
||||
{
|
||||
$entity1[$property][$entity2[$indexField]] = $entity2;
|
||||
}
|
||||
|
@ -134,7 +132,7 @@ class Doctrine_ORM_Internal_Hydration_ArrayDriver
|
|||
* last seen instance of each Entity type. This is used for graph construction.
|
||||
*
|
||||
* @param array $resultPointers The result pointers.
|
||||
* @param array|Collection $coll The element.
|
||||
* @param array $coll The element.
|
||||
* @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.
|
||||
|
|
|
@ -16,20 +16,21 @@
|
|||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
/**
|
||||
* Hydration strategy used for creating graphs of entities.
|
||||
* Defines the object hydration strategy.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @link www.doctrine-project.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @internal All the methods in this class are performance-sentitive.
|
||||
*/
|
||||
class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
||||
{
|
||||
|
@ -38,15 +39,18 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
|||
/** Memory for initialized relations */
|
||||
private $_initializedRelations = array();
|
||||
/** Null object */
|
||||
private $_nullObject;
|
||||
//private $_nullObject;
|
||||
/** The EntityManager */
|
||||
private $_em;
|
||||
private $_uow;
|
||||
private $_metadataMap = array();
|
||||
private $_entityData = array();
|
||||
|
||||
public function __construct(Doctrine_ORM_EntityManager $em)
|
||||
{
|
||||
$this->_nullObject = Doctrine_ORM_Internal_Null::$INSTANCE;
|
||||
//$this->_nullObject = Doctrine_ORM_Internal_Null::$INSTANCE;
|
||||
$this->_em = $em;
|
||||
$this->_uow = $this->_em->getUnitOfWork();
|
||||
}
|
||||
|
||||
public function getElementCollection($component)
|
||||
|
@ -59,7 +63,7 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
|||
public function getLastKey($coll)
|
||||
{
|
||||
// check needed because of mixed results.
|
||||
// is_object instead of is_array because is_array is slow.
|
||||
// is_object instead of is_array because is_array is slow on large arrays.
|
||||
if (is_object($coll)) {
|
||||
$coll->end();
|
||||
return $coll->key();
|
||||
|
@ -71,10 +75,8 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
|||
|
||||
public function initRelatedCollection($entity, $name)
|
||||
{
|
||||
//$class = get_class($entity);
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
$classMetadata = $this->_metadataMap[$oid];
|
||||
//$classMetadata = $this->_em->getClassMetadata(get_class($entity));
|
||||
if ( ! isset($this->_initializedRelations[$oid][$name])) {
|
||||
$relation = $classMetadata->getAssociationMapping($name);
|
||||
$relatedClass = $this->_em->getClassMetadata($relation->getTargetEntityName());
|
||||
|
@ -83,6 +85,7 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
|||
$coll->_setHydrationFlag(true);
|
||||
$classMetadata->getReflectionProperty($name)->setValue($entity, $coll);
|
||||
$this->_initializedRelations[$oid][$name] = true;
|
||||
$this->_uow->setOriginalEntityProperty($oid, $name, $coll);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,91 +96,102 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
|||
|
||||
public function getNullPointer()
|
||||
{
|
||||
return $this->_nullObject;
|
||||
//TODO: Return VirtualProxy if lazy association
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getElement(array $data, $className)
|
||||
{
|
||||
$entity = $this->_em->getUnitOfWork()->createEntity($className, $data);
|
||||
|
||||
$this->_metadataMap[spl_object_id($entity)] = $this->_em->getClassMetadata($className);
|
||||
|
||||
$oid = spl_object_hash($entity);
|
||||
$this->_metadataMap[$oid] = $this->_em->getClassMetadata($className);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an element to an indexed collection-valued property.
|
||||
*
|
||||
* @param <type> $entity1
|
||||
* @param <type> $property
|
||||
* @param <type> $entity2
|
||||
* @param <type> $indexField
|
||||
*/
|
||||
public function addRelatedIndexedElement($entity1, $property, $entity2, $indexField)
|
||||
{
|
||||
$classMetadata1 = $this->_metadataMap[spl_object_id($entity1)];
|
||||
$classMetadata2 = $this->_metadataMap[spl_object_id($entity2)];
|
||||
//$classMetadata1 = $this->_em->getClassMetadata(get_class($entity1));
|
||||
//$classMetadata2 = $this->_em->getClassMetadata(get_class($entity2));
|
||||
$classMetadata1 = $this->_metadataMap[spl_object_hash($entity1)];
|
||||
$classMetadata2 = $this->_metadataMap[spl_object_hash($entity2)];
|
||||
$indexValue = $classMetadata2->getReflectionProperty($indexField)->getValue($entity2);
|
||||
$classMetadata1->getReflectionProperty($property)->getValue($entity1)->add($entity2, $indexValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an element to a collection-valued property.
|
||||
*
|
||||
* @param <type> $entity1
|
||||
* @param <type> $property
|
||||
* @param <type> $entity2
|
||||
*/
|
||||
public function addRelatedElement($entity1, $property, $entity2)
|
||||
{
|
||||
$classMetadata1 = $this->_metadataMap[spl_object_id($entity1)];
|
||||
//$classMetadata1 = $this->_em->getClassMetadata(get_class($entity1));
|
||||
$classMetadata1->getReflectionProperty($property)
|
||||
->getValue($entity1)->add($entity2);
|
||||
$classMetadata1 = $this->_metadataMap[spl_object_hash($entity1)];
|
||||
$classMetadata1->getReflectionProperty($property)->getValue($entity1)->add($entity2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a related element.
|
||||
*
|
||||
* @param <type> $entity1
|
||||
* @param <type> $property
|
||||
* @param <type> $entity2
|
||||
*/
|
||||
public function setRelatedElement($entity1, $property, $entity2)
|
||||
{
|
||||
$classMetadata1 = $this->_metadataMap[spl_object_id($entity1)];
|
||||
//$classMetadata1 = $this->_em->getClassMetadata(get_class($entity1));
|
||||
$classMetadata1->getReflectionProperty($property)
|
||||
->setValue($entity1, $entity2);
|
||||
$oid = spl_object_hash($entity1);
|
||||
$classMetadata1 = $this->_metadataMap[$oid];
|
||||
$classMetadata1->getReflectionProperty($property)->setValue($entity1, $entity2);
|
||||
$this->_uow->setOriginalEntityProperty($oid, $property, $entity2);
|
||||
$relation = $classMetadata1->getAssociationMapping($property);
|
||||
if ($relation->isOneToOne()) {
|
||||
$targetClass = $this->_em->getClassMetadata($relation->getTargetEntityName());
|
||||
if ($relation->isOwningSide()) {
|
||||
// If there is an inverse mapping on the target class its bidirectional
|
||||
if ($targetClass->hasInverseAssociationMapping($property)) {
|
||||
$refProp = $targetClass->getReflectionProperty(
|
||||
$targetClass->getInverseAssociationMapping($fieldName)
|
||||
->getSourceFieldName());
|
||||
$refProp->setValue($entity2, $entity1);
|
||||
$oid2 = spl_object_hash($entity2);
|
||||
$sourceProp = $targetClass->getInverseAssociationMapping($fieldName)->getSourceFieldName();
|
||||
$targetClass->getReflectionProperty($sourceProp)->setValue($entity2, $entity1);
|
||||
$this->_entityData[$oid2][$sourceProp] = $entity1;
|
||||
}
|
||||
} else {
|
||||
// for sure bidirectional, as there is no inverse side in unidirectional
|
||||
$targetClass->getReflectionProperty($relation->getMappedByFieldName())
|
||||
->setValue($entity2, $entity1);
|
||||
$mappedByProp = $relation->getMappedByFieldName();
|
||||
$targetClass->getReflectionProperty($mappedByProp)->setValue($entity2, $entity1);
|
||||
$this->_entityData[spl_object_hash($entity2)][$mappedByProp] = $entity1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isIndexKeyInUse($entity, $assocField, $indexField)
|
||||
{
|
||||
return $this->_metadataMap[spl_object_id($entity)]->getReflectionProperty($assocField)
|
||||
return $this->_metadataMap[spl_object_hash($entity)]->getReflectionProperty($assocField)
|
||||
->getValue($entity)->containsKey($indexField);
|
||||
/*return $this->_em->getClassMetadata(get_class($entity))->getReflectionProperty($assocField)
|
||||
->getValue($entity)->containsKey($indexField);*/
|
||||
}
|
||||
|
||||
public function isFieldSet($entity, $field)
|
||||
{
|
||||
return $this->_metadataMap[spl_object_id($entity)]->getReflectionProperty($field)
|
||||
return $this->_metadataMap[spl_object_hash($entity)]->getReflectionProperty($field)
|
||||
->getValue($entity) !== null;
|
||||
/*return $this->_em->getClassMetadata(get_class($entity))->getReflectionProperty($field)
|
||||
->getValue($entity) !== null;*/
|
||||
}
|
||||
|
||||
public function getFieldValue($entity, $field)
|
||||
{
|
||||
return $this->_metadataMap[spl_object_id($entity)]->getReflectionProperty($field)
|
||||
return $this->_metadataMap[spl_object_hash($entity)]->getReflectionProperty($field)
|
||||
->getValue($entity);
|
||||
/*return $this->_em->getClassMetadata(get_class($entity))->getReflectionProperty($field)
|
||||
->getValue($entity);*/
|
||||
}
|
||||
|
||||
public function getReferenceValue($entity, $field)
|
||||
{
|
||||
return $this->_metadataMap[spl_object_id($entity)]->getReflectionProperty($field)
|
||||
return $this->_metadataMap[spl_object_hash($entity)]->getReflectionProperty($field)
|
||||
->getValue($entity);
|
||||
/*return $this->_em->getClassMetadata(get_class($entity))->getReflectionProperty($field)
|
||||
->getValue($entity);*/
|
||||
}
|
||||
|
||||
public function addElementToIndexedCollection($coll, $entity, $keyField)
|
||||
|
@ -195,14 +209,15 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
|||
* last seen instance of each Entity type. This is used for graph construction.
|
||||
*
|
||||
* @param array $resultPointers The result pointers.
|
||||
* @param array|Collection $coll The element.
|
||||
* @param Collection $coll The element.
|
||||
* @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.
|
||||
*/
|
||||
public function updateResultPointer(&$resultPointers, &$coll, $index, $dqlAlias, $oneToOne)
|
||||
{
|
||||
if ($coll === $this->_nullObject) {
|
||||
if ($coll === /*$this->_nullObject*/null) {
|
||||
echo "HERE!";
|
||||
unset($resultPointers[$dqlAlias]); // Ticket #1228
|
||||
return;
|
||||
}
|
||||
|
@ -230,10 +245,13 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
|
|||
foreach ($this->_collections as $coll) {
|
||||
$coll->_takeSnapshot();
|
||||
$coll->_setHydrationFlag(false);
|
||||
$this->_uow->addManagedCollection($coll);
|
||||
}
|
||||
// clean up
|
||||
$this->_collections = array();
|
||||
$this->_initializedRelations = array();
|
||||
$this->_metadataMap = array();
|
||||
$this->_entityData = array();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
/**
|
||||
* The hydrator has the tedious to process result sets returned by the database
|
||||
* The hydrator has the tedious task to process result sets returned by the database
|
||||
* and turn them into useable structures.
|
||||
*
|
||||
* Runtime complexity: The following gives the overall number of iterations
|
||||
|
@ -63,10 +63,6 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
*
|
||||
* This is method defines the core of Doctrine's object population algorithm.
|
||||
*
|
||||
* @todo: Detailed documentation. Refactor (too long & nesting level).
|
||||
*
|
||||
* @param mixed $stmt
|
||||
* @param array $tableAliases Array that maps table aliases (SQL alias => DQL alias)
|
||||
* @param array $aliasMap Array that maps DQL aliases to their components
|
||||
* (DQL alias => array(
|
||||
* 'metadata' => Table object,
|
||||
|
@ -134,8 +130,6 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
|
||||
// Initialize
|
||||
foreach ($this->_queryComponents as $dqlAlias => $component) {
|
||||
// disable lazy-loading of related elements during hydration
|
||||
//$component['metadata']->setAttribute('loadReferences', false);
|
||||
$identifierMap[$dqlAlias] = array();
|
||||
$resultPointers[$dqlAlias] = array();
|
||||
$idTemplate[$dqlAlias] = '';
|
||||
|
@ -152,7 +146,8 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
$result = $this->_gatherScalarRowData($result[0], $cache);
|
||||
return array_shift($result);
|
||||
}
|
||||
|
||||
|
||||
$resultCounter = 0;
|
||||
// Process result set
|
||||
while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
// Evaluate HYDRATE_SCALAR
|
||||
|
@ -178,12 +173,14 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
$result[] = array(
|
||||
$driver->getFieldValue($element, $field) => $element
|
||||
);
|
||||
++$resultCounter;
|
||||
} else {
|
||||
$driver->addElementToIndexedCollection($result, $element, $field);
|
||||
}
|
||||
} else {
|
||||
if ($parserResult->isMixedQuery()) {
|
||||
$result[] = array($element);
|
||||
++$resultCounter;
|
||||
} else {
|
||||
$driver->addElementToCollection($result, $element);
|
||||
}
|
||||
|
@ -226,7 +223,7 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
continue;
|
||||
}
|
||||
|
||||
// check the type of the relation (many or single-valued)
|
||||
// Check the type of the relation (many or single-valued)
|
||||
if ( ! $relation->isOneToOne()) {
|
||||
// x-to-many relation
|
||||
$oneToOne = false;
|
||||
|
@ -270,7 +267,6 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
$coll =& $baseElement[$relationAlias];
|
||||
} else {
|
||||
$coll = $driver->getReferenceValue($baseElement, $relationAlias);
|
||||
//$baseElement->_internalGetReference($relationAlias);
|
||||
}
|
||||
|
||||
if ($coll !== null) {
|
||||
|
@ -279,11 +275,9 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
}
|
||||
|
||||
// Append scalar values to mixed result sets
|
||||
//TODO: we dont need to count every time here, instead count with the loop
|
||||
if (isset($scalars)) {
|
||||
$rowNumber = count($result) - 1;
|
||||
foreach ($scalars as $name => $value) {
|
||||
$result[$rowNumber][$name] = $value;
|
||||
$result[$resultCounter - 1][$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,11 +285,6 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
$stmt->closeCursor();
|
||||
$driver->flush();
|
||||
|
||||
/*// re-enable lazy loading
|
||||
foreach ($this->_queryComponents as $dqlAlias => $data) {
|
||||
$data['metadata']->setAttribute('loadReferences', true);
|
||||
}*/
|
||||
|
||||
$e = microtime(true);
|
||||
echo 'Hydration took: ' . ($e - $s) . PHP_EOL;
|
||||
|
||||
|
@ -514,7 +503,6 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
}
|
||||
|
||||
/**
|
||||
* prepareValue
|
||||
* this method performs special data preparation depending on
|
||||
* the type of the given column
|
||||
*
|
||||
|
@ -536,6 +524,7 @@ class Doctrine_ORM_Internal_Hydration_StandardHydrator extends Doctrine_ORM_Inte
|
|||
* for the field can be skipped. Used i.e. during hydration to
|
||||
* improve performance on large and/or complex results.
|
||||
* @return mixed prepared value
|
||||
* @todo Remove. Should be handled by the Type classes. No need for this switch stuff.
|
||||
*/
|
||||
public function prepareValue(Doctrine_ClassMetadata $class, $fieldName, $value, $typeHint = null)
|
||||
{
|
||||
|
|
|
@ -18,20 +18,20 @@
|
|||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::ORM::Internal;
|
||||
|
||||
#namespace Doctrine\ORM\Internal;
|
||||
|
||||
/**
|
||||
* Null class representing a null value that has been fetched from
|
||||
* the database or a fetched, empty association. This is for internal use only.
|
||||
* User code should never deal with this null object.
|
||||
*
|
||||
* Semantics are as follows:
|
||||
*
|
||||
* Regular PHP null : Value is undefined. When a field with that value is accessed
|
||||
* and lazy loading is used the database is queried.
|
||||
*
|
||||
* Null object: Null valued of a field or empty association that has already been loaded.
|
||||
* Null class representing a null value that has been fetched from
|
||||
* the database or a fetched, empty association. This is for internal use only.
|
||||
* User code should never deal with this null object.
|
||||
*
|
||||
* Semantics are as follows:
|
||||
*
|
||||
* Regular PHP null : Value is undefined. When a field with that value is accessed
|
||||
* and lazy loading is used the database is queried.
|
||||
*
|
||||
* Null object: Null valued of a field or empty association that has already been loaded.
|
||||
* On access, the database is not queried.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
|
@ -39,6 +39,7 @@
|
|||
* @since 1.0
|
||||
* @version $Revision: 4723 $
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @todo No longer needed?
|
||||
*/
|
||||
// static initializer
|
||||
Doctrine_ORM_Internal_Null::$INSTANCE = new Doctrine_ORM_Internal_Null();
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* @since 2.0
|
||||
* @todo Rename to AssociationMapping.
|
||||
*/
|
||||
class Doctrine_ORM_Mapping_AssociationMapping implements Serializable
|
||||
abstract class Doctrine_ORM_Mapping_AssociationMapping implements Serializable
|
||||
{
|
||||
const FETCH_MANUAL = 1;
|
||||
const FETCH_LAZY = 2;
|
||||
|
@ -443,6 +443,8 @@ class Doctrine_ORM_Mapping_AssociationMapping implements Serializable
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract public function lazyLoadFor($entity);
|
||||
|
||||
/* Serializable implementation */
|
||||
|
||||
|
|
|
@ -31,10 +31,8 @@
|
|||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
* @todo Rename to ClassDescriptor.
|
||||
*/
|
||||
class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
||||
implements Doctrine_Common_Configurable, Serializable
|
||||
class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata implements Serializable
|
||||
{
|
||||
/* The inheritance mapping types */
|
||||
/**
|
||||
|
@ -136,7 +134,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
|
||||
/**
|
||||
* The field names of all fields that are part of the identifier/primary key
|
||||
* of the described entity class.
|
||||
* of the mapped entity class.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
|
@ -331,26 +329,49 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
$prop->setAccessible(true);
|
||||
$this->_reflectionProperties[$prop->getName()] = $prop;
|
||||
}
|
||||
//$this->_isVirtualPropertyObject = is_subclass_of($entityName, 'Doctrine\Common\VirtualPropertyObject');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionClass instance of the mapped class.
|
||||
*
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
public function getReflectionClass()
|
||||
{
|
||||
return $this->_reflectionClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ReflectionPropertys of the mapped class.
|
||||
*
|
||||
* @return array An array of ReflectionProperty instances.
|
||||
*/
|
||||
public function getReflectionProperties()
|
||||
{
|
||||
return $this->_reflectionProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a ReflectionProperty for a specific field of the mapped class.
|
||||
*
|
||||
* @param string $name
|
||||
* @return ReflectionProperty
|
||||
*/
|
||||
public function getReflectionProperty($name)
|
||||
{
|
||||
return $this->_reflectionProperties[$name];
|
||||
}
|
||||
|
||||
public function getSingleIdReflectionProperty()
|
||||
{
|
||||
if ($this->_isIdentifierComposite) {
|
||||
throw new Doctrine_Exception("getSingleIdReflectionProperty called on entity with composite key.");
|
||||
}
|
||||
return $this->_reflectionProperties[$this->_identifier[0]];
|
||||
}
|
||||
|
||||
/**
|
||||
* getComponentName
|
||||
* Gets the name of the mapped class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -360,11 +381,11 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the root class of the entity hierarchy. If the entity described
|
||||
* by the ClassMetadata is not participating in a hierarchy, this is the same as the
|
||||
* Gets the name of the root class of the mapped entity hierarchy. If the entity described
|
||||
* by this ClassMetadata instance is not participating in a hierarchy, this is the same as the
|
||||
* name returned by {@link getClassName()}.
|
||||
*
|
||||
* @return string
|
||||
* @return string The name of the root class of the entity hierarchy.
|
||||
*/
|
||||
public function getRootClassName()
|
||||
{
|
||||
|
@ -387,7 +408,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if the class has a composite identifier.
|
||||
* Checks if the class has a composite identifier.
|
||||
*
|
||||
* @param string $fieldName The field name
|
||||
* @return boolean TRUE if the identifier is composite, FALSE otherwise.
|
||||
|
@ -449,12 +470,10 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
if ( ! array_key_exists($name, $this->_tableOptions)) {
|
||||
throw new Doctrine_ClassMetadata_Exception("Unknown table option: '$name'.");
|
||||
}
|
||||
|
||||
return $this->_tableOptions[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* getTableOptions
|
||||
* returns all table options.
|
||||
*
|
||||
* @return array all options and their values
|
||||
|
@ -469,7 +488,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
* If the column name for the field cannot be found, the given field name
|
||||
* is returned.
|
||||
*
|
||||
* @param string $alias The field name.
|
||||
* @param string $fieldName The field name.
|
||||
* @return string The column name.
|
||||
*/
|
||||
public function getColumnName($fieldName)
|
||||
|
@ -479,7 +498,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the mapping of a (regular) fields that holds some data but not a
|
||||
* Gets the mapping of a (regular) field that holds some data but not a
|
||||
* reference to another object.
|
||||
*
|
||||
* @param string $fieldName The field name.
|
||||
|
@ -490,7 +509,6 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
if ( ! isset($this->_fieldMappings[$fieldName])) {
|
||||
throw Doctrine_MappingException::mappingNotFound($fieldName);
|
||||
}
|
||||
|
||||
return $this->_fieldMappings[$fieldName];
|
||||
}
|
||||
|
||||
|
@ -499,14 +517,13 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
*
|
||||
* @param string $fieldName The field name that represents the association in
|
||||
* the object model.
|
||||
* @return Doctrine::ORM::Mapping::AssociationMapping The mapping.
|
||||
* @return Doctrine\ORM\Mapping\AssociationMapping The mapping.
|
||||
*/
|
||||
public function getAssociationMapping($fieldName)
|
||||
{
|
||||
if ( ! isset($this->_associationMappings[$fieldName])) {
|
||||
throw new Doctrine_Exception("Mapping not found: $fieldName");
|
||||
}
|
||||
|
||||
return $this->_associationMappings[$fieldName];
|
||||
}
|
||||
|
||||
|
@ -514,7 +531,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
* Gets the inverse association mapping for the given fieldname.
|
||||
*
|
||||
* @param string $mappedByFieldName
|
||||
* @return Doctrine::ORM::Mapping::AssociationMapping The mapping.
|
||||
* @return Doctrine\ORM\Mapping\AssociationMapping The mapping.
|
||||
*/
|
||||
public function getInverseAssociationMapping($mappedByFieldName)
|
||||
{
|
||||
|
@ -608,7 +625,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Validates & completes the field mapping. Default values are applied here.
|
||||
* Validates & completes the field mapping.
|
||||
*
|
||||
* @param array $mapping The field mapping to validated & complete.
|
||||
* @return array The validated and completed field mapping.
|
||||
|
@ -689,59 +706,6 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
//...
|
||||
}
|
||||
|
||||
private $_entityIdentifiers = array();
|
||||
/**
|
||||
* Gets the identifier of an entity.
|
||||
*
|
||||
* @param object $entity
|
||||
* @return array Map of identifier field names to values.
|
||||
*/
|
||||
public function getEntityIdentifier($entity)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
if ( ! isset($this->_entityIdentifiers[$oid])) {
|
||||
if ( ! $this->isIdentifierComposite()) {
|
||||
$idField = $this->_identifier[0];
|
||||
$idValue = $this->_reflectionProperties[$idField]->getValue($entity);
|
||||
if (isset($idValue)) {
|
||||
//return array($idField => $idValue);
|
||||
$this->_entityIdentifiers[$oid] = array($idField => $idValue);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
//$this->_entityIdentifiers[$oid] = false;
|
||||
} else {
|
||||
$id = array();
|
||||
foreach ($this->getIdentifierFieldNames() as $idFieldName) {
|
||||
$idValue = $this->_reflectionProperties[$idFieldName]->getValue($entity);
|
||||
if (isset($idValue)) {
|
||||
$id[$idFieldName] = $idValue;
|
||||
}
|
||||
}
|
||||
//return $id;
|
||||
$this->_entityIdentifiers[$oid] = $id;
|
||||
}
|
||||
}
|
||||
return $this->_entityIdentifiers[$oid];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param <type> $entity
|
||||
* @param <type> $identifier
|
||||
*/
|
||||
public function setEntityIdentifier($entity, $identifier)
|
||||
{
|
||||
if (is_array($identifier)) {
|
||||
foreach ($identifier as $fieldName => $value) {
|
||||
$this->_reflectionProperties[$fieldName]->setValue($entity, $value);
|
||||
}
|
||||
} else {
|
||||
$this->_reflectionProperties[$this->_identifier[0]]->setValue($entity, $identifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier (primary key) field names of the class.
|
||||
*
|
||||
|
@ -852,7 +816,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the type of Id generator to use for this class.
|
||||
* Sets the type of Id generator to use for the mapped class.
|
||||
*/
|
||||
public function setIdGeneratorType($generatorType)
|
||||
{
|
||||
|
@ -860,9 +824,9 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks whether the class uses an Id generator.
|
||||
* Checks whether the mapped class uses an Id generator.
|
||||
*
|
||||
* @return boolean TRUE if the class uses an Id generator, FALSE otherwise.
|
||||
* @return boolean TRUE if the mapped class uses an Id generator, FALSE otherwise.
|
||||
*/
|
||||
public function usesIdGenerator()
|
||||
{
|
||||
|
@ -1010,7 +974,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the inheritance mapping type used by the class.
|
||||
* Gets the inheritance mapping type used by the mapped class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -1020,7 +984,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the subclasses of the class.
|
||||
* Sets the subclasses of the mapped class.
|
||||
* All entity classes that participate in a hierarchy and have subclasses
|
||||
* need to declare them this way.
|
||||
*
|
||||
|
@ -1136,10 +1100,6 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
*/
|
||||
public function getInheritanceOption($name)
|
||||
{
|
||||
/*if ( ! array_key_exists($name, $this->_inheritanceOptions)) {
|
||||
throw new Doctrine_ClassMetadata_Exception("Unknown inheritance option: '$name'.");
|
||||
}*/
|
||||
|
||||
return $this->_inheritanceOptions[$name];
|
||||
}
|
||||
|
||||
|
@ -1179,7 +1139,6 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
throw Doctrine_MappingException::invalidInheritanceOption($name);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_inheritanceOptions[$name] = $value;
|
||||
}
|
||||
|
||||
|
@ -1350,7 +1309,6 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
public function serialize()
|
||||
{
|
||||
//$contents = get_object_vars($this);
|
||||
/* @TODO How to handle $this->_em and $this->_parser ? */
|
||||
//return serialize($contents);
|
||||
return "";
|
||||
}
|
||||
|
@ -1506,7 +1464,7 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
*/
|
||||
public function setCustomRepositoryClass($repositoryClassName)
|
||||
{
|
||||
if ( ! is_subclass_of($repositoryClassName, 'Doctrine_EntityRepository')) {
|
||||
if ( ! is_subclass_of($repositoryClassName, 'Doctrine\ORM\EntityRepository')) {
|
||||
throw new Doctrine_ClassMetadata_Exception("The custom repository must be a subclass"
|
||||
. " of Doctrine_EntityRepository.");
|
||||
}
|
||||
|
@ -1640,37 +1598,15 @@ class Doctrine_ORM_Mapping_ClassMetadata extends Doctrine_Common_ClassMetadata
|
|||
{
|
||||
return $columnName === $this->_inheritanceOptions['discriminatorColumn'];
|
||||
}
|
||||
|
||||
public function hasAttribute($name)
|
||||
{
|
||||
return isset($this->_attributes[$name]);
|
||||
}
|
||||
|
||||
public function getAttribute($name)
|
||||
{
|
||||
if ($this->hasAttribute($name)) {
|
||||
return $this->_attributes[$name];
|
||||
}
|
||||
}
|
||||
|
||||
public function setAttribute($name, $value)
|
||||
{
|
||||
if ($this->hasAttribute($name)) {
|
||||
$this->_attributes[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function hasAssociation($fieldName)
|
||||
{
|
||||
return isset($this->_associationMappings[$fieldName]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return spl_object_hash($this);
|
||||
return __CLASS__ . '@' . spl_object_hash($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
#namespace Doctrine::ORM::Mapping;
|
||||
#namespace Doctrine\ORM\Mapping;
|
||||
|
||||
/**
|
||||
* Represents a one-to-many mapping.
|
||||
|
@ -66,7 +66,7 @@ class Doctrine_ORM_Mapping_OneToManyMapping extends Doctrine_ORM_Mapping_Associa
|
|||
}
|
||||
|
||||
/**
|
||||
* Validates and completed the mapping.
|
||||
* Validates and completes the mapping.
|
||||
*
|
||||
* @param array $mapping The mapping to validate and complete.
|
||||
* @return array The validated and completed mapping.
|
||||
|
@ -106,6 +106,15 @@ class Doctrine_ORM_Mapping_OneToManyMapping extends Doctrine_ORM_Mapping_Associa
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <type> $entity
|
||||
* @override
|
||||
*/
|
||||
public function lazyLoadFor($entity)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -130,10 +130,10 @@ class Doctrine_ORM_Mapping_OneToOneMapping extends Doctrine_ORM_Mapping_Associat
|
|||
/**
|
||||
* Lazy-loads the associated entity for a given entity.
|
||||
*
|
||||
* @param Doctrine::ORM::Entity $entity
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return void
|
||||
*/
|
||||
public function lazyLoadFor(Doctrine_ORM_Entity $entity)
|
||||
public function lazyLoadFor($entity)
|
||||
{
|
||||
if ($entity->getClassName() != $this->_sourceClass->getClassName()) {
|
||||
//error?
|
||||
|
|
|
@ -41,7 +41,7 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
/**
|
||||
* Metadata object that descibes the mapping of the mapped entity class.
|
||||
*
|
||||
* @var Doctrine_ClassMetadata
|
||||
* @var Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
protected $_classMetadata;
|
||||
|
||||
|
@ -53,26 +53,28 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
protected $_entityName;
|
||||
|
||||
/**
|
||||
* The Doctrine_Connection object that the database connection of this mapper.
|
||||
* The Connection instance.
|
||||
*
|
||||
* @var Doctrine::DBAL::Connection $conn
|
||||
* @var Doctrine\DBAL\Connection $conn
|
||||
*/
|
||||
protected $_conn;
|
||||
|
||||
/**
|
||||
* The EntityManager.
|
||||
* The EntityManager instance.
|
||||
*
|
||||
* @var Doctrine::ORM::EntityManager
|
||||
* @var Doctrine\ORM\EntityManager
|
||||
*/
|
||||
protected $_em;
|
||||
|
||||
/**
|
||||
* Null object.
|
||||
*/
|
||||
private $_nullObject;
|
||||
//private $_nullObject;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityPersister.
|
||||
* Initializes a new instance of a class derived from AbstractEntityPersister
|
||||
* that uses the given EntityManager and persists instances of the class described
|
||||
* by the given class metadata descriptor.
|
||||
*/
|
||||
public function __construct(Doctrine_ORM_EntityManager $em, Doctrine_ORM_Mapping_ClassMetadata $classMetadata)
|
||||
{
|
||||
|
@ -80,31 +82,36 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
$this->_entityName = $classMetadata->getClassName();
|
||||
$this->_conn = $em->getConnection();
|
||||
$this->_classMetadata = $classMetadata;
|
||||
$this->_nullObject = Doctrine_ORM_Internal_Null::$INSTANCE;
|
||||
//$this->_nullObject = Doctrine_ORM_Internal_Null::$INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an entity.
|
||||
*
|
||||
* @param Doctrine::ORM::Entity $entity The entity to insert.
|
||||
* @return void
|
||||
* @param Doctrine\ORM\Entity $entity The entity to insert.
|
||||
* @return mixed
|
||||
*/
|
||||
public function insert($entity)
|
||||
{
|
||||
$insertData = array();
|
||||
$this->_prepareData($entity, $insertData, true);
|
||||
$this->_conn->insert($this->_classMetadata->getTableName(), $insertData);
|
||||
$idGen = $this->_em->getIdGenerator($this->_classMetadata->getClassName());
|
||||
if ($idGen->isPostInsertGenerator()) {
|
||||
return $idGen->generate($entity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an entity.
|
||||
*
|
||||
* @param Doctrine::ORM::Entity $entity The entity to update.
|
||||
* @param Doctrine\ORM\Entity $entity The entity to update.
|
||||
* @return void
|
||||
*/
|
||||
public function update(Doctrine_ORM_Entity $entity)
|
||||
{
|
||||
$dataChangeSet = $entity->_getDataChangeSet();
|
||||
/*$dataChangeSet = $entity->_getDataChangeSet();
|
||||
$referenceChangeSet = $entity->_getReferenceChangeSet();
|
||||
|
||||
foreach ($referenceChangeSet as $field => $change) {
|
||||
|
@ -118,14 +125,14 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
}
|
||||
//...
|
||||
}
|
||||
|
||||
*/
|
||||
//TODO: perform update
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entity.
|
||||
*
|
||||
* @param Doctrine::ORM::Entity $entity The entity to delete.
|
||||
* @param Doctrine\ORM\Entity $entity The entity to delete.
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Doctrine_ORM_Entity $entity)
|
||||
|
@ -209,7 +216,6 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
|
||||
/**
|
||||
* Callback that is invoked during the SQL construction process.
|
||||
* @todo Move to ClassMetadata?
|
||||
*/
|
||||
public function getCustomJoins()
|
||||
{
|
||||
|
@ -218,7 +224,6 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
|
||||
/**
|
||||
* Callback that is invoked during the SQL construction process.
|
||||
* @todo Move to ClassMetadata?
|
||||
*/
|
||||
public function getCustomFields()
|
||||
{
|
||||
|
@ -226,24 +231,7 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
}
|
||||
|
||||
/**
|
||||
* Assumes that the keys of the given field array are field names and converts
|
||||
* them to column names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
/*protected function _convertFieldToColumnNames(array $fields, Doctrine_ClassMetadata $class)
|
||||
{
|
||||
$converted = array();
|
||||
foreach ($fields as $fieldName => $value) {
|
||||
$converted[$class->getColumnName($fieldName)] = $value;
|
||||
}
|
||||
|
||||
return $converted;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Returns an array of modified fields and values with data preparation
|
||||
* adds column aggregation inheritance and converts Records into primary key values
|
||||
* Prepares all the entity data for insertion into the database.
|
||||
*
|
||||
* @param array $array
|
||||
* @return void
|
||||
|
@ -255,7 +243,7 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
$type = $this->_classMetadata->getTypeOfField($field);
|
||||
$columnName = $this->_classMetadata->getColumnName($field);
|
||||
|
||||
if ($newVal === Doctrine_ORM_Internal_Null::$INSTANCE) {
|
||||
if (is_null($newVal)) {
|
||||
$result[$columnName] = null;
|
||||
} else if (is_object($newVal)) {
|
||||
$assocMapping = $this->_classMetadata->getAssociationMapping($field);
|
||||
|
@ -301,336 +289,7 @@ abstract class Doctrine_ORM_Persisters_AbstractEntityPersister
|
|||
$result[$discColumn] = array_search($this->_entityName, $discMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#############################################################
|
||||
|
||||
# The following is old code that needs to be removed/ported
|
||||
|
||||
|
||||
/**
|
||||
* 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_ORM_Entity $record)
|
||||
{
|
||||
$classMetadata = $this->_classMetadata;
|
||||
foreach ($classMetadata->getRelations() as $fk) {
|
||||
if ($fk->isComposite()) {
|
||||
$obj = $record->get($fk->getAlias());
|
||||
if ($obj instanceof Doctrine_ORM_Entity &&
|
||||
$obj->_state() != Doctrine_ORM_Entity::STATE_LOCKED) {
|
||||
$obj->delete($this->_mapper->getConnection());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection the mapper is currently using.
|
||||
*
|
||||
* @return Doctrine_Connection|null The connection object.
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->_conn;
|
||||
}
|
||||
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->_em;
|
||||
}
|
||||
|
||||
/**
|
||||
* getComponentName
|
||||
*
|
||||
* @return void
|
||||
* @deprecated Use getMappedClassName()
|
||||
*/
|
||||
public function getComponentName()
|
||||
{
|
||||
return $this->_domainClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an entity.
|
||||
*
|
||||
* @param Doctrine_Entity $record The entity to save.
|
||||
* @param Doctrine_Connection $conn The connection to use. Will default to the mapper's
|
||||
* connection.
|
||||
*/
|
||||
public function save(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
if ( ! ($record instanceof $this->_domainClassName)) {
|
||||
throw new Doctrine_Mapper_Exception("Mapper of type " . $this->_domainClassName . "
|
||||
can't save instances of type" . get_class($record) . ".");
|
||||
}
|
||||
|
||||
if ($conn === null) {
|
||||
$conn = $this->_conn;
|
||||
}
|
||||
|
||||
$state = $record->_state();
|
||||
if ($state === Doctrine_ORM_Entity::STATE_LOCKED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$record->_state(Doctrine_ORM_Entity::STATE_LOCKED);
|
||||
|
||||
try {
|
||||
$conn->beginInternalTransaction();
|
||||
$saveLater = $this->_saveRelated($record);
|
||||
|
||||
$record->_state($state);
|
||||
|
||||
if ($record->isValid()) {
|
||||
$this->_insertOrUpdate($record);
|
||||
} else {
|
||||
$conn->getTransaction()->addInvalid($record);
|
||||
}
|
||||
|
||||
$state = $record->_state();
|
||||
$record->_state(Doctrine_ORM_Entity::STATE_LOCKED);
|
||||
|
||||
foreach ($saveLater as $fk) {
|
||||
$alias = $fk->getAlias();
|
||||
if ($record->hasReference($alias)) {
|
||||
$obj = $record->$alias;
|
||||
// check that the related object is not an instance of Doctrine_Null
|
||||
if ( ! ($obj instanceof Doctrine_Null)) {
|
||||
$obj->save($conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save the MANY-TO-MANY associations
|
||||
$this->saveAssociations($record);
|
||||
// reset state
|
||||
$record->_state($state);
|
||||
$conn->commit();
|
||||
} catch (Exception $e) {
|
||||
$conn->rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates an entity, depending on it's state.
|
||||
*
|
||||
* @param Doctrine_Entity $record The entity to insert/update.
|
||||
*/
|
||||
protected function _insertOrUpdate(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
//$record->preSave();
|
||||
//$this->notifyEntityListeners($record, 'preSave', Doctrine_Event::RECORD_SAVE);
|
||||
|
||||
switch ($record->_state()) {
|
||||
case Doctrine_ORM_Entity::STATE_TDIRTY:
|
||||
$this->_insert($record);
|
||||
break;
|
||||
case Doctrine_ORM_Entity::STATE_DIRTY:
|
||||
case Doctrine_ORM_Entity::STATE_PROXY:
|
||||
$this->_update($record);
|
||||
break;
|
||||
case Doctrine_ORM_Entity::STATE_CLEAN:
|
||||
case Doctrine_ORM_Entity::STATE_TCLEAN:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
//$record->postSave();
|
||||
//$this->notifyEntityListeners($record, 'postSave', Doctrine_Event::RECORD_SAVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* saves the given record
|
||||
*
|
||||
* @param Doctrine_Entity $record
|
||||
* @return void
|
||||
*/
|
||||
public function saveSingleRecord(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
$this->_insertOrUpdate($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* saves all related records to $record
|
||||
*
|
||||
* @throws PDOException if something went wrong at database level
|
||||
* @param Doctrine_Entity $record
|
||||
*/
|
||||
protected function _saveRelated(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
$saveLater = array();
|
||||
foreach ($record->_getReferences() as $k => $v) {
|
||||
$rel = $record->getTable()->getRelation($k);
|
||||
|
||||
$local = $rel->getLocal();
|
||||
$foreign = $rel->getForeign();
|
||||
|
||||
if ($rel instanceof Doctrine_Relation_ForeignKey) {
|
||||
$saveLater[$k] = $rel;
|
||||
} else if ($rel instanceof Doctrine_Relation_LocalKey) {
|
||||
// ONE-TO-ONE relationship
|
||||
$obj = $record->get($rel->getAlias());
|
||||
|
||||
// Protection against infinite function recursion before attempting to save
|
||||
if ($obj instanceof Doctrine_ORM_Entity && $obj->isModified()) {
|
||||
$obj->save();
|
||||
|
||||
/** Can this be removed?
|
||||
$id = array_values($obj->identifier());
|
||||
|
||||
foreach ((array) $rel->getLocal() as $k => $field) {
|
||||
$record->set($field, $id[$k]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* @throws Doctrine_Connection_Exception if something went wrong at database level
|
||||
* @param Doctrine_Entity $record
|
||||
* @return void
|
||||
*/
|
||||
public function saveAssociations(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
foreach ($record->_getReferences() as $relationName => $relatedObject) {
|
||||
if ($relatedObject === Doctrine_Null::$INSTANCE) {
|
||||
continue;
|
||||
}
|
||||
$rel = $record->getTable()->getRelation($relationName);
|
||||
|
||||
if ($rel instanceof Doctrine_Relation_Association) {
|
||||
$relatedObject->save($this->_conn);
|
||||
$assocTable = $rel->getAssociationTable();
|
||||
|
||||
foreach ($relatedObject->getDeleteDiff() as $r) {
|
||||
$query = 'DELETE FROM ' . $assocTable->getTableName()
|
||||
. ' WHERE ' . $rel->getForeign() . ' = ?'
|
||||
. ' AND ' . $rel->getLocal() . ' = ?';
|
||||
// FIXME: composite key support
|
||||
$ids1 = $r->identifier();
|
||||
$id1 = count($ids1) > 0 ? array_pop($ids1) : null;
|
||||
$ids2 = $record->identifier();
|
||||
$id2 = count($ids2) > 0 ? array_pop($ids2) : null;
|
||||
$this->_conn->execute($query, array($id1, $id2));
|
||||
}
|
||||
|
||||
$assocMapper = $this->_conn->getMapper($assocTable->getComponentName());
|
||||
foreach ($relatedObject->getInsertDiff() as $r) {
|
||||
$assocRecord = $assocMapper->create();
|
||||
$assocRecord->set($assocTable->getFieldName($rel->getForeign()), $r);
|
||||
$assocRecord->set($assocTable->getFieldName($rel->getLocal()), $record);
|
||||
$assocMapper->save($assocRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an entity.
|
||||
*
|
||||
* @param Doctrine_Entity $record record to be updated
|
||||
* @return boolean whether or not the update was successful
|
||||
* @todo Move to Doctrine_Table (which will become Doctrine_Mapper).
|
||||
*/
|
||||
protected function _update(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
$record->preUpdate();
|
||||
$this->notifyEntityListeners($record, 'preUpdate', Doctrine_Event::RECORD_UPDATE);
|
||||
|
||||
$table = $this->_classMetadata;
|
||||
$this->_doUpdate($record);
|
||||
|
||||
$record->postUpdate();
|
||||
$this->notifyEntityListeners($record, 'postUpdate', Doctrine_Event::RECORD_UPDATE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract protected function _doUpdate(Doctrine_ORM_Entity $entity);
|
||||
|
||||
/**
|
||||
* Inserts an entity.
|
||||
*
|
||||
* @param Doctrine_Entity $record record to be inserted
|
||||
* @return boolean
|
||||
*/
|
||||
protected function _insert(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
//$record->preInsert();
|
||||
//$this->notifyEntityListeners($record, 'preInsert', Doctrine_Event::RECORD_INSERT);
|
||||
|
||||
$this->_doInsert($record);
|
||||
$this->addRecord($record);
|
||||
|
||||
//$record->postInsert();
|
||||
//$this->notifyEntityListeners($record, 'postInsert', Doctrine_Event::RECORD_INSERT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract protected function _doInsert(Doctrine_ORM_Entity $entity);
|
||||
|
||||
/**
|
||||
* Deletes given entity and all it's related entities.
|
||||
*
|
||||
* Triggered Events: onPreDelete, onDelete.
|
||||
*
|
||||
* @return boolean true on success, false on failure
|
||||
* @throws Doctrine_Mapper_Exception
|
||||
*/
|
||||
public function delete_old(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
if ( ! $record->exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! ($record instanceof $this->_domainClassName)) {
|
||||
throw new Doctrine_Mapper_Exception("Mapper of type " . $this->_domainClassName . "
|
||||
can't save instances of type" . get_class($record) . ".");
|
||||
}
|
||||
|
||||
if ($conn == null) {
|
||||
$conn = $this->_conn;
|
||||
}
|
||||
|
||||
$record->preDelete();
|
||||
$this->notifyEntityListeners($record, 'preDelete', Doctrine_Event::RECORD_DELETE);
|
||||
|
||||
$table = $this->_classMetadata;
|
||||
|
||||
$state = $record->_state();
|
||||
$record->_state(Doctrine_ORM_Entity::STATE_LOCKED);
|
||||
|
||||
$this->_doDelete($record);
|
||||
|
||||
$record->postDelete();
|
||||
$this->notifyEntityListeners($record, 'postDelete', Doctrine_Event::RECORD_DELETE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @version $Revision$
|
||||
* @link www.phpdoctrine.org
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
*/
|
||||
class Doctrine_ORM_Persisters_StandardEntityPersister extends Doctrine_ORM_Persisters_AbstractEntityPersister
|
||||
|
@ -40,10 +40,8 @@ class Doctrine_ORM_Persisters_StandardEntityPersister extends Doctrine_ORM_Persi
|
|||
*/
|
||||
protected function _doDelete(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
$conn = $this->_conn;
|
||||
$metadata = $this->_classMetadata;
|
||||
try {
|
||||
$conn->beginInternalTransaction();
|
||||
/*try {
|
||||
$this->_conn->beginInternalTransaction();
|
||||
$this->_deleteComposites($record);
|
||||
|
||||
$record->_state(Doctrine_ORM_Entity::STATE_TDIRTY);
|
||||
|
@ -57,18 +55,16 @@ class Doctrine_ORM_Persisters_StandardEntityPersister extends Doctrine_ORM_Persi
|
|||
} catch (Exception $e) {
|
||||
$conn->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a single entity into the database, without any related entities.
|
||||
* Inserts a single entity into the database.
|
||||
*
|
||||
* @param Doctrine_Entity $record The entity to insert.
|
||||
* @param Doctrine\ORM\Entity $entity The entity to insert.
|
||||
*/
|
||||
protected function _doInsert(Doctrine_ORM_Entity $record)
|
||||
{
|
||||
$conn = $this->_conn;
|
||||
|
||||
$fields = $record->getPrepared();
|
||||
if (empty($fields)) {
|
||||
return false;
|
||||
|
|
|
@ -32,11 +32,8 @@
|
|||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 4947 $
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @todo Rename: Doctrine::ORM::UnitOfWork.
|
||||
* @todo Turn connection exceptions into UnitOfWorkExceptions.
|
||||
*/
|
||||
class Doctrine_ORM_UnitOfWork
|
||||
{
|
||||
|
@ -89,6 +86,13 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
protected $_identityMap = array();
|
||||
|
||||
/**
|
||||
* Map of all identifiers. Keys are object ids.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_entityIdentifiers = array();
|
||||
|
||||
/**
|
||||
* Map of the original entity data of entities fetched from the database.
|
||||
* Keys are object ids. This is used for calculating changesets at commit time.
|
||||
|
@ -199,7 +203,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
public function commit()
|
||||
{
|
||||
// Compute changes in managed entities
|
||||
$this->_computeDataChangeSet();
|
||||
$this->computeDataChangeSet();
|
||||
|
||||
if (empty($this->_newEntities) &&
|
||||
empty($this->_deletedEntities) &&
|
||||
|
@ -244,7 +248,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
public function getDataChangeSet($entity)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
if (isset($this->_dataChangeSets[$oid])) {
|
||||
return $this->_dataChangeSets[$oid];
|
||||
}
|
||||
|
@ -261,7 +265,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
* map are computed.
|
||||
* @return void
|
||||
*/
|
||||
private function _computeDataChangeSet(array $entities = null)
|
||||
public function computeDataChangeSet(array $entities = null)
|
||||
{
|
||||
$entitySet = array();
|
||||
if ( ! is_null($entities)) {
|
||||
|
@ -279,7 +283,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
foreach ($entitySet as $className => $entities) {
|
||||
$class = $this->_em->getClassMetadata($className);
|
||||
foreach ($entities as $entity) {
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
if ($this->getEntityState($entity) == self::STATE_MANAGED) {
|
||||
if ( ! $class->isInheritanceTypeNone()) {
|
||||
$class = $this->_em->getClassMetadata(get_class($entity));
|
||||
|
@ -317,7 +321,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
/**
|
||||
* Executes all entity insertions for entities of the specified type.
|
||||
*
|
||||
* @param Doctrine::ORM::Mapping::ClassMetadata $class
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
*/
|
||||
private function _executeInserts($class)
|
||||
{
|
||||
|
@ -329,11 +333,14 @@ class Doctrine_ORM_UnitOfWork
|
|||
$persister = $this->_em->getEntityPersister($className);
|
||||
foreach ($this->_newEntities as $entity) {
|
||||
if (get_class($entity) == $className) {
|
||||
$persister->insert($entity);
|
||||
if ($class->isIdGeneratorIdentity()) {
|
||||
$id = $this->_em->getIdGenerator($class->getIdGeneratorType());
|
||||
$class->setEntityIdentifier($entity, $id);
|
||||
$this->_entityStates[spl_object_id($oid)] = self::STATE_MANAGED;
|
||||
$returnVal = $persister->insert($entity);
|
||||
if ( ! is_null($returnVal)) {
|
||||
$oid = spl_object_hash($entity);
|
||||
$class->getReflectionProperty($class->getSingleIdentifierFieldName())
|
||||
->setValue($entity, $returnVal);
|
||||
$this->_entityIdentifiers[$oid] = array($returnVal);
|
||||
$this->_entityStates[$oid] = self::STATE_MANAGED;
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +349,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
/**
|
||||
* Executes all entity updates for entities of the specified type.
|
||||
*
|
||||
* @param Doctrine::ORM::Mapping::ClassMetadata $class
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
*/
|
||||
private function _executeUpdates($class)
|
||||
{
|
||||
|
@ -358,7 +365,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
/**
|
||||
* Executes all entity deletions for entities of the specified type.
|
||||
*
|
||||
* @param Doctrine::ORM::Mapping::ClassMetadata $class
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
*/
|
||||
private function _executeDeletions($class)
|
||||
{
|
||||
|
@ -441,11 +448,8 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
public function registerNew($entity)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
|
||||
/*if ( ! $entity->_identifier()) {
|
||||
throw new Doctrine_Connection_Exception("Entity without identity cant be registered as new.");
|
||||
}*/
|
||||
if (isset($this->_dirtyEntities[$oid])) {
|
||||
throw new Doctrine_Connection_Exception("Dirty object can't be registered as new.");
|
||||
}
|
||||
|
@ -457,7 +461,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
}
|
||||
|
||||
$this->_newEntities[$oid] = $entity;
|
||||
if ($this->_em->getClassMetadata(get_class($entity))->getEntityIdentifier($entity)) {
|
||||
if (isset($this->_entityIdentifiers[$oid])) {
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
}
|
||||
|
@ -465,36 +469,25 @@ class Doctrine_ORM_UnitOfWork
|
|||
/**
|
||||
* Checks whether an entity is registered as new on the unit of work.
|
||||
*
|
||||
* @param Doctrine_ORM_Entity $entity
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return boolean
|
||||
* @todo Rename to isScheduledForInsert().
|
||||
*/
|
||||
public function isRegisteredNew($entity)
|
||||
{
|
||||
return isset($this->_newEntities[spl_object_id($entity)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a clean entity.
|
||||
* The entity is simply put into the identity map.
|
||||
*
|
||||
* @param object $entity
|
||||
*/
|
||||
public function registerClean($entity)
|
||||
{
|
||||
$this->addToIdentityMap($entity);
|
||||
return isset($this->_newEntities[spl_object_hash($entity)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a dirty entity.
|
||||
*
|
||||
* @param Doctrine::ORM::Entity $entity
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @todo Rename to scheduleForUpdate().
|
||||
*/
|
||||
public function registerDirty($entity)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
if ( ! $entity->_identifier()) {
|
||||
$oid = spl_object_hash($entity);
|
||||
if ( ! isset($this->_entityIdentifiers[$oid])) {
|
||||
throw new Doctrine_Exception("Entity without identity "
|
||||
. "can't be registered as dirty.");
|
||||
}
|
||||
|
@ -518,7 +511,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
public function isRegisteredDirty($entity)
|
||||
{
|
||||
return isset($this->_dirtyEntities[spl_object_id($entity)]);
|
||||
return isset($this->_dirtyEntities[spl_object_hash($entity)]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -528,12 +521,13 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
public function registerDeleted($entity)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
if ( ! $this->isInIdentityMap($entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->removeFromIdentityMap($entity);
|
||||
$className = get_class($entity);
|
||||
|
||||
if (isset($this->_newEntities[$oid])) {
|
||||
unset($this->_newEntities[$oid]);
|
||||
|
@ -552,13 +546,13 @@ class Doctrine_ORM_UnitOfWork
|
|||
* Checks whether an entity is registered as removed/deleted with the unit
|
||||
* of work.
|
||||
*
|
||||
* @param Doctrine::ORM::Entity $entity
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return boolean
|
||||
* @todo Rename to isScheduledForDelete().
|
||||
*/
|
||||
public function isRegisteredRemoved($entity)
|
||||
{
|
||||
return isset($this->_deletedEntities[spl_object_id($entity)]);
|
||||
return isset($this->_deletedEntities[spl_object_hash($entity)]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -570,25 +564,26 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
public function detach($entity)
|
||||
{
|
||||
if ($this->isInIdentityMap($entity)) {
|
||||
$this->removeFromIdentityMap($entity);
|
||||
}
|
||||
$oid = spl_object_hash($entity);
|
||||
$this->removeFromIdentityMap($entity);
|
||||
unset($this->_newEntities[$oid], $this->_dirtyEntities[$oid],
|
||||
$this->_deletedEntities[$oid], $this->_entityIdentifiers[$oid],
|
||||
$this->_entityStates[$oid]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param Doctrine_ORM_Entity $entity
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return unknown
|
||||
* @todo Rename to isScheduled()
|
||||
*/
|
||||
public function isEntityRegistered($entity)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
return isset($this->_newEntities[$oid]) ||
|
||||
isset($this->_dirtyEntities[$oid]) ||
|
||||
isset($this->_deletedEntities[$oid]) ||
|
||||
$this->isInIdentityMap($entity);
|
||||
isset($this->_deletedEntities[$oid]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -606,10 +601,16 @@ class Doctrine_ORM_UnitOfWork
|
|||
$numDetached = 0;
|
||||
if ($entityName !== null && isset($this->_identityMap[$entityName])) {
|
||||
$numDetached = count($this->_identityMap[$entityName]);
|
||||
foreach ($this->_identityMap[$entityName] as $entity) {
|
||||
$this->detach($entity);
|
||||
}
|
||||
$this->_identityMap[$entityName] = array();
|
||||
} else {
|
||||
$numDetached = count($this->_identityMap);
|
||||
$this->_identityMap = array();
|
||||
$this->_newEntities = array();
|
||||
$this->_dirtyEntities = array();
|
||||
$this->_deletedEntities = array();
|
||||
}
|
||||
|
||||
return $numDetached;
|
||||
|
@ -627,9 +628,9 @@ class Doctrine_ORM_UnitOfWork
|
|||
public function addToIdentityMap($entity)
|
||||
{
|
||||
$classMetadata = $this->_em->getClassMetadata(get_class($entity));
|
||||
$idHash = $this->getIdentifierHash($classMetadata->getEntityIdentifier($entity));
|
||||
$idHash = $this->getIdentifierHash($this->_entityIdentifiers[spl_object_hash($entity)]);
|
||||
if ($idHash === '') {
|
||||
throw new Doctrine_Exception("Entity with oid '" . spl_object_id($entity)
|
||||
throw new Doctrine_Exception("Entity with oid '" . spl_object_hash($entity)
|
||||
. "' has no identity and therefore can't be added to the identity map.");
|
||||
}
|
||||
$className = $classMetadata->getRootClassName();
|
||||
|
@ -648,23 +649,22 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
public function getEntityState($entity)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
return isset($this->_entityStates[$oid]) ? $this->_entityStates[$oid] :
|
||||
self::STATE_NEW;
|
||||
$oid = spl_object_hash($entity);
|
||||
return isset($this->_entityStates[$oid]) ? $this->_entityStates[$oid] : self::STATE_NEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an entity from the identity map.
|
||||
*
|
||||
* @param Doctrine_ORM_Entity $entity
|
||||
* @return unknown
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @return boolean
|
||||
*/
|
||||
public function removeFromIdentityMap($entity)
|
||||
{
|
||||
$classMetadata = $this->_em->getClassMetadata(get_class($entity));
|
||||
$idHash = $this->getIdentifierHash($classMetadata->getEntityIdentifier($entity));
|
||||
$idHash = $this->getIdentifierHash($this->_entityIdentifiers[spl_object_hash($entity)]);
|
||||
if ($idHash === '') {
|
||||
throw new Doctrine_Exception("Entity with oid '" . spl_object_id($entity)
|
||||
throw new Doctrine_Exception("Entity with oid '" . spl_object_hash($entity)
|
||||
. "' has no identity and therefore can't be removed from the identity map.");
|
||||
}
|
||||
$className = $classMetadata->getRootClassName();
|
||||
|
@ -681,7 +681,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
*
|
||||
* @param string $idHash
|
||||
* @param string $rootClassName
|
||||
* @return Doctrine::ORM::Entity
|
||||
* @return Doctrine\ORM\Entity
|
||||
*/
|
||||
public function getByIdHash($idHash, $rootClassName)
|
||||
{
|
||||
|
@ -729,8 +729,12 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
public function isInIdentityMap($entity)
|
||||
{
|
||||
$oid = spl_object_hash($entity);
|
||||
if ( ! isset($this->_entityIdentifiers[$oid])) {
|
||||
return false;
|
||||
}
|
||||
$classMetadata = $this->_em->getClassMetadata(get_class($entity));
|
||||
$idHash = $this->getIdentifierHash($classMetadata->getEntityIdentifier($entity));
|
||||
$idHash = $this->getIdentifierHash($this->_entityIdentifiers[$oid]);
|
||||
if ($idHash === '') {
|
||||
return false;
|
||||
}
|
||||
|
@ -765,15 +769,15 @@ class Doctrine_ORM_UnitOfWork
|
|||
$this->_doSave($entity, $visited, $insertNow);
|
||||
if ( ! empty($insertNow)) {
|
||||
// We have no choice. This means that there are new entities
|
||||
// with an IDENTITY column key generation.
|
||||
$this->_computeDataChangeSet($insertNow);
|
||||
// with an IDENTITY column key generation strategy.
|
||||
$this->computeDataChangeSet($insertNow);
|
||||
$commitOrder = $this->_getCommitOrder($insertNow);
|
||||
foreach ($commitOrder as $class) {
|
||||
$this->_executeInserts($class);
|
||||
}
|
||||
// remove them from _newEntities
|
||||
$this->_newEntities = array_diff_key($this->_newEntities, $insertNow);
|
||||
$this->_dataChangeSets = array();
|
||||
$this->_dataChangeSets = array_diff_key($this->_dataChangeSets, $insertNow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,7 +791,7 @@ class Doctrine_ORM_UnitOfWork
|
|||
*/
|
||||
private function _doSave($entity, array &$visited, array &$insertNow)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
if (isset($visited[$oid])) {
|
||||
return; // Prevent infinite recursion
|
||||
}
|
||||
|
@ -800,12 +804,16 @@ class Doctrine_ORM_UnitOfWork
|
|||
// nothing to do
|
||||
break;
|
||||
case self::STATE_NEW:
|
||||
$result = $this->_em->getIdGenerator($class->getClassName())->generate($entity);
|
||||
if ($result == Doctrine_ORM_Id_AbstractIdGenerator::POST_INSERT_INDICATOR) {
|
||||
$idGen = $this->_em->getIdGenerator($class->getClassName());
|
||||
if ($idGen->isPostInsertGenerator()) {
|
||||
$insertNow[$oid] = $entity;
|
||||
} else {
|
||||
$class->setEntityIdentifier($entity, $result);
|
||||
$idValue = $idGen->generate($entity);
|
||||
$this->_entityIdentifiers[$oid] = array($idValue);
|
||||
$this->_entityStates[$oid] = self::STATE_MANAGED;
|
||||
if ( ! $idGen instanceof Doctrine_ORM_Id_Assigned) {
|
||||
$class->getSingleIdReflectionProperty()->setValue($entity, $idValue);
|
||||
}
|
||||
}
|
||||
$this->registerNew($entity);
|
||||
break;
|
||||
|
@ -844,19 +852,18 @@ class Doctrine_ORM_UnitOfWork
|
|||
/**
|
||||
* Enter description here...
|
||||
*
|
||||
* @param Doctrine_ORM_Entity $entity
|
||||
* @param Doctrine\ORM\Entity $entity
|
||||
* @param array $visited
|
||||
*/
|
||||
private function _doDelete($entity, array &$visited)
|
||||
{
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
if (isset($visited[$oid])) {
|
||||
return; // Prevent infinite recursion
|
||||
}
|
||||
|
||||
$visited[$oid] = $entity; // mark visited
|
||||
|
||||
//$class = $entity->getClass();
|
||||
switch ($this->getEntityState($entity)) {
|
||||
case self::STATE_NEW:
|
||||
case self::STATE_DELETED:
|
||||
|
@ -951,47 +958,43 @@ class Doctrine_ORM_UnitOfWork
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates an entity. Used for reconstitution as well as initial creation.
|
||||
* Creates an entity. Used for reconstitution of entities during hydration.
|
||||
*
|
||||
* @param string $className The name of the entity class.
|
||||
* @param array $data The data for the entity.
|
||||
* @return Doctrine\ORM\Entity
|
||||
* @internal Performance-sensitive method.
|
||||
*/
|
||||
public function createEntity($className, array $data, Doctrine_Query $query = null)
|
||||
public function createEntity($className, array $data, $query = null)
|
||||
{
|
||||
$className = $this->_inferCorrectClassName($data, $className);
|
||||
$classMetadata = $this->_em->getClassMetadata($className);
|
||||
if ( ! empty($data)) {
|
||||
|
||||
$id = array();
|
||||
if ($classMetadata->isIdentifierComposite()) {
|
||||
$identifierFieldNames = $classMetadata->getIdentifier();
|
||||
$isNew = false;
|
||||
foreach ($identifierFieldNames as $fieldName) {
|
||||
if ( ! isset($data[$fieldName])) {
|
||||
// id field not found return new entity
|
||||
$isNew = true;
|
||||
break;
|
||||
}
|
||||
$id[] = $data[$fieldName];
|
||||
}
|
||||
|
||||
if ($isNew) {
|
||||
$entity = new $className;
|
||||
} else {
|
||||
$idHash = $this->getIdentifierHash($id);
|
||||
$entity = $this->tryGetByIdHash($idHash, $classMetadata->getRootClassName());
|
||||
if ($entity) {
|
||||
$this->_mergeData($entity, $data, $classMetadata/*, $query->getHint('doctrine.refresh')*/);
|
||||
return $entity;
|
||||
} else {
|
||||
$entity = new $className;
|
||||
$this->_mergeData($entity, $data, $classMetadata, true);
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
}
|
||||
$idHash = $this->getIdentifierHash($id);
|
||||
} else {
|
||||
$id = array($data[$classMetadata->getSingleIdentifierFieldName()]);
|
||||
$idHash = $id[0];
|
||||
}
|
||||
$entity = $this->tryGetByIdHash($idHash, $classMetadata->getRootClassName());
|
||||
if ($entity) {
|
||||
$oid = spl_object_hash($entity);
|
||||
$this->_mergeData($entity, $data, $classMetadata/*, $query->getHint('doctrine.refresh')*/);
|
||||
return $entity;
|
||||
} else {
|
||||
$entity = new $className;
|
||||
$oid = spl_object_hash($entity);
|
||||
$this->_mergeData($entity, $data, $classMetadata, true);
|
||||
$this->_entityIdentifiers[$oid] = $id;
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
|
||||
$this->_originalEntityData[spl_object_id($entity)] = $data;
|
||||
$this->_originalEntityData[$oid] = $data;
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
@ -1011,11 +1014,11 @@ class Doctrine_ORM_UnitOfWork
|
|||
$class->getReflectionProperty($field)->setValue($entity, $value);
|
||||
}
|
||||
} else {
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
foreach ($data as $field => $value) {
|
||||
$currentValue = $class->getReflectionProperty($field)->getValue($entity);
|
||||
if ( ! isset($this->_originalEntityData[$oid]) ||
|
||||
$currentValue == $this->_originalEntityData[$oid]) {
|
||||
if ( ! isset($this->_originalEntityData[$oid][$field]) ||
|
||||
$currentValue == $this->_originalEntityData[$oid][$field]) {
|
||||
$class->getReflectionProperty($field)->setValue($entity, $value);
|
||||
}
|
||||
}
|
||||
|
@ -1058,6 +1061,61 @@ class Doctrine_ORM_UnitOfWork
|
|||
{
|
||||
return $this->_identityMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original data of an entity. The original data is the data that was
|
||||
* present at the time the entity was reconstituted from the database.
|
||||
*
|
||||
* @param object $entity
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginalEntityData($entity)
|
||||
{
|
||||
$oid = spl_object_hash($entity);
|
||||
if (isset($this->_originalEntityData[$oid])) {
|
||||
return $this->_originalEntityData[$oid];
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* For hydration purposes only.
|
||||
*
|
||||
* Sets a property of the original data array of an entity.
|
||||
*
|
||||
* @param string $oid
|
||||
* @param string $property
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setOriginalEntityProperty($oid, $property, $value)
|
||||
{
|
||||
$this->_originalEntityData[$oid][$property] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* For hydration purposes only.
|
||||
*
|
||||
* Adds a managed collection to the UnitOfWork.
|
||||
*
|
||||
* @param Doctrine\ORM\Collection $coll
|
||||
*/
|
||||
public function addManagedCollection(Doctrine_ORM_Collection $coll)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the identifier of an entity.
|
||||
*
|
||||
* @param object $entity
|
||||
* @return array The identifier values.
|
||||
*/
|
||||
public function getEntityIdentifier($entity)
|
||||
{
|
||||
return $this->_entityIdentifiers[spl_object_hash($entity)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -871,6 +871,7 @@ class Orm_Hydration_BasicHydrationTest extends Doctrine_OrmTestCase
|
|||
$this->assertEquals(3, count($result[0]->boards));
|
||||
$this->assertTrue(isset($result[1]->boards));
|
||||
$this->assertEquals(1, count($result[1]->boards));
|
||||
|
||||
} else if ($hydrationMode == Doctrine_ORM_Query::HYDRATE_SCALAR) {
|
||||
//...
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
require_once 'lib/DoctrineTestInit.php';
|
||||
require_once 'lib/mocks/Doctrine_EntityManagerMock.php';
|
||||
require_once 'lib/mocks/Doctrine_ConnectionMock.php';
|
||||
require_once 'lib/mocks/Doctrine_ClassMetadataMock.php';
|
||||
require_once 'lib/mocks/Doctrine_UnitOfWorkMock.php';
|
||||
require_once 'lib/mocks/Doctrine_IdentityIdGeneratorMock.php';
|
||||
|
||||
/**
|
||||
* UnitOfWork tests.
|
||||
|
@ -12,16 +13,11 @@ require_once 'lib/mocks/Doctrine_ClassMetadataMock.php';
|
|||
class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
private $_unitOfWork;
|
||||
private $_user;
|
||||
|
||||
// Mocks
|
||||
|
||||
// Provides a sequence mock to the UnitOfWork
|
||||
private $_connectionMock;
|
||||
// The sequence mock
|
||||
private $_idGeneratorMock;
|
||||
// The persister mock used by the UnitOfWork
|
||||
private $_persisterMock;
|
||||
// The EntityManager mock that provides the mock persister
|
||||
private $_emMock;
|
||||
|
||||
|
@ -30,106 +26,141 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase
|
|||
|
||||
$this->_connectionMock = new Doctrine_ConnectionMock(array());
|
||||
$this->_emMock = Doctrine_EntityManagerMock::create($this->_connectionMock, "uowMockEm");
|
||||
$this->_idGeneratorMock = new Doctrine_SequenceMock($this->_emMock);
|
||||
$this->_emMock->setIdGenerator('ForumUser', $this->_idGeneratorMock);
|
||||
$this->_emMock->setIdGenerator('ForumAvatar', $this->_idGeneratorMock);
|
||||
|
||||
$this->_persisterMock = new Doctrine_EntityPersisterMock(
|
||||
$this->_emMock, $this->_emMock->getClassMetadata("ForumUser"));
|
||||
$this->_emMock->setEntityPersister($this->_persisterMock);
|
||||
|
||||
$this->_emMock->activate();
|
||||
|
||||
// SUT
|
||||
$this->_unitOfWork = $this->_emMock->getUnitOfWork();
|
||||
|
||||
$this->_user = new ForumUser();
|
||||
$this->_user->id = 1;
|
||||
$this->_user->username = 'romanb';
|
||||
$this->_unitOfWork = new Doctrine_UnitOfWorkMock($this->_emMock);
|
||||
$this->_emMock->setUnitOfWork($this->_unitOfWork);
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
//$this->_user->free();
|
||||
}
|
||||
|
||||
/* Basic registration tests */
|
||||
|
||||
public function testRegisterNew()
|
||||
{
|
||||
// registerNew() is normally called in save()/persist()
|
||||
$this->_unitOfWork->registerNew($this->_user);
|
||||
$this->assertTrue($this->_unitOfWork->isRegisteredNew($this->_user));
|
||||
$this->assertTrue($this->_unitOfWork->isInIdentityMap($this->_user));
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredDirty($this->_user));
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
|
||||
}
|
||||
|
||||
/*public function testRegisterNewPerf() {
|
||||
$s = microtime(true);
|
||||
|
||||
for ($i=1; $i<40000; $i++) {
|
||||
$user = new ForumUser();
|
||||
$user->id = $i;
|
||||
$this->_unitOfWork->registerNew($user);
|
||||
}
|
||||
$e = microtime(true);
|
||||
|
||||
echo $e - $s . " seconds" . PHP_EOL;
|
||||
}*/
|
||||
|
||||
public function testRegisterRemovedOnNewEntityIsIgnored()
|
||||
{
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
|
||||
$this->_unitOfWork->registerDeleted($this->_user);
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
|
||||
$user = new ForumUser();
|
||||
$user->username = 'romanb';
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($user));
|
||||
$this->_unitOfWork->registerDeleted($user);
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($user));
|
||||
}
|
||||
|
||||
|
||||
/* Operational tests */
|
||||
|
||||
public function testSavingSingleEntityWithIdentityColumnForcesInsert()
|
||||
{
|
||||
$this->_unitOfWork->save($this->_user);
|
||||
|
||||
$this->assertEquals(1, count($this->_persisterMock->getInserts())); // insert forced
|
||||
$this->assertEquals(0, count($this->_persisterMock->getUpdates()));
|
||||
$this->assertEquals(0, count($this->_persisterMock->getDeletes()));
|
||||
|
||||
$this->assertTrue($this->_unitOfWork->isInIdentityMap($this->_user));
|
||||
|
||||
{
|
||||
// Setup fake persister and id generator for identity generation
|
||||
$userPersister = new Doctrine_EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("ForumUser"));
|
||||
$this->_emMock->setEntityPersister('ForumUser', $userPersister);
|
||||
$idGeneratorMock = new Doctrine_IdentityIdGeneratorMock($this->_emMock);
|
||||
$this->_emMock->setIdGenerator('ForumUser', $idGeneratorMock);
|
||||
$userPersister->setMockIdGeneratorType(Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
||||
|
||||
// Test
|
||||
$user = new ForumUser();
|
||||
$user->username = 'romanb';
|
||||
$this->_unitOfWork->save($user);
|
||||
|
||||
// Check
|
||||
$this->assertEquals(1, count($userPersister->getInserts())); // insert forced
|
||||
$this->assertEquals(0, count($userPersister->getUpdates()));
|
||||
$this->assertEquals(0, count($userPersister->getDeletes()));
|
||||
$this->assertTrue($this->_unitOfWork->isInIdentityMap($user));
|
||||
// should no longer be scheduled for insert
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredNew($this->_user));
|
||||
$this->assertFalse($this->_unitOfWork->isRegisteredNew($user));
|
||||
// should have an id
|
||||
$this->assertTrue(is_numeric($this->_user->id));
|
||||
$this->assertTrue(is_numeric($user->id));
|
||||
|
||||
// Now lets check whether a subsequent commit() does anything
|
||||
|
||||
$this->_persisterMock->reset();
|
||||
|
||||
$userPersister->reset();
|
||||
|
||||
// Test
|
||||
$this->_unitOfWork->commit(); // shouldnt do anything
|
||||
|
||||
// verify that nothing happened
|
||||
$this->assertEquals(0, count($this->_persisterMock->getInserts()));
|
||||
$this->assertEquals(0, count($this->_persisterMock->getUpdates()));
|
||||
$this->assertEquals(0, count($this->_persisterMock->getDeletes()));
|
||||
// Check. Verify that nothing happened.
|
||||
$this->assertEquals(0, count($userPersister->getInserts()));
|
||||
$this->assertEquals(0, count($userPersister->getUpdates()));
|
||||
$this->assertEquals(0, count($userPersister->getDeletes()));
|
||||
}
|
||||
|
||||
public function testCommitOrder()
|
||||
|
||||
/**
|
||||
* Tests a scenario where a save() operation is cascaded from a ForumUser
|
||||
* to its associated ForumAvatar, both entities using IDENTITY id generation.
|
||||
*/
|
||||
public function testCascadedIdentityColumnInsert()
|
||||
{
|
||||
// Setup fake persister and id generator for identity generation
|
||||
//ForumUser
|
||||
$userPersister = new Doctrine_EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("ForumUser"));
|
||||
$this->_emMock->setEntityPersister('ForumUser', $userPersister);
|
||||
$userIdGeneratorMock = new Doctrine_IdentityIdGeneratorMock($this->_emMock);
|
||||
$this->_emMock->setIdGenerator('ForumUser', $userIdGeneratorMock);
|
||||
$userPersister->setMockIdGeneratorType(Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
||||
// ForumAvatar
|
||||
$avatarPersister = new Doctrine_EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("ForumAvatar"));
|
||||
$this->_emMock->setEntityPersister('ForumAvatar', $avatarPersister);
|
||||
$avatarIdGeneratorMock = new Doctrine_IdentityIdGeneratorMock($this->_emMock);
|
||||
$this->_emMock->setIdGenerator('ForumAvatar', $avatarIdGeneratorMock);
|
||||
$avatarPersister->setMockIdGeneratorType(Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_IDENTITY);
|
||||
|
||||
// Test
|
||||
$user = new ForumUser();
|
||||
$user->username = 'romanb';
|
||||
$avatar = new ForumAvatar();
|
||||
$this->_user->avatar = $avatar;
|
||||
$this->_unitOfWork->save($this->_user); // save cascaded to avatar
|
||||
|
||||
$this->assertEquals(2, count($this->_persisterMock->getInserts())); // insert forced
|
||||
$this->assertEquals(0, count($this->_persisterMock->getUpdates()));
|
||||
$this->assertEquals(0, count($this->_persisterMock->getDeletes()));
|
||||
// verify order of inserts()s
|
||||
$inserts = $this->_persisterMock->getInserts();
|
||||
$this->assertSame($avatar, $inserts[0]);
|
||||
$this->assertSame($this->_user, $inserts[1]);
|
||||
|
||||
//...
|
||||
$user->avatar = $avatar;
|
||||
$this->_unitOfWork->save($user); // save cascaded to avatar
|
||||
|
||||
$this->assertTrue(is_numeric($user->id));
|
||||
$this->assertTrue(is_numeric($avatar->id));
|
||||
|
||||
$this->assertEquals(1, count($userPersister->getInserts())); // insert forced
|
||||
$this->assertEquals(0, count($userPersister->getUpdates()));
|
||||
$this->assertEquals(0, count($userPersister->getDeletes()));
|
||||
|
||||
$this->assertEquals(1, count($avatarPersister->getInserts())); // insert forced
|
||||
$this->assertEquals(0, count($avatarPersister->getUpdates()));
|
||||
$this->assertEquals(0, count($avatarPersister->getDeletes()));
|
||||
}
|
||||
|
||||
public function testComputeDataChangeSet()
|
||||
{
|
||||
$user1 = new ForumUser();
|
||||
$user1->id = 1;
|
||||
$user1->username = "romanb";
|
||||
$user1->avatar = new ForumAvatar();
|
||||
// Fake managed state
|
||||
$this->_unitOfWork->setEntityState($user1, Doctrine_ORM_UnitOfWork::STATE_MANAGED);
|
||||
|
||||
$user2 = new ForumUser();
|
||||
$user2->id = 2;
|
||||
$user2->username = "jwage";
|
||||
$this->_unitOfWork->setEntityState($user2, Doctrine_ORM_UnitOfWork::STATE_MANAGED);
|
||||
|
||||
$this->_unitOfWork->setOriginalEntityData($user1, array(
|
||||
'id' => 1, 'username' => 'roman'
|
||||
));
|
||||
$this->_unitOfWork->setOriginalEntityData($user2, array(
|
||||
'id' => 2, 'username' => 'jon'
|
||||
));
|
||||
|
||||
$this->_unitOfWork->computeDataChangeSet(array($user1, $user2));
|
||||
|
||||
$user1ChangeSet = $this->_unitOfWork->getDataChangeSet($user1);
|
||||
$this->assertTrue(is_array($user1ChangeSet));
|
||||
$this->assertEquals(2, count($user1ChangeSet));
|
||||
$this->assertTrue(isset($user1ChangeSet['username']));
|
||||
$this->assertEquals(array('roman' => 'romanb'), $user1ChangeSet['username']);
|
||||
$this->assertTrue(isset($user1ChangeSet['avatar']));
|
||||
$this->assertSame(array(null => $user1->avatar), $user1ChangeSet['avatar']);
|
||||
|
||||
$user2ChangeSet = $this->_unitOfWork->getDataChangeSet($user2);
|
||||
$this->assertTrue(is_array($user2ChangeSet));
|
||||
$this->assertEquals(1, count($user2ChangeSet));
|
||||
$this->assertTrue(isset($user2ChangeSet['username']));
|
||||
$this->assertEquals(array('jon' => 'jwage'), $user2ChangeSet['username']);
|
||||
}
|
||||
|
||||
/*
|
||||
public function testSavingSingleEntityWithSequenceIdGeneratorSchedulesInsert()
|
||||
{
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
require_once 'lib/mocks/Doctrine_EntityPersisterMock.php';
|
||||
|
||||
/**
|
||||
* Special EntityManager mock used for testing purposes.
|
||||
*/
|
||||
class Doctrine_EntityManagerMock extends Doctrine_ORM_EntityManager
|
||||
{
|
||||
private $_persisterMock;
|
||||
|
@ -13,8 +16,8 @@ class Doctrine_EntityManagerMock extends Doctrine_ORM_EntityManager
|
|||
*/
|
||||
public function getEntityPersister($entityName)
|
||||
{
|
||||
return isset($this->_persisterMock) ? $this->_persisterMock :
|
||||
parent::getEntityPersister($entityName);
|
||||
return isset($this->_persisterMock[$entityName]) ?
|
||||
$this->_persisterMock[$entityName] : parent::getEntityPersister($entityName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,24 +30,36 @@ class Doctrine_EntityManagerMock extends Doctrine_ORM_EntityManager
|
|||
|
||||
/* Mock API */
|
||||
|
||||
/**
|
||||
* Sets a (mock) UnitOfWork that will be returned when getUnitOfWork() is called.
|
||||
*
|
||||
* @param <type> $uow
|
||||
*/
|
||||
public function setUnitOfWork($uow)
|
||||
{
|
||||
$this->_uowMock = $uow;
|
||||
}
|
||||
|
||||
public function setEntityPersister($persister)
|
||||
/**
|
||||
* Sets a (mock) persister for an entity class that will be returned when
|
||||
* getEntityPersister() is invoked for that class.
|
||||
*
|
||||
* @param <type> $entityName
|
||||
* @param <type> $persister
|
||||
*/
|
||||
public function setEntityPersister($entityName, $persister)
|
||||
{
|
||||
$this->_persisterMock = $persister;
|
||||
$this->_persisterMock[$entityName] = $persister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock factory method.
|
||||
* Mock factory method to create an EntityManager.
|
||||
*
|
||||
* @param unknown_type $conn
|
||||
* @param unknown_type $name
|
||||
* @param Doctrine_Configuration $config
|
||||
* @param Doctrine_EventManager $eventManager
|
||||
* @return unknown
|
||||
* @return Doctrine\ORM\EntityManager
|
||||
*/
|
||||
public static function create($conn, $name, Doctrine_ORM_Configuration $config = null,
|
||||
Doctrine_Common_EventManager $eventManager = null)
|
||||
|
|
|
@ -1,22 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* EntityPersister implementation used for mocking during tests.
|
||||
*/
|
||||
class Doctrine_EntityPersisterMock extends Doctrine_ORM_Persisters_StandardEntityPersister
|
||||
{
|
||||
private $_inserts = array();
|
||||
private $_updates = array();
|
||||
private $_deletes = array();
|
||||
|
||||
private $_identityColumnValueCounter = 0;
|
||||
|
||||
private $_mockIdGeneratorType;
|
||||
|
||||
/**
|
||||
* @param <type> $entity
|
||||
* @return <type>
|
||||
* @override
|
||||
*/
|
||||
public function insert($entity)
|
||||
{
|
||||
$class = $this->_em->getClassMetadata(get_class($entity));
|
||||
if ($class->isIdGeneratorIdentity()) {
|
||||
$class->setEntityIdentifier($entity, $this->_identityColumnValueCounter++);
|
||||
$this->_em->getUnitOfWork()->addToIdentityMap($entity);
|
||||
}
|
||||
|
||||
$this->_inserts[] = $entity;
|
||||
if ( ! is_null($this->_mockIdGeneratorType) && $this->_mockIdGeneratorType == Doctrine_ORM_Mapping_ClassMetadata::GENERATOR_TYPE_IDENTITY
|
||||
|| $this->_classMetadata->isIdGeneratorIdentity()) {
|
||||
return $this->_identityColumnValueCounter++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setMockIdGeneratorType($genType) {
|
||||
$this->_mockIdGeneratorType = $genType;
|
||||
}
|
||||
|
||||
public function update(Doctrine_ORM_Entity $entity)
|
||||
|
@ -51,7 +61,5 @@ class Doctrine_EntityPersisterMock extends Doctrine_ORM_Persisters_StandardEntit
|
|||
$this->_updates = array();
|
||||
$this->_deletes = array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
20
tests/lib/mocks/Doctrine_IdentityIdGeneratorMock.php
Normal file
20
tests/lib/mocks/Doctrine_IdentityIdGeneratorMock.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Description of Doctrine_IdentityIdGeneratorMock
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class Doctrine_IdentityIdGeneratorMock extends Doctrine_ORM_Id_IdentityGenerator
|
||||
{
|
||||
private $_mockPostInsertId;
|
||||
|
||||
public function setMockPostInsertId($id) {
|
||||
$this->_mockPostInsertId = $id;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -15,8 +15,6 @@ class Doctrine_SequenceMock extends Doctrine_ORM_Id_SequenceGenerator
|
|||
return $this->_sequenceNumber++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
|
|
|
@ -17,7 +17,7 @@ class Doctrine_UnitOfWorkMock extends Doctrine_ORM_UnitOfWork {
|
|||
* @override
|
||||
*/
|
||||
public function getDataChangeSet($entity) {
|
||||
$oid = spl_object_id($entity);
|
||||
$oid = spl_object_hash($entity);
|
||||
return isset($this->_mockDataChangeSets[$oid]) ?
|
||||
$this->_mockDataChangeSets[$oid] : parent::getDataChangeSet($entity);
|
||||
}
|
||||
|
@ -25,7 +25,17 @@ class Doctrine_UnitOfWorkMock extends Doctrine_ORM_UnitOfWork {
|
|||
/* MOCK API */
|
||||
|
||||
public function setDataChangeSet($entity, array $mockChangeSet) {
|
||||
$this->_mockDataChangeSets[spl_object_id($entity)] = $mockChangeSet;
|
||||
$this->_mockDataChangeSets[spl_object_hash($entity)] = $mockChangeSet;
|
||||
}
|
||||
|
||||
public function setEntityState($entity, $state)
|
||||
{
|
||||
$this->_entityStates[spl_object_hash($entity)] = $state;
|
||||
}
|
||||
|
||||
public function setOriginalEntityData($entity, array $originalData)
|
||||
{
|
||||
$this->_originalEntityData[spl_object_hash($entity)] = $originalData;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,18 @@ class ForumUser
|
|||
|
||||
public static function initMetadata($mapping)
|
||||
{
|
||||
/*$mapping->setClassMetadata(array(
|
||||
'doctrine.inheritanceType' => 'joined',
|
||||
'doctrine.discriminatorColumn' => 'dtype',
|
||||
'doctrine.discriminatorMap' => array('user' => 'ForumUser', 'admin' => 'ForumAdministrator'),
|
||||
'doctrine.subclasses' => array('ForumAdministrator')
|
||||
));
|
||||
$mapping->setFieldMetadata('id', array(
|
||||
'doctrine.type' => 'integer',
|
||||
'doctrine.id' => true,
|
||||
'doctrine.idGenerator' => 'auto'
|
||||
));*/
|
||||
|
||||
// inheritance mapping
|
||||
$mapping->setInheritanceType('joined', array(
|
||||
'discriminatorColumn' => 'dtype',
|
||||
|
|
Loading…
Add table
Reference in a new issue