ContainerAwareDispatcher   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 41
dl 0
loc 121
rs 10
c 0
b 0
f 0
wmc 19

5 Methods

Rating   Name   Duplication   Size   Complexity  
A addListener() 0 10 3
A dispatch() 0 18 3
A __construct() 0 13 4
A dispatchEvent() 0 17 4
A addSubscriber() 0 12 5
1
<?php
2
3
/*
4
 * event-symfony-event-dispatcher (https://github.com/phpgears/event-symfony-event-dispatcher).
5
 * Event bus with Symfony Event Dispatcher.
6
 *
7
 * @license MIT
8
 * @link https://github.com/phpgears/event-symfony-event-dispatcher
9
 * @author Julián Gutiérrez <[email protected]>
10
 */
11
12
declare(strict_types=1);
13
14
namespace Gears\Event\Symfony\Dispatcher;
15
16
use Gears\Event\EventHandler;
17
use Psr\Container\ContainerInterface;
18
use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyEventDispatcher;
19
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
20
use Symfony\Contracts\EventDispatcher\Event as SymfonyEvent;
21
22
class ContainerAwareDispatcher extends SymfonyEventDispatcher implements EventDispatcher
23
{
24
    /**
25
     * @var ContainerInterface
26
     */
27
    private $container;
28
29
    /**
30
     * ContainerAwareEventDispatcher constructor.
31
     *
32
     * @param ContainerInterface   $container
33
     * @param array<string, mixed> $listenersMap
34
     */
35
    public function __construct(ContainerInterface $container, array $listenersMap = [])
36
    {
37
        parent::__construct();
38
39
        $this->container = $container;
40
41
        foreach ($listenersMap as $eventName => $listeners) {
42
            if (!\is_array($listeners)) {
43
                $listeners = [$listeners];
44
            }
45
46
            foreach ($listeners as $listener) {
47
                $this->addListener($eventName, $listener);
48
            }
49
        }
50
    }
51
52
    /**
53
     * Adds an event subscriber.
54
     *
55
     * @param EventSubscriberInterface $subscriber
56
     */
57
    public function addSubscriber(EventSubscriberInterface $subscriber): void
58
    {
59
        foreach ($subscriber::getSubscribedEvents() as $eventName => $params) {
60
            if (!\is_array($params)) {
61
                $params = [$params];
62
            }
63
64
            foreach ($params as $listener) {
65
                if (\is_string($listener)) {
66
                    $this->addListener($eventName, $listener);
67
                } else {
68
                    $this->addListener($eventName, $listener[0], $listener[1] ?? 0);
69
                }
70
            }
71
        }
72
    }
73
74
    /**
75
     * Adds an event listener that listens on the specified events.
76
     *
77
     * @param string          $eventName
78
     * @param callable|string $listener
79
     * @param int             $priority
80
     */
81
    public function addListener($eventName, $listener, $priority = 0): void
82
    {
83
        if (!\is_string($listener)) {
84
            throw new \InvalidArgumentException(\sprintf(
85
                'Event handler must be a container entry, "%s" given',
86
                \is_object($listener) ? \get_class($listener) : \gettype($listener)
87
            ));
88
        }
89
90
        parent::addListener($eventName, $listener, $priority);
91
    }
92
93
    /**
94
     * Dispatches an event to all registered listeners.
95
     *
96
     * @param mixed $eventEnvelope
97
     *
98
     * @return SymfonyEvent
99
     */
100
    public function dispatch($eventEnvelope): SymfonyEvent
101
    {
102
        if ($eventEnvelope === null) {
103
            throw new \InvalidArgumentException('Dispatched event cannot be empty');
104
        }
105
106
        if (!$eventEnvelope instanceof EventEnvelope) {
107
            throw new \InvalidArgumentException(\sprintf(
108
                'Dispatched event must implement "%s", "%s" given',
109
                EventEnvelope::class,
110
                \get_class($eventEnvelope)
111
            ));
112
        }
113
114
        $eventListeners = $this->getListeners($eventEnvelope->getWrappedEvent()->getEventType());
115
        $this->dispatchEvent($eventListeners, $eventEnvelope);
116
117
        return $eventEnvelope;
118
    }
119
120
    /**
121
     * Dispatch event to registered listeners.
122
     *
123
     * @param string[]      $listeners
124
     * @param EventEnvelope $event
125
     */
126
    private function dispatchEvent(array $listeners, EventEnvelope $event): void
127
    {
128
        $dispatchEvent = $event->getWrappedEvent();
129
130
        foreach ($listeners as $listener) {
131
            /* @var EventHandler $handler */
132
            $handler = $this->container->get($listener);
133
134
            if (!$handler instanceof EventHandler) {
135
                throw new \RuntimeException(\sprintf(
136
                    'Event handler should implement "%s", "%s" given',
137
                    EventHandler::class,
138
                    \is_object($handler) ? \get_class($handler) : \gettype($handler)
139
                ));
140
            }
141
142
            $handler->handle($dispatchEvent);
143
        }
144
    }
145
}
146