Completed
Push — master ( 5b0212...47d481 )
by Julián
09:40
created

ContainerAwareDispatcher::addSubscriber()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4222
c 0
b 0
f 0
cc 5
nc 7
nop 1
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;
15
16
use Gears\Event\EventHandler;
17
use Psr\Container\ContainerInterface;
18
use Symfony\Component\EventDispatcher\Event as SymfonyEvent;
19
use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyEventDispatcher;
20
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
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
        $this->container = $container;
38
39
        foreach ($listenersMap as $eventName => $listeners) {
40
            if (!\is_array($listeners)) {
41
                $listeners = [$listeners];
42
            }
43
44
            foreach ($listeners as $listener) {
45
                $this->addListener($eventName, $listener);
46
            }
47
        }
48
    }
49
50
    /**
51
     * Adds an event subscriber.
52
     *
53
     * @param EventSubscriberInterface $subscriber
54
     */
55
    public function addSubscriber(EventSubscriberInterface $subscriber): void
56
    {
57
        foreach ($subscriber::getSubscribedEvents() as $eventName => $params) {
58
            if (!\is_array($params)) {
59
                $params = [$params];
60
            }
61
62
            foreach ($params as $listener) {
63
                if (\is_string($listener)) {
64
                    $this->addListener($eventName, $listener);
65
                } else {
66
                    $this->addListener($eventName, $listener[0], $listener[1] ?? 0);
67
                }
68
            }
69
        }
70
    }
71
72
    /**
73
     * Adds an event listener that listens on the specified events.
74
     *
75
     * @param string          $eventName
76
     * @param callable|string $listener
77
     * @param int             $priority
78
     */
79
    public function addListener($eventName, $listener, $priority = 0): void
80
    {
81
        if (!\is_string($listener)) {
82
            throw new \InvalidArgumentException(\sprintf(
83
                'Event handler must be a container entry, %s given',
84
                \is_object($listener) ? \get_class($listener) : \gettype($listener)
85
            ));
86
        }
87
88
        parent::addListener($eventName, $listener, $priority);
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function dispatch($eventName, SymfonyEvent $event = null): SymfonyEvent
95
    {
96
        if ($event === null) {
97
            throw new \InvalidArgumentException('Dispatched event cannot be empty');
98
        }
99
100
        if (!$event instanceof EventEnvelope) {
101
            throw new \InvalidArgumentException(\sprintf(
102
                'Dispatched event must implement %s, %s given',
103
                EventEnvelope::class,
104
                \get_class($event)
105
            ));
106
        }
107
108
        $this->dispatchEvent($this->getListeners($eventName), $event);
109
110
        return $event;
111
    }
112
113
    /**
114
     * Dispatch event to registered listeners.
115
     *
116
     * @param string[]      $listeners
117
     * @param EventEnvelope $event
118
     */
119
    private function dispatchEvent(array $listeners, EventEnvelope $event): void
120
    {
121
        $dispatchEvent = $event->getWrappedEvent();
122
123
        foreach ($listeners as $listener) {
124
            /* @var EventHandler $handler */
125
            $handler = $this->container->get($listener);
126
127
            if (!$handler instanceof EventHandler) {
128
                throw new \RuntimeException(\sprintf(
129
                    'Event handler should implement %s, %s given',
130
                    EventHandler::class,
131
                    \is_object($handler) ? \get_class($handler) : \gettype($handler)
132
                ));
133
            }
134
135
            $handler->handle($dispatchEvent);
136
        }
137
    }
138
}
139