1
0
mirror of synced 2025-01-19 06:51:40 +03:00

[2.0] Fixed DDC-18. Simplified proxy classes. Just 1 proxy class per entity now, instead of 2.

This commit is contained in:
romanb 2009-10-28 15:32:55 +00:00
parent aa72619c5d
commit f572c372dc
12 changed files with 97 additions and 181 deletions

View File

@ -323,7 +323,7 @@ class EntityManager
if ( ! is_array($identifier)) { if ( ! is_array($identifier)) {
$identifier = array($class->identifier[0] => $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()); $this->_unitOfWork->registerManaged($entity, $identifier, array());
return $entity; return $entity;

View File

@ -75,7 +75,6 @@ class ObjectHydrator extends AbstractHydrator
if (isset($this->_rsm->relationMap[$dqlAlias])) { if (isset($this->_rsm->relationMap[$dqlAlias])) {
$targetClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]]; $targetClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
$targetClass = $this->_getClassMetadata($targetClassName); $targetClass = $this->_getClassMetadata($targetClassName);
$this->_ce[$targetClassName] = $targetClass;
$assoc = $targetClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]]; $assoc = $targetClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$this->_hints['fetched'][$assoc->sourceEntityName][$assoc->sourceFieldName] = true; $this->_hints['fetched'][$assoc->sourceEntityName][$assoc->sourceFieldName] = true;
if ($assoc->mappedByFieldName) { if ($assoc->mappedByFieldName) {

View File

@ -8,4 +8,9 @@ class ORMException extends \Exception
{ {
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID."); 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");
}
} }

View File

@ -368,7 +368,8 @@ final class PersistentCollection implements \Doctrine\Common\Collections\Collect
$removed = $this->_coll->remove($key); $removed = $this->_coll->remove($key);
if ($removed) { if ($removed) {
$this->_changed(); $this->_changed();
if ($this->_association->isOneToMany() && $this->_association->orphanRemoval) { if ($this->_association !== null && $this->_association->isOneToMany() &&
$this->_association->orphanRemoval) {
$this->_em->getUnitOfWork()->scheduleOrphanRemoval($removed); $this->_em->getUnitOfWork()->scheduleOrphanRemoval($removed);
} }
} }

View File

@ -22,6 +22,7 @@
namespace Doctrine\ORM\Persisters; namespace Doctrine\ORM\Persisters;
use Doctrine\Common\DoctrineException, use Doctrine\Common\DoctrineException,
Doctrine\ORM\ORMException,
Doctrine\Common\Collections\ArrayCollection, Doctrine\Common\Collections\ArrayCollection,
Doctrine\DBAL\Connection, Doctrine\DBAL\Connection,
Doctrine\DBAL\Types\Type, Doctrine\DBAL\Types\Type,
@ -410,13 +411,6 @@ class StandardEntityPersister
public function load(array $criteria, $entity = null, $assoc = null) public function load(array $criteria, $entity = null, $assoc = null)
{ {
$stmt = $this->_conn->prepare($this->_getSelectEntitiesSql($criteria, $assoc)); $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)); $stmt->execute(array_values($criteria));
$result = $stmt->fetch(Connection::FETCH_ASSOC); $result = $stmt->fetch(Connection::FETCH_ASSOC);
$stmt->closeCursor(); $stmt->closeCursor();
@ -464,12 +458,10 @@ class StandardEntityPersister
if ($assoc->isOwningSide) { if ($assoc->isOwningSide) {
$joinColumnValues = array(); $joinColumnValues = array();
$targetColumns = array();
foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) { foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) {
if ($metaColumns[$srcColumn] !== null) { if ($metaColumns[$srcColumn] !== null) {
$joinColumnValues[] = $metaColumns[$srcColumn]; $joinColumnValues[$targetColumn] = $metaColumns[$srcColumn];
} }
$targetColumns[] = $targetColumn;
} }
if ( ! $joinColumnValues && $value !== null) { if ( ! $joinColumnValues && $value !== null) {
$this->_class->reflFields[$field]->setValue($entity, null); $this->_class->reflFields[$field]->setValue($entity, null);
@ -486,16 +478,16 @@ class StandardEntityPersister
$targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($found, $entity); $targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($found, $entity);
} }
$newData[$field] = $found; $newData[$field] = $found;
} else if ((array)$this->_class->getIdentifierValues($value) != $joinColumnValues) { } else {
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumnValues); $proxy = $this->_em->getProxyFactory()->getProxy($assoc->targetEntityName, $joinColumnValues);
$this->_class->reflFields[$field]->setValue($entity, $proxy); $this->_class->reflFields[$field]->setValue($entity, $proxy);
$newData[$field] = $proxy; $newData[$field] = $proxy;
$this->_em->getUnitOfWork()->addToIdentityMap($proxy);
} }
} }
} else { } else {
// Inverse side of 1-1/1-x can never be lazy // Inverse side of 1-1/1-x can never be lazy.
$assoc->load($entity, null, $this->_em); $newData[$field] = $assoc->load($entity, null, $this->_em);
$newData[$field] = $this->_class->reflFields[$field]->getValue($entity);
} }
} else if ($value instanceof PersistentCollection && $value->isInitialized()) { } else if ($value instanceof PersistentCollection && $value->isInitialized()) {
$value->setInitialized(false); $value->setInitialized(false);
@ -643,10 +635,12 @@ class StandardEntityPersister
if (isset($this->_class->columnNames[$field])) { if (isset($this->_class->columnNames[$field])) {
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform); $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) { } else if ($assoc !== null) {
$conditionSql .= $assoc->getQuotedJoinColumnName($field, $this->_platform); $conditionSql .= $assoc->getQuotedJoinColumnName($field, $this->_platform);
} else { } else {
throw DoctrineException::unrecognizedField($field); throw ORMException::unrecognizedField($field);
} }
$conditionSql .= ' = ?'; $conditionSql .= ' = ?';
} }

