1
0
mirror of synced 2025-01-18 06:21:40 +03:00

Using Doctrine\Common\Util\ClassUtil for class_name resolutionThis avoids exceptions when passing a Proxy instance to the public API of the EntityManager, ClassMetadataFactory or UnitOfWork when the Proxy itself isn't generated by the EntityManager itself, while discovering the correct ClassMetadata instance for the proxy

This commit is contained in:
Marco Pivetta 2012-03-30 23:15:44 +02:00
parent 022d27e4e9
commit cbe4987e18
6 changed files with 48 additions and 44 deletions

View File

@ -22,7 +22,7 @@ namespace Doctrine\ORM;
use Doctrine\DBAL\Types\Type, use Doctrine\DBAL\Types\Type,
Doctrine\DBAL\Cache\QueryCacheProfile, Doctrine\DBAL\Cache\QueryCacheProfile,
Doctrine\ORM\Query\QueryException, Doctrine\ORM\Query\QueryException,
Doctrine\ORM\Internal\Hydration\CacheHydrator; Doctrine\Common\Util\ClassUtils;
/** /**
* Base contract for ORM queries. Base class for Query and NativeQuery. * Base contract for ORM queries. Base class for Query and NativeQuery.
@ -241,7 +241,7 @@ abstract class AbstractQuery
return $value; 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); return $this->convertObjectParameterToScalarValue($value);
default: default:

View File

@ -22,6 +22,7 @@ namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMException;
use Doctrine\Common\Util\ClassUtils;
/** /**
* Special generator for application-assigned identifiers (doesnt really generate anything). * Special generator for application-assigned identifiers (doesnt really generate anything).
@ -43,7 +44,7 @@ class AssignedGenerator extends AbstractIdGenerator
*/ */
public function generate(EntityManager $em, $entity) public function generate(EntityManager $em, $entity)
{ {
$class = $em->getClassMetadata(get_class($entity)); $class = $em->getClassMetadata(ClassUtils::getClass($entity));
$idFields = $class->getIdentifierFieldNames(); $idFields = $class->getIdentifierFieldNames();
$identifier = array(); $identifier = array();

View File

@ -22,7 +22,8 @@ namespace Doctrine\ORM;
use Doctrine\ORM\Mapping\ClassMetadata, use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\Common\Collections\Collection, Doctrine\Common\Collections\Collection,
Doctrine\Common\Collections\ArrayCollection, Doctrine\Common\Collections\ArrayCollection,
Closure; Closure,
Doctrine\Common\Util\ClassUtils;
/** /**
* A PersistentCollection represents a collection of elements that have persistent state. * A PersistentCollection represents a collection of elements that have persistent state.
@ -306,7 +307,7 @@ final class PersistentCollection implements Collection
$this->association['isOwningSide'] && $this->association['isOwningSide'] &&
$this->association['type'] === ClassMetadata::MANY_TO_MANY && $this->association['type'] === ClassMetadata::MANY_TO_MANY &&
$this->owner && $this->owner &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) { $this->em->getClassMetadata(ClassUtils::getClass($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner); $this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
} }
} }

View File

@ -32,7 +32,8 @@ use PDO,
Doctrine\ORM\Mapping\MappingException, Doctrine\ORM\Mapping\MappingException,
Doctrine\ORM\Mapping\ClassMetadata, Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Events, 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. * A BasicEntityPersiter maps an entity to a single table in a relational database.
@ -1499,11 +1500,11 @@ class BasicEntityPersister
*/ */
private function getIndividualValue($value) 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) { if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value); $idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
} else { } else {
$class = $this->_em->getClassMetadata(get_class($value)); $class = $this->_em->getClassMetadata(ClassUtils::getClass($value));
$idValues = $class->getIdentifierValues($value); $idValues = $class->getIdentifierValues($value);
} }

View File

