public function testManyToOneAssociation() { $association1 = new TestAssociation1(); $association1->setField1('a'); $association2 = new TestAssociation1(); $association2->setField1('b'); $collection = new ArrayCollection(array($association1, $association2)); $this->dataObject1->setAssociation2($collection); $emMock = Mockery::mock('Doctrine\\ORM\\EntityManagerInterface'); $classMetaDataMock = Mockery::mock('Doctrine\\ORM\\Mapping\\ClassMetadata'); $emMock->shouldReceive('getClassMetadata')->andReturn($classMetaDataMock); $classMetaDataMock->shouldReceive('getAssociationNames')->andReturn(array('association1', 'association2')); $sut = new ProxyManager($emMock); $proxy = $sut->transform($this->dataObject1); $this->assertTrue($proxy->getAssociation2() instanceof ArrayCollection); $this->assertEquals(2, count($proxy->getAssociation2())); $item1 = $proxy->getAssociation2()[0]; $item2 = $proxy->getAssociation2()[1]; $this->assertTrue($item1 instanceof TestAssociationProxy1); $this->assertEquals('a', $item1->getField1()); $this->assertTrue($item2 instanceof TestAssociationProxy1); $this->assertEquals('b', $item2->getField1()); }
/** * Transform Entity to proxy object * * @param $objSrc * @return mixed * @throws \Exception */ public function transform($objSrc) { // No need to transform scalar or null values if (is_scalar($objSrc) || is_null($objSrc)) { return $objSrc; } $objSrcData = $this->hydrator->extract($objSrc); $objSrcClass = $this->annotationReader->getDoctrineProxyResolver()->unwrapDoctrineProxyClass(get_class($objSrc)); $proxyClass = $this->annotationReader->getProxyTargetClass(get_class($objSrc)); if (!$proxyClass) { return $objSrc; } if ($proxyClass != $objSrcClass) { $doctrineAnnotations = $this->annotationReader->getDoctrineAnnotations($this->class); $associations = $doctrineAnnotations->getAssociationNames(); /** * Lazy Load Associations */ foreach ($associations as $key) { if (isset($objSrcData[$key])) { $propertyValue = $objSrcData[$key]; $factory = new LazyLoadingValueHolderFactory(); $initializer = function (&$wrappedObject, LazyLoadingInterface $proxy, $method, array $parameters, &$initializer) use($propertyValue) { $initializer = null; if ($propertyValue instanceof ArrayCollection) { $items = array(); foreach ($propertyValue as $item) { $items[] = $this->proxyManager->transform($item); } $wrappedObject = new ArrayCollection($items); } else { $wrappedObject = $this->proxyManager->transform($propertyValue); } return true; }; // check if property final $reflectionClass = new \ReflectionClass(get_class($propertyValue)); if ($reflectionClass->isFinal()) { $objSrcData[$key] = $propertyValue; } else { if ($propertyValue instanceof Collection) { $objSrcData[$key] = $factory->createProxy(get_class($propertyValue), $initializer); } else { $objSrcData[$key] = $factory->createProxy($this->annotationReader->getProxyTargetClass(get_class($propertyValue)), $initializer); } } } } $objDest = $this->proxyManager->instantiate($proxyClass); /** * Throw Exceptions */ if (!$objDest instanceof $objSrcClass) { throw new \Exception('The proxy target class should extend the underlying data object. Proxy Class: ' . $proxyClass); } if (!$this->isProxy($objDest)) { throw new \Exception('The proxy target class should use the Proxy trait. Proxy Class: ' . $proxyClass); } /** * Hydrate the data */ $this->hydrate($objSrcData, $objDest); /** * Sync Properties */ $syncProperties = $this->annotationReader->getProxySyncedProperties($this->class); if ($syncProperties == Constants::SYNC_PROPERTIES_ALL) { $syncProperties = array_keys($objSrcData); } /** * Sync Methods */ $syncMethods = $this->annotationReader->getProxySyncMethods($this->class); if ($syncMethods == Constants::SYNC_METHODS_ALL) { $syncMethods = array(); foreach (array_keys($objSrcData) as $property) { $syncMethods[] = Inflector::camelize('set_' . $property); } foreach ($associations as $associationKey => $association) { $associationKey = Inflector::singularize($associationKey); $associationKeyPlural = Inflector::pluralize($associationKey); $syncMethods[] = Inflector::camelize('add_' . $associationKey); $syncMethods[] = Inflector::camelize('remove_' . $associationKey); $syncMethods[] = Inflector::camelize('set_' . $associationKeyPlural); $syncMethods[] = Inflector::camelize('set_' . $associationKey); } } elseif ($syncMethods == Constants::SYNC_METHODS_NONE) { $syncMethods = array(); } /** * Set properties on proxied object */ PropertyAccess::set($objDest, 'dataObject', $objSrc); PropertyAccess::set($objDest, 'transformer', $this); PropertyAccess::set($objDest, 'syncProperties', $syncProperties); PropertyAccess::set($objDest, 'syncMethods', $syncMethods); /** * Attach Interceptors */ $factory = new Factory(); $proxy = $factory->createProxy($objDest, array()); foreach ($syncMethods as $syncMethod) { $proxy->setMethodSuffixInterceptor($syncMethod, function ($proxy, $instance) use($syncMethod) { $syncMethods = PropertyAccess::get($instance, 'syncMethods'); if (is_array($syncMethods) && in_array($syncMethod, $syncMethods)) { $instance->syncData(); } }); } return $proxy; } return $objSrc; }