From 0cab827f244c2b542b7e104f14a12fe295628d82 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Fri, 7 Mar 2025 18:47:24 +0100 Subject: [PATCH] fix: use Doctrine metadata event when persist is disabled --- src/Persistence/PersistentObjectFactory.php | 22 ++++++++----- .../EntityFactoryRelationshipTestCase.php | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/Persistence/PersistentObjectFactory.php b/src/Persistence/PersistentObjectFactory.php index e8a2c116..a89aaffb 100644 --- a/src/Persistence/PersistentObjectFactory.php +++ b/src/Persistence/PersistentObjectFactory.php @@ -291,10 +291,15 @@ protected function normalizeParameter(string $field, mixed $value): mixed if ($inversedRelationshipMetadata && !$inversedRelationshipMetadata->isCollection) { $inverseField = $inversedRelationshipMetadata->inverseField; - // we need to handle the circular dependency involved by inversed one-to-one relationship: - // a placeholder object is used, which will be replaced by the real object, after its instantiation - $inversedObject = $value->withPersistMode(PersistMode::NO_PERSIST_BUT_SCHEDULE_FOR_INSERT) - ->create([$inverseField => $placeholder = (new \ReflectionClass(static::class()))->newInstanceWithoutConstructor()]); + $inversedObject = $value->withPersistMode( + $this->isPersisting() ? PersistMode::NO_PERSIST_BUT_SCHEDULE_FOR_INSERT : PersistMode::WITHOUT_PERSISTING + ) + + // we need to handle the circular dependency involved by inversed one-to-one relationship: + // a placeholder object is used, which will be replaced by the real object, after its instantiation + ->create([ + $inverseField => $placeholder = (new \ReflectionClass(static::class()))->newInstanceWithoutConstructor(), + ]); $inversedObject = unproxy($inversedObject, withAutoRefresh: false); @@ -312,7 +317,7 @@ protected function normalizeParameter(string $field, mixed $value): mixed protected function normalizeCollection(string $field, FactoryCollection $collection): array { - if (!$this->isPersisting() || !$collection->factory instanceof self) { + if (!Configuration::instance()->isPersistenceAvailable() || !$collection->factory instanceof self) { return parent::normalizeCollection($field, $collection); } @@ -321,10 +326,13 @@ protected function normalizeCollection(string $field, FactoryCollection $collect $inverseRelationshipMetadata = $pm->inverseRelationshipMetadata(static::class(), $collection->factory::class(), $field); if ($inverseRelationshipMetadata && $inverseRelationshipMetadata->isCollection) { - $this->tempAfterInstantiate[] = static function(object $object) use ($collection, $inverseRelationshipMetadata, $field) { + $this->tempAfterInstantiate[] = function(object $object) use ($collection, $inverseRelationshipMetadata, $field) { $inverseField = $inverseRelationshipMetadata->inverseField; - $inverseObjects = $collection->withPersistMode(PersistMode::NO_PERSIST_BUT_SCHEDULE_FOR_INSERT)->create([$inverseField => $object]); + $inverseObjects = $collection->withPersistMode( + $this->isPersisting() ? PersistMode::NO_PERSIST_BUT_SCHEDULE_FOR_INSERT : PersistMode::WITHOUT_PERSISTING + ) + ->create([$inverseField => $object]); $inverseObjects = unproxy($inverseObjects, withAutoRefresh: false); diff --git a/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php b/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php index 66020e55..844b74a9 100644 --- a/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php +++ b/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php @@ -324,11 +324,21 @@ public function disabling_persistence_cascades_to_children(): void foreach ($contact->getTags() as $tag) { $this->assertNull($tag->id); } + } + /** @test */ + #[Test] + #[DataProvider('provideCascadeRelationshipsCombinations')] + #[UsingRelationships(Contact::class, ['category'])] + public function disabling_persistence_cascades_to_children_one_to_many(): void + { $category = static::categoryFactory()->withoutPersisting()->create([ 'contacts' => static::contactFactory()->many(3), ]); + // ensure nothing was persisted in Doctrine by flushing + self::getContainer()->get(EntityManagerInterface::class)->flush(); // @phpstan-ignore method.notFound + static::contactFactory()::assert()->empty(); static::categoryFactory()::assert()->empty(); @@ -340,6 +350,27 @@ public function disabling_persistence_cascades_to_children(): void } } + /** @test */ + #[Test] + #[DataProvider('provideCascadeRelationshipsCombinations')] + #[UsingRelationships(Contact::class, ['address'])] + public function disabling_persistence_cascades_to_children_inversed_one_to_one(): void + { + $address = static::addressFactory()->withoutPersisting()->create([ + 'contact' => static::contactFactory(), + ]); + + // ensure nothing was persisted in Doctrine by flushing + self::getContainer()->get(EntityManagerInterface::class)->flush(); // @phpstan-ignore method.notFound + + static::contactFactory()::assert()->empty(); + static::addressFactory()::assert()->empty(); + + $this->assertNull($address->id); + $this->assertInstanceOf(Contact::class, $address->getContact()); + $this->assertNull($address->getContact()->id); + } + /** @test */ #[Test] #[DataProvider('provideCascadeRelationshipsCombinations')]