1
0
mirror of synced 2025-01-29 19:41:45 +03:00

Merge pull request #315 from Ocramius/getclass-on-proxies-refactoring

Allowing proxies to be passed to ORM public API
This commit is contained in:
Benjamin Eberlei 2012-05-04 10:04:14 -07:00
commit e09a9c7deb
6 changed files with 178 additions and 45 deletions

View File

@ -22,7 +22,7 @@ namespace Doctrine\ORM;
use Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Cache\QueryCacheProfile,
Doctrine\ORM\Query\QueryException,
Doctrine\ORM\Internal\Hydration\CacheHydrator;
Doctrine\Common\Util\ClassUtils;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@ -241,7 +241,7 @@ abstract class AbstractQuery
return $value;
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)):
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value)):
return $this->convertObjectParameterToScalarValue($value);
default:

View File

@ -24,6 +24,7 @@ use ReflectionException,
Doctrine\ORM\EntityManager,
Doctrine\DBAL\Platforms,
Doctrine\ORM\Events,
Doctrine\Common\Util\ClassUtils,
Doctrine\Common\Persistence\Mapping\RuntimeReflectionService,
Doctrine\Common\Persistence\Mapping\ReflectionService,
Doctrine\Common\Persistence\Mapping\ClassMetadataFactory as ClassMetadataFactoryInterface;
@ -154,41 +155,44 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
*/
public function getMetadataFor($className)
{
if ( ! isset($this->loadedMetadata[$className])) {
$realClassName = $className;
if (isset($this->loadedMetadata[$className])) {
return $this->loadedMetadata[$className];
}
// Check for namespace alias
if (strpos($className, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $className);
$realClassName = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
$realClassName = $className;
if (isset($this->loadedMetadata[$realClassName])) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
// Check for namespace alias
if (strpos($className, ':') !== false) {
list($namespaceAlias, $simpleClassName) = explode(':', $className);
$realClassName = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
} else {
$realClassName = ClassUtils::getRealClass($realClassName);
}
return $this->loadedMetadata[$realClassName];
}
}
if (isset($this->loadedMetadata[$realClassName])) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
return $this->loadedMetadata[$realClassName];
}
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
$this->wakeupReflection($cached, $this->getReflectionService());
$this->loadedMetadata[$realClassName] = $cached;
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
$this->cacheDriver->save(
"$loadedClassName\$CLASSMETADATA", $this->loadedMetadata[$loadedClassName], null
);
}
}
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
$this->wakeupReflection($cached, $this->getReflectionService());
$this->loadedMetadata[$realClassName] = $cached;
} else {
$this->loadMetadata($realClassName);
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
$this->cacheDriver->save(
"$loadedClassName\$CLASSMETADATA", $this->loadedMetadata[$loadedClassName], null
);
}
}
} else {
$this->loadMetadata($realClassName);
}
if ($className != $realClassName) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
}
if ($className != $realClassName) {
// We do not have the alias name in the map, include it
$this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
}
return $this->loadedMetadata[$className];

View File

@ -32,7 +32,8 @@ use PDO,
Doctrine\ORM\Mapping\MappingException,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Events,
Doctrine\ORM\Event\LifecycleEventArgs;
Doctrine\ORM\Event\LifecycleEventArgs,
Doctrine\Common\Util\ClassUtils;
/**
* A BasicEntityPersiter maps an entity to a single table in a relational database.
@ -1499,7 +1500,7 @@ class BasicEntityPersister
*/
private function getIndividualValue($value)
{
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
} else {

View File

@ -93,10 +93,6 @@ class ProxyFactory
require $fileName;
}
if ( ! $this->_em->getMetadataFactory()->hasMetadataFor($fqn)) {
$this->_em->getMetadataFactory()->setMetadataFor($fqn, $this->_em->getClassMetadata($className));
}
$entityPersister = $this->_em->getUnitOfWork()->getEntityPersister($className);
return new $fqn($entityPersister, $identifier);

View File

