Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ObjectManager::isUninitializedObject #2569

Merged
merged 1 commit into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/Doctrine/ODM/MongoDB/DocumentManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ public function initializeObject($obj)
$this->unitOfWork->initializeObject($obj);
}

/**
* Helper method to check whether a lazy loading proxy or persistent collection has been initialized.
*/
public function isUninitializedObject(object $obj): bool
{
return $this->unitOfWork->isUninitializedObject($obj);
}

/**
* Gets the UnitOfWork used by the DocumentManager to coordinate operations.
*/
Expand Down
5 changes: 2 additions & 3 deletions lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
use MongoDB\Driver\Exception\WriteException;
use MongoDB\Driver\WriteConcern;
use MongoDB\GridFS\Bucket;
use ProxyManager\Proxy\GhostObjectInterface;
use stdClass;

use function array_combine;
Expand Down Expand Up @@ -749,7 +748,7 @@ private function loadReferenceManyCollectionOwningSide(PersistentCollectionInter
}

// only query for the referenced object if it is not already initialized or the collection is sorted
if (! (($reference instanceof GhostObjectInterface && ! $reference->isProxyInitialized())) && ! $sorted) {
if (! $this->uow->isUninitializedObject($reference) && ! $sorted) {
continue;
}

Expand Down Expand Up @@ -787,7 +786,7 @@ private function loadReferenceManyCollectionOwningSide(PersistentCollectionInter
$documents = $cursor->toArray();
foreach ($documents as $documentData) {
$document = $this->uow->getById($documentData['_id'], $class);
if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) {
if ($this->uow->isUninitializedObject($document)) {
$data = $this->hydratorFactory->hydrate($document, $documentData);
$this->uow->setOriginalDocumentData($document, $data);
}
Expand Down
5 changes: 2 additions & 3 deletions lib/Doctrine/ODM/MongoDB/Query/ReferencePrimer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Doctrine\ODM\MongoDB\UnitOfWork;
use InvalidArgumentException;
use LogicException;
use ProxyManager\Proxy\GhostObjectInterface;
use Traversable;

use function array_push;
Expand Down Expand Up @@ -138,7 +137,7 @@ public function primeReferences(ClassMetadata $class, $documents, string $fieldN
continue;
}

if ($mapping['type'] === ClassMetadata::ONE && $fieldValue instanceof GhostObjectInterface && ! $fieldValue->isProxyInitialized()) {
if ($mapping['type'] === ClassMetadata::ONE && $this->uow->isUninitializedObject($fieldValue)) {
$refClass = $this->dm->getClassMetadata($fieldValue::class);
$id = $this->uow->getDocumentIdentifier($fieldValue);
$groupedIds[$refClass->name][serialize($id)] = $id;
Expand Down Expand Up @@ -269,7 +268,7 @@ private function addManyReferences(PersistentCollectionInterface $persistentColl

$document = $this->uow->tryGetById($id, $class);

if ($document && ! (($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()))) {
if ($document && ! $this->uow->isUninitializedObject($document)) {
continue;
}

Expand Down
46 changes: 26 additions & 20 deletions lib/Doctrine/ODM/MongoDB/UnitOfWork.php
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,7 @@ public function computeChangeSets(): void

foreach ($documentsToProcess as $document) {
// Ignore uninitialized proxy objects
if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) {
if ($this->isUninitializedObject($document)) {
continue;
}

Expand Down Expand Up @@ -1061,7 +1061,7 @@ private function computeAssociationChanges(object $parentDocument, array $assoc,
public function recomputeSingleDocumentChangeSet(ClassMetadata $class, object $document): void
{
// Ignore uninitialized proxy objects
if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) {
if ($this->isUninitializedObject($document)) {
return;
}

Expand Down Expand Up @@ -1489,10 +1489,7 @@ public function addToIdentityMap(object $document): bool

$this->identityMap[$class->name][$id] = $document;

if (
$document instanceof NotifyPropertyChanged &&
( ! $document instanceof GhostObjectInterface || $document->isProxyInitialized())
) {
if ($document instanceof NotifyPropertyChanged && ! $this->isUninitializedObject($document)) {
$document->addPropertyChangedListener($this);
}

Expand Down Expand Up @@ -1881,8 +1878,8 @@ private function doMerge(object $document, array &$visited, ?object $prevManaged
$managedCopy = $document;

if ($this->getDocumentState($document, self::STATE_DETACHED) !== self::STATE_MANAGED) {
if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) {
$document->initializeProxy();
if ($this->isUninitializedObject($document)) {
$this->initializeObject($document);
}

$identifier = $class->getIdentifier();
Expand All @@ -1899,8 +1896,8 @@ private function doMerge(object $document, array &$visited, ?object $prevManaged
throw new InvalidArgumentException('Removed entity detected during merge. Cannot merge with a removed entity.');
}

if ($managedCopy instanceof GhostObjectInterface && ! $managedCopy->isProxyInitialized()) {
$managedCopy->initializeProxy();
if ($managedCopy && $this->isUninitializedObject($managedCopy)) {
$this->initializeObject($managedCopy);
}
}

Expand Down Expand Up @@ -1946,7 +1943,7 @@ private function doMerge(object $document, array &$visited, ?object $prevManaged

if ($other === null) {
$prop->setValue($managedCopy, null);
} elseif ($other instanceof GhostObjectInterface && ! $other->isProxyInitialized()) {
} elseif ($this->isUninitializedObject($other)) {
// Do not merge fields marked lazy that have not been fetched
continue;
} elseif (! $assoc2['isCascadeMerge']) {
Expand Down Expand Up @@ -2305,9 +2302,7 @@ private function cascadeRemove(object $document, array &$visited): void
continue;
}

if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) {
$document->initializeProxy();
}
$this->initializeObject($document);

$relatedDocuments = $class->reflFields[$mapping['fieldName']]->getValue($document);
if ($relatedDocuments instanceof Collection || is_array($relatedDocuments)) {
Expand Down Expand Up @@ -2459,10 +2454,7 @@ private function fixPersistentCollectionOwnership(PersistentCollectionInterface
if ($owner === null) { // cloned
$coll->setOwner($document, $class->fieldMappings[$propName]);
} elseif ($owner !== $document) { // no clone, we have to fix
if (! $coll->isInitialized()) {
$coll->initialize(); // we have to do this otherwise the cols share state
}

$this->initializeObject($coll); // we have to do this otherwise the cols share state
$newValue = clone $coll;
$newValue->setOwner($document, $class->fieldMappings[$propName]);
$class->reflFields[$propName]->setValue($document, $newValue);
Expand Down Expand Up @@ -2807,7 +2799,7 @@ public function getOrCreateDocument(string $className, array $data, array &$hint
/** @psalm-var T $document */
$document = $this->identityMap[$class->name][$serializedId];
$oid = spl_object_hash($document);
if ($document instanceof GhostObjectInterface && ! $document->isProxyInitialized()) {
if ($this->isUninitializedObject($document)) {
$document->setProxyInitializer(null);
$overrideLocalValues = true;
if ($document instanceof NotifyPropertyChanged) {
Expand Down Expand Up @@ -3088,13 +3080,27 @@ public function getScheduledCollectionUpdates(): array
*/
public function initializeObject(object $obj): void
{
if ($obj instanceof GhostObjectInterface) {
if ($obj instanceof GhostObjectInterface && $obj->isProxyInitialized() === false) {
$obj->initializeProxy();
} elseif ($obj instanceof PersistentCollectionInterface) {
$obj->initialize();
}
}

/**
* Helper method to check whether a lazy loading proxy or persistent collection has been initialized.
*
* @internal
*/
public function isUninitializedObject(object $obj): bool
{
return match (true) {
$obj instanceof GhostObjectInterface => $obj->isProxyInitialized() === false,
$obj instanceof PersistentCollectionInterface => $obj->isInitialized() === false,
default => false
};
}

private function objToStr(object $obj): string
{
return method_exists($obj, '__toString') ? (string) $obj : $obj::class . '@' . spl_object_hash($obj);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function testGetIdentifierValue(): void
$userTest = $test->getUser();
self::assertEquals($user->getId(), $userTest->getId());
self::assertInstanceOf(LazyLoadingInterface::class, $userTest);
self::assertFalse($userTest->isProxyInitialized());
self::assertTrue($this->uow->isUninitializedObject($userTest));

$this->dm->clear();

Expand All @@ -43,10 +43,10 @@ public function testGetIdentifierValue(): void
self::assertEquals($user->getId(), $class->getIdentifierValue($user));
self::assertEquals($user->getId(), $class->getFieldValue($foundUser, 'id'));
self::assertInstanceOf(LazyLoadingInterface::class, $foundUser);
self::assertFalse($foundUser->isProxyInitialized());
self::assertTrue($this->uow->isUninitializedObject($foundUser));

self::assertEquals('jwage', $foundUser->getUsername());
self::assertTrue($foundUser->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($foundUser));
}

public function testIdentifiersAreSet(): void
Expand Down
20 changes: 10 additions & 10 deletions tests/Doctrine/ODM/MongoDB/Tests/Functional/ReferencePrimerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function testPrimeReferencesWithDBRefObjects(): void

foreach ($qb->getQuery() as $user) {
self::assertInstanceOf(GhostObjectInterface::class, $user->getAccount());
self::assertTrue($user->getAccount()->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($user->getAccount()));

self::assertCount(2, $user->getGroups());

Expand Down Expand Up @@ -134,7 +134,7 @@ public function testPrimeReferencesWithSimpleReferences(): void

foreach ($qb->getQuery() as $simpleUser) {
self::assertInstanceOf(GhostObjectInterface::class, $simpleUser->getUser());
self::assertTrue($simpleUser->getUser()->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($simpleUser->getUser()));

self::assertCount(2, $simpleUser->getUsers());

Expand Down Expand Up @@ -197,7 +197,7 @@ public function testPrimeReferencesNestedInNamedEmbeddedReference(): void
self::assertInstanceOf(EmbeddedWhichReferences::class, $embeddedDoc);

self::assertInstanceOf(GhostObjectInterface::class, $embeddedDoc->referencedDoc);
self::assertTrue($embeddedDoc->referencedDoc->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($embeddedDoc->referencedDoc));

self::assertCount(2, $embeddedDoc->referencedDocs);
foreach ($embeddedDoc->referencedDocs as $referencedDoc) {
Expand Down Expand Up @@ -253,7 +253,7 @@ public function testPrimeReferencesWithDifferentStoreAsReferences(): void
$user = $referenceUser->getUser();
self::assertInstanceOf(User::class, $user);
self::assertInstanceOf(GhostObjectInterface::class, $user);
self::assertTrue($user->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($user));

self::assertCount(1, $referenceUser->getUsers());

Expand All @@ -265,7 +265,7 @@ public function testPrimeReferencesWithDifferentStoreAsReferences(): void
$parentUser = $referenceUser->getParentUser();
self::assertInstanceOf(GhostObjectInterface::class, $parentUser);
self::assertInstanceOf(User::class, $parentUser);
self::assertTrue($parentUser->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($parentUser));

self::assertCount(1, $referenceUser->getParentUsers());

Expand All @@ -277,7 +277,7 @@ public function testPrimeReferencesWithDifferentStoreAsReferences(): void
$otherUser = $referenceUser->getOtherUser();
self::assertInstanceOf(User::class, $otherUser);
self::assertInstanceOf(GhostObjectInterface::class, $otherUser);
self::assertTrue($otherUser->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($otherUser));

self::assertCount(1, $referenceUser->getOtherUsers());

Expand Down Expand Up @@ -332,7 +332,7 @@ public function testPrimeReferencesWithDiscriminatedReferenceOne(): void

foreach ($qb->getQuery() as $agent) {
self::assertInstanceOf(GhostObjectInterface::class, $agent->server);
self::assertTrue($agent->server->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($agent->server));
}
}

Expand Down Expand Up @@ -523,7 +523,7 @@ public function testPrimeEmbeddedReferenceTwoLevelsDeep(): void

self::assertInstanceOf(GhostObjectInterface::class, $currency);
self::assertInstanceOf(Currency::class, $currency);
self::assertTrue($currency->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($currency));
}

public function testPrimeReferencesInReferenceMany(): void
Expand All @@ -550,7 +550,7 @@ public function testPrimeReferencesInReferenceMany(): void

$comment = $post->comments->first();
self::assertInstanceOf(GhostObjectInterface::class, $comment->author);
self::assertTrue($comment->author->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($comment->author));
}

public function testPrimeReferencesInReferenceManyWithRepositoryMethodEager(): void
Expand All @@ -577,6 +577,6 @@ public function testPrimeReferencesInReferenceManyWithRepositoryMethodEager(): v

$comment = $post->repoCommentsWithPrimer->first();
self::assertInstanceOf(GhostObjectInterface::class, $comment->author);
self::assertTrue($comment->author->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($comment->author));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public function testLazyLoadedWithNotifyPropertyChanged(): void
$user = $this->dm->find($user::class, $user->getId());
$profile = $user->getProfileNotify();
self::assertInstanceOf(GhostObjectInterface::class, $profile);
self::assertFalse($profile->isProxyInitialized());
self::assertTrue($this->uow->isUninitializedObject($profile));

$user->getProfileNotify()->setLastName('Malarz');
$this->dm->flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ public function testProxy(): void
self::assertNotNull($user);
self::assertInstanceOf(User::class, $user);
self::assertInstanceOf(GhostObjectInterface::class, $user);
self::assertFalse($user->isProxyInitialized());
self::assertTrue($this->uow->isUninitializedObject($user));
self::assertEquals('jwage', $user->getUsername());
self::assertTrue($user->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($user));
}

public function testPersistentCollectionOwningSide(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function testPrimeWithGetSingleResult(): void

self::assertInstanceOf(GH520Document::class, $document);
self::assertInstanceOf(GhostObjectInterface::class, $document->ref);
self::assertTrue($document->ref->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($document->ref));
}

public function testPrimeWithGetSingleResultWillNotPrimeEntireResultSet(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ public function testReferenceManyOwningSidePreparesFilterCriteria(): void
self::assertCount(2, $user1following);

self::assertInstanceOf(GhostObjectInterface::class, $user1following[0]);
self::assertTrue($user1following[0]->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($user1following[0]));
self::assertEquals($user2->getId(), $user1following[0]->getId());

self::assertInstanceOf(GhostObjectInterface::class, $user1following[1]);
self::assertFalse($user1following[1]->isProxyInitialized());
self::assertTrue($this->uow->isUninitializedObject($user1following[1]));
self::assertEquals($user3->getId(), $user1following[1]->getId());

$this->expectException(DocumentNotFoundException::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ public function testReferenceManyOwningSidePreparesFilterCriteriaForDifferentCla
self::assertCount(2, $user1likes);

self::assertInstanceOf(GhostObjectInterface::class, $user1likes[0]);
self::assertTrue($user1likes[0]->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($user1likes[0]));
self::assertEquals($thing1->getId(), $user1likes[0]->getId());

self::assertInstanceOf(GhostObjectInterface::class, $user1likes[1]);
self::assertFalse($user1likes[1]->isProxyInitialized());
self::assertTrue($this->uow->isUninitializedObject($user1likes[1]));
self::assertEquals($thing2->getId(), $user1likes[1]->getId());

$this->expectException(DocumentNotFoundException::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ public function testA(Closure $idGenerator): void

self::assertInstanceOf(GhostObjectInterface::class, $parent->refOne);
self::assertInstanceOf(GH852Document::class, $parent->refOne);
self::assertFalse($parent->refOne->isProxyInitialized());
self::assertTrue($this->uow->isUninitializedObject($parent->refOne));
self::assertEquals($idGenerator('childA'), $parent->refOne->id);
self::assertEquals('childA', $parent->refOne->name);
self::assertTrue($parent->refOne->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($parent->refOne));

self::assertCount(2, $parent->refMany);

Expand All @@ -63,13 +63,13 @@ public function testA(Closure $idGenerator): void
*/
self::assertInstanceOf(GhostObjectInterface::class, $parent->refMany[0]);
self::assertInstanceOf(GH852Document::class, $parent->refMany[0]);
self::assertTrue($parent->refMany[0]->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($parent->refMany[0]));
self::assertEquals($idGenerator('childB'), $parent->refMany[0]->id);
self::assertEquals('childB', $parent->refMany[0]->name);

self::assertInstanceOf(GhostObjectInterface::class, $parent->refMany[1]);
self::assertInstanceOf(GH852Document::class, $parent->refMany[1]);
self::assertTrue($parent->refMany[1]->isProxyInitialized());
self::assertFalse($this->uow->isUninitializedObject($parent->refMany[1]));
self::assertEquals($idGenerator('childC'), $parent->refMany[1]->id);
self::assertEquals('childC', $parent->refMany[1]->name);

Expand Down
Loading
Loading