View File

@ -75,9 +75,9 @@ class ProxyFactory
* @param mixed $identifier * @param mixed $identifier
* @return object * @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; $fqn = $this->_proxyNamespace . '\\' . $proxyClassName;
if ($this->_autoGenerate && ! class_exists($fqn, false)) { if ($this->_autoGenerate && ! class_exists($fqn, false)) {
@ -95,32 +95,6 @@ class ProxyFactory
return new $fqn($entityPersister, $identifier); 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. * Generates proxy classes for all given classes.
* *
@ -134,12 +108,9 @@ class ProxyFactory
$proxyDir = $toDir ?: $this->_proxyDir; $proxyDir = $toDir ?: $this->_proxyDir;
$proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; $proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
foreach ($classes as $class) { foreach ($classes as $class) {
$AproxyClassName = str_replace('\\', '', $class->name) . 'AProxy'; $proxyClassName = str_replace('\\', '', $class->name) . 'Proxy';
$RproxyClassName = str_replace('\\', '', $class->name) . 'RProxy'; $proxyFileName = $proxyDir . $proxyClassName . '.php';
$AproxyFileName = $proxyDir . $AproxyClassName . '.php'; $this->_generateProxyClass($class, $proxyClassName, $proxyFileName, self::$_proxyClassTemplate);
$RproxyFileName = $proxyDir . $RproxyClassName . '.php';
$this->_generateProxyClass($class, $RproxyClassName, $RproxyFileName, self::$_proxyClassTemplate);
$this->_generateProxyClass($class, $AproxyClassName, $AproxyFileName, self::$_assocProxyClassTemplate);
} }
} }
@ -301,47 +272,4 @@ namespace <namespace> {
} }
} }
}'; }';
/** Association Proxy class code template */
private static $_assocProxyClassTemplate =
'<?php
namespace <namespace> {
/**
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
*/
class <proxyClassName> extends \<className> 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;
<constructorInvocation>
}
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; }
<methods>
public function __sleep() {
if (!$this->_loaded) {
throw new \RuntimeException("Not fully loaded proxy can not be serialized.");
}
<sleepImpl>
}
}
}';
} }

View File

@ -59,8 +59,7 @@ final class Query extends AbstractQuery
const HINT_REFRESH = 'doctrine.refresh'; const HINT_REFRESH = 'doctrine.refresh';
/** /**
* The forcePartialLoad query hint forces a particular query to return * The forcePartialLoad query hint forces a particular query to return
* partial objects when partial objects in general are disallowed in the * partial objects.
* configuration.
* *
* @var string * @var string
*/ */

View File