@ -886,7 +886,7 @@ class UnitOfWork implements PropertyChangedListener
$hasListeners = $this->evm->hasListeners(Events::postPersist);
foreach ($this->entityInsertions as $oid => $entity) {
if (get_class($entity) !== $className) {
if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
continue;
}
@ -945,7 +945,7 @@ class UnitOfWork implements PropertyChangedListener
$hasPostUpdateListeners = $this->evm->hasListeners(Events::postUpdate);
foreach ($this->entityUpdates as $oid => $entity) {
if ( ! (get_class($entity) === $className || $entity instanceof Proxy && get_parent_class($entity) === $className)) {
if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
continue;
}
@ -992,7 +992,7 @@ class UnitOfWork implements PropertyChangedListener
$hasListeners = $this->evm->hasListeners(Events::postRemove);
foreach ($this->entityDeletions as $oid => $entity) {
if ( ! (get_class($entity) == $className || $entity instanceof Proxy && get_parent_class($entity) == $className)) {
if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
continue;
}
@ -1043,7 +1043,7 @@ class UnitOfWork implements PropertyChangedListener
$newNodes = array();
foreach ($entityChangeSet as $entity) {
$className = get_class($entity);
$className = $this->em->getClassMetadata(get_class($entity))->name;
if ($calc->hasClass($className)) {
continue;
@ -1357,7 +1357,7 @@ class UnitOfWork implements PropertyChangedListener
}
// db lookup
if ($this->getEntityPersister(get_class($entity))->exists($entity)) {
if ($this->getEntityPersister($class->name)->exists($entity)) {
return self::STATE_DETACHED;
}
@ -1374,7 +1374,7 @@ class UnitOfWork implements PropertyChangedListener
}
// db lookup
if ($this->getEntityPersister(get_class($entity))->exists($entity)) {
if ($this->getEntityPersister($class->name)->exists($entity)) {
return self::STATE_DETACHED;
}
@ -2151,13 +2151,12 @@ class UnitOfWork implements PropertyChangedListener
throw ORMInvalidArgumentException::entityNotManaged($entity);
}
$entityName = get_class($entity);
$class = $this->em->getClassMetadata($entityName);
$class = $this->em->getClassMetadata(get_class($entity));
switch ($lockMode) {
case \Doctrine\DBAL\LockMode::OPTIMISTIC;
if ( ! $class->isVersioned) {
throw OptimisticLockException::notVersioned($entityName);
throw OptimisticLockException::notVersioned($class->name);
}
if ($lockVersion === null) {

View File

@ -0,0 +1,133 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Common\Util\ClassUtils,
Doctrine\Tests\Models\CMS\CmsUser,
Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser as Proxy;
/**
* Test that Doctrine ORM correctly works with proxy instances exactly like with ordinary Entities
*
* The test considers two possible cases:
* a) __initialized__ = true and no identifier set in proxy
* b) __initialized__ = false and identifier set in proxy and in property
* @todo All other cases would cause lazy loading issues
*/
class ProxiesLikeEntitiesTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
/**
* @var CmsUser
*/
protected $user;
protected function setUp()
{
parent::setUp();
try {
$this->_schemaTool->createSchema(array(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'),
));
} catch (\Exception $e) {
}
$this->user = new CmsUser();
$this->user->username = 'ocramius';
$this->user->name = 'Marco';
$this->_em->persist($this->user);
$this->_em->flush();
$this->_em->clear();
}
/**
* Verifies that a proxy can be successfully persisted and updated
*/
public function testPersistUpdate()
{
// Considering case (a)
$persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\CMS\CmsUser');
$proxy = new Proxy($persister, array());
$proxy->__isInitialized__ = true;
$proxy->username = 'ocra';
$proxy->name = 'Marco';
$this->_em->persist($proxy);
$this->_em->flush();
$this->assertNotNull($proxy->getId());
$proxy->name = 'Marco Pivetta';
$this
->_em
->getUnitOfWork()
->computeChangeSet($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), $proxy);
$this->assertNotEmpty($this->_em->getUnitOfWork()->getEntityChangeSet($proxy));
$this->assertEquals('Marco Pivetta', $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $proxy->getId())->name);
$this->_em->remove($proxy);
$this->_em->flush();
}
public function testEntityWithIdentifier()
{
// Considering case (b)
$persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\CMS\CmsUser');
$uninitializedProxy = new Proxy($persister, array('id' => $this->user->getId()));
$uninitializedProxy->id = $this->user->getId();
$uninitializedProxy->username = 'ocra';
$uninitializedProxy->name = 'Marco Pivetta';
$this->_em->persist($uninitializedProxy);
$this->_em->flush();
$this->assertEquals($this->user->getId(), $uninitializedProxy->getId());
$this->_em->remove($uninitializedProxy);
$this->_em->flush();
}
/**
* Verifying that proxies can be used without problems as query parameters
*/
public function testProxyAsDqlParameterPersist()
{
$persister = $this->_em->getUnitOfWork()->getEntityPersister('Doctrine\Tests\Models\CMS\CmsUser');
$proxy = new Proxy($persister, array('id' => $this->user->getId()));
$proxy->id = $this->user->getId();
$result = $this
->_em
->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u = ?1')
->setParameter(1, $proxy)
->getSingleResult();
$this->assertSame($this->user->getId(), $result->getId());
$this->_em->remove($proxy);
$this->_em->flush();
}
/**
* Verifying that proxies can be used without problems as query parameters
*/
public function testFindWithProxyName()
{
$result = $this
->_em
->find('Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser', $this->user->getId());
$this->assertSame($this->user->getId(), $result->getId());
$this->_em->clear();
$result = $this
->_em
->getReference('Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser', $this->user->getId());
$this->assertSame($this->user->getId(), $result->getId());
$this->_em->clear();
$result = $this
->_em
->getRepository('Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser')
->findOneBy(array('username' => $this->user->username));
$this->assertSame($this->user->getId(), $result->getId());
$this->_em->clear();
$result = $this
->_em
->createQuery('SELECT u FROM Doctrine\Tests\Proxies\__CG__\Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1')
->setParameter(1, $this->user->getId())
->getSingleResult();
$this->assertSame($this->user->getId(), $result->getId());
$this->_em->clear();
}
protected function tearDown()
{
$this->_em->createQuery('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u')->execute();
}
}