Skip to content

Commit

Permalink
tidying up some loose ends
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettw committed Nov 24, 2024
1 parent 94aa57c commit a3fcafb
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 74 deletions.
1 change: 0 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@ trim_trailing_whitespace = false

[**/*.{yml,yaml,yml.dist}]
indent_size = 2
3
33 changes: 29 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
Venue
======
# Venue

Venue is a full-featured, [PSR-14](http://www.php-fig.org/psr/psr-14/) compliant event library for PHP, combining the Mediator and Observer patterns.
Venue is a full-featured, [PSR-14](http://www.php-fig.org/psr/psr-14/)-compliant event library for PHP, combining the Mediator and Observer patterns.
It includes an event dispatcher and a basic listener provider, as per the spec, and adds listener collections and
other variations on listener providers to meet special needs.

Currently in the middle of a major refactoring so documentation and tests are incomplete.

### Inspired by
- https://github.com/DavidRockin/Podiya
- https://github.com/yiisoft/event-dispatcher

### Planned features
- Event/listener ordering
- Consider dispatcher mechanism for error tracking/debugging
- Support async event processing via ListenerProviders that interface with MQs/DBs

### Future inspiration to be taken from:
- https://symfony.com/doc/current/event_dispatcher.html (messenger?)
- https://laravel.com/docs/11.x/events (queues?)
- https://docs.laminas.dev/laminas-eventmanager/
- https://event.thephpleague.com/
- https://github.com/crell/tukio
- https://hive.blog/php/@crell/psr-14-being-a-good-provider
- https://github.com/phoole/event
- https://github.com/pleets/php-event-dispatcher
- https://github.com/Superbalist/php-pubsub
- https://github.com/phly/phly-event-dispatcher
- https://packagist.org/packages/phpactor/phly-event-dispatcher
- https://github.com/circli/event-dispatcher
- https://github.com/bytic/event-dispatcher
- https://github.com/rbergDrox/pinoven-event-dispatcher
- https://github.com/bmack/kart-composer-plugin

## Install
```bash
composer require garrettw/venue
Expand Down Expand Up @@ -46,7 +71,7 @@ $event->data = 'some string';
$dispatcher->dispatch($event);
```

## Creating Your Own Event Classes
## Creating Event Classes
Venue provides a few interfaces and traits you may want to use when writing
event classes.

Expand Down
25 changes: 0 additions & 25 deletions TODO.md

This file was deleted.

4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "garrettw/venue",
"type": "library",
"description": "PHP event library following PSR-14 and the Mediator/Observer behavioral patterns",
"keywords": ["event","listener","hook","mediator","publish-subscribe","observer","psr-14"],
"description": "PHP event-dispatcher library following PSR-14 and the Mediator/Observer patterns",
"keywords": ["event","listener","dispatcher","hook","mediator","publish-subscribe","observer","psr-14"],
"homepage": "https://github.com/garrettw/venue",
"license": "MIT",
"require": {
Expand Down
2 changes: 0 additions & 2 deletions src/Contracts/Hook.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

namespace Venue\Contracts;

/**
Expand Down
5 changes: 3 additions & 2 deletions src/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ public function dispatch(object $event): object
}
$listener($event);
} catch (\Throwable $e) {
// only dispatch a Throwable the first time around
// otherwise it could result in an endless loop
// only dispatch a Throwable the first time around -
// otherwise it could result in an endless loop in the
// case where a throwable listener throws an exception
if (!($event instanceof \Throwable)) {
$this->dispatch($e);
}
Expand Down
21 changes: 12 additions & 9 deletions src/ListenerCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function add(callable $listener): static
/**
* Remove all listeners for a certain event name.
*/
public function detachAll(string $eventName): void
public function removeAllForEvent(string $eventName): void
{
unset($this->listeners[$eventName]);
}
Expand All @@ -65,28 +65,31 @@ public function detachAll(string $eventName): void
* @param callable $listener The exact listener that was originally attached
* @param string $eventName The event it is listening for, if different from the parameter's typehint
*/
public function detach(callable $listener, string $eventName = '')
public function remove(callable $listener, string $eventName = '')
{
// Detach from manual event name
$key = array_search($listener, $this->listeners[$eventName]);
if ($key !== false) {
unset($this->listeners[$eventName][$key]);
// If there are no more listeners, remove the event
if (empty($this->listeners[$eventName])) {
$this->detachAll($eventName);
$this->removeAllForEvent($eventName);
}
return;
}

// Detach from all event class names
foreach ($this->getCallableParamTypes($listener) as $paramType) {
$key = array_search($listener, $this->listeners[$paramType]); // todo: check param 2 for existence
if ($key !== false) {
if (
!empty($this->listeners[$paramType])
&& ($key = array_search($listener, $this->listeners[$paramType])) !== false
) {
unset($this->listeners[$paramType][$key]);
// If there are no more listeners, remove the event
if (empty($this->listeners[$paramType])) {
$this->detachAll($paramType);
}
}

// If there are no more listeners, remove the event
if (empty($this->listeners[$paramType])) {
unset($this->listeners[$paramType]);
}
}
}
Expand Down
46 changes: 21 additions & 25 deletions src/TaggedListenerCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ class TaggedListenerCollection
/**
* @param array $listeners Takes the form of: ['tagName' => ['EventClass' => [callable, ...], ...], ...]
*/
public function __construct(private array $listeners = [])
{
}
public function __construct(private array $listeners = []) {}

/**
* Get listeners for the tag name specified.
*
* @param string $tag
* @return iterable<callable> listeners
*/
public function getListenersForTag(string $tag): iterable
{
return $this->listeners[$tag] ?? [];
Expand All @@ -26,21 +30,10 @@ public function getListenersForTag(string $tag): iterable
*
* @param string $tag
* @param callable $listener Must accept one typehinted parameter: an event object
* @param string|array $events The event(s) it will listen for, if different from the parameter's typehint
* @throws InvalidArgumentException if listener validation fails
*/
public function add(string $tag, callable $listener, string|array $events = ''): static
public function add(string $tag, callable $listener): static
{
if (!empty($events)) {
if (is_string($events)) {
$events = [$events];
}
foreach ($events as $eventName) {
$this->listeners[$tag][$eventName][] = $listener;
}
return $this;
}

$matched = false;
foreach ($this->getCallableParamTypes($listener) as $paramType) {
$this->listeners[$tag][$paramType][] = $listener;
Expand All @@ -56,9 +49,9 @@ public function add(string $tag, callable $listener, string|array $events = ''):
}

/**
* Remove all listeners for a certain tag and/or event name.
* Remove all listeners for a certain tag or an event name under a certain tag.
*/
public function detachAll(string $tag, string $eventName = ''): void
public function removeAllForTag(string $tag, string $eventName = ''): void
{
if (empty($eventName)) {
unset($this->listeners[$tag]);
Expand All @@ -74,28 +67,31 @@ public function detachAll(string $tag, string $eventName = ''): void
* @param callable $listener The exact listener that was originally attached
* @param string $eventName The event it is listening for, if different from the parameter's typehint
*/
public function detach(string $tag, callable $listener, string $eventName = '')
public function remove(string $tag, callable $listener, string $eventName = '')
{
// Detach from manual event name
$key = array_search($listener, $this->listeners[$tag][$eventName]);
if ($key !== false) {
unset($this->listeners[$tag][$eventName][$key]);
// If there are no more listeners, remove the event
if (empty($this->listeners[$tag][$eventName])) {
$this->detachAll($tag, $eventName);
$this->removeAllForTag($tag, $eventName);
}
return;
}

// Detach from all event class names
foreach ($this->getCallableParamTypes($listener) as $paramType) {
$key = array_search($listener, $this->listeners[$tag][$paramType]); // todo: check param 2 for existence
if ($key !== false) {
if (
!empty($this->listeners[$tag][$paramType])
&& ($key = array_search($listener, $this->listeners[$tag][$paramType])) !== false
) {
unset($this->listeners[$tag][$paramType][$key]);
// If there are no more listeners, remove the event
if (empty($this->listeners[$tag][$paramType])) {
$this->detachAll($tag, $paramType);
}
}

// If there are no more listeners, remove the event
if (empty($this->listeners[$tag][$paramType])) {
unset($this->listeners[$tag][$paramType]);
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/Traits/CanBeStopped.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

namespace Venue\Traits;

/**
Expand Down
2 changes: 0 additions & 2 deletions src/Traits/CanStopPropagation.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

namespace Venue\Traits;

/**
Expand Down

0 comments on commit a3fcafb

Please sign in to comment.