From 0a3d6966d6ff3216bc76948a04956b1f536efd23 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Tue, 20 Jan 2015 14:21:51 +0100 Subject: [PATCH] DDC-2704 - providing hotfix - also storing inherited transient properties in the class metadata --- .../ORM/Mapping/ClassMetadataInfo.php | 76 ++++++++++++++++++- lib/Doctrine/ORM/UnitOfWork.php | 2 +- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index c3c8d8c83..0968aa631 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Mapping; use BadMethodCallException; +use Doctrine\Common\Persistence\Mapping\ReflectionService; use Doctrine\Instantiator\Instantiator; use InvalidArgumentException; use RuntimeException; @@ -649,6 +650,12 @@ class ClassMetadataInfo implements ClassMetadata */ private $instantiator; + /** + * @var \ReflectionProperty[]|null (null if not yet initialized) - all instance properties of the class, + * transient or not, in accessible form. + */ + private $reflectionProperties; + /** * Initializes a new ClassMetadata instance that will hold the object-relational mapping * metadata of the class with the given name. @@ -667,13 +674,30 @@ class ClassMetadataInfo implements ClassMetadata /** * Gets the ReflectionProperties of the mapped class. * - * @return array An array of ReflectionProperty instances. + * @return \ReflectionProperty[] An array of ReflectionProperty instances. */ public function getReflectionProperties() { return $this->reflFields; } + /** + * Retrieves all ReflectionProperties of this class, considering inherited and transient ones + * + * Note that this method should only be used after `wakeupReflection` + */ + public function getAllReflectionProperties() + { + if (null === $this->reflectionProperties) { + throw new \RuntimeException(sprintf( + 'You cannot read the reflection properties before calling %s#wakeupReflection() first', + get_class($this) + )); + } + + return $this->reflectionProperties; + } + /** * Gets a ReflectionProperty for a specific field of the mapped class. * @@ -963,6 +987,8 @@ class ClassMetadataInfo implements ClassMetadata ? $reflService->getAccessibleProperty($mapping['declared'], $field) : $reflService->getAccessibleProperty($this->name, $field); } + + $this->initializeAllReflectionProperties($reflService); } /** @@ -3313,4 +3339,52 @@ class ClassMetadataInfo implements ClassMetadata return $sequencePrefix; } + + /** + * Initializes the internal `reflectionProperties` property + * + * @param ReflectionService $reflectionService + */ + private function initializeAllReflectionProperties(ReflectionService $reflectionService) + { + $class = $this->reflClass; + $properties = array(); + + do { + $className = $class->getName(); + + foreach ($class->getProperties() as $property) { + // static properties are not instance properties + if ($property->isStatic()) { + continue; + } + + // indexing by logical name to avoid duplicates + $logicalName = $property->getDeclaringClass()->getName() . $property->getName(); + $propertyName = $property->getName(); + $existingField = isset($this->reflFields[$propertyName]) ? $this->reflFields[$propertyName] : null; + + if (! $existingField) { + $properties[$logicalName] = $reflectionService->getAccessibleProperty($className, $propertyName); + + continue; + } + + // private properties are not inherited: need to handle them separately and precisely + if ($property->isPrivate() + && $existingField->getDeclaringClass()->getName() !== $property->getDeclaringClass()->getName() + ) { + $properties[$logicalName] = $reflectionService->getAccessibleProperty($className, $propertyName); + + continue; + } + + $properties[$logicalName] = $existingField; + } + + $parentClass = $class->getParentClass(); + } while ($parentClass && $class = $reflectionService->getClass($parentClass->getName())); + + $this->reflectionProperties = array_values($properties); + } } diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index cd7c718d6..6e1d5428b 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -3348,7 +3348,7 @@ class UnitOfWork implements PropertyChangedListener { $class = $this->em->getClassMetadata(get_class($entity)); - foreach ($class->reflClass->getProperties() as $prop) { + foreach ($class->getAllReflectionProperties() as $prop) { $name = $prop->name; $prop->setAccessible(true);