Subscribe and listen for various events that occur within your application.
Make sure that your server is configured with following PHP version and extensions:
- PHP 8.0+
- Spiral framework 2.9+
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
],
//...
];
}
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);
}
}
class UserDeleted
{
public function __construct(public string $name) {}
}
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);
}
}
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);
}
}
If you want to push listener to a queue, you can add Spiral\EventBus\QueueableInterface
class DeleteUserComments implements \Spiral\EventBus\QueueableInterface
{
// ...
}
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)
);
}
}
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;
}
}
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();
}
}
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.