From d644104cbe86e3f31c72b1e410800d5241ca3b52 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Sun, 5 Jan 2025 21:39:45 +0100 Subject: [PATCH] fix: add unpersisted object to relation --- src/Persistence/PersistenceManager.php | 1 + src/Persistence/PersistentObjectFactory.php | 21 +++++++++- .../EntityFactoryRelationshipTestCase.php | 38 +++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/Persistence/PersistenceManager.php b/src/Persistence/PersistenceManager.php index 3525791f..8175e09a 100644 --- a/src/Persistence/PersistenceManager.php +++ b/src/Persistence/PersistenceManager.php @@ -190,6 +190,7 @@ public function refresh(object &$object, bool $force = false): object public function isPersisted(object $object): bool { + // prevents doctrine to use its cache and think the object is persisted if ($this->strategyFor($object::class)->isScheduledForInsert($object)) { return false; } diff --git a/src/Persistence/PersistentObjectFactory.php b/src/Persistence/PersistentObjectFactory.php index 7e023d39..d38baaa5 100644 --- a/src/Persistence/PersistentObjectFactory.php +++ b/src/Persistence/PersistentObjectFactory.php @@ -355,12 +355,29 @@ protected function normalizeObject(object $object): object $configuration = Configuration::instance(); - if (!$configuration->isPersistenceAvailable() || !$configuration->persistence()->hasPersistenceFor($object)) { + if (!$configuration->isPersistenceAvailable()) { return $object; } + $persistenceManager = $configuration->persistence(); + + if ($object instanceof Proxy) { + $proxy = $object; + $proxy->_disableAutoRefresh(); + $object = $proxy->_real(); + $proxy->_enableAutoRefresh(); + } + + if (!$persistenceManager->hasPersistenceFor($object)) { + return $object; + } + + if (!$persistenceManager->isPersisted($object)) { + $persistenceManager->scheduleForInsert($object); + } + try { - return $configuration->persistence()->refresh($object, true); + return $persistenceManager->refresh($object, force: true); } catch (RefreshObjectFailed|VarExportLogicException) { return $object; } diff --git a/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php b/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php index 4d004dba..d489d1e1 100644 --- a/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php +++ b/tests/Integration/ORM/EntityRelationship/EntityFactoryRelationshipTestCase.php @@ -31,6 +31,7 @@ use Zenstruck\Foundry\Tests\Fixture\Entity\Contact; use Zenstruck\Foundry\Tests\Fixture\Entity\Tag; +use function Zenstruck\Foundry\Persistence\refresh; use function Zenstruck\Foundry\Persistence\unproxy; /** @@ -361,6 +362,43 @@ public function ensure_one_to_many_relations_are_not_pre_persisted(): void } } + /** @test */ + #[Test] + #[DataProvider('provideCascadeRelationshipsCombinations')] + #[UsingRelationships(Category::class, ['contacts'])] + public function it_can_add_managed_entity_to_many_to_one(): void + { + $this->it_can_add_entity_to_many_to_one( + static::categoryFactory()->create() + ); + } + + /** @test */ + #[Test] + #[DataProvider('provideCascadeRelationshipsCombinations')] + #[UsingRelationships(Category::class, ['contacts'])] + public function it_can_add_unmanaged_entity_to_many_to_one(): void + { + $this->it_can_add_entity_to_many_to_one( + static::categoryFactory()->withoutPersisting()->create() + ); + } + + private function it_can_add_entity_to_many_to_one(Category $category): void + { + self::assertCount(0, $category->getContacts()); + + $contact1 = static::contactFactory()->create(['category' => $category]); + $contact2 = static::contactFactory()->create(['category' => $category]); + + static::categoryFactory()::assert()->count(1); + + self::assertCount(2, $category->getContacts()); + + self::assertSame(unproxy($category), $contact1->getCategory()); + self::assertSame(unproxy($category), $contact2->getCategory()); + } + /** @return PersistentObjectFactory */ protected static function contactFactoryWithoutCategory(): PersistentObjectFactory {