1
0
mirror of synced 2025-01-18 22:41:43 +03:00

Fixed DDC-455, DDC-600. Some behavior and API polish in the UoW as well as continued _ prefix removal in some core classes. Cleanups and fixes for one-to-one orphan removal including tests.

This commit is contained in:
Roman S. Borschel 2010-07-08 00:20:54 +02:00
parent 88b0813536
commit 4212b88edc
11 changed files with 789 additions and 656 deletions

View File

@ -43,66 +43,66 @@ class EntityManager
*
* @var Doctrine\ORM\Configuration
*/
private $_config;
private $config;
/**
* The database connection used by the EntityManager.
*
* @var Doctrine\DBAL\Connection
*/
private $_conn;
private $conn;
/**
* The metadata factory, used to retrieve the ORM metadata of entity classes.
*
* @var Doctrine\ORM\Mapping\ClassMetadataFactory
*/
private $_metadataFactory;
private $metadataFactory;
/**
* The EntityRepository instances.
*
* @var array
*/
private $_repositories = array();
private $repositories = array();
/**
* The UnitOfWork used to coordinate object-level transactions.
*
* @var Doctrine\ORM\UnitOfWork
*/
private $_unitOfWork;
private $unitOfWork;
/**
* The event manager that is the central point of the event system.
*
* @var Doctrine\Common\EventManager
*/
private $_eventManager;
private $eventManager;
/**
* The maintained (cached) hydrators. One instance per type.
*
* @var array
*/
private $_hydrators = array();
private $hydrators = array();
/**
* The proxy factory used to create dynamic proxies.
*
* @var Doctrine\ORM\Proxy\ProxyFactory
*/
private $_proxyFactory;
private $proxyFactory;
/**
* @var ExpressionBuilder The expression builder instance used to generate query expressions.
*/
private $_expressionBuilder;
private $expressionBuilder;
/**
* Whether the EntityManager is closed or not.
*/
private $_closed = false;
private $closed = false;
/**
* Creates a new EntityManager that operates on the given database connection
@ -114,13 +114,13 @@ class EntityManager
*/
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
{
$this->_conn = $conn;
$this->_config = $config;
$this->_eventManager = $eventManager;
$this->_metadataFactory = new ClassMetadataFactory($this);
$this->_metadataFactory->setCacheDriver($this->_config->getMetadataCacheImpl());
$this->_unitOfWork = new UnitOfWork($this);
$this->_proxyFactory = new ProxyFactory($this,
$this->conn = $conn;
$this->config = $config;
$this->eventManager = $eventManager;
$this->metadataFactory = new ClassMetadataFactory($this);
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
$this->unitOfWork = new UnitOfWork($this);
$this->proxyFactory = new ProxyFactory($this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses());
@ -133,7 +133,7 @@ class EntityManager
*/
public function getConnection()
{
return $this->_conn;
return $this->conn;
}
/**
@ -143,7 +143,7 @@ class EntityManager
*/
public function getMetadataFactory()
{
return $this->_metadataFactory;
return $this->metadataFactory;
}
/**
@ -162,10 +162,10 @@ class EntityManager
*/
public function getExpressionBuilder()
{
if ($this->_expressionBuilder === null) {
$this->_expressionBuilder = new Query\Expr;
if ($this->expressionBuilder === null) {
$this->expressionBuilder = new Query\Expr;
}
return $this->_expressionBuilder;
return $this->expressionBuilder;
}
/**
@ -175,7 +175,7 @@ class EntityManager
*/
public function beginTransaction()
{
$this->_conn->beginTransaction();
$this->conn->beginTransaction();
}
/**
@ -192,14 +192,14 @@ class EntityManager
*/
public function transactional(Closure $func)
{
$this->_conn->beginTransaction();
$this->conn->beginTransaction();
try {
$func($this);
$this->flush();
$this->_conn->commit();
$this->conn->commit();
} catch (Exception $e) {
$this->close();
$this->_conn->rollback();
$this->conn->rollback();
throw $e;
}
}
@ -211,7 +211,7 @@ class EntityManager
*/
public function commit()
{
$this->_conn->commit();
$this->conn->commit();
}
/**
@ -221,7 +221,7 @@ class EntityManager
*/
public function rollback()
{
$this->_conn->rollback();
$this->conn->rollback();
}
/**
@ -232,7 +232,7 @@ class EntityManager
*/
public function getClassMetadata($className)
{
return $this->_metadataFactory->getMetadataFor($className);
return $this->metadataFactory->getMetadataFor($className);
}
/**
@ -258,7 +258,7 @@ class EntityManager
*/
public function createNamedQuery($name)
{
return $this->createQuery($this->_config->getNamedQuery($name));
return $this->createQuery($this->config->getNamedQuery($name));
}
/**
@ -284,7 +284,7 @@ class EntityManager
*/
public function createNamedNativeQuery($name)
{
list($sql, $rsm) = $this->_config->getNamedNativeQuery($name);
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
@ -308,8 +308,8 @@ class EntityManager
*/
public function flush()
{
$this->_errorIfClosed();
$this->_unitOfWork->commit();
$this->errorIfClosed();
$this->unitOfWork->commit();
}
/**
@ -340,17 +340,17 @@ class EntityManager
*/
public function getReference($entityName, $identifier)
{
$class = $this->_metadataFactory->getMetadataFor($entityName);
$class = $this->metadataFactory->getMetadataFor($entityName);
// Check identity map first, if its already in there just return it.
if ($entity = $this->_unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
return $entity;
}
if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $identifier);
}
$entity = $this->_proxyFactory->getProxy($class->name, $identifier);
$this->_unitOfWork->registerManaged($entity, $identifier, array());
$entity = $this->proxyFactory->getProxy($class->name, $identifier);
$this->unitOfWork->registerManaged($entity, $identifier, array());
return $entity;
}
@ -364,7 +364,7 @@ class EntityManager
public function clear($entityName = null)
{
if ($entityName === null) {
$this->_unitOfWork->clear();
$this->unitOfWork->clear();
} else {
//TODO
throw new ORMException("EntityManager#clear(\$entityName) not yet implemented.");
@ -379,7 +379,7 @@ class EntityManager
public function close()
{
$this->clear();
$this->_closed = true;
$this->closed = true;
}
/**
@ -398,8 +398,8 @@ class EntityManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->_errorIfClosed();
$this->_unitOfWork->persist($entity);
$this->errorIfClosed();
$this->unitOfWork->persist($entity);
}
/**
@ -415,8 +415,8 @@ class EntityManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->_errorIfClosed();
$this->_unitOfWork->remove($entity);
$this->errorIfClosed();
$this->unitOfWork->remove($entity);
}
/**
@ -430,8 +430,8 @@ class EntityManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->_errorIfClosed();
$this->_unitOfWork->refresh($entity);
$this->errorIfClosed();
$this->unitOfWork->refresh($entity);
}
/**
@ -448,7 +448,7 @@ class EntityManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->_unitOfWork->detach($entity);
$this->unitOfWork->detach($entity);
}
/**
@ -464,8 +464,8 @@ class EntityManager
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
}
$this->_errorIfClosed();
return $this->_unitOfWork->merge($entity);
$this->errorIfClosed();
return $this->unitOfWork->merge($entity);
}
/**
@ -492,7 +492,7 @@ class EntityManager
*/
public function lock($entity, $lockMode, $lockVersion = null)
{
$this->_unitOfWork->lock($entity, $lockMode, $lockVersion);
$this->unitOfWork->lock($entity, $lockMode, $lockVersion);
}
/**
@ -503,8 +503,8 @@ class EntityManager
*/
public function getRepository($entityName)
{
if (isset($this->_repositories[$entityName])) {
return $this->_repositories[$entityName];
if (isset($this->repositories[$entityName])) {
return $this->repositories[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
@ -516,7 +516,7 @@ class EntityManager
$repository = new EntityRepository($this, $metadata);
}
$this->_repositories[$entityName] = $repository;
$this->repositories[$entityName] = $repository;
return $repository;
}
@ -529,9 +529,9 @@ class EntityManager
*/
public function contains($entity)
{
return $this->_unitOfWork->isScheduledForInsert($entity) ||
$this->_unitOfWork->isInIdentityMap($entity) &&
! $this->_unitOfWork->isScheduledForDelete($entity);
return $this->unitOfWork->isScheduledForInsert($entity) ||
$this->unitOfWork->isInIdentityMap($entity) &&
! $this->unitOfWork->isScheduledForDelete($entity);
}
/**
@ -541,7 +541,7 @@ class EntityManager
*/
public function getEventManager()
{
return $this->_eventManager;
return $this->eventManager;
}
/**
@ -551,7 +551,7 @@ class EntityManager
*/
public function getConfiguration()
{
return $this->_config;
return $this->config;
}
/**
@ -559,9 +559,9 @@ class EntityManager
*
* @throws ORMException If the EntityManager is closed.
*/
private function _errorIfClosed()
private function errorIfClosed()
{
if ($this->_closed) {
if ($this->closed) {
throw ORMException::entityManagerClosed();
}
}
@ -573,7 +573,7 @@ class EntityManager
*/
public function getUnitOfWork()
{
return $this->_unitOfWork;
return $this->unitOfWork;
}
/**
@ -587,11 +587,11 @@ class EntityManager
*/
public function getHydrator($hydrationMode)
{
if ( ! isset($this->_hydrators[$hydrationMode])) {
$this->_hydrators[$hydrationMode] = $this->newHydrator($hydrationMode);
if ( ! isset($this->hydrators[$hydrationMode])) {
$this->hydrators[$hydrationMode] = $this->newHydrator($hydrationMode);
}
return $this->_hydrators[$hydrationMode];
return $this->hydrators[$hydrationMode];
}
/**
@ -616,7 +616,7 @@ class EntityManager
$hydrator = new Internal\Hydration\SingleScalarHydrator($this);
break;
default:
if ($class = $this->_config->getCustomHydrationMode($hydrationMode)) {
if ($class = $this->config->getCustomHydrationMode($hydrationMode)) {
$hydrator = new $class($this);
break;
}
@ -633,7 +633,7 @@ class EntityManager
*/
public function getProxyFactory()
{
return $this->_proxyFactory;
return $this->proxyFactory;
}
/**

View File

@ -45,23 +45,6 @@ class ORMException extends Exception
return new self("Unrecognized field: $field");
}
public static function removedEntityInCollectionDetected($entity, $assoc)
{
return new self("Removed entity of type " . get_class($entity)
. " detected in collection '" . $assoc->sourceFieldName . "' during flush."
. " Remove deleted entities from collections.");
}
public static function invalidEntityState($state)
{
return new self("Invalid entity state: $state.");
}
public static function detachedEntityCannotBeRemoved()
{
return new self("A detached entity can not be removed.");
}
public static function invalidFlushMode($mode)
{
return new self("'$mode' is an invalid flush mode.");

View File

@ -46,14 +46,14 @@ final class PersistentCollection implements Collection
*
* @var array
*/
private $_snapshot = array();
private $snapshot = array();
/**
* The entity that owns this collection.
*
* @var object
*/
private $_owner;
private $owner;
/**
* The association mapping the collection belongs to.
@ -61,14 +61,14 @@ final class PersistentCollection implements Collection
*
* @var Doctrine\ORM\Mapping\AssociationMapping
*/
private $_association;
private $association;
/**
* The EntityManager that manages the persistence of the collection.
*
* @var Doctrine\ORM\EntityManager
*/
private $_em;
private $em;
/**
* The name of the field on the target entities that points to the owner
@ -76,12 +76,12 @@ final class PersistentCollection implements Collection
*
* @var string
*/
private $_backRefFieldName;
private $backRefFieldName;
/**
* The class descriptor of the collection's entity type.
*/
private $_typeClass;
private $typeClass;
/**
* Whether the collection is dirty and needs to be synchronized with the database
@ -89,21 +89,21 @@ final class PersistentCollection implements Collection
*
* @var boolean
*/
private $_isDirty = false;
private $isDirty = false;
/**
* Whether the collection has already been initialized.
*
* @var boolean
*/
private $_initialized = true;
private $initialized = true;
/**
* The wrapped Collection instance.
*
* @var Collection
*/
private $_coll;
private $coll;
/**
* Creates a new persistent collection.
@ -114,9 +114,9 @@ final class PersistentCollection implements Collection
*/
public function __construct(EntityManager $em, $class, $coll)
{
$this->_coll = $coll;
$this->_em = $em;
$this->_typeClass = $class;
$this->coll = $coll;
$this->em = $em;
$this->typeClass = $class;
}
/**
@ -129,9 +129,9 @@ final class PersistentCollection implements Collection
*/
public function setOwner($entity, AssociationMapping $assoc)
{
$this->_owner = $entity;
$this->_association = $assoc;
$this->_backRefFieldName = $assoc->inversedBy ?: $assoc->mappedBy;
$this->owner = $entity;
$this->association = $assoc;
$this->backRefFieldName = $assoc->inversedBy ?: $assoc->mappedBy;
}
/**
@ -142,12 +142,12 @@ final class PersistentCollection implements Collection
*/
public function getOwner()
{
return $this->_owner;
return $this->owner;
}
public function getTypeClass()
{
return $this->_typeClass;
return $this->typeClass;
}
/**
@ -159,17 +159,17 @@ final class PersistentCollection implements Collection
*/
public function hydrateAdd($element)
{
$this->_coll->add($element);
$this->coll->add($element);
// If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference.
if ($this->_backRefFieldName && $this->_association->isOneToMany()) {
if ($this->backRefFieldName && $this->association->isOneToMany()) {
// Set back reference to owner
$this->_typeClass->reflFields[$this->_backRefFieldName]
->setValue($element, $this->_owner);
$this->_em->getUnitOfWork()->setOriginalEntityProperty(
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
$this->em->getUnitOfWork()->setOriginalEntityProperty(
spl_object_hash($element),
$this->_backRefFieldName,
$this->_owner);
$this->backRefFieldName,
$this->owner);
}
}
@ -182,13 +182,13 @@ final class PersistentCollection implements Collection
*/
public function hydrateSet($key, $element)
{
$this->_coll->set($key, $element);
$this->coll->set($key, $element);
// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->_backRefFieldName && $this->_association->isOneToMany()) {
if ($this->backRefFieldName && $this->association->isOneToMany()) {
// Set back reference to owner
$this->_typeClass->reflFields[$this->_backRefFieldName]
->setValue($element, $this->_owner);
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
}
}
@ -196,24 +196,24 @@ final class PersistentCollection implements Collection
* Initializes the collection by loading its contents from the database
* if the collection is not yet initialized.
*/
private function _initialize()
private function initialize()
{
if ( ! $this->_initialized && $this->_association) {
if ($this->_isDirty) {
if ( ! $this->initialized && $this->association) {
if ($this->isDirty) {
// Has NEW objects added through add(). Remember them.
$newObjects = $this->_coll->toArray();
$newObjects = $this->coll->toArray();
}
$this->_coll->clear();
$this->_association->load($this->_owner, $this, $this->_em);
$this->coll->clear();
$this->association->load($this->owner, $this, $this->em);
$this->takeSnapshot();
// Reattach NEW objects added through add(), if any.
if (isset($newObjects)) {
foreach ($newObjects as $obj) {
$this->_coll->add($obj);
$this->coll->add($obj);
}
$this->_isDirty = true;
$this->isDirty = true;
}
$this->_initialized = true;
$this->initialized = true;
}
}
@ -223,8 +223,8 @@ final class PersistentCollection implements Collection
*/
public function takeSnapshot()
{
$this->_snapshot = $this->_coll->toArray();
$this->_isDirty = false;
$this->snapshot = $this->coll->toArray();
$this->isDirty = false;
}
/**
@ -235,7 +235,7 @@ final class PersistentCollection implements Collection
*/
public function getSnapshot()
{
return $this->_snapshot;
return $this->snapshot;
}
/**
@ -246,7 +246,7 @@ final class PersistentCollection implements Collection
*/
public function getDeleteDiff()
{
return array_udiff_assoc($this->_snapshot, $this->_coll->toArray(),
return array_udiff_assoc($this->snapshot, $this->coll->toArray(),
function($a, $b) {return $a === $b ? 0 : 1;});
}
@ -258,7 +258,7 @@ final class PersistentCollection implements Collection
*/
public function getInsertDiff()
{
return array_udiff_assoc($this->_coll->toArray(), $this->_snapshot,
return array_udiff_assoc($this->coll->toArray(), $this->snapshot,
function($a, $b) {return $a === $b ? 0 : 1;});
}
@ -269,18 +269,18 @@ final class PersistentCollection implements Collection
*/
public function getMapping()
{
return $this->_association;
return $this->association;
}
/**
* Marks this collection as changed/dirty.
*/
private function _changed()
private function changed()
{
if ( ! $this->_isDirty) {
$this->_isDirty = true;
//if ($this->_isNotifyRequired) {
//$this->_em->getUnitOfWork()->scheduleCollectionUpdate($this);
if ( ! $this->isDirty) {
$this->isDirty = true;
//if ($this->isNotifyRequired) {
//$this->em->getUnitOfWork()->scheduleCollectionUpdate($this);
//}
}
}
@ -293,7 +293,7 @@ final class PersistentCollection implements Collection
*/
public function isDirty()
{
return $this->_isDirty;
return $this->isDirty;
}
/**
@ -303,7 +303,7 @@ final class PersistentCollection implements Collection
*/
public function setDirty($dirty)
{
$this->_isDirty = $dirty;
$this->isDirty = $dirty;
}
/**
@ -313,7 +313,7 @@ final class PersistentCollection implements Collection
*/
public function setInitialized($bool)
{
$this->_initialized = $bool;
$this->initialized = $bool;
}
/**
@ -323,21 +323,21 @@ final class PersistentCollection implements Collection
*/
public function isInitialized()
{
return $this->_initialized;
return $this->initialized;
}
/** {@inheritdoc} */
public function first()
{
$this->_initialize();
return $this->_coll->first();
$this->initialize();
return $this->coll->first();
}
/** {@inheritdoc} */
public function last()
{
$this->_initialize();
return $this->_coll->last();
$this->initialize();
return $this->coll->last();
}
/**
@ -349,13 +349,13 @@ final class PersistentCollection implements Collection
// and the collection is not initialized and orphanRemoval is
// not used we can issue a straight SQL delete/update on the
// association (table). Without initializing the collection.
$this->_initialize();
$removed = $this->_coll->remove($key);
$this->initialize();
$removed = $this->coll->remove($key);
if ($removed) {
$this->_changed();
if ($this->_association !== null && $this->_association->isOneToMany() &&
$this->_association->orphanRemoval) {
$this->_em->getUnitOfWork()->scheduleOrphanRemoval($removed);
$this->changed();
if ($this->association !== null && $this->association->isOneToMany() &&
$this->association->orphanRemoval) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
}
}
@ -372,14 +372,14 @@ final class PersistentCollection implements Collection
// if the collection is not initialized, we could issue a straight
// SQL DELETE/UPDATE on the association (table) without initializing
// the collection.
/*if ( ! $this->_initialized) {
$this->_em->getUnitOfWork()->getCollectionPersister($this->_association)
/*if ( ! $this->initialized) {
$this->em->getUnitOfWork()->getCollectionPersister($this->association)
->deleteRows($this, $element);
}*/
$this->_initialize();
$result = $this->_coll->removeElement($element);
$this->_changed();
$this->initialize();
$result = $this->coll->removeElement($element);
$this->changed();
return $result;
}
@ -388,8 +388,8 @@ final class PersistentCollection implements Collection
*/
public function containsKey($key)
{
$this->_initialize();
return $this->_coll->containsKey($key);
$this->initialize();
return $this->coll->containsKey($key);
}
/**
@ -398,24 +398,24 @@ final class PersistentCollection implements Collection
public function contains($element)
{
/* DRAFT
if ($this->_initialized) {
return $this->_coll->contains($element);
if ($this->initialized) {
return $this->coll->contains($element);
} else {
if ($element is MANAGED) {
if ($this->_coll->contains($element)) {
if ($this->coll->contains($element)) {
return true;
}
$exists = check db for existence;
if ($exists) {
$this->_coll->add($element);
$this->coll->add($element);
}
return $exists;
}
return false;
}*/
$this->_initialize();
return $this->_coll->contains($element);
$this->initialize();
return $this->coll->contains($element);
}
/**
@ -423,8 +423,8 @@ final class PersistentCollection implements Collection
*/
public function exists(Closure $p)
{
$this->_initialize();
return $this->_coll->exists($p);
$this->initialize();
return $this->coll->exists($p);
}
/**
@ -432,8 +432,8 @@ final class PersistentCollection implements Collection
*/
public function indexOf($element)
{
$this->_initialize();
return $this->_coll->indexOf($element);
$this->initialize();
return $this->coll->indexOf($element);
}
/**
@ -441,8 +441,8 @@ final class PersistentCollection implements Collection
*/
public function get($key)
{
$this->_initialize();
return $this->_coll->get($key);
$this->initialize();
return $this->coll->get($key);
}
/**
@ -450,8 +450,8 @@ final class PersistentCollection implements Collection
*/
public function getKeys()
{
$this->_initialize();
return $this->_coll->getKeys();
$this->initialize();
return $this->coll->getKeys();
}
/**
@ -459,8 +459,8 @@ final class PersistentCollection implements Collection
*/
public function getValues()
{
$this->_initialize();
return $this->_coll->getValues();
$this->initialize();
return $this->coll->getValues();
}
/**
@ -468,8 +468,8 @@ final class PersistentCollection implements Collection
*/
public function count()
{
$this->_initialize();
return $this->_coll->count();
$this->initialize();
return $this->coll->count();
}
/**
@ -477,9 +477,9 @@ final class PersistentCollection implements Collection
*/
public function set($key, $value)
{
$this->_initialize();
$this->_coll->set($key, $value);
$this->_changed();
$this->initialize();
$this->coll->set($key, $value);
$this->changed();
}
/**
@ -487,8 +487,8 @@ final class PersistentCollection implements Collection
*/
public function add($value)
{
$this->_coll->add($value);
$this->_changed();
$this->coll->add($value);
$this->changed();
return true;
}
@ -497,8 +497,8 @@ final class PersistentCollection implements Collection
*/
public function isEmpty()
{
$this->_initialize();
return $this->_coll->isEmpty();
$this->initialize();
return $this->coll->isEmpty();
}
/**
@ -506,8 +506,8 @@ final class PersistentCollection implements Collection
*/
public function getIterator()
{
$this->_initialize();
return $this->_coll->getIterator();
$this->initialize();
return $this->coll->getIterator();
}
/**
@ -515,8 +515,8 @@ final class PersistentCollection implements Collection
*/
public function map(Closure $func)
{
$this->_initialize();
return $this->_coll->map($func);
$this->initialize();
return $this->coll->map($func);
}
/**
@ -524,8 +524,8 @@ final class PersistentCollection implements Collection
*/
public function filter(Closure $p)
{
$this->_initialize();
return $this->_coll->filter($p);
$this->initialize();
return $this->coll->filter($p);
}
/**
@ -533,8 +533,8 @@ final class PersistentCollection implements Collection
*/
public function forAll(Closure $p)
{
$this->_initialize();
return $this->_coll->forAll($p);
$this->initialize();
return $this->coll->forAll($p);
}
/**
@ -542,8 +542,8 @@ final class PersistentCollection implements Collection
*/
public function partition(Closure $p)
{
$this->_initialize();
return $this->_coll->partition($p);
$this->initialize();
return $this->coll->partition($p);
}
/**
@ -551,8 +551,8 @@ final class PersistentCollection implements Collection
*/
public function toArray()
{
$this->_initialize();
return $this->_coll->toArray();
$this->initialize();
return $this->coll->toArray();
}
/**
@ -560,14 +560,14 @@ final class PersistentCollection implements Collection
*/
public function clear()
{
$this->_initialize();
$result = $this->_coll->clear();
if ($this->_association->isOwningSide) {
$this->_changed();
$this->_em->getUnitOfWork()->scheduleCollectionDeletion($this);
$this->initialize(); // TODO: not needed!?
$result = $this->coll->clear();
if ($this->association->isOwningSide) {
$this->changed();
$this->em->getUnitOfWork()->scheduleCollectionDeletion($this);
$this->takeSnapshot();
}
return $result;
}
@ -580,7 +580,7 @@ final class PersistentCollection implements Collection
*/
public function __sleep()
{
return array('_coll', '_initialized');
return array('coll', 'initialized');
}
/* ArrayAccess implementation */
@ -623,7 +623,7 @@ final class PersistentCollection implements Collection
public function key()
{
return $this->_coll->key();
return $this->coll->key();
}
/**
@ -631,7 +631,7 @@ final class PersistentCollection implements Collection
*/
public function current()
{
return $this->_coll->current();
return $this->coll->current();
}
/**
@ -639,7 +639,7 @@ final class PersistentCollection implements Collection
*/
public function next()
{
return $this->_coll->next();
return $this->coll->next();
}
/**
@ -647,6 +647,6 @@ final class PersistentCollection implements Collection
*/
public function unwrap()
{
return $this->_coll;
return $this->coll;
}
}

View File

@ -20,9 +20,10 @@
namespace Doctrine\ORM\Persisters;
use PDO,
Doctrine\DBAL\LockMode,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\ORMException,
Doctrine\ORM\OptimisticLockException,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager,
Doctrine\ORM\Query,
Doctrine\ORM\PersistentCollection,
@ -393,7 +394,7 @@ class BasicEntityPersister
}
foreach ($uow->getEntityChangeSet($entity) as $field => $change) {
if ($versioned && $versionField == $field) { //TODO: Needed?
if ($versioned && $versionField == $field) {
continue;
}
@ -792,9 +793,9 @@ class BasicEntityPersister
: '';
$lockSql = '';
if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) {
if ($lockMode == LockMode::PESSIMISTIC_READ) {
$lockSql = ' ' . $this->_platform->getReadLockSql();
} else if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) {
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
$lockSql = ' ' . $this->_platform->getWriteLockSql();
}
@ -1006,7 +1007,7 @@ class BasicEntityPersister
*
* @param string $className
* @return string The SQL table alias.
* @todo Remove. Binding table aliases to class names is not such a good idea.
* @todo Reconsider. Binding table aliases to class names is not such a good idea.
*/
protected function _getSQLTableAlias($className)
{
@ -1030,9 +1031,9 @@ class BasicEntityPersister
{
$conditionSql = $this->_getSelectConditionSQL($criteria);
if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_READ) {
if ($lockMode == LockMode::PESSIMISTIC_READ) {
$lockSql = $this->_platform->getReadLockSql();
} else if ($lockMode == \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) {
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
$lockSql = $this->_platform->getWriteLockSql();
}

File diff suppressed because it is too large Load Diff

View File

@ -40,4 +40,9 @@ class CmsArticle
public function setAuthor(CmsUser $author) {
$this->user = $author;
}
public function addComment(CmsComment $comment) {
$this->comments[] = $comment;
$comment->setArticle($this);
}
}

View File

@ -27,4 +27,12 @@ class CmsComment
* @JoinColumn(name="article_id", referencedColumnName="id")
*/
public $article;
public function setArticle(CmsArticle $article) {
$this->article = $article;
}
public function __toString() {
return __CLASS__."[id=".$this->id."]";
}
}

View File

@ -36,7 +36,7 @@ class CmsUser
*/
public $articles;
/**
* @OneToOne(targetEntity="CmsAddress", mappedBy="user", cascade={"persist"})
* @OneToOne(targetEntity="CmsAddress", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
*/
public $address;
/**

View File

@ -7,6 +7,8 @@ use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\Tests\Models\CMS\CmsGroup;
use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\CMS\CmsComment;
require_once __DIR__ . '/../../TestInit.php';
@ -448,7 +450,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$articleNew = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $articleId);
$this->assertEquals("Lorem ipsum dolor sunt. And stuff!", $articleNew->text);
}
public function testFlushDoesNotIssueUnnecessaryUpdates()
{
$user = new CmsUser;
@ -515,10 +517,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(null);
}
/**
* @group ref
*/
public function testQueryEntityByReference()
{
$user = new CmsUser;
@ -552,6 +551,168 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('Berlin', $address2->city);
$this->assertEquals('12345', $address2->zip);
}
public function testOneToOneNullUpdate()
{
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin E.";
$user->status = 'active';
$address = new CmsAddress();
$address->city = "Bonn";
$address->zip = "12354";
$address->country = "Germany";
$address->street = "somestreet";
$address->user = $user;
$this->_em->persist($address);
$this->_em->persist($user);
$this->_em->flush();
$this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select 1 from cms_addresses where user_id = ".$user->id));
$address->user = null;
$this->_em->flush();
$this->assertFalse($this->_em->getConnection()->fetchColumn("select 1 from cms_addresses where user_id = ".$user->id));
}
/**
* @group DDC-600
* @group DDC-455
*/
public function testNewAssociatedEntityDuringFlushThrowsException()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin E.";
$user->status = 'active';
$address = new CmsAddress();
$address->city = "Bonn";
$address->zip = "12354";
$address->country = "Germany";
$address->street = "somestreet";
$address->user = $user;
$this->_em->persist($address);
// pretend we forgot to persist $user
try {
$this->_em->flush(); // should raise an exception
$this->fail();
} catch (\InvalidArgumentException $expected) {}
}
/**
* @group DDC-600
* @group DDC-455
*/
public function testNewAssociatedEntityDuringFlushThrowsException2()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin E.";
$user->status = 'active';
$address = new CmsAddress();
$address->city = "Bonn";
$address->zip = "12354";
$address->country = "Germany";
$address->street = "somestreet";
$address->user = $user;
$this->_em->persist($address);
$this->_em->persist($user);
$this->_em->flush();
$u2 = new CmsUser;
$u2->username = "beberlei";
$u2->name = "Benjamin E.";
$u2->status = 'inactive';
$address->user = $u2;
// pretend we forgot to persist $u2
try {
$this->_em->flush(); // should raise an exception
$this->fail();
} catch (\InvalidArgumentException $expected) {}
}
/**
* @group DDC-600
* @group DDC-455
*/
public function testNewAssociatedEntityDuringFlushThrowsException3()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$art = new CmsArticle();
$art->topic = 'topic';
$art->text = 'the text';
$com = new CmsComment();
$com->topic = 'Good';
$com->text = 'Really good!';
$art->addComment($com);
$this->_em->persist($art);
// pretend we forgot to persist $com
try {
$this->_em->flush(); // should raise an exception
$this->fail();
} catch (\InvalidArgumentException $expected) {}
}
/**
* @group orphan
*/
public function testOneToOneOrphanRemoval()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin E.";
$user->status = 'active';
$address = new CmsAddress();
$address->city = "Bonn";
$address->zip = "12354";
$address->country = "Germany";
$address->street = "somestreet";
$address->user = $user;
$user->address = $address;
$this->_em->persist($address);
$this->_em->persist($user);
$this->_em->flush();
$addressId = $address->getId();
$user->address = null;
$this->_em->flush();
$this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses"));
// check orphan removal through replacement
$user->address = $address;
$address->user = $user;
$this->_em->flush();
$this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses"));
$newAddress = new CmsAddress();
$newAddress->city = "NewBonn";
$newAddress->zip = "12354";
$newAddress->country = "NewGermany";
$newAddress->street = "somenewstreet";
$newAddress->user = $user;
$user->address = $newAddress;
$this->_em->flush();
$this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses"));
$this->assertEquals(0, $this->_em->getConnection()->fetchColumn("select count(*) from cms_addresses where id=".$addressId.""));
}
//DRAFT OF EXPECTED/DESIRED BEHAVIOR
/*public function testPersistentCollectionContainsDoesNeverInitialize()

View File

@ -87,10 +87,9 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
}
/**
* @expectedException InvalidArgumentException
* @group DDC-203
*/
public function testDetachedEntityWithAssignedIdentityThrowsExceptionOnPersist()
public function testDetachedEntityThrowsExceptionOnFlush()
{
$ph = new CmsPhonenumber();
$ph->phonenumber = '12345';
@ -98,6 +97,10 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->flush();
$this->_em->clear();
$this->_em->persist($ph);
try {
$this->_em->flush();
$this->fail();
} catch (\Exception $expected) {}
}
/**

View File

@ -172,14 +172,7 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase
$persister->reset();
// setNew should avoid exists() check
$this->_unitOfWork->setNew($ph);
$this->assertEquals(UnitOfWork::STATE_NEW, $this->_unitOfWork->getEntityState($ph));
$this->assertFalse($persister->isExistsCalled());
$persister->reset();
// if the entity is already managed the exists() check should also be skipped
// if the entity is already managed the exists() check should be skipped
$this->_unitOfWork->registerManaged($ph, array('phonenumber' => '12345'), array());
$this->assertEquals(UnitOfWork::STATE_MANAGED, $this->_unitOfWork->getEntityState($ph));
$this->assertFalse($persister->isExistsCalled());