diff --git a/.editorconfig b/.editorconfig index f76123f..e8e3e4c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,4 +16,3 @@ trim_trailing_whitespace = false [**/*.{yml,yaml,yml.dist}] indent_size = 2 -3 \ No newline at end of file diff --git a/README.md b/README.md index 20b93cb..58db076 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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. diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 548db86..0000000 --- a/TODO.md +++ /dev/null @@ -1,25 +0,0 @@ -Check out other libs -- https://github.com/phoole/event -- https://github.com/pleets/php-event-dispatcher -- https://github.com/yiisoft/event-dispatcher -- https://github.com/Superbalist/php-pubsub - -Concerns: -- event ordering -- should the event manage pipeline return values? -- should the hub provide more mechanisms for error tracking and debugging? -- sync/async event processing (drivers; rabbitmq, kafka, sqs, activemq,) -- laravel (queues?) https://laravel.com/docs/11.x/events -- symfony (messenger?) https://symfony.com/doc/current/event_dispatcher.html -- https://docs.zendframework.com/zend-eventmanager/ -- https://event.thephpleague.com/ -- https://github.com/crell/tukio -- https://github.com/phly/phly-event-dispatcher - - https://packagist.org/packages/phpactor/phly-event-dispatcher -- https://github.com/bmack/kart-composer-plugin -- https://github.com/circli/event-dispatcher -- https://github.com/bytic/event-dispatcher -- https://github.com/rbergDrox/pinoven-event-dispatcher - -Also see: -- https://hive.blog/php/@crell/psr-14-being-a-good-provider diff --git a/composer.json b/composer.json index 80f8b3f..b3cea03 100644 --- a/composer.json +++ b/composer.json @@ -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": { diff --git a/src/Contracts/Hook.php b/src/Contracts/Hook.php index dc0cf92..cb4cc98 100644 --- a/src/Contracts/Hook.php +++ b/src/Contracts/Hook.php @@ -1,7 +1,5 @@ dispatch($e); } diff --git a/src/ListenerCollection.php b/src/ListenerCollection.php index 6e7dc2d..792ded9 100644 --- a/src/ListenerCollection.php +++ b/src/ListenerCollection.php @@ -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]); } @@ -65,7 +65,7 @@ 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]); @@ -73,20 +73,23 @@ public function detach(callable $listener, string $eventName = '') 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]); } } } diff --git a/src/TaggedListenerCollection.php b/src/TaggedListenerCollection.php index 083bab7..44b3162 100644 --- a/src/TaggedListenerCollection.php +++ b/src/TaggedListenerCollection.php @@ -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 listeners + */ public function getListenersForTag(string $tag): iterable { return $this->listeners[$tag] ?? []; @@ -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; @@ -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]); @@ -74,7 +67,7 @@ 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]); @@ -82,20 +75,23 @@ public function detach(string $tag, callable $listener, string $eventName = '') 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]); } } } diff --git a/src/Traits/CanBeStopped.php b/src/Traits/CanBeStopped.php index 21a37a4..b3b8497 100644 --- a/src/Traits/CanBeStopped.php +++ b/src/Traits/CanBeStopped.php @@ -1,7 +1,5 @@