Skip to content

Commit

Permalink
Refactor to v4, simplified, type-safe API
Browse files Browse the repository at this point in the history
  • Loading branch information
cspray committed May 30, 2024
1 parent 786c9cf commit 860bded
Show file tree
Hide file tree
Showing 41 changed files with 661 additions and 3,669 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.github export-ignore
test export-ignore
phpunit.xml.dist export-ignore
psalm.xml export-ignore
CONTRIBUTING.md export-ignore
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.phpunit.cache
.phpunit.result.cache
composer.lock
/vendor
/build
/docs/_site/
Expand Down
30 changes: 26 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
# Changelog

## Unreleased Changes
## v4.0.0

#### Added

- Provided tests for the `ListenerService` attribute, code coverage is not at 100%.
- Added the `Labrador\AsyncEvent\ListenerRemovableBasedOnHandleCount`
- Added template parameters where appropriate to more properly convey typing information
- Added a `Labrador\AsyncEvent\AbstractEvent` to more easily create domain events out of the box.
- Added a `Labrador\AsyncEvent\FinishedNotifier` to represent when a queued event has finished being emitted

#### Changed

- Renamed the `EventListener` attribute to `ListenerService`.
- Renamed `Labrador\AsyncEvent\EventEmitter` -> `Labrador\AsyncEvent\Emitter`
- Renamed `Labrador\AsyncEvent\AmpEventEmitter` -> `Labrador\AsyncEvent\AmpEmitter`
- Renamed `Labrador\AsyncEvent\Event::target()` -> `Labrador\AsyncEvent\Event::payload()`
- Changed the `Emitter::register(Listener)` method signature to `Emitter::register(string, Listener)` where the
first argument is the event name to register.
- Changed the `Emitter::queue(Event) : void` method signature to `Emitter::queue(Event) : FinishedNotifier` to allow
doing something when a queued event is finished being emitted without potentially blocking, negating the intent of a
queued fire & forget event.

#### Removed

- Removed `cspray/annotated-container` library. The functionality previously provided by these
- Removed the `Labrador\AsyncEvent\OneTimeListener`. Implement the `Labrador\AsyncEvent\ListenerRemovableBasedOnHandleCount` interface to
replicate this functionality.
- Removed the `Labrador\AsyncEvent\ListenerProvider` interface and implementations.
- Removed the `Labrador\AsyncEvent\Listener::setRegistration` method. Registration removal and association to the listener
is handled internally without leaking this detail to listeners.


## v3.0.0

#### Removed

- Removed `cspray/annotated-container` library. The functionality previously provided by the implementations using this
library are available at `labrador-kennel/async-event-autowire`

