Events
Events let one part of your application announce that something happened without naming everything that should react to it.
Event.listen<PostPublished>(SendPostPublishedMail().call);
await event(PostPublished(postId: 42));Defining Events
Generate an event with Sesh:
maat make:event PostPublishedAn event is a plain Dart object carrying the data its listeners need:
import 'package:maat/maat.dart';
class PostPublished with Dispatchable { PostPublished({required this.postId});
final int postId;}Dispatchable is optional. It adds an instance dispatch() method; the
event() helper and Event.dispatch() work with any object.
Defining Listeners
maat make:listener SendPostPublishedMail --event=PostPublishedimport 'package:maat/maat.dart';
import '../events/post_published.dart';
class SendPostPublishedMail extends Listener<PostPublished> { @override Future<void> handle(PostPublished event) async { final post = await Post.query().findOrFail(event.postId); final author = await post.user().get(); if (author != null) { await Mail.to(author.email).send(PostPublishedMail(post)); } }}Closures work anywhere a listener class does:
Event.listen<PostPublished>( (event) => Log.info('post.published id=${event.postId}'),);Registering Listeners
Register listeners in a service provider’s boot() method, after every
application binding exists:
class AppServiceProvider extends ServiceProvider { AppServiceProvider(super.app);
@override void boot() { Event.listen<PostPublished>(SendPostPublishedMail().call); Event.listen<PostPublished>(NotifyPostAuthor().call); }}Listeners run sequentially in registration order, and asynchronous listeners are awaited before the next listener starts.
Dispatching Events
All three forms use the same application dispatcher:
await event(PostPublished(postId: 42));await Event.dispatch(PostPublished(postId: 42));await PostPublished(postId: 42).dispatch();dispatch() returns the listener responses in order. A listener returning
false stops propagation, and its false response is not added to the list.
Event.listen<PostPublished>((event) { if (event.postId < 1) return false;});Event.until() stops at the first non-null response and returns it:
final allowed = await Event.until(PostPublished(postId: 42));if (allowed == false) return;Wildcards and Interfaces
Listener matching uses Dart’s is operator. An interface listener sees every
implementation, while an Object listener sees every event:
Event.listen<Auditable>((event) => audit.record(event));Event.listen<Object>((event) => Log.debug('event: ${event.runtimeType}'));Subscribers
A subscriber registers several related listeners together:
class PostEventSubscriber extends EventSubscriber { @override void subscribe(Dispatcher events) { events.listen<PostPublished>(_published); events.listen<PostArchived>(_archived); }
Future<void> _published(PostPublished event) async {} Future<void> _archived(PostArchived event) async {}}
Event.subscribe(PostEventSubscriber());Inspecting and Removing Listeners
Event.hasListeners<PostPublished>();Event.forget<PostPublished>();hasListeners<E>() includes listeners registered for Object.
forget<E>() removes listeners registered for exactly E.
Testing
Event.fake() records events instead of running their listeners. See
Testing — Faking Events.
Queued listeners, automatic event discovery, and event:list are not included.
Listeners run in the current isolate; queues can add deferred delivery later.