Skip to content

Commit 4fbc535

Browse files
committed
docs: Provides documentation of all functionality
1 parent 4da978e commit 4fbc535

File tree

6 files changed

+295
-5
lines changed

6 files changed

+295
-5
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ Run the following to install this library:
1313
```bash
1414
$ composer require phly/phly-event-dispatcher
1515
```
16+
17+
## Documentation
18+
19+
Documentation is available in the [docs/book/](docs/book/) tree.

docs/book/dispatcher.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# The EventDispatcher
2+
3+
`Phly\EventDispatcher\EventDispatcher` provides a
4+
`Psr\EventDispatcher\EventDispatcherInterface` implementation. It accepts a
5+
`Psr\EventDispatcher\ListenerProviderInterface` to its constructor, and, when
6+
dispatching events, queries the provider for listeners to notify.
7+
8+
At its most basic, usage looks like this:
9+
10+
```php
11+
use Phly\EventDispatcher\EventDispatcher;
12+
use Phly\EventDispatcher\ListenerProvider\AttachableListenerProvider;
13+
14+
$provider = new AttachableListenerProvider();
15+
$provider->listen(SomeEvent::class, function (SomeEvent $event) : void {
16+
// do something with the event
17+
});
18+
19+
$dispatcher = new EventDispatcher($provider);
20+
21+
$dispatcher->dispatch(new SomeEvent());
22+
```
23+
24+
## ErrorEmittingDispatcher
25+
26+
Occasionally, listeners may raise exceptions. PSR-14 indicates that these should
27+
be thrown verbatim from the dispatcher. However, what if you'd like to trigger
28+
an event when an error occurs, such as occurs with Node's event loop?
29+
30+
To handle this scenario, the library provides `Phly\EventDispatcher\ErrorEmittingDispatcher`.
31+
This implementation catches any exception or throwable, and then casts it to a
32+
special `Phly\EventDispatcher\ErrorEvent`, which it then dispatches. This
33+
allows you to add listeners to the `ErrorEvent` class in order to receive
34+
notifications about errors!
35+
36+
The `ErrorEvent` exposes three methods for retrieving information about the
37+
error:
38+
39+
- `getEvent()` will return the original event that was dispatched when the error
40+
was caught.
41+
- `getListener()` will return the listener that raised the error.
42+
- `getThrowable() `will return the throwable that was raised.
43+
44+
As an example:
45+
46+
```php
47+
use Phly\EventDispatcher\ErrorEmittingDispatcher;
48+
use Phly\EventDispatcher\ErrorEvent;
49+
use Phly\EventDispatcher\ListenerProvider\AttachableListenerProvider;
50+
use Psr\Logger\LoggerInterface;
51+
52+
$provider = new AttachableListenerProvider();
53+
$provider->listen(SomeEvent::class, function (SomeEvent $event) : void {
54+
// Raise an exception
55+
throw new RuntimeException('Could not handle the event!');
56+
});
57+
58+
// @var LoggerInterface $logger
59+
$provider->listen(ErrorEvent::class, function (ErrorEvent $event) use ($logger) : void {
60+
$logger->error('Error processing event of type {type}: {message}', [
61+
'type' => get_class($event->getEvent()),
62+
'message' => $event->getThrowable()->getMessage(),
63+
]);
64+
});
65+
66+
$dispatcher = new EventDispatcher($provider);
67+
68+
$dispatcher->dispatch(new SomeEvent());
69+
```
70+
71+
The exception will still be thrown; however, it will also be logged, due to our
72+
`ErrorEvent` listener!

docs/book/intro.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1-
# event-dispatcher
1+
# phly-event-dispatcher
22

