Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b6d9ce6

Browse files
Fix cloning entities when using lazy-ghost proxies
1 parent 0b9060c commit b6d9ce6

2 files changed

Lines changed: 34 additions & 39 deletions

File tree

lib/Doctrine/ORM/Proxy/ProxyFactory.php

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,12 @@ class <proxyShortClassName> extends \<className> implements \<baseProxyInterface
4848
{
4949
<useLazyGhostTrait>
5050
51-
/**
52-
* @internal
53-
*/
54-
public bool $__isCloning = false;
55-
56-
public function __construct(?\Closure $initializer = null)
51+
public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null)
5752
{
53+
if ($cloner !== null) {
54+
return;
55+
}
56+
5857
self::createLazyGhost($initializer, <skippedProperties>, $this);
5958
}
6059
@@ -63,17 +62,6 @@ public function __isInitialized(): bool
6362
return isset($this->lazyObjectState) && $this->isLazyObjectInitialized();
6463
}
6564
66-
public function __clone()
67-
{
68-
$this->__isCloning = true;
69-
70-
try {
71-
$this->__doClone();
72-
} finally {
73-
$this->__isCloning = false;
74-
}
75-
}
76-
7765
public function __serialize(): array
7866
{
7967
<serializeImpl>
@@ -98,6 +86,9 @@ public function __serialize(): array
9886
*/
9987
private $identifierFlattener;
10088

89+
/** @var ProxyDefinition[] */
90+
private $definitions = [];
91+
10192
/**
10293
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
10394
* connected to the given <tt>EntityManager</tt>.
@@ -131,6 +122,21 @@ public function __construct(EntityManagerInterface $em, $proxyDir, $proxyNs, $au
131122
$this->identifierFlattener = new IdentifierFlattener($this->uow, $em->getMetadataFactory());
132123
}
133124

125+
/**
126+
* {@inheritDoc}
127+
*/
128+
public function getProxy($className, array $identifier)
129+
{
130+
$proxy = parent::getProxy($className, $identifier);
131+
$initializer = $this->definitions[$className]->initializer;
132+
133+
$proxy->__construct(static function (Proxy $object) use ($initializer, $proxy): void {
134+
$initializer($object, $proxy);
135+
});
136+
137+
return $proxy;
138+
}
139+
134140
/**
135141
* {@inheritDoc}
136142
*/
@@ -158,7 +164,7 @@ protected function createProxyDefinition($className)
158164
$cloner = $this->createCloner($classMetadata, $entityPersister);
159165
}
160166

161-
return new ProxyDefinition(
167+
return $this->definitions[$className] = new ProxyDefinition(
162168
ClassUtils::generateProxyClassName($className, $this->proxyNs),
163169
$classMetadata->getIdentifierFieldNames(),
164170
$classMetadata->getReflectionProperties(),
@@ -237,9 +243,9 @@ private function createInitializer(ClassMetadata $classMetadata, EntityPersister
237243
*/
238244
private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister): Closure
239245
{
240-
return function (Proxy $proxy) use ($entityPersister, $classMetadata): void {
241-
$identifier = $classMetadata->getIdentifierValues($proxy);
242-
$entity = $entityPersister->loadById($identifier, $proxy->__isCloning ? null : $proxy);
246+
return function (Proxy $proxy, Proxy $original) use ($entityPersister, $classMetadata): void {
247+
$identifier = $classMetadata->getIdentifierValues($original);
248+
$entity = $entityPersister->loadById($identifier, $original);
243249

244250
if ($entity === null) {
245251
throw EntityNotFoundException::fromClassNameAndIdentifier(
@@ -248,7 +254,7 @@ private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersi
248254
);
249255
}
250256

251-
if (! $proxy->__isCloning) {
257+
if ($proxy === $original) {
252258
return;
253259
}
254260

@@ -315,15 +321,14 @@ private function generateUseLazyGhostTrait(ClassMetadata $class): string
315321
isLazyObjectInitialized as private;
316322
createLazyGhost as private;
317323
resetLazyObject as private;
318-
__clone as private __doClone;
319324
}'), $code);
320325

321326
return $code;
322327
}
323328

324329
private function generateSkippedProperties(ClassMetadata $class): string
325330
{
326-
$skippedProperties = ['__isCloning' => true];
331+
$skippedProperties = [];
327332
$identifiers = array_flip($class->getIdentifierFieldNames());
328333
$filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE;
329334
$reflector = $class->getReflectionClass();

tests/Doctrine/Tests/ORM/Proxy/ProxyFactoryTest.php

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Doctrine\Tests\ORM\Proxy;
66

77
use Doctrine\Common\EventManager;
8-
use Doctrine\Common\Proxy\Proxy as CommonProxy;
98
use Doctrine\DBAL\Connection;
109
use Doctrine\DBAL\Platforms\AbstractPlatform;
1110
use Doctrine\ORM\EntityNotFoundException;
@@ -227,21 +226,12 @@ public function testProxyClonesParentFields(): void
227226
->expects(self::atLeastOnce())
228227
->method('loadById');
229228

230-
if ($proxy instanceof CommonProxy) {
231-
$loadByIdMock->willReturn($companyEmployee);
229+
$loadByIdMock->willReturn($companyEmployee);
232230

233-
$persister
234-
->expects(self::atLeastOnce())
235-
->method('getClassMetadata')
236-
->willReturn($classMetaData);
237-
} else {
238-
$loadByIdMock->willReturnCallback(static function (array $id, CompanyEmployee $companyEmployee) {
239-
$companyEmployee->setSalary(1000); // A property on the CompanyEmployee
240-
$companyEmployee->setName('Bob'); // A property on the parent class, CompanyPerson
241-
242-
return $companyEmployee;
243-
});
244-
}
231+
$persister
232+
->expects(self::atLeastOnce())
233+
->method('getClassMetadata')
234+
->willReturn($classMetaData);
245235

246236
$cloned = clone $proxy;
247237
assert($cloned instanceof CompanyEmployee);

0 commit comments

Comments
 (0)