diff --git a/lib/Doctrine/ORM/EntityManager.php b/lib/Doctrine/ORM/EntityManager.php index b0a2e5e16..3d44d1f14 100644 --- a/lib/Doctrine/ORM/EntityManager.php +++ b/lib/Doctrine/ORM/EntityManager.php @@ -323,7 +323,7 @@ class EntityManager if ( ! is_array($identifier)) { $identifier = array($class->identifier[0] => $identifier); } - $entity = $this->_proxyFactory->getReferenceProxy($entityName, $identifier); + $entity = $this->_proxyFactory->getProxy($entityName, $identifier); $this->_unitOfWork->registerManaged($entity, $identifier, array()); return $entity; diff --git a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php index b03c51d73..69341385f 100644 --- a/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php +++ b/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php @@ -75,7 +75,6 @@ class ObjectHydrator extends AbstractHydrator if (isset($this->_rsm->relationMap[$dqlAlias])) { $targetClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]]; $targetClass = $this->_getClassMetadata($targetClassName); - $this->_ce[$targetClassName] = $targetClass; $assoc = $targetClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]]; $this->_hints['fetched'][$assoc->sourceEntityName][$assoc->sourceFieldName] = true; if ($assoc->mappedByFieldName) { diff --git a/lib/Doctrine/ORM/ORMException.php b/lib/Doctrine/ORM/ORMException.php index 87f809b8f..abde5f253 100644 --- a/lib/Doctrine/ORM/ORMException.php +++ b/lib/Doctrine/ORM/ORMException.php @@ -8,4 +8,9 @@ class ORMException extends \Exception { return new self("Entity of type " . get_class($entity) . " is missing an assigned ID."); } + + public static function unrecognizedField($field) + { + return new self("Unrecognized field: $field"); + } } diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index ecdb99299..4a615cd0e 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -368,7 +368,8 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect $removed = $this->_coll->remove($key); if ($removed) { $this->_changed(); - if ($this->_association->isOneToMany() && $this->_association->orphanRemoval) { + if ($this->_association !== null && $this->_association->isOneToMany() && + $this->_association->orphanRemoval) { $this->_em->getUnitOfWork()->scheduleOrphanRemoval($removed); } } diff --git a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php index 3fcb3e2a4..e51a00898 100644 --- a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php @@ -22,6 +22,7 @@ namespace Doctrine\ORM\Persisters; use Doctrine\Common\DoctrineException, + Doctrine\ORM\ORMException, Doctrine\Common\Collections\ArrayCollection, Doctrine\DBAL\Connection, Doctrine\DBAL\Types\Type, @@ -410,13 +411,6 @@ class StandardEntityPersister public function load(array $criteria, $entity = null, $assoc = null) { $stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($criteria, $assoc)); - if ($stmt === null) { - try { - throw new \Exception(); - } catch (\Exception $e) { - var_dump($e->getTraceAsString()); - } - } $stmt->execute(array_values($criteria)); $result = $stmt->fetch(Connection::FETCH_ASSOC); $stmt->closeCursor(); @@ -464,12 +458,10 @@ class StandardEntityPersister if ($assoc->isOwningSide) { $joinColumnValues = array(); - $targetColumns = array(); foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) { if ($metaColumns[$srcColumn] !== null) { - $joinColumnValues[] = $metaColumns[$srcColumn]; + $joinColumnValues[$targetColumn] = $metaColumns[$srcColumn]; } - $targetColumns[] = $targetColumn; } if ( ! $joinColumnValues && $value !== null) { $this->_class->reflFields[$field]->setValue($entity, null); @@ -486,16 +478,16 @@ class StandardEntityPersister $targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($found, $entity); } $newData[$field] = $found; - } else if ((array)$this->_class->getIdentifierValues($value) != $joinColumnValues) { - $proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnValues); + } else { + $proxy = $this->_em->getProxyFactory()->getProxy($assoc->targetEntityName, $joinColumnValues); $this->_class->reflFields[$field]->setValue($entity, $proxy); $newData[$field] = $proxy; + $this->_em->getUnitOfWork()->addToIdentityMap($proxy); } } } else { - // Inverse side of 1-1/1-x can never be lazy - $assoc->load($entity, null, $this->_em); - $newData[$field] = $this->_class->reflFields[$field]->getValue($entity); + // Inverse side of 1-1/1-x can never be lazy. + $newData[$field] = $assoc->load($entity, null, $this->_em); } } else if ($value instanceof PersistentCollection && $value->isInitialized()) { $value->setInitialized(false); @@ -643,10 +635,12 @@ class StandardEntityPersister if (isset($this->_class->columnNames[$field])) { $conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform); + } else if (isset($this->_class->fieldNames[$field])) { + $conditionSql .= $this->_class->getQuotedColumnName($this->_class->fieldNames[$field], $this->_platform); } else if ($assoc !== null) { $conditionSql .= $assoc->getQuotedJoinColumnName($field, $this->_platform); } else { - throw DoctrineException::unrecognizedField($field); + throw ORMException::unrecognizedField($field); } $conditionSql .= ' = ?'; } diff --git a/lib/Doctrine/ORM/Proxy/ProxyFactory.php b/lib/Doctrine/ORM/Proxy/ProxyFactory.php index 135b28457..8e76b29ee 100644 --- a/lib/Doctrine/ORM/Proxy/ProxyFactory.php +++ b/lib/Doctrine/ORM/Proxy/ProxyFactory.php @@ -75,9 +75,9 @@ class ProxyFactory * @param mixed $identifier * @return object */ - public function getReferenceProxy($className, $identifier) + public function getProxy($className, $identifier) { - $proxyClassName = str_replace('\\', '', $className) . 'RProxy'; + $proxyClassName = str_replace('\\', '', $className) . 'Proxy'; $fqn = $this->_proxyNamespace . '\\' . $proxyClassName; if ($this->_autoGenerate && ! class_exists($fqn, false)) { @@ -95,32 +95,6 @@ class ProxyFactory return new $fqn($entityPersister, $identifier); } - /** - * Gets an association proxy instance. - * - * @param object $owner - * @param AssociationMapping $assoc - * @param array $joinColumnValues - * @return object - */ - public function getAssociationProxy($owner, AssociationMapping $assoc, array $joinColumnValues) - { - $proxyClassName = str_replace('\\', '', $assoc->targetEntityName) . 'AProxy'; - $fqn = $this->_proxyNamespace . '\\' . $proxyClassName; - - if ($this->_autoGenerate && ! class_exists($fqn, false)) { - $fileName = $this->_proxyDir . DIRECTORY_SEPARATOR . $proxyClassName . '.php'; - $this->_generateProxyClass($this->_em->getClassMetadata($assoc->targetEntityName), $proxyClassName, $fileName, self::$_assocProxyClassTemplate); - require $fileName; - } - - if ( ! $this->_em->getMetadataFactory()->hasMetadataFor($fqn)) { - $this->_em->getMetadataFactory()->setMetadataFor($fqn, $this->_em->getClassMetadata($assoc->targetEntityName)); - } - - return new $fqn($this->_em, $assoc, $owner, $joinColumnValues); - } - /** * Generates proxy classes for all given classes. * @@ -134,12 +108,9 @@ class ProxyFactory $proxyDir = $toDir ?: $this->_proxyDir; $proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; foreach ($classes as $class) { - $AproxyClassName = str_replace('\\', '', $class->name) . 'AProxy'; - $RproxyClassName = str_replace('\\', '', $class->name) . 'RProxy'; - $AproxyFileName = $proxyDir . $AproxyClassName . '.php'; - $RproxyFileName = $proxyDir . $RproxyClassName . '.php'; - $this->_generateProxyClass($class, $RproxyClassName, $RproxyFileName, self::$_proxyClassTemplate); - $this->_generateProxyClass($class, $AproxyClassName, $AproxyFileName, self::$_assocProxyClassTemplate); + $proxyClassName = str_replace('\\', '', $class->name) . 'Proxy'; + $proxyFileName = $proxyDir . $proxyClassName . '.php'; + $this->_generateProxyClass($class, $proxyClassName, $proxyFileName, self::$_proxyClassTemplate); } } @@ -301,47 +272,4 @@ namespace { } } }'; - - /** Association Proxy class code template */ - private static $_assocProxyClassTemplate = -' { - /** - * THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE. - */ - class extends \ implements \Doctrine\ORM\Proxy\Proxy { - private $_em; - private $_assoc; - private $_owner; - private $_joinColumnValues; - private $_loaded = false; - public function __construct($em, $assoc, $owner, array $joinColumnValues) { - $this->_em = $em; - $this->_assoc = $assoc; - $this->_owner = $owner; - $this->_joinColumnValues = $joinColumnValues; - - } - private function _load() { - if ( ! $this->_loaded) { - $this->_assoc->load($this->_owner, $this, $this->_em, $this->_joinColumnValues); - unset($this->_em); - unset($this->_owner); - unset($this->_assoc); - unset($this->_joinColumnValues); - $this->_loaded = true; - } - } - public function __isInitialized__() { return $this->_loaded; } - - - - public function __sleep() { - if (!$this->_loaded) { - throw new \RuntimeException("Not fully loaded proxy can not be serialized."); - } - - } - } -}'; } diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index d69cda88a..5c3f4831a 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -59,8 +59,7 @@ final class Query extends AbstractQuery const HINT_REFRESH = 'doctrine.refresh'; /** * The forcePartialLoad query hint forces a particular query to return - * partial objects when partial objects in general are disallowed in the - * configuration. + * partial objects. * * @var string */ diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index f99b1f548..51a86e699 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -1330,10 +1330,17 @@ class UnitOfWork implements PropertyChangedListener $prop->setValue($managedCopy, $prop->getValue($entity)); } else { $assoc2 = $class->associationMappings[$name]; - if ($assoc2->isOneToOne() && ! $assoc2->isCascadeMerge) { - $targetClass = $this->_em->getClassMetadata($assoc2->targetEntityName); - $prop->setValue($managedCopy, $this->_em->getProxyFactory() - ->getReferenceProxy($assoc2->targetEntityName, $targetClass->getIdentifierValues($entity))); + if ($assoc2->isOneToOne()) { + if ( ! $assoc2->isCascadeMerge) { + $other = $class->reflFields[$name]->getValue($entity); + if ($other !== null) { + $targetClass = $this->_em->getClassMetadata($assoc2->targetEntityName); + $id = $targetClass->getIdentifierValues($other); + $proxy = $this->_em->getProxyFactory()->getProxy($assoc2->targetEntityName, $id); + $prop->setValue($managedCopy, $proxy); + $this->registerManaged($proxy, (array)$id, array()); + } + } } else { $coll = new PersistentCollection($this->_em, $this->_em->getClassMetadata($assoc2->targetEntityName), @@ -1695,49 +1702,59 @@ class UnitOfWork implements PropertyChangedListener if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) { foreach ($class->associationMappings as $field => $assoc) { // Check if the association is not among the fetch-joined associations already. - if ( ! isset($hints['fetched'][$className][$field])) { - if ($assoc->isOneToOne()) { - if ($assoc->isOwningSide) { - $joinColumns = array(); - foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { - $joinColumnValue = $data[$assoc->joinColumnFieldNames[$srcColumn]]; - if ($joinColumnValue !== null) { - $joinColumns[$srcColumn] = $joinColumnValue; - } - } - if ( ! $joinColumns) { - $class->reflFields[$field]->setValue($entity, null); - $this->_originalEntityData[$oid][$field] = null; - } else { - //TODO: If its in the identity map just get it from there if possible! - // Inject proxy - $proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumns); - $this->_originalEntityData[$oid][$field] = $proxy; - $class->reflFields[$field]->setValue($entity, $proxy); + if (isset($hints['fetched'][$className][$field])) { + continue; + } + + $targetClass = $this->_em->getClassMetadata($assoc->targetEntityName); + + if ($assoc->isOneToOne()) { + if ($assoc->isOwningSide) { + $associatedId = array(); + foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) { + $joinColumnValue = $data[$srcColumn]; + if ($joinColumnValue !== null) { + $associatedId[$targetColumn] = $joinColumnValue; } + } + if ( ! $associatedId) { + $class->reflFields[$field]->setValue($entity, null); + $this->_originalEntityData[$oid][$field] = null; } else { - // Inverse side can never be lazy. - $targetEntity = $assoc->load($entity, new $assoc->targetEntityName, $this->_em); - $class->reflFields[$field]->setValue($entity, $targetEntity); + // Check identity map first + // FIXME: Can break easily with composite keys if join column values are in + // wrong order. The correct order is the one in ClassMetadata#identifier. + $relatedIdHash = implode(' ', $associatedId); + if (isset($this->_identityMap[$targetClass->rootEntityName][$relatedIdHash])) { + $newValue = $this->_identityMap[$targetClass->rootEntityName][$relatedIdHash]; + } else { + $newValue = $this->_em->getProxyFactory()->getProxy($assoc->targetEntityName, $associatedId); + $this->_entityIdentifiers[spl_object_hash($newValue)] = $associatedId; + $this->_identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue; + } + $this->_originalEntityData[$oid][$field] = $newValue; + $class->reflFields[$field]->setValue($entity, $newValue); } } else { - // Inject collection - $reflField = $class->reflFields[$field]; - $pColl = new PersistentCollection( - $this->_em, - $this->_em->getClassMetadata($assoc->targetEntityName), - $reflField->getValue($entity) ?: new ArrayCollection - ); - $pColl->setOwner($entity, $assoc); - $reflField->setValue($entity, $pColl); - if ($assoc->isLazilyFetched()) { - $pColl->setInitialized(false); - } else { - //TODO: Allow more efficient and configurable batching of these loads - $assoc->load($entity, $pColl, $this->_em); - } - $this->_originalEntityData[$oid][$field] = $pColl; + // Inverse side can never be lazy + $targetEntity = $assoc->load($entity, new $assoc->targetEntityName, $this->_em); + $class->reflFields[$field]->setValue($entity, $targetEntity); } + } else { + // Inject collection + $reflField = $class->reflFields[$field]; + $pColl = new PersistentCollection( + $this->_em, $targetClass, + $reflField->getValue($entity) ?: new ArrayCollection + ); + $pColl->setOwner($entity, $assoc); + $reflField->setValue($entity, $pColl); + if ($assoc->isLazilyFetched()) { + $pColl->setInitialized(false); + } else { + $assoc->load($entity, $pColl, $this->_em); + } + $this->_originalEntityData[$oid][$field] = $pColl; } } } diff --git a/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php b/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php index 4bc13c70b..6a3db8936 100644 --- a/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php @@ -74,8 +74,6 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->persist($ph2); - //$removed = $user->removePhonenumber(1); // [romanb] this is currently broken, I'm on it. - // Merge back in $user = $this->_em->merge($user); // merge cascaded to phonenumbers $this->_em->flush(); diff --git a/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php b/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php index c0ddc0ffc..762b43c84 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php @@ -38,7 +38,7 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase $id = $product->getId(); - $productProxy = $this->_factory->getReferenceProxy('Doctrine\Tests\Models\ECommerce\ECommerceProduct', array('id' => $id)); + $productProxy = $this->_factory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceProduct', array('id' => $id)); $this->assertEquals('Doctrine Cookbook', $productProxy->getName()); } } diff --git a/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php b/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php index 477746137..afe2276dd 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/ObjectHydratorTest.php @@ -122,12 +122,12 @@ class ObjectHydratorTest extends HydrationTestCase ); // mocking the proxy factory - $proxyFactory = $this->getMock('Doctrine\ORM\Proxy\ProxyFactory', array('getAssociationProxy'), array(), '', false, false, false); + $proxyFactory = $this->getMock('Doctrine\ORM\Proxy\ProxyFactory', array('getProxy'), array(), '', false, false, false); $proxyFactory->expects($this->once()) - ->method('getAssociationProxy') - ->with($this->isInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct'), - $this->isInstanceOf('Doctrine\ORM\Mapping\OneToOneMapping'), - array('shipping_id' => 42)); + ->method('getProxy') + ->with($this->equalTo('Doctrine\Tests\Models\ECommerce\ECommerceShipping'), + array('id' => 42)) + ->will($this->returnValue(new \stdClass)); $this->_em->setProxyFactory($proxyFactory); diff --git a/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php b/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php index cdbefb510..cad4dce53 100644 --- a/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php +++ b/tests/Doctrine/Tests/ORM/Proxy/ProxyClassGeneratorTest.php @@ -48,11 +48,11 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase public function testReferenceProxyDelegatesLoadingToThePersister() { $identifier = array('id' => 42); - $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; + $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy'; $persister = $this->_getMockPersister(); $this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); - $proxy = $this->_proxyFactory->getReferenceProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier); + $proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier); $persister->expects($this->atLeastOnce()) ->method('load') @@ -64,10 +64,10 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase public function testReferenceProxyExecutesLoadingOnlyOnce() { $identifier = array('id' => 42); - $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; + $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy'; $persister = $this->_getMockPersister(); $this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); - $proxy = $this->_proxyFactory->getReferenceProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier); + $proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier); $persister->expects($this->atLeastOnce()) ->method('load') ->with($this->equalTo($identifier), $this->isInstanceOf($proxyClass)); @@ -77,10 +77,10 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase public function testReferenceProxyRespectsMethodsParametersTypeHinting() { - $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; + $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy'; $persister = $this->_getMockPersister(); $this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); - $proxy = $this->_proxyFactory->getReferenceProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', null); + $proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', null); $method = new \ReflectionMethod(get_class($proxy), 'setProduct'); $params = $method->getParameters(); @@ -91,43 +91,18 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase public function testCreatesAssociationProxyAsSubclassOfTheOriginalOne() { - $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; + $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy'; $this->assertTrue(is_subclass_of($proxyClass, 'Doctrine\Tests\Models\ECommerce\ECommerceFeature')); } public function testAllowsConcurrentCreationOfBothProxyTypes() { - $referenceProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; + $referenceProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy'; $associationProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureAProxy'; $this->assertNotEquals($referenceProxyClass, $associationProxyClass); } - public function testAssociationProxyDelegatesLoadingToTheAssociation() - { - $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureAProxy'; - $product = new ECommerceProduct; - $foreignKeys = array('customer_id' => 42); - $assoc = $this->_getAssociationMock(); - $assoc->targetEntityName = 'Doctrine\Tests\Models\ECommerce\ECommerceFeature'; - $proxy = $this->_proxyFactory->getAssociationProxy($product, $assoc, $foreignKeys); - $assoc->expects($this->atLeastOnce()) - ->method('load') - ->with($product, $this->isInstanceOf($proxyClass), $this->isInstanceOf('Doctrine\Tests\Mocks\EntityManagerMock'), $foreignKeys); - $proxy->getDescription(); - } - - public function testAssociationProxyExecutesLoadingOnlyOnce() - { - $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureAProxy'; - $assoc = $this->_getAssociationMock(); - $assoc->targetEntityName = 'Doctrine\Tests\Models\ECommerce\ECommerceFeature'; - $proxy = $this->_proxyFactory->getAssociationProxy(null, $assoc, array()); - $assoc->expects($this->once())->method('load'); - $proxy->getDescription(); - $proxy->getDescription(); - } - protected function _getAssociationMock() { $assoc = $this->getMock('Doctrine\ORM\Mapping\AssociationMapping', array('load'), array(), '', false, false, false);