diff --git a/src/Proxy/ProxyFactory.php b/src/Proxy/ProxyFactory.php index dc8a72bfcea..12023176106 100644 --- a/src/Proxy/ProxyFactory.php +++ b/src/Proxy/ProxyFactory.php @@ -447,7 +447,7 @@ private function getProxyFactory(string $className): Closure foreach ($reflector->getProperties($filter) as $property) { $name = $property->name; - if ($property->isStatic() || (($class->hasField($name) || $class->hasAssociation($name)) && ! isset($identifiers[$name]))) { + if ($property->isStatic() || ! isset($identifiers[$name])) { continue; } diff --git a/tests/Tests/Models/Product/Product.php b/tests/Tests/Models/Product/Product.php new file mode 100644 index 00000000000..d2db0d8928f --- /dev/null +++ b/tests/Tests/Models/Product/Product.php @@ -0,0 +1,62 @@ +name = $name; + } + + public function getId(): int + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function getImage(): ?string + { + return $this->image; + } + + public function setImage(string $image): void + { + $this->image = $image; + } +} diff --git a/tests/Tests/ORM/Functional/LifecycleCallbackTest.php b/tests/Tests/ORM/Functional/LifecycleCallbackTest.php index 2317363b114..14934298445 100644 --- a/tests/Tests/ORM/Functional/LifecycleCallbackTest.php +++ b/tests/Tests/ORM/Functional/LifecycleCallbackTest.php @@ -47,6 +47,8 @@ protected function setUp(): void { parent::setUp(); + LifecycleCallbackTestEntity::$staticPostLoadCallbackInvoked = false; + $this->createSchemaForModels( LifecycleCallbackEventArgEntity::class, LifecycleCallbackTestEntity::class, @@ -132,10 +134,10 @@ public function testGetReferenceWithPostLoadEventIsDelayedUntilProxyTrigger(): v $this->_em->clear(); $reference = $this->_em->getReference(LifecycleCallbackTestEntity::class, $id); - self::assertFalse($reference->postLoadCallbackInvoked); + self::assertFalse(LifecycleCallbackTestEntity::$staticPostLoadCallbackInvoked); $reference->getValue(); // trigger proxy load - self::assertTrue($reference->postLoadCallbackInvoked); + self::assertTrue(LifecycleCallbackTestEntity::$staticPostLoadCallbackInvoked); } /** @group DDC-958 */ @@ -494,6 +496,9 @@ class LifecycleCallbackTestEntity /** @var bool */ public $postLoadCallbackInvoked = false; + /** @var bool */ + public static $staticPostLoadCallbackInvoked = false; + /** @var bool */ public $postLoadCascaderNotNull = false; @@ -546,8 +551,9 @@ public function doStuffOnPostPersist(): void /** @PostLoad */ public function doStuffOnPostLoad(): void { - $this->postLoadCallbackInvoked = true; - $this->postLoadCascaderNotNull = isset($this->cascader); + $this->postLoadCallbackInvoked = true; + self::$staticPostLoadCallbackInvoked = true; + $this->postLoadCascaderNotNull = isset($this->cascader); } /** @PreUpdate */ diff --git a/tests/Tests/ORM/Proxy/ProxyFactoryTest.php b/tests/Tests/ORM/Proxy/ProxyFactoryTest.php index e6335c46c8f..ff70d2d38d4 100644 --- a/tests/Tests/ORM/Proxy/ProxyFactoryTest.php +++ b/tests/Tests/ORM/Proxy/ProxyFactoryTest.php @@ -18,6 +18,7 @@ use Doctrine\Tests\Models\Company\CompanyEmployee; use Doctrine\Tests\Models\Company\CompanyPerson; use Doctrine\Tests\Models\ECommerce\ECommerceFeature; +use Doctrine\Tests\Models\Product\Product; use Doctrine\Tests\OrmTestCase; use Doctrine\Tests\PHPUnitCompatibility\MockBuilderCompatibilityTools; use Exception; @@ -239,6 +240,41 @@ public function testProxyClonesParentFields(): void self::assertSame(1000, $cloned->getSalary(), 'Expect properties on the CompanyEmployee class to be cloned'); self::assertSame('Bob', $cloned->getName(), 'Expect properties on the CompanyPerson class to be cloned'); } + + public function testUnmanagedPropertyTriggerProxyLoad(): void + { + $product = new Product('someName'); + $product->setImage('someImage'); + $identifier = ['id' => 42]; + + $classMetaData = $this->emMock->getClassMetadata(Product::class); + + $persister = $this + ->getMockBuilder(BasicEntityPersister::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->uowMock->setEntityPersister(Product::class, $persister); + + $persister + ->expects(self::atLeastOnce()) + ->method('loadById') + ->with(self::equalTo($identifier)) + ->willReturn($product); + + $persister + ->expects(self::atLeastOnce()) + ->method('getClassMetadata') + ->willReturn($classMetaData); + + $proxy = $this->proxyFactory->getProxy(Product::class, $identifier); + + self::assertFalse($proxy->__isInitialized()); + $proxy->getId(); + self::assertFalse($proxy->__isInitialized()); + $proxy->getImage(); + self::assertTrue($proxy->__isInitialized()); + } } abstract class AbstractClass