From 1f39e922914d9f412736467e41a0f24e9a7622c1 Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Thu, 6 Mar 2025 10:30:38 -0500 Subject: [PATCH 1/8] Resolved a bug where a soft-deleted object isn't remove from the ObjectManager --- src/SoftDeleteable/SoftDeleteableListener.php | 30 +++++++++++++++- .../SoftDeleteable/Fixture/Entity/Article.php | 5 +++ .../SoftDeleteableEntityTest.php | 36 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/SoftDeleteable/SoftDeleteableListener.php b/src/SoftDeleteable/SoftDeleteableListener.php index 7157e11380..ea20ea2d00 100644 --- a/src/SoftDeleteable/SoftDeleteableListener.php +++ b/src/SoftDeleteable/SoftDeleteableListener.php @@ -51,6 +51,14 @@ class SoftDeleteableListener extends MappedEventSubscriber */ public const POST_SOFT_DELETE = 'postSoftDelete'; + + /** + * Objects soft-deleted on flush. + * + * @var array + */ + private array $softDeletedObjects = []; + /** * @return string[] */ @@ -59,6 +67,7 @@ public function getSubscribedEvents() return [ 'loadClassMetadata', 'onFlush', + 'postFlush', ]; } @@ -102,7 +111,7 @@ public function onFlush(EventArgs $args) $evm->dispatchEvent( self::PRE_SOFT_DELETE, - $preSoftDeleteEventArgs + $preSoftDeleteEventArgs, ); } @@ -129,10 +138,29 @@ public function onFlush(EventArgs $args) $postSoftDeleteEventArgs ); } + + $this->softDeletedObjects[] = $object; } } } + /** + * Detach soft-deleted objects from object manager. + * + * @param EventArgs $args + * + * @return void + */ + public function postFlush(EventArgs $args) + { + $ea = $this->getEventAdapter($args); + $om = $ea->getObjectManager(); + foreach ($this->softDeletedObjects as $index => $object) { + $om->detach($object); + unset($this->softDeletedObjects[$index]); + } + } + /** * Maps additional metadata * diff --git a/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php b/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php index 5c6c1e0a35..af93803ec9 100644 --- a/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php +++ b/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php @@ -92,4 +92,9 @@ public function addComment(Comment $comment): void { $this->comments[] = $comment; } + + public function getComments(): Collection + { + return $this->comments; + } } diff --git a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php index daddb99c0f..d8902fff9d 100644 --- a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php +++ b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php @@ -522,6 +522,42 @@ public function testShouldFilterBeQueryCachedCorrectlyWhenToggledForEntity(): vo static::assertCount(0, $data); } + public function testSoftDeletedObjectIsRemovedPostFlush(): void + { + $repo = $this->em->getRepository(Article::class); + $commentRepo = $this->em->getRepository(Comment::class); + + $comment = new Comment(); + $commentValue = 'Comment 1'; + $comment->setComment($commentValue); + + $art0 = new Article(); + $field = 'title'; + $value = 'Title 1'; + $art0->setTitle($value); + $art0->addComment($comment); + + $this->em->persist($art0); + $this->em->flush(); + + $art = $repo->findOneBy([$field => $value]); + + $this->assertNull($art->getDeletedAt()); + $this->assertNull($comment->getDeletedAt()); + $this->assertCount(1, $art->getComments()); + + $this->em->remove($comment); + + // The Comment has been marked for removal, but not yet flushed. This means the + // Comment should still be available. + $this->assertInstanceOf(Comment::class, $commentRepo->find($comment->getId())); + + $this->em->flush(); + + // Now that we've flushed, the Comment should no longer be available and should return null + $this->assertNull($commentRepo->find($comment->getId())); + } + public function testPostSoftDeleteEventIsDispatched(): void { $this->em->getEventManager()->addEventSubscriber(new WithPreAndPostSoftDeleteEventArgsTypeListener()); From dd1902451386a46875702f6747c0c207c42d3c27 Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Sun, 9 Mar 2025 16:05:09 -0400 Subject: [PATCH 2/8] CS fixes --- src/SoftDeleteable/SoftDeleteableListener.php | 2 -- .../Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/SoftDeleteable/SoftDeleteableListener.php b/src/SoftDeleteable/SoftDeleteableListener.php index ea20ea2d00..b81127806b 100644 --- a/src/SoftDeleteable/SoftDeleteableListener.php +++ b/src/SoftDeleteable/SoftDeleteableListener.php @@ -147,8 +147,6 @@ public function onFlush(EventArgs $args) /** * Detach soft-deleted objects from object manager. * - * @param EventArgs $args - * * @return void */ public function postFlush(EventArgs $args) diff --git a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php index d8902fff9d..9379088c5f 100644 --- a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php +++ b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php @@ -542,20 +542,20 @@ public function testSoftDeletedObjectIsRemovedPostFlush(): void $art = $repo->findOneBy([$field => $value]); - $this->assertNull($art->getDeletedAt()); - $this->assertNull($comment->getDeletedAt()); - $this->assertCount(1, $art->getComments()); + static::assertNull($art->getDeletedAt()); + static::assertNull($comment->getDeletedAt()); + static::assertCount(1, $art->getComments()); $this->em->remove($comment); // The Comment has been marked for removal, but not yet flushed. This means the // Comment should still be available. - $this->assertInstanceOf(Comment::class, $commentRepo->find($comment->getId())); + static::assertInstanceOf(Comment::class, $commentRepo->find($comment->getId())); $this->em->flush(); // Now that we've flushed, the Comment should no longer be available and should return null - $this->assertNull($commentRepo->find($comment->getId())); + static::assertNull($commentRepo->find($comment->getId())); } public function testPostSoftDeleteEventIsDispatched(): void From ecb4b8b87df823fdf169e36f13ef2ba0fd0d2637 Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Sun, 9 Mar 2025 16:07:55 -0400 Subject: [PATCH 3/8] CS fixes --- tests/Gedmo/Blameable/Fixture/Entity/Article.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Gedmo/Blameable/Fixture/Entity/Article.php b/tests/Gedmo/Blameable/Fixture/Entity/Article.php index f780508a6c..0f50421126 100644 --- a/tests/Gedmo/Blameable/Fixture/Entity/Article.php +++ b/tests/Gedmo/Blameable/Fixture/Entity/Article.php @@ -43,12 +43,12 @@ class Article implements Blameable private ?string $title = null; /** - * @var Collection + * @var Collection * * @ORM\OneToMany(targetEntity="Gedmo\Tests\Blameable\Fixture\Entity\Comment", mappedBy="article") */ #[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'article')] - private $comments; + private Collection $comments; /** * @Gedmo\Blameable(on="create") @@ -115,7 +115,7 @@ public function addComment(Comment $comment): void } /** - * @return Collection + * @return Collection */ public function getComments(): Collection { From 5adf81728964e4e0d4b1d3bd3f9b85e79a3d40ae Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Sun, 9 Mar 2025 16:24:36 -0400 Subject: [PATCH 4/8] CS fixes --- src/SoftDeleteable/SoftDeleteableListener.php | 1 - tests/Gedmo/Blameable/Fixture/Entity/Article.php | 4 ++-- tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/SoftDeleteable/SoftDeleteableListener.php b/src/SoftDeleteable/SoftDeleteableListener.php index b81127806b..133aeb1927 100644 --- a/src/SoftDeleteable/SoftDeleteableListener.php +++ b/src/SoftDeleteable/SoftDeleteableListener.php @@ -51,7 +51,6 @@ class SoftDeleteableListener extends MappedEventSubscriber */ public const POST_SOFT_DELETE = 'postSoftDelete'; - /** * Objects soft-deleted on flush. * diff --git a/tests/Gedmo/Blameable/Fixture/Entity/Article.php b/tests/Gedmo/Blameable/Fixture/Entity/Article.php index 0f50421126..0ecb4263d5 100644 --- a/tests/Gedmo/Blameable/Fixture/Entity/Article.php +++ b/tests/Gedmo/Blameable/Fixture/Entity/Article.php @@ -43,7 +43,7 @@ class Article implements Blameable private ?string $title = null; /** - * @var Collection + * @var Collection * * @ORM\OneToMany(targetEntity="Gedmo\Tests\Blameable\Fixture\Entity\Comment", mappedBy="article") */ @@ -115,7 +115,7 @@ public function addComment(Comment $comment): void } /** - * @return Collection + * @return Collection */ public function getComments(): Collection { diff --git a/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php b/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php index af93803ec9..bb467ef452 100644 --- a/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php +++ b/tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php @@ -93,6 +93,9 @@ public function addComment(Comment $comment): void $this->comments[] = $comment; } + /** + * @return Collection + */ public function getComments(): Collection { return $this->comments; From 6baee2deae01cb4812862ec65dc30a935dd1f935 Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Sun, 9 Mar 2025 16:27:20 -0400 Subject: [PATCH 5/8] CHANGELOG updated --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43f2f02cf3..7762214d33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ a release. ## [Unreleased] +### Fixed +- SoftDeleteable: Resolved a bug where a soft-deleted object isn't remove from the ObjectManager (#2930) + ## [3.19.0] - 2025-02-24 ### Added - Actor provider for use with extensions with user references (#2914) @@ -103,7 +106,7 @@ a release. - Dropped support for doctrine/dbal < 3.2 ### Deprecated -- Calling `Gedmo\Mapping\Event\Adapter\ORM::getObjectManager()` and `getObject()` on EventArgs that do not implement `getObjectManager()` and `getObject()` (such as old EventArgs implementing `getEntityManager()` and `getEntity()`) +- Calling `Gedmo\Mapping\Event\Adapter\ORM::getObjectManager()` and `getObject()` on EventArgs that do not implement `getObjectManager()` and `getObject()` (such as old EventArgs implementing `getEntityManager()` and `getEntity()`) - Calling `Gedmo\Uploadable\Event\UploadableBaseEventArgs::getEntityManager()` and `getEntity()`. Call `getObjectManager()` and `getObject()` instead. ## [3.13.0] - 2023-09-06 From 435364093680afb2cdb6f3adb7301eea7caeea8a Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Sun, 9 Mar 2025 16:51:23 -0400 Subject: [PATCH 6/8] Update tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php Co-authored-by: Javier Spagnoletti --- tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php index 9379088c5f..4a2fd0f4ec 100644 --- a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php +++ b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php @@ -548,7 +548,7 @@ public function testSoftDeletedObjectIsRemovedPostFlush(): void $this->em->remove($comment); - // The Comment has been marked for removal, but not yet flushed. This means the + // The Comment has been marked for removal, but not yet flushed. This means the // Comment should still be available. static::assertInstanceOf(Comment::class, $commentRepo->find($comment->getId())); From 80e17658f61ca4553706d648891e39b9ea3fd6ce Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Sun, 9 Mar 2025 16:51:58 -0400 Subject: [PATCH 7/8] Update CHANGELOG.md Co-authored-by: Javier Spagnoletti --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7762214d33..84fd078452 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,6 @@ a release. --- ## [Unreleased] - ### Fixed - SoftDeleteable: Resolved a bug where a soft-deleted object isn't remove from the ObjectManager (#2930) From da98f1f5042544f45c6079b63b534bc024945eb8 Mon Sep 17 00:00:00 2001 From: Jacob Thomason Date: Sun, 9 Mar 2025 16:52:05 -0400 Subject: [PATCH 8/8] Update tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php Co-authored-by: Javier Spagnoletti --- tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php index 4a2fd0f4ec..d377e68e56 100644 --- a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php +++ b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php @@ -554,7 +554,7 @@ public function testSoftDeletedObjectIsRemovedPostFlush(): void $this->em->flush(); - // Now that we've flushed, the Comment should no longer be available and should return null + // Now that we've flushed, the Comment should no longer be available and should return null. static::assertNull($commentRepo->find($comment->getId())); }