Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[DDC-93] Implement first working version of value objects using a Ref…

…lectionProxy object, bypassing changes to UnitOfWork, Persisters and Hydrators.
  • Loading branch information...
commit 0204a8b69a33883c83a26be108b528fac320c729 1 parent 32988b3
@beberlei beberlei authored
View
5 lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
@@ -136,6 +136,11 @@ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonS
$this->completeIdGeneratorMapping($class);
}
+ foreach ($class->embeddedClasses as $property => $embeddableClass) {
+ $embeddableMetadata = $this->getMetadataFor($embeddableClass);
+ $class->inlineEmbeddable($property, $embeddableMetadata);
+ }
+
if ($parent && $parent->isInheritanceTypeSingleTable()) {
$class->setPrimaryTable($parent->table);
}
View
70 lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
@@ -268,6 +268,13 @@ class ClassMetadataInfo implements ClassMetadata
public $subClasses = array();
/**
+ * READ-ONLY: The names of all embedded classes based on properties.
+ *
+ * @var array
+ */
+ public $embeddedClasses = array();
+
+ /**
* READ-ONLY: The named queries allowed to be called directly from Repository.
*
* @var array
@@ -887,6 +894,15 @@ public function wakeupReflection($reflService)
$this->reflClass = $reflService->getClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
+ if (isset($mapping['declaredField'])) {
+ $this->reflFields[$field] = new ReflectionProxy(
+ $reflService->getAccessibleProperty($this->name, $mapping['declaredField']),
+ $reflService->getAccessibleProperty($this->embeddedClasses[$mapping['declaredField']], $mapping['originalField']),
+ $this->embeddedClasses[$mapping['declaredField']]
+ );
+ continue;
+ }
+
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
@@ -2166,9 +2182,8 @@ private function _isInheritanceType($type)
public function mapField(array $mapping)
{
$this->_validateAndCompleteFieldMapping($mapping);
- if (isset($this->fieldMappings[$mapping['fieldName']]) || isset($this->associationMappings[$mapping['fieldName']])) {
- throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
- }
+ $this->assertFieldNotMapped($mapping['fieldName']);
+
$this->fieldMappings[$mapping['fieldName']] = $mapping;
}
@@ -2416,9 +2431,7 @@ protected function _storeAssociationMapping(array $assocMapping)
{
$sourceFieldName = $assocMapping['fieldName'];
- if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
- throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
- }
+ $this->assertFieldNotMapped($sourceFieldName);
$this->associationMappings[$sourceFieldName] = $assocMapping;
}
@@ -3030,4 +3043,49 @@ public function fullyQualifiedClassName($className)
return $className;
}
+
+ /**
+ * Map Embedded Class
+ *
+ * @array $mapping
+ * @return void
+ */
+ public function mapEmbedded(array $mapping)
+ {
+ $this->assertFieldNotMapped($mapping['fieldName']);
+
+ $this->embeddedClasses[$mapping['fieldName']] = $this->fullyQualifiedClassName($mapping['class']);
+ }
+
+ /**
+ * Inline the embeddable class
+ *
+ * @param string $property
+ * @param ClassMetadataInfo $embeddable
+ */
+ public function inlineEmbeddable($property, ClassMetadataInfo $embeddable)
+ {
+ foreach ($embeddable->fieldMappings as $fieldMapping) {
+ $fieldMapping['declaredField'] = $property;
+ $fieldMapping['originalField'] = $fieldMapping['fieldName'];
+ $fieldMapping['fieldName'] = $property . $fieldMapping['fieldName'];
+ $fieldMapping['columnName'] = $property . "_" . $fieldMapping['columnName'];
+
+ $this->mapField($fieldMapping);
+ }
+ }
+
+ /**
+ * @param string $fieldName
+ * @throws MappingException
+ */
+ private function assertFieldNotMapped($fieldName)
+ {
+ if (isset($this->fieldMappings[$fieldName]) ||
+ isset($this->associationMappings[$fieldName]) ||
+ isset($this->embeddedClasses[$fieldName])) {
+
+ throw MappingException::duplicateFieldMapping($this->name, $fieldName);
+ }
+ }
}
View
3  lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
@@ -366,6 +366,9 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
}
$metadata->mapManyToMany($mapping);
+ } else if ($embeddedAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Embedded')) {
+ $mapping['class'] = $embeddedAnnot->class;
+ $metadata->mapEmbedded($mapping);
}
}
View
64 lib/Doctrine/ORM/Mapping/ReflectionProxy.php
@@ -0,0 +1,64 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\ORM\Mapping;
+
+/**
+ * Acts as a proxy to a nested Property structure, making it look like
+ * just a single scalar property.
+ *
+ * This way value objects "just work" without UnitOfWork, Persisters or Hydrators
+ * needing any changes.
+ */
+class ReflectionProxy
+{
+ private $parentProperty;
+ private $childProperty;
+ private $class;
+
+ public function __construct($parentProperty, $childProperty, $class)
+ {
+ $this->parentProperty = $parentProperty;
+ $this->childProperty = $childProperty;
+ $this->class = $class;
+ }
+
+ public function getValue($object)
+ {
+ $embeddedObject = $this->parentProperty->getValue($object);
+
+ if ($embeddedObject === null) {
+ return null;
+ }
+
+ return $this->childProperty->getValue($embeddedObject);
+ }
+
+ public function setValue($object, $value)
+ {
+ $embeddedObject = $this->parentProperty->getValue($object);
+
+ if ($embeddedObject === null) {
+ $embeddedObject = new $this->class; // TODO
+ $this->parentProperty->setValue($object, $embeddedObject);
+ }
+
+ $this->childProperty->setValue($embeddedObject, $value);
+ }
+}
View
4 tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php
@@ -32,7 +32,11 @@ public function testMetadata()
$this->_em->clear();
$person = $this->_em->find(DDC93Person::CLASSNAME, $person->id);
+
$this->assertInstanceOf(DDC93Address::CLASSNAME, $person->address);
+ $this->assertEquals('United States of Tara Street', $person->address->street);
+ $this->assertEquals('12345', $person->address->zip);
+ $this->assertEquals('funkytown', $person->address->city);
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.