Skip to content

Commit b6df490

Browse files
committed
SoftDeleteable: Add option to enable or disable handling of postFlush
1 parent ea1d375 commit b6df490

File tree

5 files changed

+196
-2
lines changed

5 files changed

+196
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ a release.
1818
---
1919

2020
## [Unreleased]
21+
### Added
22+
- SoftDeleteable: Add option to enable or disable handling of the `postFlush` event (#2958)
2123

2224
## [3.20.0] - 2025-04-04
2325
### Fixed

src/SoftDeleteable/SoftDeleteableListener.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,25 @@ class SoftDeleteableListener extends MappedEventSubscriber
5151
*/
5252
public const POST_SOFT_DELETE = 'postSoftDelete';
5353

54+
/**
55+
* Whether the postFlush event should be handled.
56+
*/
57+
private bool $handlePostFlushEvent;
58+
5459
/**
5560
* Objects soft-deleted on flush.
5661
*
5762
* @var array<object>
5863
*/
5964
private array $softDeletedObjects = [];
6065

66+
public function __construct(bool $handlePostFlushEvent = false)
67+
{
68+
parent::__construct();
69+
70+
$this->handlePostFlushEvent = $handlePostFlushEvent;
71+
}
72+
6173
/**
6274
* @return string[]
6375
*/
@@ -138,7 +150,9 @@ public function onFlush(EventArgs $args)
138150
);
139151
}
140152

