Passed
Push — master ( 315034...3914e6 )
by Alexander
06:41
created

EventConfigurator   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Test Coverage

Coverage 68.28%

Importance

Changes 4
Bugs 1 Features 0
Metric Value
eloc 40
c 4
b 1
f 0
dl 0
loc 87
ccs 28
cts 41
cp 0.6828
rs 10
wmc 17

3 Methods

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