spiral-packages / event-bus
A simple observer pattern implementation based on symfony event handler, allowing you to subscribe and listen for various events that occur within your application.
Installs: 2 313
Dependents: 0
Suggesters: 0
Security: 0
Stars: 6
Watchers: 2
Forks: 2
Open Issues: 1
Requires
- php: ^8.1
- spiral/attributes: ^2.8 || ^3.0
- spiral/boot: ^3.0
- spiral/config: ^3.0
- spiral/core: ^3.0
- spiral/hmvc: ^3.0
- spiral/queue: ^3.0
- spiral/tokenizer: ^3.0
- symfony/event-dispatcher: ^6.0
Requires (Dev)
- spiral/testing: ^2.0
- vimeo/psalm: ^4.9
This package is auto-updated.
Last update: 2024-12-07 06:40:26 UTC
README
Subscribe and listen for various events that occur within your application.
Requirements
Make sure that your server is configured with following PHP version and extensions:
- PHP 8.0+
- Spiral framework 2.9+
Installation
You can install the package via composer:
composer require spiral-packages/event-bus
After package install you need to register bootloader from the package.
protected const LOAD = [ // ... \Spiral\EventBus\Bootloader\EventBusBootloader::class, ];
or
namespace App\Bootloader; use Spiral\EventBus\Bootloader\EventBusBootloader as BaseBootloader class EventBusBootloader extends BaseBootloader { protected const LISTENS = [ \App\Event\UserCreated::class => [ \App\Listener\SendWelcomeMessageListener::class ], //... ]; }
Usage
At first need create config file app/config/event-bus.php
, where you can specify listeners.
<?php declare(strict_types=1); return [ 'queueConnection' => env('EVENT_BUS_QUEUE_CONNECTION'), // default queue connection for Listeners with \Spiral\EventBus\QueueableInterface 'discoverListeners' => env('EVENT_BUS_DISCOVER_LISTENERS', true), // Discover listeners with \Spiral\EventBus\Attribute\Listener attribute 'listeners' => [ UserDeleted::class => [ DeleteUserComments::class, ] ], 'interceptors' => [ BroadcastEventInterceptor::class ] ];
You can also register listeners via Spiral\EventBus\ListenerRegistryInterface
class MyPackageBootloader extends Spiral\Boot\Bootloader\Bootloader { public function start(Spiral\EventBus\ListenerRegistryInterface $registry) { $registry->addListener(UserDeleted::class, DeleteUserComments::class); } }
Event example
class UserDeleted { public function __construct(public string $name) {} }
Listener example
Make sure to use variable
$event
for event handler method. It's required.
class DeleteUserComments { public function __construct(private CommentService $service) {} public function __invoke(UserDeleted $event) { $this->service->deleteCommentsForUser($event->name); } }
Listener example with attributes
If you are using listeners with attributes 'discoverListeners' = true
, you don't need to register them, they will be
registered automatically.
use Spiral\EventBus\Attribute\Listener; class DeleteUserComments { public function __construct(private CommentService $service) {} #[Listener] public function handleDeletedUser(UserDeleted $event) { $this->service->deleteCommentsForUser($event->usernname); } #[Listener] public function handleCreatedUser(UserCreated $event) { $this->service->creaateUserProfile($event->usernname); } #[Listener] public function notifyAdmins(UserCreated|UserDeleted $event) { $this->service->notifyAdmins($event->usernname); } }
Listener example that should be handled in a queue
If you want to push listener to a queue, you can add Spiral\EventBus\QueueableInterface
class DeleteUserComments implements \Spiral\EventBus\QueueableInterface { // ... }
Event dispatching
use Symfony\Component\EventDispatcher\EventDispatcherInterface; class UserService { public function __construct(private EventDispatcherInterface $events) {} public function deleteUserById(string $id): void { $user = User::findById($id); //.. $this->events->dispatch( new UserDeleted($user->username) ); } }
Interceptors
The package provides convenient Bootloader to configure core
interceptors Spiral\EventBus\Bootloader\EventBusBootloader
automatically:
namespace App\Bootloader; use Spiral\EventBus\Bootloader\EventBusBootloader as BaseBootloader class EventBusBootloader extends BaseBootloader { protected const INTERCEPTORS = [ \App\Event\Interceptor\BroadcastEventInterceptor::class, //... ]; }
or via config app/config/event-bus.php
<?php declare(strict_types=1); return [ // ... 'interceptors' => [ BroadcastEventInterceptor::class ] ];
namespace App\Event\Interceptor; use Spiral\Broadcasting\BroadcastInterface; class BroadcastEventInterceptor implements \Spiral\Core\CoreInterceptorInterface { public function __construct( private BroadcastInterface $broadcast ) {} public function process(string $eventName, string $action, array , CoreInterface $core): mixed { $event = $parameters['event']; // Event object $listeners = $parameters['listeners']; // array of invokable listeners $result = $core->callAction($eventName, $action, $parameters); if ($event instanceof ShouldBroadcastInterface) { $this->broadcast->publish( $event->getBroadcasTopics(), \json_encode($event->toBroadcast()) ); } return $result; } }
Testing
composer test
If you are using spiral/testing
package in your application, you can additionally
use trait Spiral\EventBus\Testing\InteractsWithEvents
in your tests cases.
class EventDispatcherTest extends TestCase { use \Spiral\EventBus\Testing\InteractsWithEvents; public function testDispatchEvent(): void { $events = $this->fakeEventDispatcher(); $this->getDispatcher()->dispatch(new SimpleEvent()); $events->assertListening(SimpleEvent::class, SimpleListener::class); $events->assertListening(SimpleEvent::class, ListenerWithAttributes::class, 'methodA'); $events->assertDispatched(SimpleEvent::class) $events->assertDispatched(SimpleEvent::class, function(SimpleEvent $event) { return $event->someProperty === 'foo'; }); $events->assertDispatchedTimes(SimpleEvent::class, 10); $events->assertNotDispatched(AnotherSimpleEvent::class); $events->assertNotDispatched(AnotherSimpleEvent::class); $events->assertNothingDispatched(); } }
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.