PHPackages                             assegaiphp/events - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. assegaiphp/events

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

assegaiphp/events
=================

A lightweight event emitter package for AssegaiPHP and standalone PHP applications.

0.9.0(2mo ago)06↓90%MITPHPPHP &gt;=8.4CI passing

Since Mar 26Pushed 2mo agoCompare

[ Source](https://github.com/assegaiphp/events)[ Packagist](https://packagist.org/packages/assegaiphp/events)[ RSS](/packages/assegaiphp-events/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (3)Dependencies (4)Versions (7)Used By (0)

 [![Assegai Logo](https://camo.githubusercontent.com/d7dab2658d76e460e31be249de2fe5d420f7a7237eb9f2a315f83123632a3b6c/68747470733a2f2f617373656761697068702e636f6d2f696d616765732f6c6f676f732f6c6f676f2d63726f707065642e706e67)](https://assegaiphp.com/)

 [![Latest release](https://camo.githubusercontent.com/60d9b4e68e310226aa14eee0930c618b877ee466eae531f355f1b4b4859b16ce/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f617373656761697068702f6576656e74733f646973706c61795f6e616d653d74616726736f72743d73656d766572267374796c653d666c61742d737175617265)](https://github.com/assegaiphp/events/releases) [![Tests](https://camo.githubusercontent.com/6363bfa20e4bde2b48da6ec9ee23e320cebec21176d9c1755f850b47a2a8c291/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f617373656761697068702f6576656e74732f7068702e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/assegaiphp/events/actions/workflows/php.yml) [![PHP 8.4+](https://camo.githubusercontent.com/51482859d8bb7cd31d259f58cf02b8eb7e56c51ad36c462afa3484f3b7a8fc2c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e342532422d3737374242343f7374796c653d666c61742d737175617265266c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/51482859d8bb7cd31d259f58cf02b8eb7e56c51ad36c462afa3484f3b7a8fc2c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e342532422d3737374242343f7374796c653d666c61742d737175617265266c6f676f3d706870266c6f676f436f6c6f723d7768697465) [![License](https://camo.githubusercontent.com/b60b3082a6c10f57875c6eed7f5c6f1c6466b386175702a7e0935c8d06798a0e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f617373656761697068702f6576656e74733f7374796c653d666c61742d737175617265)](https://github.com/assegaiphp/events/blob/main/LICENSE) [![Status active](https://camo.githubusercontent.com/1214b36790042a591c22d285a8cbfdc3c33d1cbbbed099a0bca2f5edd79ca2a0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617475732d6163746976652d3130623938313f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/1214b36790042a591c22d285a8cbfdc3c33d1cbbbed099a0bca2f5edd79ca2a0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617475732d6163746976652d3130623938313f7374796c653d666c61742d737175617265)

Assegai Events
==============

[](#assegai-events)

`assegaiphp/events` is a small event emitter package for both AssegaiPHP projects and standalone PHP applications.

It is intentionally framework-light:

- emit named events such as `orders.created`
- emit event objects such as `new OrderCreated(...)`
- register listeners directly with `on(...)` / `once(...)`
- register listener classes with `#[OnEvent(...)]`
- use wildcard listeners such as `orders.*`
- auto-register `#[OnEvent(...)]` listeners in Assegai modules through `EventsModule`
- observe listener failures with failure hooks
- record durable events into an outbox store when in-process delivery is not enough

Contribution workflow
---------------------

[](#contribution-workflow)

For commit and pull request conventions in this repo, see:

- [docs/commit-and-pr-guidelines.md](./docs/commit-and-pr-guidelines.md)

For package maintenance, `composer test` exercises the standalone package surface. `composer test:integration` runs the optional Assegai and ORM bridge coverage when those packages are installed.

Install
-------

[](#install)

```
composer require assegaiphp/events
```

For Assegai projects, the CLI shortcut is:

```
assegai add events
```

The standalone emitter lives under `Assegai\Events\...`. The optional Assegai bridge now lives under `Assegai\Events\Bridge\...`. The older `Assegai\Events\Assegai\...` namespace still works as a compatibility alias, but `Bridge` is the preferred path going forward.

Assegai usage
-------------

[](#assegai-usage)

Import the optional Assegai bridge module once, then inject the emitter into your services and declare listeners with `#[OnEvent(...)]`.

```
use Assegai\Core\Attributes\Injectable;
use Assegai\Core\Attributes\Modules\Module;
use Assegai\Core\Consumers\MiddlewareConsumer;
use Assegai\Core\Interfaces\AssegaiModuleInterface;
use Assegai\Events\Bridge\AssegaiEventEmitter;
use Assegai\Events\Bridge\EventsModule;
use Assegai\Events\Attributes\OnEvent;

#[Injectable]
final class OrdersService
{
  public function __construct(
    private readonly AssegaiEventEmitter $events,
  )
  {
  }

  public function create(array $order): void
  {
    $this->events->emit('orders.created', $order);
  }
}

#[Injectable]
final class OrderListener
{
  #[OnEvent('orders.created')]
  public function handle(array $payload): void
  {
    // send email, write audit log, update projections...
  }
}

#[Module(
  imports: [EventsModule::class],
  providers: [OrdersService::class, OrderListener::class],
)]
final class AppModule implements AssegaiModuleInterface
{
  public function configure(MiddlewareConsumer $consumer): void
  {
  }
}
```

By default, the Assegai bridge registers `#[OnEvent(...)]` listeners during application bootstrap. That means events emitted from very early bootstrap code can still be missed, just like the NestJS pattern this package is modeled after.

If you need to delay an early emit until listener registration has completed, inject the readiness watcher and wait for it:

```
use Assegai\Events\Bridge\EventEmitterReadinessWatcherProvider;

public function __construct(
  private readonly EventEmitterReadinessWatcherProvider $eventsReady,
  private readonly AssegaiEventEmitter $events,
)
{
}

public function boot(): void
{
  $this->eventsReady->waitUntilReady();
  $this->events->emit('orders.created', ['orderId' => 1]);
}
```

Standalone usage
----------------

[](#standalone-usage)

```
use Assegai\Events\EventEmitter;

$events = new EventEmitter();

$events->on('orders.created', function (array $payload) {
  // send email, update projections, etc.
});

$events->emit('orders.created', [
  'orderId' => 42,
]);
```

Event objects
-------------

[](#event-objects)

```
use Assegai\Events\EventEmitter;

final readonly class OrderCreated
{
  public function __construct(public int $orderId)
  {
  }
}

$events = new EventEmitter();

$events->on(OrderCreated::class, function (OrderCreated $event) {
  // handle typed event object
});

$events->emit(new OrderCreated(42));
```

Attribute-based listeners
-------------------------

[](#attribute-based-listeners)

```
use Assegai\Events\Attributes\OnEvent;
use Assegai\Events\EventEmitter;
use Assegai\Events\ReflectiveListenerProvider;

final class OrderListener
{
  #[OnEvent('orders.created')]
  public function onNamedEvent(array $payload): void
  {
    // ...
  }

  #[OnEvent(OrderCreated::class)]
  public function onTypedEvent(OrderCreated $event): void
  {
    // ...
  }
}

$events = new EventEmitter();
$provider = new ReflectiveListenerProvider($events);
$provider->register(new OrderListener());
```

Registering the same listener instance more than once through the reflective provider is safe. Duplicate method registrations for the same object instance are ignored.

Failure hooks
-------------

[](#failure-hooks)

By default, listener exceptions bubble up unless a listener is registered with `suppressErrors: true`.

If you want logging, metrics, or alerts around listener failures, attach a failure hook:

```
use Assegai\Events\EventEmitter;
use Assegai\Events\EventListenerFailure;

$events = new EventEmitter();

$events->onFailure(function (EventListenerFailure $failure): void {
  error_log(sprintf(
    'Event listener failed for %s (%s): %s',
    $failure->eventName,
    $failure->listenerId,
    $failure->throwable->getMessage(),
  ));
});
```

Failure hooks are observational. They run when a listener throws, but they do not replace the normal exception policy.

Durable delivery with an outbox
-------------------------------

[](#durable-delivery-with-an-outbox)

This package stays synchronous and in-process on purpose. If the work must survive process restarts or be retried later, record a durable event and let a relay publish it to a queue or broker.

The generic durable seam is `DurableOutboxStoreInterface`:

```
use Assegai\Events\Interfaces\DurableOutboxStoreInterface;
use Assegai\Events\Outbox\OutboxMessage;
use Assegai\Events\Outbox\OutboxRecorder;
use DateTimeImmutable;
use Throwable;

final class DatabaseOutboxStore implements DurableOutboxStoreInterface
{
  public function append(OutboxMessage $message): void
  {
    // persist to a database table, message log, or transactional outbox
  }

  public function leasePending(int $limit = 100, ?DateTimeImmutable $now = null): array
  {
    return [];
  }

  public function markDispatched(string|int $id, ?DateTimeImmutable $dispatchedAt = null): void
  {
  }

  public function markFailed(string|int $id, string|Throwable $error, ?DateTimeImmutable $retryAt = null): void
  {
  }
}

$outbox = new OutboxRecorder(new DatabaseOutboxStore());
$outbox->record('orders.created', ['orderId' => 42], ['source' => 'checkout']);
```

For Assegai projects there is also a ready-made bridge:

- `EventsOutboxModule`
- `OrmOutboxStore`
- `AssegaiOutboxRelayService`

```
use Assegai\Core\Attributes\Modules\Module;
use Assegai\Core\Consumers\MiddlewareConsumer;
use Assegai\Core\Interfaces\AssegaiModuleInterface;
use Assegai\Events\Bridge\Outbox\EventsOutboxModule;

#[Module(
  imports: [EventsOutboxModule::class],
)]
final class AppModule implements AssegaiModuleInterface
{
  public function configure(MiddlewareConsumer $consumer): void
  {
  }
}
```

Relay configuration lives in `assegai.json`:

```
{
  "events": {
    "outbox": {
      "queue": "rabbitmq.events",
      "batchSize": 100,
      "retryDelaySeconds": 60
    }
  }
}
```

Then drain the outbox onto the configured queue connection:

```
use Assegai\Core\Attributes\Injectable;
use Assegai\Events\Bridge\Outbox\AssegaiOutboxRelayService;

#[Injectable]
final class OutboxDrainService
{
  public function __construct(
    private readonly AssegaiOutboxRelayService $relay,
  )
  {
  }

  public function flush(): void
  {
    $this->relay->relayPending();
  }
}
```

One important boundary: the ORM-backed store gives you a real durable table and relay flow, but strict single-transaction outbox guarantees still depend on how your application manages database transactions. If you need the domain write and outbox append to share the exact same transaction, construct the store around a repository or manager that participates in that same unit of work.

Notes
-----

[](#notes)

- Listeners run synchronously in the current process.
- Wildcards are enabled by default.
- This package is designed to stay usable outside AssegaiPHP, so it does not require `assegaiphp/core`.
- In Assegai apps, `#[OnEvent(...)]` listeners should stay application-scoped. Request-scoped listeners are intentionally skipped during bootstrap registration.

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance88

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~15 days

Total

3

Last Release

60d ago

PHP version history (2 changes)0.7.0PHP &gt;=8.3

0.9.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/b56f1a86c97a44aa8b6e391bdfff3e41895f2262f6fd9295195806a068921e23?d=identicon)[amasiye](/maintainers/amasiye)

---

Top Contributors

[![amasiye](https://avatars.githubusercontent.com/u/5607605?v=4)](https://github.com/amasiye "amasiye (17 commits)")

---

Tags

eventsevent-emitterobserverassegai

###  Code Quality

TestsPest

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/assegaiphp-events/health.svg)

```
[![Health](https://phpackages.com/badges/assegaiphp-events/health.svg)](https://phpackages.com/packages/assegaiphp-events)
```

###  Alternatives

[doctrine/event-manager

The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.

6.0k517.6M148](/packages/doctrine-event-manager)[psr/event-dispatcher

Standard interfaces for event handling.

2.3k650.1M1.2k](/packages/psr-event-dispatcher)[evenement/evenement

Événement is a very simple event dispatching library for PHP

1.4k160.0M336](/packages/evenement-evenement)[laminas/laminas-eventmanager

Trigger and listen to events within a PHP application

1.0k71.7M250](/packages/laminas-laminas-eventmanager)[simshaun/recurr

PHP library for working with recurrence rules

1.6k16.7M51](/packages/simshaun-recurr)[chelout/laravel-relationship-events

Missing relationship events for Laravel

5252.4M17](/packages/chelout-laravel-relationship-events)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
