@@ -172,6 +172,59 @@ public function testPublishUpdate(): void
172172 $ this ->assertEquals ([null , null , null , null , null , 10 , null ], $ retry );
173173 }
174174
175+ public function testResetDropsTheUpdatesCollectedByAFailedFlush (): void
176+ {
177+ $ failed = new Dummy ();
178+ $ failed ->setId (1 );
179+ $ published = new Dummy ();
180+ $ published ->setId (2 );
181+
182+ $ resourceClassResolverProphecy = $ this ->prophesize (ResourceClassResolverInterface::class);
183+ $ resourceClassResolverProphecy ->getResourceClass (Argument ::type (Dummy::class))->willReturn (Dummy::class);
184+ $ resourceClassResolverProphecy ->isResourceClass (Dummy::class)->willReturn (true );
185+
186+ $ iriConverterProphecy = $ this ->prophesize (IriConverterInterface::class);
187+ $ iriConverterProphecy ->getIriFromResource ($ failed , Argument ::cetera ())->shouldNotBeCalled ();
188+ $ iriConverterProphecy ->getIriFromResource ($ published , UrlGeneratorInterface::ABS_URL , Argument ::any ())->willReturn ('http://example.com/dummies/2 ' )->shouldBeCalled ();
189+
190+ $ resourceMetadataFactoryProphecy = $ this ->prophesize (ResourceMetadataCollectionFactoryInterface::class);
191+ $ resourceMetadataFactoryProphecy ->create (Dummy::class)->willReturn (new ResourceMetadataCollection (Dummy::class, [(new ApiResource ())->withOperations (new Operations ([
192+ 'get ' => (new Get ())->withShortName ('Dummy ' )->withMercure (['hub ' => 'managed ' , 'enable_async_update ' => false ]),
193+ ]))]));
194+
195+ $ serializerProphecy = $ this ->prophesize (SerializerInterface::class);
196+ $ serializerProphecy ->serialize ($ published , 'jsonld ' , [])->willReturn ('2 ' );
197+
198+ $ topics = [];
199+ $ managedHub = $ this ->createMockHub (static function (Update $ update ) use (&$ topics ): string {
200+ $ topics = array_merge ($ topics , $ update ->getTopics ());
201+
202+ return 'id ' ;
203+ });
204+
205+ $ listener = new PublishMercureUpdatesListener (
206+ $ resourceClassResolverProphecy ->reveal (),
207+ $ iriConverterProphecy ->reveal (),
208+ $ resourceMetadataFactoryProphecy ->reveal (),
209+ $ serializerProphecy ->reveal (),
210+ ['jsonld ' => ['application/ld+json ' ]],
211+ null ,
212+ new HubRegistry ($ this ->createStub (HubInterface::class), [
213+ 'managed ' => $ managedHub ,
214+ ]),
215+ );
216+
217+ // the commit of the first flush fails: Doctrine dispatches onFlush, but never postFlush
218+ $ listener ->onFlush ($ this ->createOnFlushEventArgs ([$ failed ]));
219+ // between two requests (or two messages), the services resetter resets the listener
220+ $ listener ->reset ();
221+
222+ $ listener ->onFlush ($ this ->createOnFlushEventArgs ([$ published ]));
223+ $ listener ->postFlush ();
224+
225+ $ this ->assertSame (['http://example.com/dummies/2 ' ], $ topics );
226+ }
227+
175228 public function testPublishUpdateMultipleTopicsUsingExpressionLanguage (): void
176229 {
177230 $ mercure = [
@@ -444,6 +497,19 @@ public function testPublishUpdateWithMultipleResources(): void
444497 $ this ->assertEquals ('{"public":1} ' , $ data [1 ]);
445498 }
446499
500+ private function createOnFlushEventArgs (array $ insertions ): OnFlushEventArgs
501+ {
502+ $ uowProphecy = $ this ->prophesize (UnitOfWork::class);
503+ $ uowProphecy ->getScheduledEntityInsertions ()->willReturn ($ insertions );
504+ $ uowProphecy ->getScheduledEntityUpdates ()->willReturn ([]);
505+ $ uowProphecy ->getScheduledEntityDeletions ()->willReturn ([]);
506+
507+ $ emProphecy = $ this ->prophesize (EntityManagerInterface::class);
508+ $ emProphecy ->getUnitOfWork ()->willReturn ($ uowProphecy ->reveal ());
509+
510+ return new OnFlushEventArgs ($ emProphecy ->reveal ());
511+ }
512+
447513 private function createMockHub (callable $ callable ): HubInterface
448514 {
449515 return new MockHub ('https://mercure.demo/.well-known/mercure ' , new StaticTokenProvider ('x ' ), $ callable );
0 commit comments