diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 7a3b729e849..d191c3782ff 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1502,7 +1502,9 @@ - + diff --git a/src/Proxy/ProxyFactory.php b/src/Proxy/ProxyFactory.php index 5b2d2eca0c9..dc8a72bfcea 100644 --- a/src/Proxy/ProxyFactory.php +++ b/src/Proxy/ProxyFactory.php @@ -354,15 +354,14 @@ private function createInitializer(ClassMetadata $classMetadata, EntityPersister /** * Creates a closure capable of initializing a proxy * - * @return Closure(InternalProxy, InternalProxy):void + * @return Closure(InternalProxy, array):void * * @throws EntityNotFoundException */ private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister, IdentifierFlattener $identifierFlattener): Closure { - return static function (InternalProxy $proxy) use ($entityPersister, $classMetadata, $identifierFlattener): void { - $identifier = $classMetadata->getIdentifierValues($proxy); - $original = $entityPersister->loadById($identifier); + return static function (InternalProxy $proxy, array $identifier) use ($entityPersister, $classMetadata, $identifierFlattener): void { + $original = $entityPersister->loadById($identifier); if ($original === null) { throw EntityNotFoundException::fromClassNameAndIdentifier( @@ -378,7 +377,7 @@ private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersi $class = $entityPersister->getClassMetadata(); foreach ($class->getReflectionProperties() as $property) { - if (! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) { + if (isset($identifier[$property->name]) || ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) { continue; } @@ -468,7 +467,9 @@ private function getProxyFactory(string $className): Closure $identifierFields = array_intersect_key($class->getReflectionProperties(), $identifiers); $proxyFactory = Closure::bind(static function (array $identifier) use ($initializer, $skippedProperties, $identifierFields, $className): InternalProxy { - $proxy = self::createLazyGhost($initializer, $skippedProperties); + $proxy = self::createLazyGhost(static function (InternalProxy $object) use ($initializer, $identifier): void { + $initializer($object, $identifier); + }, $skippedProperties); foreach ($identifierFields as $idField => $reflector) { if (! isset($identifier[$idField])) { diff --git a/tests/Tests/Models/ECommerce/ECommerceProduct2.php b/tests/Tests/Models/ECommerce/ECommerceProduct2.php new file mode 100644 index 00000000000..4d676ddc5fc --- /dev/null +++ b/tests/Tests/Models/ECommerce/ECommerceProduct2.php @@ -0,0 +1,59 @@ +id; + } + + public function getName(): string + { + return $this->name; + } + + public function __clone() + { + $this->id = null; + $this->name = 'Clone of ' . $this->name; + } +} diff --git a/tests/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php b/tests/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php index 01f82c8de7d..1cd05c3fc5a 100644 --- a/tests/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php +++ b/tests/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php @@ -58,7 +58,7 @@ protected function setUp(): void public function testPersistUpdate(): void { // Considering case (a) - $proxy = $this->_em->getProxyFactory()->getProxy(CmsUser::class, ['id' => 123]); + $proxy = $this->_em->getProxyFactory()->getProxy(CmsUser::class, ['id' => $this->user->getId()]); $proxy->id = null; $proxy->username = 'ocra'; diff --git a/tests/Tests/ORM/Functional/ReferenceProxyTest.php b/tests/Tests/ORM/Functional/ReferenceProxyTest.php index 88c14253e20..bb4a2cfb36c 100644 --- a/tests/Tests/ORM/Functional/ReferenceProxyTest.php +++ b/tests/Tests/ORM/Functional/ReferenceProxyTest.php @@ -9,6 +9,7 @@ use Doctrine\ORM\Proxy\InternalProxy; use Doctrine\Tests\Models\Company\CompanyAuction; use Doctrine\Tests\Models\ECommerce\ECommerceProduct; +use Doctrine\Tests\Models\ECommerce\ECommerceProduct2; use Doctrine\Tests\Models\ECommerce\ECommerceShipping; use Doctrine\Tests\OrmFunctionalTestCase; @@ -112,6 +113,24 @@ public function testCloneProxy(): void self::assertFalse($entity->isCloned); } + public function testCloneProxyWithResetId(): void + { + $id = $this->createProduct(); + + $entity = $this->_em->getReference(ECommerceProduct2::class, $id); + assert($entity instanceof ECommerceProduct2); + + $clone = clone $entity; + assert($clone instanceof ECommerceProduct2); + + self::assertEquals($id, $entity->getId()); + self::assertEquals('Doctrine Cookbook', $entity->getName()); + + self::assertFalse($this->_em->contains($clone)); + self::assertNull($clone->getId()); + self::assertEquals('Clone of Doctrine Cookbook', $clone->getName()); + } + /** @group DDC-733 */ public function testInitializeProxy(): void {