3-
This component provides ...
3+
This component provides a [PSR-14](https://github.com/php-fig/fig-standards/blob/eab4613522cfb585ed7fdc13e501f78220886a02/proposed/event-dispatcher.md)
4+
implementation, specifically implementing each of:
5+
6+
- `Psr\EventDispatcher\EventDispatcherInterface`
7+
- `Psr\EventDispatcher\ListenerProviderInterface`
8+
9+
The package provides a standard event dispatcher, as well as one that provides
10+
error handling. It also provides a number of additional listener provider
11+
interfaces, as well as implementations, spanning basic attachment, prioritized
12+
attachment, reflection-based attachment, and more.
13+
14+
On top of these facilities, it provides a number of additional features,
15+
including lazy-loading listeners.

docs/book/lazy-listeners.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Lazy Listeners
2+
3+
To save on the cost of loading potentially expensive objects, you may want to
4+
_lazy load_ listeners. For the purposes of this library, lazy loading refers
5+
specifically to retrieving a listener from a [PSR-11 dependency injection
6+
container](https://www.php-fig.org/psr/psr-11/) at the point of listener
7+
invocation.
8+
9+
The library provides `Phly\EventDispatcher\LazyListener` to facilitate such
10+
operations. The class has a constructor that accepts a PSR-11 container, the
11+
string service name to pull from the container, and, optionally, a method to
12+
call on that service (if none is provided, it assumes the class is invokable).
13+
14+
As an example:
15+
16+
```php
17+
$listener = new LazyListener($container, ActualListener::class);
18+
```
19+
20+
## lazyListener()
21+
22+
As a shortcut, we also provide the function
23+
`Phly\EventDispatcher\lazyListener()`, which accepts the same arguments as the
24+
`LazyListener` constructor. This is particularly useful when attaching
25+
listeners:
26+
27+
```php
28+
use function Phly\EventManager\lazyListener;
29+
30+
$provider->listen(lazyListener($container, ActualListener::class));
31+
```

docs/book/listener-providers.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Listener Providers
2+
3+
Listener providers aggregate listeners, and allow a [dispatcher](dispatcher.md)
4+
to retrieve all listeners capable of listening to the event it is currently
5+
dispatching.
6+
7+
This library provides several additional provider interfaces, as well as
8+
implementations, for common listener registration patterns.
9+
10+
## Basic listener attachment
11+
12+
`Phly\EventDispatcher\ListenerProvider\AttachableListenerProviderInterface`
13+
extends `Psr\EventDispatcher\ListenerProviderInterface` and defines a very basic
14+
attachment pattern:
15+
16+
```php
17+
public function listen(string $eventName, callable $listener) : void
18+
```
19+
20+
The library provides an implementation via
21+
`Phly\EventDispatcher\ListenerProvider\AttachableListenerProvider`.
22+
23+
## Positionable attachment
24+
25+
`Phly\EventDispatcher\ListenerProvider\PositionalListenerProviderInterface`
26+
extends `AttachableListenerProviderInterface`, and adds the following two
27+
methods:
28+
29+
```php
30+
public function listenAfter(string $listenerTypeToAppend, string $eventType, callable $newListener) : void;
31+
public function listenBefore(string $listenerTypeToPrepend, string $eventType, callable $newListener) : void;
32+
```
33+
34+
In both cases, the implication is that implementations will append or prepend
35+
the new listener to the last or first listener that matches the type of the
36+
first argument.
37+
38+
As an example,
39+
40+
```php
41+
$provider->listenAfter(
42+
SendMailListener::class,
43+
ContactEvent::class,
44+
lazyListener($container, LoggingListener::class)
45+
)
46+
```
47+
48+
would add a new `LoggingListener` to the provider, to execute after any
49+
previously registered `SendMailListener` instances.
50+
51+
> See the chapter on [lazy listeners](lazy-listeners.md) for information on the
52+
> `lazyListener()` function.
53+
54+
This library does not currently provide any implementations of this interface.
55+
56+
## Prioritized attachment
57+
58+
`Phly\EventDispatcher\ListenerProvider\PrioritizedListenerProviderInterface`
59+
extends the PSR-14 `ListenerProviderInterface`, and defines a single method for
60+
attaching listeners:
61+
62+
```php
63+
public function listen(string $eventType, callable $listener, int $priority = 1) : void;
64+
```
65+
66+
Priority values are expected to follow the same behavior as `SplPriorityQueue`:
67+
larger values should execute first, while negative values should execute last.
68+
Listeners registered at the same priority should execute in the order in which
69+
they are attached to the provider.
70+
71+
As an example:
72+
73+
```php
74+
$provider = new PrioritizedListenerProvider();
75+
76+
class SomeEvent
77+
{
78+
public $counter = [];
79+
}
80+
81+
$factory = function (int $index) : callable {
82+
return function (object $event) use ($index) : void {
83+
$event->counter[] = $index;
84+
};
85+
};
86+
87+
$provider->listen(SomeEvent::class, $factory(1));
88+
$provider->listen(SomeEvent::class, $factory(2), -100);
89+
$provider->listen(SomeEvent::class, $factory(3), 100);
90+
91+
$dispatcher = new EventDispatcher($provider);
92+
93+
var_export($dispatcher->dispatch(new SomeEvent()));
94+
/*
95+
array (
96+
0 => 3,
97+
1 => 1,
98+
2 => 2,
99+
)
100+
*/
101+
```
102+
103+
This library provides an implementation via the class
104+
`Phly\EventDispatcher\ListenerProvider\PrioritizedListenerProvider`.
105+
106+
## Randomized attachment
107+
108+
If you do not care what order listeners are called in, and, in fact, want to
109+
enforce that the order is random, you can use
110+
`Phly\EventDispatcher\ListenerProvider\RandomizedListenerProvider`. This class
111+
defines the same `listen()` method as the `AttachableListenerProvider` detailed
112+
in an earlier section, but has a `getListenersForEvent()` method that randomizes
113+
the order in which listeners are returned during iteration.
114+
115+
## Reflection-based attachment
116+
117+
Since events are objects, one way to identify if a listener can listen to a
118+
given event is to _reflect_ on its argument, to see what type it accepts.
119+
This package defines an interface for providers that can do this, via
120+
`Phly\EventDispatcher\ListenerProvider\ReflectableListenerProviderInterface`:
121+
122+
```php
123+
public function listen(callable $listener, string $eventType = null) : void;
124+
```
125+
126+
When called with a single argument, implementations are expected to use
127+
reflection to determine which event type(s) the listener can accept. As an
128+
example:
129+
130+
```php
131+
$provider = new ReflectionBasedListenerProvider();
132+
133+
class SomeEvent
134+
{
135+
}
136+
137+
$listener = function (SomeEvent $event) : void {
138+
// do something
139+
};
140+
141+
$provider->listen($listener);
142+
143+
// This will dispatch $listener:
144+
$dispatcher->dispatch(new SomeEvent());
145+
```
146+
147+
The package provides an implementation via `Phly\EventDispatcher\ListenerProvider\ReflectionBasedListenerProvider`.
148+
149+
## Provider aggregation
150+
151+
You may want to allow multiple providers in your application, but still have a
152+
single dispatcher. `Phly\EventDispatcher\ListenerProvider\ListenerProviderAggregate`
153+
allows aggregating multiple providers into a single one, which will then loop
154+
through each to yield listeners.
155+
156+
```php
157+
$nonPrioritized = new AttachableListenerProvider();
158+
$prioritized = new PrioritizedListenerProvider();
159+
$reflected = new ReflectionBasedListenerProvider();
160+
161+
$provider = new ListenerProviderAggregate();
162+
$provider->attach($nonPrioritized);
163+
$provider->attach($prioritized);
164+
$provider->attach($reflected);
165+
166+
$dispatcher = new EventDispatcher($provider);
167+
```

mkdocs.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
docs_dir: docs/book
22
site_dir: docs/html
33
pages:
4-
- index.md
4+
- Home: index.md
55
- Introduction: intro.md
6-
site_name: Component Name Goes Here
6+
- Reference:
7+
- "Event Dispatcher": dispatcher.md
8+
- "Listener Providers": listener-providers.md
9+
- "Lazy Listeners": lazy-listeners.md
10+
site_name: 'phly-event-dispatcher'
711
site_description: 'Component Description goes here'
812
repo_url: 'https://github.com/phly/event-dispatcher'
9-
copyright: 'Copyright (c) 2018 <a href="https://www.zend.com/">Zend Technologies USA Inc.</a>'
13+
copyright: 'Copyright (c) <a href="https://mwop.net/">Matthew Weier O\'Phinney</a>'

0 commit comments

Comments
 (0)