diff --git a/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php b/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php index 80c257d66c..65931a1eec 100644 --- a/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php +++ b/lib/Doctrine/ODM/MongoDB/Persisters/PersistenceBuilder.php @@ -282,19 +282,35 @@ public function prepareUpsertData($document) } } + // @EmbedMany + } elseif ($mapping['association'] === ClassMetadata::EMBED_MANY && ! CollectionHelper::isAtomic($mapping['strategy'])) { + foreach ($new as $key => $embeddedDoc) { + if ($this->uow->isScheduledForInsert($embeddedDoc)) { + continue; + } + + $update = $this->prepareUpsertData($embeddedDoc); + foreach ($update as $cmd => $values) { + foreach ($values as $name => $value) { + $updateData[$cmd][$mapping['name'] . '.' . $key . '.' . $name] = $value; + } + } + } + // @ReferenceOne } elseif ($mapping['association'] === ClassMetadata::REFERENCE_ONE) { $updateData['$set'][$mapping['name']] = $this->prepareReferencedDocumentValue($mapping, $new); - // @ReferenceMany, @EmbedMany + // @ReferenceMany } elseif ( $mapping['type'] === ClassMetadata::MANY && ! $mapping['isInverseSide'] - && $new instanceof PersistentCollectionInterface && $new->isDirty() - && CollectionHelper::isAtomic($mapping['strategy']) + && $new instanceof PersistentCollectionInterface && $new->isDirty() + && CollectionHelper::isAtomic($mapping['strategy']) ) { $updateData['$set'][$mapping['name']] = $this->prepareAssociatedCollectionValue($new, true); } - // @EmbedMany and @ReferenceMany are handled by CollectionPersister + + // @ReferenceMany is handled by CollectionPersister } // add discriminator if the class has one diff --git a/lib/Doctrine/ODM/MongoDB/UnitOfWork.php b/lib/Doctrine/ODM/MongoDB/UnitOfWork.php index 82d4195aa6..69e5ed68d9 100644 --- a/lib/Doctrine/ODM/MongoDB/UnitOfWork.php +++ b/lib/Doctrine/ODM/MongoDB/UnitOfWork.php @@ -1790,7 +1790,12 @@ private function doPersist(object $document, array &$visited): void // Document becomes managed again unset($this->scheduledDocumentDeletions[$oid]); - $this->persistNew($class, $document); + if ($class->isEmbeddedDocument) { + $this->documentStates[$oid] = self::STATE_MANAGED; + } else { + $this->persistNew($class, $document); + } + break; case self::STATE_DETACHED: diff --git a/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2767Test.php b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2767Test.php new file mode 100644 index 0000000000..18bcefef66 --- /dev/null +++ b/tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2767Test.php @@ -0,0 +1,75 @@ +dm->persist($document); + $this->dm->flush(); + $id = $document->id; + + // Remove the document + $this->dm->remove($document); + + // Increase the removedCount of the parent document and the embedded document by 1 + $document->incrementRemovedCount(); + + // Re-persist the same document + $this->dm->persist($document); + + $this->dm->flush(); + $this->dm->clear(); + + $repository = $this->dm->getRepository(GH2767TestDocument::class); + $result = $repository->find($id); + + self::assertEquals(1, $result->removedCount); + self::assertEquals(1, $result->embeddedDocuments[0]->removedCount); + } +} + +#[ODM\Document] +class GH2767TestDocument +{ + #[ODM\Id] + public ?string $id = null; + + #[ODM\Field(type: 'int')] + public int $removedCount = 0; + + /** @var Collection */ + #[ODM\EmbedMany(targetDocument: GH2767TestEmbeddedDocument::class)] + public $embeddedDocuments; + + /** @param GH2767TestEmbeddedDocument[] $embeddedDocuments */ + public function __construct(array $embeddedDocuments) + { + $this->embeddedDocuments = new ArrayCollection($embeddedDocuments); + } + + public function incrementRemovedCount(): void + { + $this->removedCount++; + foreach ($this->embeddedDocuments as $embeddedDocument) { + $embeddedDocument->removedCount++; + } + } +} + +#[ODM\EmbeddedDocument] +class GH2767TestEmbeddedDocument +{ + #[ODM\Field(type: 'int')] + public int $removedCount = 0; +}