Skip to content

Commit 5a8f4a6

Browse files
authored
Avoid duplicate processing of entities in certain situations (#91)
In certain situations where Doctrine detectes new entities with `cascade: persist` during a flush operation, it might happen that the same entity ends up twice in the map of tracked entities, leading to duplicate `PersistentTranslatable::eject()` calls and failures (nothing left to eject after the first call). This can be avoided by making sure we track each object (instance) only once.
1 parent e40e3de commit 5a8f4a6

2 files changed

Lines changed: 17 additions & 11 deletions

File tree

src/Doctrine/PolyglotListener.php

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
namespace Webfactory\Bundle\PolyglotBundle\Doctrine;
1111

1212
use Doctrine\ORM\EntityManager;
13+
use Doctrine\ORM\Event\OnClearEventArgs;
1314
use Doctrine\ORM\Event\PostFlushEventArgs;
1415
use Doctrine\ORM\Event\PreFlushEventArgs;
1516
use Doctrine\Persistence\Event\LifecycleEventArgs;
1617
use Doctrine\Persistence\Mapping\RuntimeReflectionService;
1718
use Psr\Log\LoggerInterface;
1819
use Psr\Log\NullLogger;
19-
use WeakReference;
20+
use WeakMap;
2021
use Webfactory\Bundle\PolyglotBundle\Locale\DefaultLocaleProvider;
2122

2223
final class PolyglotListener
@@ -39,9 +40,9 @@ final class PolyglotListener
3940
private array $translatedClasses = [];
4041

4142
/**
42-
* @var array<WeakReference>
43+
* @var WeakMap<object, true>
4344
*/
44-
private array $entitiesWithTranslatables = [];
45+
private WeakMap $entitiesWithTranslatables;
4546

4647
/**
4748
* @var list<PersistentTranslatable>
@@ -53,6 +54,12 @@ public function __construct(
5354
private readonly LoggerInterface $logger = null ?? new NullLogger(),
5455
private readonly RuntimeReflectionService $reflectionService = new RuntimeReflectionService(),
5556
) {
57+
$this->entitiesWithTranslatables = new WeakMap();
58+
}
59+
60+
public function onClear(OnClearEventArgs $args): void
61+
{
62+
$this->entitiesWithTranslatables = new WeakMap();
5663
}
5764

5865
public function postLoad(LifecycleEventArgs $event): void
@@ -69,6 +76,10 @@ public function prePersist(LifecycleEventArgs $event): void
6976

7077
private function injectPersistentTranslatables(EntityManager $entityManager, object $object): void
7178
{
79+
if (isset($this->entitiesWithTranslatables[$object])) {
80+
return;
81+
}
82+
7283
$hasTranslatables = false;
7384

7485
foreach ($this->getTranslationMetadatas($object, $entityManager) as $tm) {
@@ -77,21 +88,15 @@ private function injectPersistentTranslatables(EntityManager $entityManager, obj
7788
}
7889

7990
if ($hasTranslatables) {
80-
$this->entitiesWithTranslatables[] = WeakReference::create($object);
91+
$this->entitiesWithTranslatables[$object] = true;
8192
}
8293
}
8394

8495
public function preFlush(PreFlushEventArgs $event): void
8596
{
8697
$em = $event->getObjectManager();
8798

88-
foreach ($this->entitiesWithTranslatables as $key => $weakRef) {
89-
$object = $weakRef->get();
90-
if (null === $object) {
91-
unset($this->entitiesWithTranslatables[$key]);
92-
continue;
93-
}
94-
99+
foreach ($this->entitiesWithTranslatables as $object => $ignored) {
95100
foreach ($this->getTranslationMetadatas($object, $em) as $tm) {
96101
$this->ejectedTranslatables = array_merge($this->ejectedTranslatables, $tm->ejectPersistentTranslatables($object));
97102
}

src/Resources/config/services.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
->tag('doctrine.event_listener', ['priority' => -100, 'event' => 'prePersist'])
1616
->tag('doctrine.event_listener', ['priority' => -100, 'event' => 'preFlush'])
1717
->tag('doctrine.event_listener', ['priority' => -100, 'event' => 'postLoad'])
18+
->tag('doctrine.event_listener', ['priority' => -100, 'event' => 'onClear'])
1819
->tag('monolog.logger', ['channel' => 'webfactory_polyglot_bundle']);
1920

2021
$services->set(\Webfactory\Bundle\PolyglotBundle\EventListener\LocaleListener::class);

0 commit comments

Comments
 (0)