Passed
Push — master ( 0c38cb...0e4d54 )
by Alexander
02:27
created

ListenerConfigurationChecker::listenerDump()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Event;
6
7
use Psr\Container\ContainerExceptionInterface;
8
9
use function get_class;
10
use function gettype;
11
use function is_object;
12
use function is_string;
13
14
/**
15
 * ListenerConfigurationChecker could be used in development mode to check if listeners are defined correctly.
16
 *
17
 * ```php
18
 * $checker->check($configuration->get('events-web'));
19
 * ```
20
 */
21
final class ListenerConfigurationChecker
22
{
23
    private CallableFactory $callableFactory;
24
25 20
    public function __construct(CallableFactory $callableFactory)
26
    {
27 20
        $this->callableFactory = $callableFactory;
28 20
    }
29
30
    /**
31
     * Checks the given event configuration and throws an exception in some cases:
32
     * - incorrect configuration format
33
     * - incorrect listener format
34
     * - listener is not a callable
35
     * - listener is meant to be a method of an object which can't be instantiated
36
     *
37
     * @param array $configuration An array in format of [eventClassName => [listeners]]
38
     */
39 20
    public function check(array $configuration): void
40
    {
41 20
        foreach ($configuration as $eventName => $listeners) {
42 20
            if (!is_string($eventName) || !class_exists($eventName)) {
43 1
                throw new InvalidEventConfigurationFormatException(
44
                    'Incorrect event listener format. Format with event name must be used. Got ' .
45 1
                    var_export($eventName, true) . '.'
46
                );
47
            }
48
49 19
            if (!is_iterable($listeners)) {
50 1
                $type = is_object($listeners) ? get_class($listeners) : gettype($listeners);
51
52 1
                throw new InvalidEventConfigurationFormatException(
53 1
                    "Event listeners for $eventName must be an iterable, $type given."
54
                );
55
            }
56
57
            /** @var mixed */
58 18
            foreach ($listeners as $listener) {
59
                try {
60 18
                    if (!$this->isCallable($listener)) {
61 10
                        throw new InvalidListenerConfigurationException(
62 17
                            'Listener must be a callable. Got ' . $this->listenerDump($listener) . '.'
63
                        );
64
                    }
65 11
                } catch (ContainerExceptionInterface $exception) {
66 1
                    throw new InvalidListenerConfigurationException(
67 1
                        'Could not instantiate event listener or listener class has invalid configuration. Got ' .
68 1
                        $this->listenerDump($listener) . '.',
69 1
                        0,
70
                        $exception
71
                    );
72
                }
73
            }
74
        }
75 7
    }
76
77
    /**
78
     * @param mixed $definition
79
     *
80
     * @throws ContainerExceptionInterface Error while retrieving the entry from container.
81
     */
82 18
    private function isCallable($definition): bool
83
    {
84
        try {
85 18
            $this->callableFactory->create($definition);
86 11
        } catch (InvalidListenerConfigurationException $e) {
87 10
            return false;
88
        }
89
90 7
        return true;
91
    }
92
93
    /**
94
     * @param mixed $listener
95
     */
96 11
    private function listenerDump($listener): string
97
    {
98 11
        return is_object($listener) ? get_class($listener) : var_export($listener, true);
99
    }
100
}
101