@ -23,7 +23,8 @@ namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\Mapping\ClassMetadata, use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\PersistentCollection, Doctrine\ORM\PersistentCollection,
Doctrine\ORM\UnitOfWork; Doctrine\ORM\UnitOfWork,
Doctrine\Common\Util\ClassUtils;
/** /**
* Persister for many-to-many collections. * Persister for many-to-many collections.
@ -43,7 +44,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
protected function _getDeleteRowSQL(PersistentCollection $coll) protected function _getDeleteRowSQL(PersistentCollection $coll)
{ {
$mapping = $coll->getMapping(); $mapping = $coll->getMapping();
$class = $this->_em->getClassMetadata(get_class($coll->getOwner())); $class = $this->_em->getClassMetadata(ClassUtils::getClass($coll->getOwner()));
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
. ' WHERE ' . implode(' = ? AND ', $mapping['joinTableColumns']) . ' = ?'; . ' WHERE ' . implode(' = ? AND ', $mapping['joinTableColumns']) . ' = ?';
@ -80,7 +81,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
{ {
$mapping = $coll->getMapping(); $mapping = $coll->getMapping();
$columns = $mapping['joinTableColumns']; $columns = $mapping['joinTableColumns'];
$class = $this->_em->getClassMetadata(get_class($coll->getOwner())); $class = $this->_em->getClassMetadata(ClassUtils::getClass($coll->getOwner()));
$joinTable = $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()); $joinTable = $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform());
@ -118,7 +119,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$identifier2 = $this->_uow->getEntityIdentifier($element); $identifier2 = $this->_uow->getEntityIdentifier($element);
if ($isComposite) { if ($isComposite) {
$class1 = $this->_em->getClassMetadata(get_class($coll->getOwner())); $class1 = $this->_em->getClassMetadata(ClassUtils::getClass($coll->getOwner()));
$class2 = $coll->getTypeClass(); $class2 = $coll->getTypeClass();
} }
@ -150,7 +151,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
*/ */
protected function _getDeleteSQL(PersistentCollection $coll) protected function _getDeleteSQL(PersistentCollection $coll)
{ {
$class = $this->_em->getClassMetadata(get_class($coll->getOwner())); $class = $this->_em->getClassMetadata(ClassUtils::getClass($coll->getOwner()));
$mapping = $coll->getMapping(); $mapping = $coll->getMapping();
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
@ -178,7 +179,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
} }
// Composite identifier // Composite identifier
$sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner())); $sourceClass = $this->_em->getClassMetadata(ClassUtils::getClass($mapping->getOwner()));
foreach ($mapping['relationToSourceKeyColumns'] as $srcColumn) { foreach ($mapping['relationToSourceKeyColumns'] as $srcColumn) {
$params[] = $identifier[$sourceClass->fieldNames[$srcColumn]]; $params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];

View File

@ -27,7 +27,8 @@ use Exception, InvalidArgumentException, UnexpectedValueException,
Doctrine\Common\Persistence\ObjectManagerAware, Doctrine\Common\Persistence\ObjectManagerAware,
Doctrine\ORM\Event\LifecycleEventArgs, Doctrine\ORM\Event\LifecycleEventArgs,
Doctrine\ORM\Mapping\ClassMetadata, Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Proxy\Proxy; Doctrine\ORM\Proxy\Proxy,
Doctrine\Common\Util\ClassUtils;
/** /**
* The UnitOfWork is responsible for tracking changes to objects during an * The UnitOfWork is responsible for tracking changes to objects during an
@ -375,7 +376,7 @@ class UnitOfWork implements PropertyChangedListener
private function computeScheduleInsertsChangeSets() private function computeScheduleInsertsChangeSets()
{ {
foreach ($this->entityInsertions as $entity) { foreach ($this->entityInsertions as $entity) {
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$this->computeChangeSet($class, $entity); $this->computeChangeSet($class, $entity);
} }
@ -398,7 +399,7 @@ class UnitOfWork implements PropertyChangedListener
throw new \InvalidArgumentException("Entity has to be managed for single computation " . self::objToStr($entity)); throw new \InvalidArgumentException("Entity has to be managed for single computation " . self::objToStr($entity));
} }
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
if ($class->isChangeTrackingDeferredImplicit()) { if ($class->isChangeTrackingDeferredImplicit()) {
$this->persist($entity); $this->persist($entity);
@ -433,7 +434,7 @@ class UnitOfWork implements PropertyChangedListener
list ($entity, $changeset) = $update; list ($entity, $changeset) = $update;
$this->entityChangeSets[$oid] = $changeset; $this->entityChangeSets[$oid] = $changeset;
$this->getEntityPersister(get_class($entity))->update($entity); $this->getEntityPersister(ClassUtils::getClass($entity))->update($entity);
} }
} }
@ -838,7 +839,7 @@ class UnitOfWork implements PropertyChangedListener
} }
if ( ! $class->isInheritanceTypeNone()) { if ( ! $class->isInheritanceTypeNone()) {
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
} }
$actualData = array(); $actualData = array();
@ -886,7 +887,7 @@ class UnitOfWork implements PropertyChangedListener
$hasListeners = $this->evm->hasListeners(Events::postPersist); $hasListeners = $this->evm->hasListeners(Events::postPersist);
foreach ($this->entityInsertions as $oid => $entity) { foreach ($this->entityInsertions as $oid => $entity) {
if (get_class($entity) !== $className) { if (ClassUtils::getClass($entity) !== $className) {
continue; continue;
} }
@ -945,7 +946,7 @@ class UnitOfWork implements PropertyChangedListener
$hasPostUpdateListeners = $this->evm->hasListeners(Events::postUpdate); $hasPostUpdateListeners = $this->evm->hasListeners(Events::postUpdate);
foreach ($this->entityUpdates as $oid => $entity) { foreach ($this->entityUpdates as $oid => $entity) {
if ( ! (get_class($entity) === $className || $entity instanceof Proxy && get_parent_class($entity) === $className)) { if (ClassUtils::getClass($entity) !== $className) {
continue; continue;
} }
@ -992,7 +993,7 @@ class UnitOfWork implements PropertyChangedListener
$hasListeners = $this->evm->hasListeners(Events::postRemove); $hasListeners = $this->evm->hasListeners(Events::postRemove);
foreach ($this->entityDeletions as $oid => $entity) { foreach ($this->entityDeletions as $oid => $entity) {
if ( ! (get_class($entity) == $className || $entity instanceof Proxy && get_parent_class($entity) == $className)) { if (ClassUtils::getClass($entity) !== $className) {
continue; continue;
} }
@ -1043,7 +1044,7 @@ class UnitOfWork implements PropertyChangedListener
$newNodes = array(); $newNodes = array();
foreach ($entityChangeSet as $entity) { foreach ($entityChangeSet as $entity) {
$className = get_class($entity); $className = ClassUtils::getClass($entity);
if ($calc->hasClass($className)) { if ($calc->hasClass($className)) {
continue; continue;
@ -1206,7 +1207,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
public function isScheduledForDirtyCheck($entity) public function isScheduledForDirtyCheck($entity)
{ {
$rootEntityName = $this->em->getClassMetadata(get_class($entity))->rootEntityName; $rootEntityName = $this->em->getClassMetadata(ClassUtils::getClass($entity))->rootEntityName;
return isset($this->scheduledForDirtyCheck[$rootEntityName][spl_object_hash($entity)]); return isset($this->scheduledForDirtyCheck[$rootEntityName][spl_object_hash($entity)]);
} }
@ -1287,7 +1288,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
public function addToIdentityMap($entity) public function addToIdentityMap($entity)
{ {
$classMetadata = $this->em->getClassMetadata(get_class($entity)); $classMetadata = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]); $idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]);
if ($idHash === '') { if ($idHash === '') {
@ -1335,7 +1336,7 @@ class UnitOfWork implements PropertyChangedListener
// Note that you can not remember the NEW or DETACHED state in _entityStates since // Note that you can not remember the NEW or DETACHED state in _entityStates since
// the UoW does not hold references to such objects and the object hash can be reused. // the UoW does not hold references to such objects and the object hash can be reused.
// More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it. // More generally because the state may "change" between NEW/DETACHED without the UoW being aware of it.
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$id = $class->getIdentifierValues($entity); $id = $class->getIdentifierValues($entity);
if ( ! $id) { if ( ! $id) {
@ -1357,7 +1358,7 @@ class UnitOfWork implements PropertyChangedListener
} }
// db lookup // db lookup
if ($this->getEntityPersister(get_class($entity))->exists($entity)) { if ($this->getEntityPersister($class->name)->exists($entity)) {
return self::STATE_DETACHED; return self::STATE_DETACHED;
} }
@ -1374,7 +1375,7 @@ class UnitOfWork implements PropertyChangedListener
} }
// db lookup // db lookup
if ($this->getEntityPersister(get_class($entity))->exists($entity)) { if ($this->getEntityPersister($class->name)->exists($entity)) {
return self::STATE_DETACHED; return self::STATE_DETACHED;
} }
@ -1465,7 +1466,7 @@ class UnitOfWork implements PropertyChangedListener
return false; return false;
} }
$classMetadata = $this->em->getClassMetadata(get_class($entity)); $classMetadata = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$idHash = implode(' ', $this->entityIdentifiers[$oid]); $idHash = implode(' ', $this->entityIdentifiers[$oid]);
if ($idHash === '') { if ($idHash === '') {
@ -1520,7 +1521,7 @@ class UnitOfWork implements PropertyChangedListener
$visited[$oid] = $entity; // Mark visited $visited[$oid] = $entity; // Mark visited
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
// We assume NEW, so DETACHED entities result in an exception on flush (constraint violation). // We assume NEW, so DETACHED entities result in an exception on flush (constraint violation).
// If we would detect DETACHED here we would throw an exception anyway with the same // If we would detect DETACHED here we would throw an exception anyway with the same
@ -1594,7 +1595,7 @@ class UnitOfWork implements PropertyChangedListener
// can cause problems when a lazy proxy has to be initialized for the cascade operation. // can cause problems when a lazy proxy has to be initialized for the cascade operation.
$this->cascadeRemove($entity, $visited); $this->cascadeRemove($entity, $visited);
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$entityState = $this->getEntityState($entity); $entityState = $this->getEntityState($entity);
switch ($entityState) { switch ($entityState) {
@ -1660,7 +1661,7 @@ class UnitOfWork implements PropertyChangedListener
$visited[$oid] = $entity; // mark visited $visited[$oid] = $entity; // mark visited
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
// First we assume DETACHED, although it can still be NEW but we can avoid // First we assume DETACHED, although it can still be NEW but we can avoid
// an extra db-roundtrip this way. If it is not MANAGED but has an identity, // an extra db-roundtrip this way. If it is not MANAGED but has an identity,
@ -1814,7 +1815,7 @@ class UnitOfWork implements PropertyChangedListener
if ($prevManagedCopy !== null) { if ($prevManagedCopy !== null) {
$assocField = $assoc['fieldName']; $assocField = $assoc['fieldName'];
$prevClass = $this->em->getClassMetadata(get_class($prevManagedCopy)); $prevClass = $this->em->getClassMetadata(ClassUtils::getClass($prevManagedCopy));
if ($assoc['type'] & ClassMetadata::TO_ONE) { if ($assoc['type'] & ClassMetadata::TO_ONE) {
$prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy); $prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy);
@ -1921,7 +1922,7 @@ class UnitOfWork implements PropertyChangedListener
$visited[$oid] = $entity; // mark visited $visited[$oid] = $entity; // mark visited
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
if ($this->getEntityState($entity) !== self::STATE_MANAGED) { if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
throw ORMInvalidArgumentException::entityNotManaged($entity); throw ORMInvalidArgumentException::entityNotManaged($entity);
@ -1943,7 +1944,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
private function cascadeRefresh($entity, array &$visited) private function cascadeRefresh($entity, array &$visited)
{ {
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$associationMappings = array_filter( $associationMappings = array_filter(
$class->associationMappings, $class->associationMappings,
@ -1984,7 +1985,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
private function cascadeDetach($entity, array &$visited) private function cascadeDetach($entity, array &$visited)
{ {
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$associationMappings = array_filter( $associationMappings = array_filter(
$class->associationMappings, $class->associationMappings,
@ -2026,7 +2027,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
private function cascadeMerge($entity, $managedCopy, array &$visited) private function cascadeMerge($entity, $managedCopy, array &$visited)
{ {
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$associationMappings = array_filter( $associationMappings = array_filter(
$class->associationMappings, $class->associationMappings,
@ -2064,7 +2065,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
private function cascadePersist($entity, array &$visited) private function cascadePersist($entity, array &$visited)
{ {
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$associationMappings = array_filter( $associationMappings = array_filter(
$class->associationMappings, $class->associationMappings,
@ -2105,7 +2106,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
private function cascadeRemove($entity, array &$visited) private function cascadeRemove($entity, array &$visited)
{ {
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$associationMappings = array_filter( $associationMappings = array_filter(
$class->associationMappings, $class->associationMappings,
@ -2151,13 +2152,12 @@ class UnitOfWork implements PropertyChangedListener
throw ORMInvalidArgumentException::entityNotManaged($entity); throw ORMInvalidArgumentException::entityNotManaged($entity);
} }
$entityName = get_class($entity); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$class = $this->em->getClassMetadata($entityName);
switch ($lockMode) { switch ($lockMode) {
case \Doctrine\DBAL\LockMode::OPTIMISTIC; case \Doctrine\DBAL\LockMode::OPTIMISTIC;
if ( ! $class->isVersioned) { if ( ! $class->isVersioned) {
throw OptimisticLockException::notVersioned($entityName); throw OptimisticLockException::notVersioned($class->name);
} }
if ($lockVersion === null) { if ($lockVersion === null) {
@ -2689,7 +2689,7 @@ class UnitOfWork implements PropertyChangedListener
*/ */
public function scheduleForDirtyCheck($entity) public function scheduleForDirtyCheck($entity)
{ {
$rootClassName = $this->em->getClassMetadata(get_class($entity))->rootEntityName; $rootClassName = $this->em->getClassMetadata(ClassUtils::getClass($entity))->rootEntityName;
$this->scheduledForDirtyCheck[$rootClassName][spl_object_hash($entity)] = $entity; $this->scheduledForDirtyCheck[$rootClassName][spl_object_hash($entity)] = $entity;
} }
@ -2827,7 +2827,7 @@ class UnitOfWork implements PropertyChangedListener
public function propertyChanged($entity, $propertyName, $oldValue, $newValue) public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
{ {
$oid = spl_object_hash($entity); $oid = spl_object_hash($entity);
$class = $this->em->getClassMetadata(get_class($entity)); $class = $this->em->getClassMetadata(ClassUtils::getClass($entity));
$isAssocField = isset($class->associationMappings[$propertyName]); $isAssocField = isset($class->associationMappings[$propertyName]);