diff --git a/lib/Doctrine/ORM/Cache/DefaultCache.php b/lib/Doctrine/ORM/Cache/DefaultCache.php index 78a22a80f1d..8934140bed3 100644 --- a/lib/Doctrine/ORM/Cache/DefaultCache.php +++ b/lib/Doctrine/ORM/Cache/DefaultCache.php @@ -41,11 +41,6 @@ class DefaultCache implements Cache private $em; /** - * @var \Doctrine\ORM\UnitOfWork - */ - private $uow; - - /** * @var \Doctrine\ORM\Cache\CacheFactory */ private $cacheFactory; @@ -66,7 +61,6 @@ class DefaultCache implements Cache public function __construct(EntityManagerInterface $em) { $this->em = $em; - $this->uow = $em->getUnitOfWork(); $this->cacheFactory = $em->getConfiguration() ->getSecondLevelCacheConfiguration() ->getCacheFactory(); @@ -78,7 +72,7 @@ public function __construct(EntityManagerInterface $em) public function getEntityCacheRegion($className) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($metadata->rootEntityName); if ( ! ($persister instanceof CachedPersister)) { return null; @@ -93,7 +87,7 @@ public function getEntityCacheRegion($className) public function getCollectionCacheRegion($className, $association) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($metadata->getAssociationMapping($association)); if ( ! ($persister instanceof CachedPersister)) { return null; @@ -108,7 +102,7 @@ public function getCollectionCacheRegion($className, $association) public function containsEntity($className, $identifier) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($metadata->rootEntityName); if ( ! ($persister instanceof CachedPersister)) { return false; @@ -123,7 +117,7 @@ public function containsEntity($className, $identifier) public function evictEntity($className, $identifier) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($metadata->rootEntityName); if ( ! ($persister instanceof CachedPersister)) { return; @@ -138,7 +132,7 @@ public function evictEntity($className, $identifier) public function evictEntityRegion($className) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($metadata->rootEntityName); if ( ! ($persister instanceof CachedPersister)) { return; @@ -152,10 +146,11 @@ public function evictEntityRegion($className) */ public function evictEntityRegions() { - $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); + $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); + $persisterFactory = $this->em->getPersisterFactory(); foreach ($metadatas as $metadata) { - $persister = $this->uow->getEntityPersister($metadata->rootEntityName); + $persister = $persisterFactory->getOrCreateEntityPersister($metadata->rootEntityName); if ( ! ($persister instanceof CachedPersister)) { continue; @@ -171,7 +166,7 @@ public function evictEntityRegions() public function containsCollection($className, $association, $ownerIdentifier) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($metadata->getAssociationMapping($association)); if ( ! ($persister instanceof CachedPersister)) { return false; @@ -186,7 +181,7 @@ public function containsCollection($className, $association, $ownerIdentifier) public function evictCollection($className, $association, $ownerIdentifier) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($metadata->getAssociationMapping($association)); if ( ! ($persister instanceof CachedPersister)) { return; @@ -201,7 +196,7 @@ public function evictCollection($className, $association, $ownerIdentifier) public function evictCollectionRegion($className, $association) { $metadata = $this->em->getClassMetadata($className); - $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association)); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($metadata->getAssociationMapping($association)); if ( ! ($persister instanceof CachedPersister)) { return; @@ -215,17 +210,16 @@ public function evictCollectionRegion($className, $association) */ public function evictCollectionRegions() { - $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); + $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); + $persisterFactory = $this->em->getPersisterFactory(); foreach ($metadatas as $metadata) { - foreach ($metadata->associationMappings as $association) { - - if ( ! $association['type'] & ClassMetadata::TO_MANY) { + if ( ! ($association['type'] & ClassMetadata::TO_MANY)) { continue; } - $persister = $this->uow->getCollectionPersister($association); + $persister = $persisterFactory->getOrCreateCollectionPersister($association); if ( ! ($persister instanceof CachedPersister)) { continue; @@ -329,7 +323,7 @@ private function buildCollectionCacheKey(ClassMetadata $metadata, $association, private function toIdentifierArray(ClassMetadata $metadata, $identifier) { if (is_object($identifier) && $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($identifier))) { - $identifier = $this->uow->getSingleIdentifierValue($identifier); + $identifier = $this->em->getUnitOfWork()->getSingleIdentifierValue($identifier); if ($identifier === null) { throw ORMInvalidArgumentException::invalidIdentifierBindingEntity(); diff --git a/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php b/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php index 79171856905..d1e06dfe696 100644 --- a/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php +++ b/lib/Doctrine/ORM/Cache/DefaultCacheFactory.php @@ -47,7 +47,7 @@ class DefaultCacheFactory implements CacheFactory /** * @var \Doctrine\Common\Cache\CacheProvider */ - private $cache; + protected $cache; /** * @var \Doctrine\ORM\Cache\RegionsConfiguration diff --git a/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php b/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php index cedd891da25..b33365e694d 100644 --- a/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php +++ b/lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php @@ -77,7 +77,7 @@ public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection) { $assoc = $metadata->associationMappings[$key->association]; - $targetPersister = $this->uow->getEntityPersister($assoc['targetEntity']); + $targetPersister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($assoc['targetEntity']); $targetRegion = $targetPersister->getCacheRegion(); $list = array(); diff --git a/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php b/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php index 1190b38fd71..fda33fdf779 100644 --- a/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php +++ b/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php @@ -136,7 +136,7 @@ public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, Ent } $assocKey = new EntityCacheKey($assoc['targetEntity'], $assocId); - $assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']); + $assocPersister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($assoc['targetEntity']); $assocRegion = $assocPersister->getCacheRegion(); $assocEntry = $assocRegion->get($assocKey); diff --git a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php index 87bb1366362..e620ee4ffbd 100644 --- a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php +++ b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php @@ -38,7 +38,7 @@ */ class DefaultQueryCache implements QueryCache { - /** + /** * @var \Doctrine\ORM\EntityManagerInterface */ private $em; @@ -107,7 +107,7 @@ public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = ar $result = array(); $entityName = reset($rsm->aliasMap); $hasRelation = ( ! empty($rsm->relationMap)); - $persister = $this->uow->getEntityPersister($entityName); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($entityName); $region = $persister->getCacheRegion(); $regionName = $region->getName(); @@ -138,7 +138,7 @@ public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = ar foreach ($entry['associations'] as $name => $assoc) { - $assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']); + $assocPersister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($assoc['targetEntity']); $assocRegion = $assocPersister->getCacheRegion(); if ($assoc['type'] & ClassMetadata::TO_ONE) { @@ -230,11 +230,12 @@ public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $h return false; } - $data = array(); - $entityName = reset($rsm->aliasMap); - $hasRelation = ( ! empty($rsm->relationMap)); - $metadata = $this->em->getClassMetadata($entityName); - $persister = $this->uow->getEntityPersister($entityName); + $data = array(); + $entityName = reset($rsm->aliasMap); + $hasRelation = ( ! empty($rsm->relationMap)); + $metadata = $this->em->getClassMetadata($entityName); + $persisterFactory = $this->em->getPersisterFactory(); + $persister = $persisterFactory->getOrCreateEntityPersister($entityName); if ( ! ($persister instanceof CachedPersister)) { throw CacheException::nonCacheableEntity($entityName); @@ -270,7 +271,7 @@ public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $h throw CacheException::nonCacheableEntityAssociation($entityName, $name); } - $assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']); + $assocPersister = $persisterFactory->getOrCreateEntityPersister($assoc['targetEntity']); $assocRegion = $assocPersister->getCacheRegion(); $assocMetadata = $assocPersister->getClassMetadata(); diff --git a/lib/Doctrine/ORM/Cache/Persister/Collection/AbstractCollectionPersister.php b/lib/Doctrine/ORM/Cache/Persister/Collection/AbstractCollectionPersister.php index 33d437253a1..8dcfa74be87 100644 --- a/lib/Doctrine/ORM/Cache/Persister/Collection/AbstractCollectionPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/Collection/AbstractCollectionPersister.php @@ -35,7 +35,12 @@ */ abstract class AbstractCollectionPersister implements CachedCollectionPersister { - /** + /** + * @var \Doctrine\ORM\EntityManagerInterface + */ + private $em; + + /** * @var \Doctrine\ORM\UnitOfWork */ protected $uow; @@ -106,6 +111,7 @@ public function __construct(CollectionPersister $persister, Region $region, Enti $this->persister = $persister; $this->association = $association; $this->regionName = $region->getName(); + $this->em = $em; $this->uow = $em->getUnitOfWork(); $this->metadataFactory = $em->getMetadataFactory(); $this->cacheLogger = $cacheConfig->getCacheLogger(); @@ -162,7 +168,7 @@ public function loadCollectionCache(PersistentCollection $collection, Collection */ public function storeCollectionCache(CollectionCacheKey $key, $elements) { - $targetPersister = $this->uow->getEntityPersister($this->targetEntity->rootEntityName); + $targetPersister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($this->targetEntity->rootEntityName); $targetRegion = $targetPersister->getCacheRegion(); $targetHydrator = $targetPersister->getEntityHydrator(); $entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements); diff --git a/lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php b/lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php index eae4c8c3343..a6714e305df 100644 --- a/lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php +++ b/lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php @@ -41,7 +41,12 @@ */ abstract class AbstractEntityPersister implements CachedEntityPersister { - /** + /** + * @var \Doctrine\ORM\EntityManagerInterface + */ + private $em; + + /** * @var \Doctrine\ORM\UnitOfWork */ protected $uow; @@ -125,6 +130,7 @@ public function __construct(EntityPersister $persister, Region $region, EntityMa $this->persister = $persister; $this->cache = $em->getCache(); $this->regionName = $region->getName(); + $this->em = $em; $this->uow = $em->getUnitOfWork(); $this->metadataFactory = $em->getMetadataFactory(); $this->cacheLogger = $cacheConfig->getCacheLogger(); @@ -273,7 +279,7 @@ private function storeJoinedAssociations($entity) $assocId = $this->uow->getEntityIdentifier($assocEntity); $assocKey = new EntityCacheKey($assoc['targetEntity'], $assocId); - $assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']); + $assocPersister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($assoc['targetEntity']); $assocPersister->storeEntityCache($assocEntity, $assocKey); } @@ -544,7 +550,7 @@ public function loadCriteria(Criteria $criteria) */ public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll) { - $persister = $this->uow->getCollectionPersister($assoc); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($assoc); $hasCache = ($persister instanceof CachedPersister); $key = null; @@ -580,7 +586,7 @@ public function loadManyToManyCollection(array $assoc, $sourceEntity, Persistent */ public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll) { - $persister = $this->uow->getCollectionPersister($assoc); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($assoc); $hasCache = ($persister instanceof CachedPersister); if ($hasCache) { diff --git a/lib/Doctrine/ORM/Decorator/EntityManagerDecorator.php b/lib/Doctrine/ORM/Decorator/EntityManagerDecorator.php index 69cc6f50739..7b1732695d0 100644 --- a/lib/Doctrine/ORM/Decorator/EntityManagerDecorator.php +++ b/lib/Doctrine/ORM/Decorator/EntityManagerDecorator.php @@ -244,6 +244,14 @@ public function getProxyFactory() return $this->wrapped->getProxyFactory(); } + /** + * {@inheritdoc} + */ + public function getPersisterFactory() + { + return $this->wrapped->getPersisterFactory(); + } + /** * {@inheritdoc} */ diff --git a/lib/Doctrine/ORM/EntityManager.php b/lib/Doctrine/ORM/EntityManager.php index 049ac0f72c5..761de79d45c 100644 --- a/lib/Doctrine/ORM/EntityManager.php +++ b/lib/Doctrine/ORM/EntityManager.php @@ -19,6 +19,7 @@ namespace Doctrine\ORM; +use Doctrine\ORM\Persisters\PersisterFactory; use Exception; use Doctrine\Common\EventManager; use Doctrine\DBAL\Connection; @@ -82,6 +83,13 @@ */ private $metadataFactory; + /** + * The persister factory, used to retrieve the ORM persister of collections and entity classes. + * + * @var \Doctrine\ORM\Persisters\PersisterFactory + */ + private $persisterFactory; + /** * The UnitOfWork used to coordinate object-level transactions. * @@ -156,6 +164,7 @@ protected function __construct(Connection $conn, Configuration $config, EventMan $this->metadataFactory->setEntityManager($this); $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl()); + $this->persisterFactory = new PersisterFactory($this); $this->repositoryFactory = $config->getRepositoryFactory(); $this->unitOfWork = new UnitOfWork($this); $this->proxyFactory = new ProxyFactory( @@ -190,6 +199,16 @@ public function getMetadataFactory() return $this->metadataFactory; } + /** + * Gets the persister factory used to manipulate collection and entity classes. + * + * @return \Doctrine\ORM\Persisters\PersisterFactory + */ + public function getPersisterFactory() + { + return $this->persisterFactory; + } + /** * {@inheritDoc} */ @@ -411,6 +430,7 @@ public function find($entityName, $id, $lockMode = null, $lockVersion = null) throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id)); } + $persister = $this->persisterFactory->getOrCreateEntityPersister($class->name); $unitOfWork = $this->getUnitOfWork(); // Check identity map first @@ -427,7 +447,6 @@ public function find($entityName, $id, $lockMode = null, $lockVersion = null) case LockMode::NONE === $lockMode: case LockMode::PESSIMISTIC_READ === $lockMode: case LockMode::PESSIMISTIC_WRITE === $lockMode: - $persister = $unitOfWork->getEntityPersister($class->name); $persister->refresh($sortedId, $entity, $lockMode); break; } @@ -435,8 +454,6 @@ public function find($entityName, $id, $lockMode = null, $lockVersion = null) return $entity; // Hit! } - $persister = $unitOfWork->getEntityPersister($class->name); - switch (true) { case LockMode::OPTIMISTIC === $lockMode: if ( ! $class->isVersioned) { @@ -540,6 +557,7 @@ public function getPartialReference($entityName, $identifier) */ public function clear($entityName = null) { + $this->persisterFactory->clear(); $this->unitOfWork->clear($entityName); } diff --git a/lib/Doctrine/ORM/EntityManagerInterface.php b/lib/Doctrine/ORM/EntityManagerInterface.php index 280ffb3c485..a0f17031cc1 100644 --- a/lib/Doctrine/ORM/EntityManagerInterface.php +++ b/lib/Doctrine/ORM/EntityManagerInterface.php @@ -271,6 +271,13 @@ public function newHydrator($hydrationMode); */ public function getProxyFactory(); + /** + * Gets the persister factory used to manipulate collection and entity classes. + * + * @return \Doctrine\ORM\Persisters\PersisterFactory + */ + public function getPersisterFactory(); + /** * Gets the enabled filters. * diff --git a/lib/Doctrine/ORM/EntityRepository.php b/lib/Doctrine/ORM/EntityRepository.php index 47d0648bead..7dc38a3083e 100644 --- a/lib/Doctrine/ORM/EntityRepository.php +++ b/lib/Doctrine/ORM/EntityRepository.php @@ -176,7 +176,7 @@ public function findAll() */ public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) { - $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); + $persister = $this->_em->getPersisterFactory()->getOrCreateEntityPersister($this->_entityName); return $persister->loadAll($criteria, $orderBy, $limit, $offset); } @@ -191,7 +191,7 @@ public function findBy(array $criteria, array $orderBy = null, $limit = null, $o */ public function findOneBy(array $criteria, array $orderBy = null) { - $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); + $persister = $this->_em->getPersisterFactory()->getOrCreateEntityPersister($this->_entityName); return $persister->load($criteria, null, null, array(), null, 1, $orderBy); } @@ -299,7 +299,7 @@ protected function getClassMetadata() */ public function matching(Criteria $criteria) { - $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); + $persister = $this->_em->getPersisterFactory()->getOrCreateEntityPersister($this->_entityName); return new LazyCriteriaCollection($persister, $criteria); } diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index d0a6d2c6cf8..205c7f13e08 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -436,7 +436,7 @@ public function removeElement($element) return $this->coll->removeElement($element); } - $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($this->association); if ($persister->removeElement($this, $element)) { return $element; @@ -473,7 +473,7 @@ public function containsKey($key) if (! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY && isset($this->association['indexBy'])) { - $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($this->association); return $this->coll->containsKey($key) || $persister->containsKey($this, $key); } @@ -488,7 +488,7 @@ public function containsKey($key) public function contains($element) { if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { - $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($this->association); return $this->coll->contains($element) || $persister->contains($this, $element); } @@ -531,7 +531,7 @@ public function get($key) return $this->em->find($this->typeClass->name, $key); } - return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key); + return $this->em->getPersisterFactory()->getOrCreateCollectionPersister($this->association)->get($this, $key); } $this->initialize(); @@ -565,7 +565,7 @@ public function getValues() public function count() { if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { - $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($this->association); return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0); } @@ -810,7 +810,7 @@ public function unwrap() public function slice($offset, $length = null) { if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) { - $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($this->association); return $persister->slice($this, $offset, $length); } @@ -868,7 +868,7 @@ public function matching(Criteria $criteria) } if ($this->association['type'] === ClassMetadata::MANY_TO_MANY) { - $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($this->association); return new ArrayCollection($persister->loadCriteria($this, $criteria)); } @@ -880,7 +880,7 @@ public function matching(Criteria $criteria) $criteria->where($expression); - $persister = $this->em->getUnitOfWork()->getEntityPersister($this->association['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($this->association['targetEntity']); return ($this->association['fetch'] === ClassMetadataInfo::FETCH_EXTRA_LAZY) ? new LazyCriteriaCollection($persister, $criteria) diff --git a/lib/Doctrine/ORM/Persisters/Collection/AbstractCollectionPersister.php b/lib/Doctrine/ORM/Persisters/Collection/AbstractCollectionPersister.php index b73744ee4a2..0fc0813260b 100644 --- a/lib/Doctrine/ORM/Persisters/Collection/AbstractCollectionPersister.php +++ b/lib/Doctrine/ORM/Persisters/Collection/AbstractCollectionPersister.php @@ -19,19 +19,20 @@ namespace Doctrine\ORM\Persisters\Collection; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\UnitOfWork; /** * Base class for all collection persisters. * * @since 2.0 + * @author Guilherme Blanco * @author Roman Borschel */ abstract class AbstractCollectionPersister implements CollectionPersister { /** - * @var EntityManager + * @var \Doctrine\ORM\EntityManagerInterface */ protected $em; @@ -62,9 +63,9 @@ abstract class AbstractCollectionPersister implements CollectionPersister /** * Initializes a new instance of a class derived from AbstractCollectionPersister. * - * @param \Doctrine\ORM\EntityManager $em + * @param \Doctrine\ORM\EntityManagerInterface $em */ - public function __construct(EntityManager $em) + public function __construct(EntityManagerInterface $em) { $this->em = $em; $this->uow = $em->getUnitOfWork(); diff --git a/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php index 40b1be95800..c9e8fab244f 100644 --- a/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php @@ -84,7 +84,7 @@ public function get(PersistentCollection $collection, $index) throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); } - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); $mappedKey = $mapping['isOwningSide'] ? $mapping['inversedBy'] : $mapping['mappedBy']; @@ -135,7 +135,7 @@ public function count(PersistentCollection $collection) . ' ON' . implode(' AND ', $this->getOnConditionSQL($association)); // And criteria conditions needs to be added - $persister = $this->uow->getEntityPersister($targetClass->name); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($targetClass->name); $visitor = new SqlExpressionVisitor($persister, $targetClass); $conditions[] = $visitor->dispatch($expression); @@ -156,7 +156,7 @@ public function count(PersistentCollection $collection) public function slice(PersistentCollection $collection, $offset, $length = null) { $mapping = $collection->getMapping(); - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); return $persister->getManyToManyCollection($mapping, $collection->getOwner(), $offset, $length); } diff --git a/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php index ee550a92200..95df342c7da 100644 --- a/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php @@ -65,7 +65,7 @@ public function get(PersistentCollection $collection, $index) throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); } - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); return $persister->load(array($mapping['mappedBy'] => $collection->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), null, 1); } @@ -76,7 +76,7 @@ public function get(PersistentCollection $collection, $index) public function count(PersistentCollection $collection) { $mapping = $collection->getMapping(); - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); // only works with single id identifier entities. Will throw an // exception in Entity Persisters if that is not the case for the @@ -92,7 +92,7 @@ public function count(PersistentCollection $collection) public function slice(PersistentCollection $collection, $offset, $length = null) { $mapping = $collection->getMapping(); - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); return $persister->getOneToManyCollection($mapping, $collection->getOwner(), $offset, $length); } @@ -108,7 +108,7 @@ public function containsKey(PersistentCollection $collection, $key) throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); } - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); // only works with single id identifier entities. Will throw an // exception in Entity Persisters if that is not the case for the @@ -131,7 +131,7 @@ public function contains(PersistentCollection $collection, $element) } $mapping = $collection->getMapping(); - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); // only works with single id identifier entities. Will throw an // exception in Entity Persisters if that is not the case for the @@ -151,7 +151,7 @@ public function removeElement(PersistentCollection $collection, $element) } $mapping = $collection->getMapping(); - $persister = $this->uow->getEntityPersister($mapping['targetEntity']); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($mapping['targetEntity']); return $persister->delete($element); } diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index e6d79696cd5..f0a8e46c5ad 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -25,7 +25,7 @@ use Doctrine\ORM\ORMException; use Doctrine\ORM\OptimisticLockException; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Query; use Doctrine\ORM\PersistentCollection; @@ -124,7 +124,7 @@ class BasicEntityPersister implements EntityPersister /** * The EntityManager instance. * - * @var \Doctrine\ORM\EntityManager + * @var \Doctrine\ORM\EntityManagerInterface */ protected $em; @@ -221,10 +221,10 @@ class BasicEntityPersister implements EntityPersister * Initializes a new BasicEntityPersister that uses the given EntityManager * and persists instances of the class described by the given ClassMetadata descriptor. * - * @param \Doctrine\ORM\EntityManager $em - * @param \Doctrine\ORM\Mapping\ClassMetadata $class + * @param \Doctrine\ORM\EntityManagerInterface $em + * @param \Doctrine\ORM\Mapping\ClassMetadata $class */ - public function __construct(EntityManager $em, ClassMetadata $class) + public function __construct(EntityManagerInterface $em, ClassMetadata $class) { $this->em = $em; $this->class = $class; diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index b1bd56d8c88..98f030a5b3e 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -130,15 +130,16 @@ public function executeInserts() return array(); } - $postInsertIds = array(); - $idGenerator = $this->class->idGenerator; - $isPostInsertId = $idGenerator->isPostInsertGenerator(); - $rootClass = ($this->class->name !== $this->class->rootEntityName) + $postInsertIds = array(); + $persisterFactory = $this->em->getPersisterFactory(); + $idGenerator = $this->class->idGenerator; + $isPostInsertId = $idGenerator->isPostInsertGenerator(); + $rootClass = ($this->class->name !== $this->class->rootEntityName) ? $this->em->getClassMetadata($this->class->rootEntityName) : $this->class; // Prepare statement for the root table - $rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->name); + $rootPersister = $persisterFactory->getOrCreateEntityPersister($rootClass->name); $rootTableName = $rootClass->getTableName(); $rootTableStmt = $this->conn->prepare($rootPersister->getInsertSQL()); @@ -154,7 +155,7 @@ public function executeInserts() $parentTableName = $parentClass->getTableName(); if ($parentClass !== $rootClass) { - $parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClassName); + $parentPersister = $persisterFactory->getOrCreateEntityPersister($parentClassName); $subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL()); } } diff --git a/lib/Doctrine/ORM/Persisters/PersisterFactory.php b/lib/Doctrine/ORM/Persisters/PersisterFactory.php new file mode 100644 index 00000000000..3341a77ff24 --- /dev/null +++ b/lib/Doctrine/ORM/Persisters/PersisterFactory.php @@ -0,0 +1,173 @@ +. + */ + +namespace Doctrine\ORM\Persisters; + +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadata; + +/** + * PersisterFactory + * + * @package Doctrine\ORM\Persisters + */ +class PersisterFactory +{ + /** + * @var \Doctrine\ORM\EntityManagerInterface + */ + private $entityManager; + + /** + * @var boolean + */ + private $hasCache; + + /** + * @var array + */ + private $entityPersisters = array(); + + /** + * @var array + */ + private $collectionPersisters = array(); + + /** + * Constructor. + * + * @param EntityManagerInterface $entityManager + */ + public function __construct(EntityManagerInterface $entityManager) + { + $this->entityManager = $entityManager; + $this->hasCache = $entityManager->getConfiguration()->isSecondLevelCacheEnabled(); + } + + /** + * Clear the list of existing loaded persisters. + * + */ + public function clear() + { + $this->entityPersisters = $this->collectionPersisters = array(); + } + + /** + * Retrieve the existing entity persisters. + * + * @return array + */ + public function getEntityPersisters() + { + return $this->entityPersisters; + } + + /** + * Retrieve the existing collection persisters. + * + * @return array + */ + public function getCollectionPersisters() + { + return $this->collectionPersisters; + } + + /** + * Get or Create the EntityPersister for a given Entity name. + * + * @param string $entityName The name of the Entity. + * + * @return \Doctrine\ORM\Persisters\Entity\EntityPersister + */ + public function getOrCreateEntityPersister($entityName) + { + if (isset($this->entityPersisters[$entityName])) { + return $this->entityPersisters[$entityName]; + } + + $class = $this->entityManager->getClassMetadata($entityName); + + switch (true) { + case ($class->isInheritanceTypeNone()): + $persister = new Entity\BasicEntityPersister($this->entityManager, $class); + break; + + case ($class->isInheritanceTypeSingleTable()): + $persister = new Entity\SingleTablePersister($this->entityManager, $class); + break; + + case ($class->isInheritanceTypeJoined()): + $persister = new Entity\JoinedSubclassPersister($this->entityManager, $class); + break; + + default: + throw new \RuntimeException('No persister found for entity.'); + } + + $hasCache = $this->entityManager->getConfiguration()->isSecondLevelCacheEnabled(); + + if ($hasCache && $class->cache !== null) { + $persister = $this->entityManager->getConfiguration() + ->getSecondLevelCacheConfiguration() + ->getCacheFactory() + ->buildCachedEntityPersister($this->entityManager, $persister, $class); + } + + $this->entityPersisters[$entityName] = $persister; + + return $this->entityPersisters[$entityName]; + } + + /** + * Get or Create a collection persister for a collection-valued association. + * + * @param array $association + * + * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister + */ + public function getOrCreateCollectionPersister(array $association) + { + $role = isset($association['cache']) + ? $association['sourceEntity'] . '::' . $association['fieldName'] + : $association['type']; + + if (isset($this->collectionPersisters[$role])) { + return $this->collectionPersisters[$role]; + } + + $persister = ClassMetadata::ONE_TO_MANY === $association['type'] + ? new Collection\OneToManyPersister($this->entityManager) + : new Collection\ManyToManyPersister($this->entityManager); + + $hasCache = $this->entityManager->getConfiguration()->isSecondLevelCacheEnabled(); + + if ($hasCache && isset($association['cache'])) { + $persister = $this->entityManager->getConfiguration() + ->getSecondLevelCacheConfiguration() + ->getCacheFactory() + ->buildCachedCollectionPersister($this->entityManager, $persister, $association); + } + + $this->collectionPersisters[$role] = $persister; + + return $this->collectionPersisters[$role]; + } +} diff --git a/lib/Doctrine/ORM/Proxy/ProxyFactory.php b/lib/Doctrine/ORM/Proxy/ProxyFactory.php index 94e29e22b36..61a89f42eb5 100644 --- a/lib/Doctrine/ORM/Proxy/ProxyFactory.php +++ b/lib/Doctrine/ORM/Proxy/ProxyFactory.php @@ -100,7 +100,7 @@ protected function skipClass(ClassMetadata $metadata) protected function createProxyDefinition($className) { $classMetadata = $this->em->getClassMetadata($className); - $entityPersister = $this->uow->getEntityPersister($className); + $entityPersister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($className); return new ProxyDefinition( ClassUtils::generateProxyClassName($className, $this->proxyNs), diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 486d4af6201..c0b54f644d4 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -406,7 +406,7 @@ private function _generateOrderedCollectionOrderByItems() continue; } - $persister = $this->em->getUnitOfWork()->getEntityPersister($qComp['metadata']->name); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($qComp['metadata']->name); foreach ($qComp['relation']['orderBy'] as $fieldName => $orientation) { $columnName = $this->quoteStrategy->getColumnName($fieldName, $qComp['metadata'], $this->platform); @@ -1288,7 +1288,7 @@ public function walkSelectExpression($selectExpression) $resultAlias = $selectExpression->fieldIdentificationVariable ?: $fieldName; $tableName = ($class->isInheritanceTypeJoined()) - ? $this->em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName) + ? $this->em->getPersisterFactory()->getOrCreateEntityPersister($class->name)->getOwningTable($fieldName) : $class->getTableName(); $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 5749273dc01..83b414c24c5 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -41,11 +41,6 @@ use Doctrine\ORM\Event\ListenersInvoker; use Doctrine\ORM\Cache\Persister\CachedPersister; -use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; -use Doctrine\ORM\Persisters\Entity\SingleTablePersister; -use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister; -use Doctrine\ORM\Persisters\Collection\OneToManyPersister; -use Doctrine\ORM\Persisters\Collection\ManyToManyPersister; use Doctrine\ORM\Utility\IdentifierFlattener; /** @@ -216,20 +211,6 @@ class UnitOfWork implements PropertyChangedListener */ private $commitOrderCalculator; - /** - * The entity persister instances used to persist entity instances. - * - * @var array - */ - private $persisters = array(); - - /** - * The collection persister instances used to persist collections. - * - * @var array - */ - private $collectionPersisters = array(); - /** * The EventManager used for dispatching events. * @@ -496,6 +477,8 @@ private function computeSingleEntityChangeSet($entity) */ private function executeExtraUpdates() { + $persisterFactory = $this->em->getPersisterFactory(); + foreach ($this->extraUpdates as $oid => $update) { list ($entity, $changeset) = $update; @@ -3035,83 +3018,6 @@ public function size() return array_sum($countArray); } - /** - * Gets the EntityPersister for an Entity. - * - * @param string $entityName The name of the Entity. - * - * @return \Doctrine\ORM\Persisters\Entity\EntityPersister - */ - public function getEntityPersister($entityName) - { - if (isset($this->persisters[$entityName])) { - return $this->persisters[$entityName]; - } - - $class = $this->em->getClassMetadata($entityName); - - switch (true) { - case ($class->isInheritanceTypeNone()): - $persister = new BasicEntityPersister($this->em, $class); - break; - - case ($class->isInheritanceTypeSingleTable()): - $persister = new SingleTablePersister($this->em, $class); - break; - - case ($class->isInheritanceTypeJoined()): - $persister = new JoinedSubclassPersister($this->em, $class); - break; - - default: - throw new \RuntimeException('No persister found for entity.'); - } - - if ($this->hasCache && $class->cache !== null) { - $persister = $this->em->getConfiguration() - ->getSecondLevelCacheConfiguration() - ->getCacheFactory() - ->buildCachedEntityPersister($this->em, $persister, $class); - } - - $this->persisters[$entityName] = $persister; - - return $this->persisters[$entityName]; - } - - /** - * Gets a collection persister for a collection-valued association. - * - * @param array $association - * - * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister - */ - public function getCollectionPersister(array $association) - { - $role = isset($association['cache']) - ? $association['sourceEntity'] . '::' . $association['fieldName'] - : $association['type']; - - if (isset($this->collectionPersisters[$role])) { - return $this->collectionPersisters[$role]; - } - - $persister = ClassMetadata::ONE_TO_MANY === $association['type'] - ? new OneToManyPersister($this->em) - : new ManyToManyPersister($this->em); - - if ($this->hasCache && isset($association['cache'])) { - $persister = $this->em->getConfiguration() - ->getSecondLevelCacheConfiguration() - ->getCacheFactory() - ->buildCachedCollectionPersister($this->em, $persister, $association); - } - - $this->collectionPersisters[$role] = $persister; - - return $this->collectionPersisters[$role]; - } - /** * INTERNAL: * Registers an entity as managed. @@ -3302,6 +3208,41 @@ public function isReadOnly($object) return isset($this->readOnlyObjects[spl_object_hash($object)]); } + /** + * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle. + * Unit of work able to fire deferred events, related to loading events here. + * + * @internal should be called internally from object hydrators + */ + public function hydrationComplete() + { + $this->hydrationCompleteHandler->hydrationComplete(); + } + + /** + * Gets the EntityPersister for an Entity. + * + * @param string $entityName The name of the Entity. + * + * @return \Doctrine\ORM\Persisters\Entity\EntityPersister + */ + protected function getEntityPersister($entityName) + { + return $this->em->getPersisterFactory()->getOrCreateEntityPersister($entityName); + } + + /** + * Gets a collection persister for a collection-valued association. + * + * @param array $association + * + * @return \Doctrine\ORM\Persisters\Collection\CollectionPersister + */ + protected function getCollectionPersister(array $association) + { + return $this->em->getPersisterFactory()->getOrCreateCollectionPersister($association); + } + /** * Perform whatever processing is encapsulated here after completion of the transaction. */ @@ -3311,13 +3252,15 @@ private function afterTransactionComplete() return; } - foreach ($this->persisters as $persister) { + $persisterFactory = $this->em->getPersisterFactory(); + + foreach ($persisterFactory->getEntityPersisters() as $persister) { if ($persister instanceof CachedPersister) { $persister->afterTransactionComplete(); } } - foreach ($this->collectionPersisters as $persister) { + foreach ($persisterFactory->getCollectionPersisters() as $persister) { if ($persister instanceof CachedPersister) { $persister->afterTransactionComplete(); } @@ -3333,13 +3276,15 @@ private function afterTransactionRolledBack() return; } - foreach ($this->persisters as $persister) { + $persisterFactory = $this->em->getPersisterFactory(); + + foreach ($persisterFactory->getEntityPersisters() as $persister) { if ($persister instanceof CachedPersister) { $persister->afterTransactionRolledBack(); } } - foreach ($this->collectionPersisters as $persister) { + foreach ($persisterFactory->getCollectionPersisters() as $persister) { if ($persister instanceof CachedPersister) { $persister->afterTransactionRolledBack(); } @@ -3392,15 +3337,4 @@ private function isIdentifierEquals($entity1, $entity2) return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2); } - - /** - * This method called by hydrators, and indicates that hydrator totally completed current hydration cycle. - * Unit of work able to fire deferred events, related to loading events here. - * - * @internal should be called internally from object hydrators - */ - public function hydrationComplete() - { - $this->hydrationCompleteHandler->hydrationComplete(); - } } diff --git a/tests/Doctrine/Tests/Mocks/EntityManagerMock.php b/tests/Doctrine/Tests/Mocks/EntityManagerMock.php index 74f4efcf0dd..cc391fd543f 100644 --- a/tests/Doctrine/Tests/Mocks/EntityManagerMock.php +++ b/tests/Doctrine/Tests/Mocks/EntityManagerMock.php @@ -38,6 +38,11 @@ class EntityManagerMock extends \Doctrine\ORM\EntityManager */ private $_proxyFactoryMock; + /** + * @var \Doctrine\ORM\Persisters\PersisterFactory|null + */ + private $_persisterFactoryMock; + /** * {@inheritdoc} */ @@ -78,6 +83,24 @@ public function getProxyFactory() return isset($this->_proxyFactoryMock) ? $this->_proxyFactoryMock : parent::getProxyFactory(); } + /** + * @param \Doctrine\ORM\Persisters\PersisterFactory $persisterFactory + * + * @return void + */ + public function setPersisterFactory($persisterFactory) + { + $this->_persisterFactoryMock = $persisterFactory; + } + + /** + * @return \Doctrine\ORM\Persisters\PersisterFactory + */ + public function getPersisterFactory() + { + return isset($this->_persisterFactoryMock) ? $this->_persisterFactoryMock : parent::getPersisterFactory(); + } + /** * Mock factory method to create an EntityManager. * diff --git a/tests/Doctrine/Tests/Mocks/PersisterFactoryMock.php b/tests/Doctrine/Tests/Mocks/PersisterFactoryMock.php new file mode 100644 index 00000000000..ccb08f3ef5d --- /dev/null +++ b/tests/Doctrine/Tests/Mocks/PersisterFactoryMock.php @@ -0,0 +1,77 @@ +_entityPersistersMock[$entityName]) + ? $this->_entityPersistersMock[$entityName] + : parent::getOrCreateEntityPersister($entityName); + } + + /** + * {@inheritdoc} + */ + public function getOrCreateCollectionPersister(array $association) + { + $role = isset($association['cache']) + ? $association['sourceEntity'] . '::' . $association['fieldName'] + : $association['type']; + + return isset($this->_collectionPersistersMock[$role]) + ? $this->_collectionPersistersMock[$role] + : parent::getOrCreateCollectionPersister($association); + } + + /* MOCK API */ + + /** + * Sets a (mock) persister for an entity class that will be returned when + * getOrCreateEntityPersister() is invoked for that class. + * + * @param string $entityName + * @param \Doctrine\ORM\Persisters\Entity\EntityPersister $persister + * + * @return void + */ + public function setEntityPersister($entityName, $persister) + { + $this->_entityPersistersMock[$entityName] = $persister; + } + + /** + * Sets a (mock) persister for a collection that will be returned when + * getOrCreateCollectionPersister() is invoked for that class. + * + * @param array $association + * @param \Doctrine\ORM\Persisters\Collection\CollectionPersister $persister + * + * @return void + */ + public function setCollectionPersister($association, $persister) + { + $role = isset($association['cache']) + ? $association['sourceEntity'] . '::' . $association['fieldName'] + : $association['type']; + + $this->_collectionPersistersMock[$role] = $persister; + } +} diff --git a/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php b/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php index 49c06375359..d13caaa9bfd 100644 --- a/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php +++ b/tests/Doctrine/Tests/Mocks/UnitOfWorkMock.php @@ -12,44 +12,16 @@ class UnitOfWorkMock extends \Doctrine\ORM\UnitOfWork */ private $_mockDataChangeSets = array(); - /** - * @var array|null - */ - private $_persisterMock; - - /** - * {@inheritdoc} - */ - public function getEntityPersister($entityName) - { - return isset($this->_persisterMock[$entityName]) ? - $this->_persisterMock[$entityName] : parent::getEntityPersister($entityName); - } - /** * {@inheritdoc} */ public function getEntityChangeSet($entity) { $oid = spl_object_hash($entity); - return isset($this->_mockDataChangeSets[$oid]) ? - $this->_mockDataChangeSets[$oid] : parent::getEntityChangeSet($entity); - } - - /* MOCK API */ - /** - * Sets a (mock) persister for an entity class that will be returned when - * getEntityPersister() is invoked for that class. - * - * @param string $entityName - * @param \Doctrine\ORM\Persisters\Entity\BasicEntityPersister $persister - * - * @return void - */ - public function setEntityPersister($entityName, $persister) - { - $this->_persisterMock[$entityName] = $persister; + return isset($this->_mockDataChangeSets[$oid]) + ? $this->_mockDataChangeSets[$oid] + : parent::getEntityChangeSet($entity); } /** diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheTest.php index c33d0839b92..871f7b89ac6 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheTest.php @@ -47,7 +47,7 @@ private function putEntityCacheEntry($className, array $identifier, array $data) $metadata = $this->em->getClassMetadata($className); $cacheKey = new EntityCacheKey($metadata->name, $identifier); $cacheEntry = new EntityCacheEntry($metadata->name, $data); - $persister = $this->em->getUnitOfWork()->getEntityPersister($metadata->rootEntityName); + $persister = $this->em->getPersisterFactory()->getOrCreateEntityPersister($metadata->rootEntityName); $persister->getCacheRegion()->put($cacheKey, $cacheEntry); } @@ -63,7 +63,7 @@ private function putCollectionCacheEntry($className, $association, array $ownerI $metadata = $this->em->getClassMetadata($className); $cacheKey = new CollectionCacheKey($metadata->name, $association, $ownerIdentifier); $cacheEntry = new CollectionCacheEntry($data); - $persister = $this->em->getUnitOfWork()->getCollectionPersister($metadata->getAssociationMapping($association)); + $persister = $this->em->getPersisterFactory()->getOrCreateCollectionPersister($metadata->getAssociationMapping($association)); $persister->getCacheRegion()->put($cacheKey, $cacheEntry); } @@ -260,4 +260,4 @@ public function testToIdentifierArrayShouldLookupForEntityIdentifier() $this->assertEquals(array('id'=>$identifier), $method->invoke($this->cache, $metadata, $identifier)); } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php b/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php index 9fa1cb8af73..91a4ca961e7 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php @@ -460,12 +460,15 @@ public function testExistsSubclass() $manager->setTitle('Awesome!'); $manager->setDepartment('IT'); - $this->assertFalse($this->_em->getUnitOfWork()->getEntityPersister(get_class($manager))->exists($manager)); + $persisterFactory = $this->_em->getPersisterFactory(); + $persister = $persisterFactory->getOrCreateEntityPersister(get_class($manager)); + + $this->assertFalse($persister->exists($manager)); $this->_em->persist($manager); $this->_em->flush(); - $this->assertTrue($this->_em->getUnitOfWork()->getEntityPersister(get_class($manager))->exists($manager)); + $this->assertTrue($persister->exists($manager)); } /** diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php index e4672b9f2b8..c9a2a4213d9 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheAbstractTest.php @@ -245,4 +245,4 @@ protected function evictRegions() $this->cache->evictEntityRegions(); $this->cache->evictCollectionRegions(); } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php index 6b177562fa2..4e2f840b655 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheConcurrentTest.php @@ -145,4 +145,4 @@ public function getTimestampRegion() { return new \Doctrine\Tests\Mocks\TimestampRegionMock(); } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheTest.php index 37dadd26ce7..aaf87ff9ec8 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheTest.php @@ -306,7 +306,7 @@ public function testCachedNewEntityExists() { $this->loadFixturesCountries(); - $persister = $this->_em->getUnitOfWork()->getEntityPersister(Country::CLASSNAME); + $persister = $this->_em->getPersisterFactory()->getOrCreateEntityPersister(Country::CLASSNAME); $queryCount = $this->getCurrentQueryCount(); $this->assertTrue($persister->exists($this->countries[0])); diff --git a/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php b/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php index 31f28db3bc4..24f7e39b4c7 100644 --- a/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php @@ -36,7 +36,7 @@ public function testAcceptsForeignKeysAsCriteria() $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart'); - $persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceCart'); + $persister = $this->_em->getPersisterFactory()->getOrCreateEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceCart'); $newCart = new ECommerceCart(); $this->_em->getUnitOfWork()->registerManaged($newCart, array('id' => $cardId), array()); $persister->load(array('customer_id' => $customer->getId()), $newCart, $class->associationMappings['customer']); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php index dad902b355c..59e351de275 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1163Test.php @@ -76,7 +76,7 @@ private function setPropertyAndAssignTagToSpecialProduct() // this screams violation of law of demeter ;) $this->assertEquals( __NAMESPACE__.'\\DDC1163SpecialProduct', - $this->_em->getUnitOfWork()->getEntityPersister(get_class($specialProduct))->getClassMetadata()->name + $this->_em->getPersisterFactory()->getOrCreateEntityPersister(get_class($specialProduct))->getClassMetadata()->name ); $tag = new DDC1163Tag('Foo'); diff --git a/tests/Doctrine/Tests/ORM/Performance/ProxyPerformanceTest.php b/tests/Doctrine/Tests/ORM/Performance/ProxyPerformanceTest.php index a43907f9ee5..ebdf99686e4 100644 --- a/tests/Doctrine/Tests/ORM/Performance/ProxyPerformanceTest.php +++ b/tests/Doctrine/Tests/ORM/Performance/ProxyPerformanceTest.php @@ -19,6 +19,8 @@ namespace Doctrine\Tests\ORM\Performance; +use Doctrine\Tests\Mocks\PersisterFactoryMock; +use Doctrine\Tests\Mocks\UnitOfWorkMock; use Doctrine\Tests\OrmPerformanceTestCase; use Doctrine\Common\Proxy\Proxy; use Doctrine\ORM\EntityManager; @@ -126,30 +128,14 @@ public function getClassMetadata($className) } /** {@inheritDoc} */ - public function getUnitOfWork() + public function getPersisterFactory() { - return new MockUnitOfWork(); - } -} - -/** - * Mock UnitOfWork manager to fake `getPersister()` - */ -class MockUnitOfWork extends UnitOfWork -{ - /** @var PersisterMock */ - private $entityPersister; + $persisterFactory = new PersisterFactoryMock($this->em); - /** */ - public function __construct() - { - $this->entityPersister = new PersisterMock(); - } + $persisterFactory->setEntityPersister('Doctrine\Tests\Models\CMS\CmsEmployee', new PersisterMock()); + $persisterFactory->setEntityPersister('Doctrine\Tests\Models\CMS\CmsUser', new PersisterMock()); - /** {@inheritDoc} */ - public function getEntityPersister($entityName) - { - return $this->entityPersister; + return $persisterFactory; } } diff --git a/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php b/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php index a8a2adaba0d..8b9fb4030cb 100644 --- a/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php @@ -8,6 +8,7 @@ use Doctrine\Common\Proxy\ProxyGenerator; use Doctrine\Tests\Mocks\ConnectionMock; use Doctrine\Tests\Mocks\EntityManagerMock; +use Doctrine\Tests\Mocks\PersisterFactoryMock; use Doctrine\Tests\Mocks\UnitOfWorkMock; use Doctrine\Tests\Mocks\DriverMock; use Doctrine\Common\Proxy\AbstractProxyFactory; @@ -33,6 +34,11 @@ class ProxyFactoryTest extends \Doctrine\Tests\OrmTestCase */ private $emMock; + /** + * @var PersisterFactoryMock + */ + private $persisterFactoryMock; + /** * @var \Doctrine\ORM\Proxy\ProxyFactory */ @@ -44,10 +50,16 @@ class ProxyFactoryTest extends \Doctrine\Tests\OrmTestCase protected function setUp() { parent::setUp(); + $this->connectionMock = new ConnectionMock(array(), new DriverMock()); $this->emMock = EntityManagerMock::create($this->connectionMock); + $this->uowMock = new UnitOfWorkMock($this->emMock); $this->emMock->setUnitOfWork($this->uowMock); + + $this->persisterFactoryMock = new PersisterFactoryMock($this->emMock); + $this->emMock->setPersisterFactory($this->persisterFactoryMock); + $this->proxyFactory = new ProxyFactory($this->emMock, sys_get_temp_dir(), 'Proxies', AbstractProxyFactory::AUTOGENERATE_ALWAYS); } @@ -55,8 +67,9 @@ public function testReferenceProxyDelegatesLoadingToThePersister() { $identifier = array('id' => 42); $proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature'; - $persister = $this->getMock('Doctrine\ORM\Persisters\Entity\BasicEntityPersister', array('load'), array(), '', false); - $this->uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); + $persister = $this->getMock('Doctrine\ORM\Persisters\Entity\BasicEntityPersister', array('load'), array(), '', false); + + $this->persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); $proxy = $this->proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier); @@ -89,7 +102,8 @@ public function testSkipAbstractClassesOnGeneration() public function testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized() { $persister = $this->getMock('Doctrine\ORM\Persisters\Entity\BasicEntityPersister', array('load'), array(), '', false); - $this->uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); + + $this->persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); /* @var $proxy \Doctrine\Common\Proxy\Proxy */ $proxy = $this->proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', array('id' => 42)); @@ -116,7 +130,8 @@ public function testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized() public function testFailedProxyCloningDoesNotMarkTheProxyAsInitialized() { $persister = $this->getMock('Doctrine\ORM\Persisters\Entity\BasicEntityPersister', array('load'), array(), '', false); - $this->uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); + + $this->persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); /* @var $proxy \Doctrine\Common\Proxy\Proxy */ $proxy = $this->proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', array('id' => 42)); diff --git a/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php b/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php index a64f2b42846..c635da22f07 100644 --- a/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php +++ b/tests/Doctrine/Tests/ORM/UnitOfWorkTest.php @@ -5,6 +5,7 @@ use Doctrine\ORM\UnitOfWork; use Doctrine\Tests\Mocks\ConnectionMock; use Doctrine\Tests\Mocks\EntityManagerMock; +use Doctrine\Tests\Mocks\PersisterFactoryMock; use Doctrine\Tests\Mocks\UnitOfWorkMock; use Doctrine\Tests\Mocks\EntityPersisterMock; use Doctrine\Tests\Models\Forum\ForumUser; @@ -15,6 +16,8 @@ */ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase { + // Provides a persister factory mock to the EntityManager + private $_persisterFactoryMock; // SUT private $_unitOfWork; // Provides a sequence mock to the UnitOfWork @@ -24,11 +27,16 @@ class UnitOfWorkTest extends \Doctrine\Tests\OrmTestCase protected function setUp() { parent::setUp(); + $this->_connectionMock = new ConnectionMock(array(), new \Doctrine\Tests\Mocks\DriverMock()); $this->_emMock = EntityManagerMock::create($this->_connectionMock); + // SUT $this->_unitOfWork = new UnitOfWorkMock($this->_emMock); $this->_emMock->setUnitOfWork($this->_unitOfWork); + + $this->_persisterFactoryMock = new PersisterFactoryMock($this->_emMock); + $this->_emMock->setPersisterFactory($this->_persisterFactoryMock); } protected function tearDown() { @@ -49,8 +57,11 @@ public function testRegisterRemovedOnNewEntityIsIgnored() public function testSavingSingleEntityWithIdentityColumnForcesInsert() { // Setup fake persister and id generator for identity generation - $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser")); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); + $userMetadata = $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser"); + $userPersister = new EntityPersisterMock($this->_emMock, $userMetadata); + + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); + $userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY); // Test @@ -90,11 +101,11 @@ public function testCascadedIdentityColumnInsert() // Setup fake persister and id generator for identity generation //ForumUser $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser")); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); $userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY); // ForumAvatar $avatarPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumAvatar")); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarPersister); + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\Forum\ForumAvatar', $avatarPersister); $avatarPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY); // Test @@ -121,9 +132,9 @@ public function testCascadedIdentityColumnInsert() public function testChangeTrackingNotify() { $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\NotifyChangedEntity")); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedEntity', $persister); + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedEntity', $persister); $itemPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\NotifyChangedRelatedItem")); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedRelatedItem', $itemPersister); + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\ORM\NotifyChangedRelatedItem', $itemPersister); $entity = new NotifyChangedEntity; $entity->setData('thedata'); @@ -165,7 +176,7 @@ public function testChangeTrackingNotify() public function testGetEntityStateOnVersionedEntityWithAssignedIdentifier() { $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity")); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity', $persister); + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\ORM\VersionedAssignedIdentifierEntity', $persister); $e = new VersionedAssignedIdentifierEntity(); $e->id = 42; @@ -176,7 +187,7 @@ public function testGetEntityStateOnVersionedEntityWithAssignedIdentifier() public function testGetEntityStateWithAssignedIdentity() { $persister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\CMS\CmsPhonenumber")); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\CMS\CmsPhonenumber', $persister); + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\CMS\CmsPhonenumber', $persister); $ph = new \Doctrine\Tests\Models\CMS\CmsPhonenumber(); $ph->phonenumber = '12345'; @@ -204,7 +215,7 @@ public function testNoUndefinedIndexNoticeOnScheduleForUpdateWithoutChanges() // Setup fake persister and id generator $userPersister = new EntityPersisterMock($this->_emMock, $this->_emMock->getClassMetadata("Doctrine\Tests\Models\Forum\ForumUser")); $userPersister->setMockIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_IDENTITY); - $this->_unitOfWork->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); + $this->_persisterFactoryMock->setEntityPersister('Doctrine\Tests\Models\Forum\ForumUser', $userPersister); // Create a test user $user = new ForumUser();