@ -1330,10 +1330,17 @@ class UnitOfWork implements PropertyChangedListener
$prop->setValue($managedCopy, $prop->getValue($entity)); $prop->setValue($managedCopy, $prop->getValue($entity));
} else { } else {
$assoc2 = $class->associationMappings[$name]; $assoc2 = $class->associationMappings[$name];
if ($assoc2->isOneToOne() && ! $assoc2->isCascadeMerge) { if ($assoc2->isOneToOne()) {
if ( ! $assoc2->isCascadeMerge) {
$other = $class->reflFields[$name]->getValue($entity);
if ($other !== null) {
$targetClass = $this->_em->getClassMetadata($assoc2->targetEntityName); $targetClass = $this->_em->getClassMetadata($assoc2->targetEntityName);
$prop->setValue($managedCopy, $this->_em->getProxyFactory() $id = $targetClass->getIdentifierValues($other);
->getReferenceProxy($assoc2->targetEntityName, $targetClass->getIdentifierValues($entity))); $proxy = $this->_em->getProxyFactory()->getProxy($assoc2->targetEntityName, $id);
$prop->setValue($managedCopy, $proxy);
$this->registerManaged($proxy, (array)$id, array());
}
}
} else { } else {
$coll = new PersistentCollection($this->_em, $coll = new PersistentCollection($this->_em,
$this->_em->getClassMetadata($assoc2->targetEntityName), $this->_em->getClassMetadata($assoc2->targetEntityName),
@ -1695,28 +1702,41 @@ class UnitOfWork implements PropertyChangedListener
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) { if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
foreach ($class->associationMappings as $field => $assoc) { foreach ($class->associationMappings as $field => $assoc) {
// Check if the association is not among the fetch-joined associations already. // Check if the association is not among the fetch-joined associations already.
if ( ! isset($hints['fetched'][$className][$field])) { if (isset($hints['fetched'][$className][$field])) {
continue;
}
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
if ($assoc->isOneToOne()) { if ($assoc->isOneToOne()) {
if ($assoc->isOwningSide) { if ($assoc->isOwningSide) {
$joinColumns = array(); $associatedId = array();
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) {
$joinColumnValue = $data[$assoc->joinColumnFieldNames[$srcColumn]]; $joinColumnValue = $data[$srcColumn];
if ($joinColumnValue !== null) { if ($joinColumnValue !== null) {
$joinColumns[$srcColumn] = $joinColumnValue; $associatedId[$targetColumn] = $joinColumnValue;
} }
} }
if ( ! $joinColumns) { if ( ! $associatedId) {
$class->reflFields[$field]->setValue($entity, null); $class->reflFields[$field]->setValue($entity, null);
$this->_originalEntityData[$oid][$field] = null; $this->_originalEntityData[$oid][$field] = null;
} else { } else {
//TODO: If its in the identity map just get it from there if possible! // Check identity map first
// Inject proxy // FIXME: Can break easily with composite keys if join column values are in
$proxy = $this->_em->getProxyFactory()->getAssociationProxy($entity, $assoc, $joinColumns); // wrong order. The correct order is the one in ClassMetadata#identifier.
$this->_originalEntityData[$oid][$field] = $proxy; $relatedIdHash = implode(' ', $associatedId);
$class->reflFields[$field]->setValue($entity, $proxy); 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 { } else {
// Inverse side can never be lazy. // Inverse side can never be lazy
$targetEntity = $assoc->load($entity, new $assoc->targetEntityName, $this->_em); $targetEntity = $assoc->load($entity, new $assoc->targetEntityName, $this->_em);
$class->reflFields[$field]->setValue($entity, $targetEntity); $class->reflFields[$field]->setValue($entity, $targetEntity);
} }
@ -1724,8 +1744,7 @@ class UnitOfWork implements PropertyChangedListener
// Inject collection // Inject collection
$reflField = $class->reflFields[$field]; $reflField = $class->reflFields[$field];
$pColl = new PersistentCollection( $pColl = new PersistentCollection(
$this->_em, $this->_em, $targetClass,
$this->_em->getClassMetadata($assoc->targetEntityName),
$reflField->getValue($entity) ?: new ArrayCollection $reflField->getValue($entity) ?: new ArrayCollection
); );
$pColl->setOwner($entity, $assoc); $pColl->setOwner($entity, $assoc);
@ -1733,7 +1752,6 @@ class UnitOfWork implements PropertyChangedListener
if ($assoc->isLazilyFetched()) { if ($assoc->isLazilyFetched()) {
$pColl->setInitialized(false); $pColl->setInitialized(false);
} else { } else {
//TODO: Allow more efficient and configurable batching of these loads
$assoc->load($entity, $pColl, $this->_em); $assoc->load($entity, $pColl, $this->_em);
} }
$this->_originalEntityData[$oid][$field] = $pColl; $this->_originalEntityData[$oid][$field] = $pColl;
@ -1741,7 +1759,6 @@ class UnitOfWork implements PropertyChangedListener
} }
} }
} }
}
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here. //TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
if (isset($class->lifecycleCallbacks[Events::postLoad])) { if (isset($class->lifecycleCallbacks[Events::postLoad])) {

View File

@ -74,8 +74,6 @@ class DetachedEntityTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($ph2); $this->_em->persist($ph2);
//$removed = $user->removePhonenumber(1); // [romanb] this is currently broken, I'm on it.
// Merge back in // Merge back in
$user = $this->_em->merge($user); // merge cascaded to phonenumbers $user = $this->_em->merge($user); // merge cascaded to phonenumbers
$this->_em->flush(); $this->_em->flush();

View File

@ -38,7 +38,7 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
$id = $product->getId(); $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()); $this->assertEquals('Doctrine Cookbook', $productProxy->getName());
} }
} }

View File

@ -122,12 +122,12 @@ class ObjectHydratorTest extends HydrationTestCase
); );
// mocking the proxy factory // 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()) $proxyFactory->expects($this->once())
->method('getAssociationProxy') ->method('getProxy')
->with($this->isInstanceOf('Doctrine\Tests\Models\ECommerce\ECommerceProduct'), ->with($this->equalTo('Doctrine\Tests\Models\ECommerce\ECommerceShipping'),
$this->isInstanceOf('Doctrine\ORM\Mapping\OneToOneMapping'), array('id' => 42))
array('shipping_id' => 42)); ->will($this->returnValue(new \stdClass));
$this->_em->setProxyFactory($proxyFactory); $this->_em->setProxyFactory($proxyFactory);

