1: <?php
2:
3: /*
4: * Library to use PortBilling events with PSR-14 event dispatch
5: */
6:
7: namespace Porta\Psr14Event;
8:
9: use Psr\EventDispatcher\ListenerProviderInterface;
10: use Porta\Psr14Event\Event;
11:
12: /**
13: * Porta-Event specific ListenerProvider with extra features for Porta events
14: *
15: * Register event type patterns with register() methos and suppy the instance to
16: * PSR-14 dispatcher.
17: *
18: * @api
19: */
20: class EventListenerProvider implements ListenerProviderInterface
21: {
22:
23: const PATTERNS = 'patterns';
24: const HANDLERS = 'handlers';
25:
26: protected array $handlers = [];
27:
28: /**
29: * Registre set of patterns to match and set of handlers to call if any pattern match
30: *
31: * While it is possible to setup multiple patterns and multiple handlers in
32: * one record, please be ecouraged to use 'one pattern to multiple handlers'
33: * or 'multiple patterns to one handler' approach.
34: *
35: * If your configuration will allow to call a handler meltiple times because
36: * it listed in two and more register() calls, and patterns will math - the
37: * same handler will be called multiple times.
38: *
39: * @param string[] $patterns Array of patterns to match agains event type.
40: * If any of array match the event type - all the handlers will run in order
41: * of given
42: * @param mixed[] $handlers Array of handlers to run. Basically, it should ne array
43: * of callable, any item which is not callable will try to resolve to callable by
44: * resolveHandler(), which do nothing for this base class. Override it if you wish
45: * to resolve your definition into callable.
46: * @return self for chaining
47: * @api
48: */
49: public function register(array $patterns, array $handlers): self
50: {
51: $this->handlers[] = [
52: self::PATTERNS => $patterns,
53: self::HANDLERS => $handlers,
54: ];
55: return $this;
56: }
57:
58: public function getListenersForEvent(object $event): iterable
59: {
60: if ($event instanceof Event) {
61: foreach ($this->handlers as $handler) {
62: if ($event->isMatchPatterns($handler[self::PATTERNS])) {
63: yield from $this->yieldHandlers($handler[self::HANDLERS]);
64: }
65: }
66: }
67: }
68:
69: protected function yieldHandlers(array $handlers): iterable
70: {
71: foreach ($handlers as $handler) {
72: if (is_callable($handler)) {
73: yield $handler;
74: } else {
75: yield from $this->resolveHandler($handler);
76: }
77: }
78: }
79:
80: /**
81: * Method to override for add handler definitions other, that just callable
82: *
83: * Also may be used to catch and log wrong callable problems. Override this
84: * method, log $handler value and return [] for other handler work.
85: *
86: * @param mixed $handler Handler definition
87: * @return iterable Must yield callable
88: * @api
89: */
90: protected function resolveHandler($handler): iterable
91: {
92: return []; // Do nothing for basic ListenerProvider;
93: }
94: }
95: