Passed
Push — master ( fefda9...498815 )
by Rustam
01:23
created

EventDispatcherProvider   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Test Coverage

Coverage 90.7%

Importance

Changes 0
Metric Value
eloc 41
dl 0
loc 89
ccs 39
cts 43
cp 0.907
rs 10
c 0
b 0
f 0
wmc 17

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A isCallable() 0 18 6
B register() 0 57 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Event;
6
7
use Psr\Container\ContainerExceptionInterface;
8
use Psr\EventDispatcher\EventDispatcherInterface;
9
use Psr\EventDispatcher\ListenerProviderInterface;
10
use Yiisoft\Di\Container;
11
use Yiisoft\Di\Support\ServiceProvider;
12
use Yiisoft\EventDispatcher\Dispatcher\Dispatcher;
13
use Yiisoft\EventDispatcher\Provider\ListenerCollection;
14
use Yiisoft\EventDispatcher\Provider\Provider;
15
use Yiisoft\Injector\Injector;
16
17
final class EventDispatcherProvider extends ServiceProvider
18
{
19
    private array $eventListeners;
20
21
    /**
22
     * @param array $eventListeners Event listener list in format ['eventName1' => [$listener1, $listener2, ...]]
23
     */
24 5
    public function __construct(array $eventListeners)
25
    {
26 5
        $this->eventListeners = $eventListeners;
27 5
    }
28
29 5
    public function register(Container $container): void
30
    {
31 5
        $listenerCollection = new ListenerCollection();
32
33 5
        $injector = new Injector($container);
34
35 5
        foreach ($this->eventListeners as $eventName => $listeners) {
36 5
            if (!is_string($eventName)) {
37 1
                throw new InvalidEventConfigurationFormatException(
38 1
                    'Incorrect event listener format. Format with event name must be used.'
39
                );
40
            }
41
42 4
            if (!is_array($listeners)) {
43 1
                $type = $this->isCallable($listeners, $container) ? 'callable' : gettype($listeners);
44
45 1
                throw new InvalidEventConfigurationFormatException(
46 1
                    "Event listeners for $eventName must be an array, $type given."
47
                );
48
            }
49
50 3
            foreach ($listeners as $callable) {
51
                /** @psalm-suppress InvalidCatch */
52
                try {
53 3
                    if (!$this->isCallable($callable, $container)) {
54 1
                        $type = gettype($callable);
55
56 1
                        throw new InvalidListenerConfigurationException(
57 3
                            "Listener must be a callable, $type given."
58
                        );
59
                    }
60 1
                } catch (ContainerExceptionInterface $exception) {
61
                    throw new InvalidListenerConfigurationException(
62
                        "Could not instantiate event listener or listener class has invalid configuration.",
63
                        0,
64
                        $exception
65
                    );
66
                }
67
68 2
                $listener = static function (object $event) use ($injector, $callable, $container) {
69 1
                    if (is_array($callable) && !is_object($callable[0])) {
70
                        $callable = [$container->get($callable[0]), $callable[1]];
71
                    }
72
73 1
                    return $injector->invoke($callable, [$event]);
74 2
                };
75 2
                $listenerCollection = $listenerCollection->add($listener, $eventName);
76
            }
77
        }
78
79 2
        $provider = new Provider($listenerCollection);
80
81
        /** @psalm-suppress InaccessibleMethod */
82 2
        $container->set(ListenerProviderInterface::class, $provider);
83
84
        /** @psalm-suppress InaccessibleMethod */
85 2
        $container->set(EventDispatcherInterface::class, Dispatcher::class);
86 2
    }
87
88 4
    private function isCallable($definition, Container $container): bool
89
    {
90 4
        if (is_callable($definition)) {
91 2
            return true;
92
        }
93
94
        if (
95 3
            is_array($definition)
96 3
            && array_keys($definition) === [0, 1]
97 3
            && is_string($definition[0])
98 3
            && $container->has($definition[0])
99
        ) {
100 1
            $object = $container->get($definition[0]);
101
102 1
            return method_exists($object, $definition[1]);
103
        }
104
105 2
        return false;
106
    }
107
}
108