View File

@ -48,11 +48,11 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
public function testReferenceProxyDelegatesLoadingToThePersister() public function testReferenceProxyDelegatesLoadingToThePersister()
{ {
$identifier = array('id' => 42); $identifier = array('id' => 42);
$proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
$persister = $this->_getMockPersister(); $persister = $this->_getMockPersister();
$this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); $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()) $persister->expects($this->atLeastOnce())
->method('load') ->method('load')
@ -64,10 +64,10 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
public function testReferenceProxyExecutesLoadingOnlyOnce() public function testReferenceProxyExecutesLoadingOnlyOnce()
{ {
$identifier = array('id' => 42); $identifier = array('id' => 42);
$proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
$persister = $this->_getMockPersister(); $persister = $this->_getMockPersister();
$this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); $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()) $persister->expects($this->atLeastOnce())
->method('load') ->method('load')
->with($this->equalTo($identifier), $this->isInstanceOf($proxyClass)); ->with($this->equalTo($identifier), $this->isInstanceOf($proxyClass));
@ -77,10 +77,10 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
public function testReferenceProxyRespectsMethodsParametersTypeHinting() public function testReferenceProxyRespectsMethodsParametersTypeHinting()
{ {
$proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
$persister = $this->_getMockPersister(); $persister = $this->_getMockPersister();
$this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister); $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'); $method = new \ReflectionMethod(get_class($proxy), 'setProduct');
$params = $method->getParameters(); $params = $method->getParameters();
@ -91,43 +91,18 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
public function testCreatesAssociationProxyAsSubclassOfTheOriginalOne() public function testCreatesAssociationProxyAsSubclassOfTheOriginalOne()
{ {
$proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; $proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
$this->assertTrue(is_subclass_of($proxyClass, 'Doctrine\Tests\Models\ECommerce\ECommerceFeature')); $this->assertTrue(is_subclass_of($proxyClass, 'Doctrine\Tests\Models\ECommerce\ECommerceFeature'));
} }
public function testAllowsConcurrentCreationOfBothProxyTypes() public function testAllowsConcurrentCreationOfBothProxyTypes()
{ {
$referenceProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureRProxy'; $referenceProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
$associationProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureAProxy'; $associationProxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureAProxy';
$this->assertNotEquals($referenceProxyClass, $associationProxyClass); $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() protected function _getAssociationMock()
{ {
$assoc = $this->getMock('Doctrine\ORM\Mapping\AssociationMapping', array('load'), array(), '', false, false, false); $assoc = $this->getMock('Doctrine\ORM\Mapping\AssociationMapping', array('load'), array(), '', false, false, false);