141-
$this->softDeletedObjects[] = $object;
153+
if ($this->handlePostFlushEvent) {
154+
$this->softDeletedObjects[] = $object;
155+
}
142156
}
143157
}
144158
}
@@ -150,6 +164,10 @@ public function onFlush(EventArgs $args)
150164
*/
151165
public function postFlush(EventArgs $args)
152166
{
167+
if (!$this->handlePostFlushEvent) {
168+
return;
169+
}
170+
153171
$ea = $this->getEventAdapter($args);
154172
$om = $ea->getObjectManager();
155173
foreach ($this->softDeletedObjects as $index => $object) {
@@ -172,6 +190,16 @@ public function loadClassMetadata(EventArgs $eventArgs)
172190
$this->loadMetadataForObjectClass($eventArgs->getObjectManager(), $eventArgs->getClassMetadata());
173191
}
174192

193+
public function setHandlePostFlushEvent(bool $handlePostFlushEvent): void
194+
{
195+
$this->handlePostFlushEvent = $handlePostFlushEvent;
196+
}
197+
198+
public function shouldHandlePostFlushEvent(): bool
199+
{
200+
return $this->handlePostFlushEvent;
201+
}
202+
175203
protected function getNamespace()
176204
{
177205
return __NAMESPACE__;

tests/Gedmo/SoftDeleteable/Fixture/Entity/Article.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ class Article
5858
#[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'article', cascade: ['persist', 'remove'])]
5959
private $comments;
6060

61+
/**
62+
* @ORM\ManyToOne(targetEntity="Author", cascade={"persist"}, inversedBy="articles")
63+
*/
64+
#[ORM\ManyToOne(targetEntity: Author::class, cascade: ['persist'], inversedBy: 'articles')]
65+
private ?Author $author = null;
66+
6167
public function __construct()
6268
{
6369
$this->comments = new ArrayCollection();
@@ -100,4 +106,14 @@ public function getComments(): Collection
100106
{
101107
return $this->comments;
102108
}
109+
110+
public function setAuthor(?Author $author): void
111+
{
112+
$this->author = $author;
113+
}
114+
115+
public function getAuthor(): ?Author
116+
{
117+
return $this->author;
118+
}
103119
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Doctrine Behavioral Extensions package.
7+
* (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Gedmo\Tests\SoftDeleteable\Fixture\Entity;
13+
14+
use Doctrine\Common\Collections\ArrayCollection;
15+
use Doctrine\Common\Collections\Collection;
16+
use Doctrine\DBAL\Types\Types;
17+
use Doctrine\ORM\Mapping as ORM;
18+
use Gedmo\Mapping\Annotation as Gedmo;
19+
use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
20+
21+
/**
22+
* @ORM\Entity
23+
*
24+
* @Gedmo\SoftDeleteable(fieldName="deletedAt")
25+
*/
26+
#[ORM\Entity]
27+
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')]
28+
class Author
29+
{
30+
use SoftDeleteableEntity;
31+
32+
/**
33+
* @var int|null
34+
*
35+
* @ORM\Id
36+
* @ORM\GeneratedValue(strategy="IDENTITY")
37+
* @ORM\Column(type="integer")
38+
*/
39+
#[ORM\Id]
40+
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
41+
#[ORM\Column(type: Types::INTEGER)]
42+
private $id;
43+
44+
/**
45+
* @ORM\Column(type="string")
46+
*/
47+
#[ORM\Column(type: Types::STRING)]
48+
private ?string $firstname = null;
49+
50+
/**
51+
* @ORM\Column(type="string")
52+
*/
53+
#[ORM\Column(type: Types::STRING)]
54+
private ?string $lastname = null;
55+
56+
/**
57+
* @var Collection<int, Article>
58+
*
59+
* @ORM\OneToMany(targetEntity="Article", mappedBy="author", cascade={"persist"})
60+
*/
61+
#[ORM\OneToMany(targetEntity: Article::class, mappedBy: 'author', cascade: ['persist'])]
62+
private Collection $articles;
63+
64+
public function __construct()
65+
{
66+
$this->articles = new ArrayCollection();
67+
}
68+
69+
public function getId(): ?int
70+
{
71+
return $this->id;
72+
}
73+
74+
public function setFirstname(?string $firstname): void
75+
{
76+
$this->firstname = $firstname;
77+
}
78+
79+
public function getFirstname(): ?string
80+
{
81+
return $this->firstname;
82+
}
83+
84+
public function setLastname(?string $lastname): void
85+
{
86+
$this->lastname = $lastname;
87+
}
88+
89+
public function getLastname(): ?string
90+
{
91+
return $this->lastname;
92+
}
93+
94+
public function addArticle(Article $article): void
95+
{
96+
$this->articles[] = $article;
97+
}
98+
99+
/**
100+
* @return Collection<int, Article>
101+
*/
102+
public function getArticles(): Collection
103+
{
104+
return $this->articles;
105+
}
106+
}

tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Gedmo\SoftDeleteable\SoftDeleteableListener;
2020
use Gedmo\Tests\Clock;
2121
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Article;
22+
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Author;
2223
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Child;
2324
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Comment;
2425
use Gedmo\Tests\SoftDeleteable\Fixture\Entity\MegaPage;
@@ -522,8 +523,10 @@ public function testShouldFilterBeQueryCachedCorrectlyWhenToggledForEntity(): vo
522523
static::assertCount(0, $data);
523524
}
524525

525-
public function testSoftDeletedObjectIsRemovedPostFlush(): void
526+
public function testSoftDeletedObjectIsRemovedPostFlushWhenEnabled(): void
526527
{
528+
$this->softDeleteableListener->setHandlePostFlushEvent(true);
529+
527530
$repo = $this->em->getRepository(Article::class);
528531
$commentRepo = $this->em->getRepository(Comment::class);
529532

@@ -558,6 +561,44 @@ public function testSoftDeletedObjectIsRemovedPostFlush(): void
558561
static::assertNull($commentRepo->find($comment->getId()));
559562
}
560563

564+
public function testSoftDeletedEntityIsNotReinsertedPostFlushWhenDisabled(): void
565+
{
566+
$authorRepo = $this->em->getRepository(Author::class);
567+
568+
$author = new Author();
569+
$firstname = 'first_name';
570+
$author->setFirstname($firstname);
571+
$lastname = 'last_name';
572+
$author->setLastname($lastname);
573+
574+
$article = new Article();
575+
$title = 'Title 1';
576+
$article->setTitle($title);
577+
$article->setAuthor($author);
578+
579+
$this->em->persist($article);
580+
$this->em->flush();
581+
582+
$this->em->clear();
583+
584+
$author = $authorRepo->findOneBy(['firstname' => $firstname]);
585+
$article = $author->getArticles()[0];
586+
587+
static::assertSame($lastname, $author->getLastname());
588+
static::assertNull($author->getDeletedAt());
589+
static::assertSame($title, $article->getTitle());
590+
591+
$this->em->remove($author);
592+
$this->em->flush();
593+
594+
// Flush again
595+
$this->em->flush();
596+
597+
// Check whether the entity was re-inserted
598+
$this->em->getFilters()->disable(self::SOFT_DELETEABLE_FILTER_NAME);
599+
static::assertSame(1, $authorRepo->count(['firstname' => $firstname]));
600+
}
601+
561602
public function testPostSoftDeleteEventIsDispatched(): void
562603
{
563604
$this->em->getEventManager()->addEventSubscriber(new WithPreAndPostSoftDeleteEventArgsTypeListener());
@@ -614,6 +655,7 @@ protected function getUsedEntityFixtures(): array
614655
{
615656
return [
616657
Article::class,
658+
Author::class,
617659
Page::class,
618660
MegaPage::class,
619661
Module::class,

0 commit comments

Comments
 (0)