From e69e3adebc2feb1685f8681bd9deaee1f9f5bb15 Mon Sep 17 00:00:00 2001 From: Ron Rise Date: Sun, 30 Nov 2025 14:53:41 -0500 Subject: [PATCH] feat: add event dispatcher destructor and implement subscriber interface with tests --- src/Events/Dispatcher.php | 10 + src/Events/Subscribers/Subscriber.php | 15 ++ .../Subscribers/SubscriberInterface.php | 10 + tests/Events/DispatcherTest.php | 172 ++++++++++++++++++ .../DispatcherServiceProviderTest.php | 15 ++ tests/Unit.php | 16 +- 6 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 src/Events/Subscribers/Subscriber.php create mode 100644 src/Events/Subscribers/SubscriberInterface.php create mode 100644 tests/Events/DispatcherTest.php create mode 100644 tests/ServiceProviders/DispatcherServiceProviderTest.php diff --git a/src/Events/Dispatcher.php b/src/Events/Dispatcher.php index 2de241e..7b817a2 100644 --- a/src/Events/Dispatcher.php +++ b/src/Events/Dispatcher.php @@ -45,6 +45,16 @@ class Dispatcher implements DispatcherContract, Arrayable $this->registerListeners(); } + /** + * @throws \Throwable + */ + public function __destruct() + { + foreach ($this->pushed as $event => $payload) { + $this->dispatch($event, $payload); + } + } + /** * Register event listeners based on the ListensFor attribute. * diff --git a/src/Events/Subscribers/Subscriber.php b/src/Events/Subscribers/Subscriber.php new file mode 100644 index 0000000..d638c02 --- /dev/null +++ b/src/Events/Subscribers/Subscriber.php @@ -0,0 +1,15 @@ +getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + + $eventFired = false; + $dispatcher->listen('TestEvent', function ($event) use (&$eventFired) { + $this->assertEquals('TestEvent', $event); + $eventFired = true; + }); + + $dispatcher->dispatch('TestEvent'); + $this->assertTrue($eventFired, 'The TestEvent listener was not fired.'); + } + + /** + * @throws BindingResolutionException + */ + public function testPushesEvents() + { + $dispatcher = $this->getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + + $eventsFired = 0; + $dispatcher->listen('PushedEvent1', function ($event) use (&$eventsFired) { + $eventsFired++; + $this->assertEquals('PushedEvent1', $event); + }); + + $dispatcher->listen('PushedEvent2', function ($event) use (&$eventsFired) { + $eventsFired++; + $this->assertEquals('PushedEvent2', $event); + }); + + $dispatcher->push('PushedEvent1'); + $dispatcher->push('PushedEvent2'); + + unset($dispatcher); // Trigger destructor + $this->assertEquals(2, $eventsFired); + } + + /** + * @throws BindingResolutionException + * @throws \Throwable + */ + public function testFlushEvent(): void + { + $dispatcher = $this->getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + + $eventFired = false; + $dispatcher->listen('FlushEvent', function ($event) use (&$eventFired) { + $this->assertEquals('FlushEvent', $event); + $eventFired = true; + }); + + $dispatcher->push('FlushEvent'); + $dispatcher->flush('FlushEvent'); + + $this->assertTrue($eventFired, 'The FlushEvent listener was not fired.'); + } + + public function testHasListeners(): void + { + $dispatcher = $this->getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + + $this->assertFalse( + $dispatcher->hasListeners( + 'NonExistentEvent' + ), + 'Expected no listeners for NonExistentEvent.' + ); + + $dispatcher->listen('ExistingEvent', function () { + // Listener logic + }); + + $this->assertTrue( + $dispatcher->hasListeners( + 'ExistingEvent' + ), + 'Expected listeners for ExistingEvent.' + ); + } + + /** + * @throws BindingResolutionException + * @throws \Throwable + */ + public function testForgetEvent(): void + { + $dispatcher = $this->getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + + $eventFired = false; + $dispatcher->listen('ForgetEvent', function ($event) use (&$eventFired) { + $this->assertEquals('ForgetEvent', $event); + $eventFired = true; + }); + + $dispatcher->push('ForgetEvent'); + $dispatcher->forget('ForgetEvent'); + + unset($dispatcher); // Trigger destructor + + $this->assertFalse($eventFired, 'The ForgetEvent listener was fired but should have been forgotten.'); + } + + /** + * @throws BindingResolutionException + */ + public function testForgetPushed() + { + $this->expectNotToPerformAssertions(); + + $dispatcher = $this->getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + + $dispatcher->listen('EventToForget', function () { + $this->fail('The EventToForget listener was fired but should have been forgotten.'); + }); + + $dispatcher->push('EventToForget'); + $dispatcher->forgetPushed(); + + unset($dispatcher); // Trigger destructor + } + + public function testToArray(): void + { + $dispatcher = $this->getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + + $dispatcher->listen('ArrayEvent', function () { + // Listener logic + }); + + $arrayRepresentation = $dispatcher->toArray(); + $this->assertArrayHasKey('ArrayEvent', $arrayRepresentation); + } + + /** + * @throws BindingResolutionException + * @throws \Throwable + */ + public function testSubscriber() + { + $subscriber = $this->getMockBuilder('Siteworxpro\App\Events\Subscribers\Subscriber') + ->onlyMethods(['handle']) + ->getMock(); + + $subscriber->expects($this->once()) + ->method('handle') + ->with('SubscribedEvent', []) + ->willReturn(null); + + $dispatcher = $this->getContainer()->make('Siteworxpro\App\Events\Dispatcher'); + $dispatcher->subscribe($subscriber); + + $dispatcher->dispatch('SubscribedEvent'); + } +} diff --git a/tests/ServiceProviders/DispatcherServiceProviderTest.php b/tests/ServiceProviders/DispatcherServiceProviderTest.php new file mode 100644 index 0000000..670cd2a --- /dev/null +++ b/tests/ServiceProviders/DispatcherServiceProviderTest.php @@ -0,0 +1,15 @@ +getContainer(); $container->bind(SWConfig::class, function () { return SWConfig::load(__DIR__ . '/../config.php');