## v3.0.0-beta1

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2022 Charles Sprayberry
Copyright (c) 2024 Charles Sprayberry

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
63 changes: 37 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
![Unit Testing & Code Lint](https://github.com/labrador-kennel/async-event/workflows/Unit%20Testing%20&%20Code%20Lint/badge.svg)
![Latest Release](https://img.shields.io/github/v/release/labrador-kennel/async-event)

Labrador Async Event provides a way to emit semantic events on the [amphp/amp](https://amphp.org) event loop. It provides a robust set of features for working with an event system, including:
Labrador Async Event provides a way to emit semantic events on the [amphp/amp](https://amphp.org) event loop. It provides a robust set
of features for working with an event system, including:

- First-class representation of an event with the `Labrador\AsyncEvent\Event` interface.
- Events include a rich set of data; including the datetime the event was emitted, the target of the event, and a set of arbitrary metadata.
- Events include a rich set of data; including the datetime the event was emitted and a type-safe, object payload.
- First-class representation of an event listener with the `Labrador\AsyncEvent\Listener` interface.
- No more tracking arbitrary listener ids, remove listeners using an object-oriented API.
- Remove listeners using an object-oriented API.
- Emit fire & forget events that don't block current execution

## Installation

Expand All @@ -20,28 +22,37 @@ composer require labrador-kennel/async-event

## Usage Guide

> This guide details how to use Async Event v3+. The upgrade from v2 to v3 represented a major backwards compatibility break. If you're using Async Event v2 it is recommended to stay on that version until a migration plan can be developed.
To get started with Async Event you'll need to implement one or more Listeners, register them to an EventEmitter, and then emit an Event. First, let's take a look at implementing a Listener.
> This guide details how to use Async Event v4+. This version makes significant changes
> and moves towards a type-safe, stable API. Please review the README in the tag for
> the version you're using.
```php
<?php declare(strict_types=1);

namespace Labrador\AsyncEvent\Demo;

use Amp\Future;
use Labrador\AsyncEvent\AbstractListener;
use Labrador\AsyncEvent\AbstractEvent;
use Labrador\AsyncEvent\Event;
use Labrador\AsyncEvent\Listener;
use Labrador\CompositeFuture\CompositeFuture;

final class MyListener extends AbstractListener {
final class MyDomainObject {}

public function canHandle(string $eventName) : bool {
return $eventName === 'my-app.event';
/**
* @extends AbstractEvent<MyDomainObject>
*/
final class MyDomainEvent extends AbstractEvent {
public function __construct(MyDomainObject $object) {
parent::__construct('my-domain-event', $object);
}

}

/**
* @implements Listener<MyDomainObject>
*/
final class MyListener implements Listener {
public function handle(Event $event) : Future|CompositeFuture|null {
// do whatever you need to do when your handled event is emitted
return null;
}

Expand All @@ -55,21 +66,21 @@ Now, create an EventEmitter and register your Listener. Then emit an event!

namespace Labrador\AsyncEvent\Demo;

use Labrador\AsyncEvent\AmpEventEmitter;
use Labrador\AsyncEvent\StandardEvent;
use stdClass;
use Amp\CompositeException;use Labrador\AsyncEvent\AmpEmitter;

$emitter = new AmpEventEmitter();
$emitter = new AmpEmitter();

// You can remove the Listener later by calling $registration->remove()
$registration = $emitter->register(new MyListener());

// You should replace this with your own semantic event target
$eventTarget = new stdClass();

// Emit an event, returns a CompositeFuture with which you can decide how to wait for Listener futures to resolve
$emitter->emit(new StandardEvent('my-app.event', $eventTarget))->await();

// Emit an event on the _next tick_ of the event loop
$emitter->queue(new StandardEvent('my-app.event', $eventTarget));
$registration = $emitter->register('my-domain-event', new MyListener());
$myDomainObject = new MyDomainObject();

// Emit an event and call an await method on the CompositeFuture returned
$emitter->emit(new MyDomainEvent($myDomainObject))->await();

// Queue a fire & forget event, pass a callback to `finished()` if you want
// to know when the listeners for queued event are finished
$emitter->queue(new MyDomainEvent($myDomainObject))
->finished(
static fn(?CompositeException $exception, array $values) => doSomething()
);
```
16 changes: 13 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@
"code-lint": "vendor/bin/labrador-cs src/ test/",
"test": "vendor/bin/phpunit"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/cspray/phpunit-util"
}
],
"require": {
"php": "^8.1",
"php": "^8.2",
"amphp/amp": "~v3.0",
"labrador-kennel/composite-future": "^1.2"
},
"require-dev": {
"amphp/phpunit-util": "~v3.0",
"amphp/phpunit-util": "dev-phpunit-10-support",
"cspray/labrador-coding-standard": "0.2.0",
"phpunit/phpunit": "^9.5",
"mockery/mockery": "^1.6",
"phpunit/phpunit": "^10",
"psalm/phar": "^5.6",
"roave/security-advisories": "dev-latest"
},
Expand All @@ -36,5 +43,8 @@
"psr-4": {
"Labrador\\AsyncEvent\\Test\\": "test/"
}
},
"suggest": {
"labrador-kennel/async-event-autowire": "If using cspray/annotated-container will allow you to automatically register Listener implementations into your Emitter."
}
}
Loading

0 comments on commit 860bded

Please sign in to comment.