Passed
Pull Request — master (#22)
by Alexander
02:04
created

ListenerConfigurationChecker::isCallable()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 36
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 11

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 20
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 36
ccs 19
cts 19
cp 1
crap 11
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 ReflectionException;
10
use ReflectionMethod;
11
use function is_array;
12
use function is_callable;
13
use function is_string;
14
15
final class ListenerConfigurationChecker
16
{
17
    private ContainerInterface $container;
18
19 14
    public function __construct(ContainerInterface $container)
20
    {
21 14
        $this->container = $container;
22 14
    }
23
24
    /**
25
     * Checks the given event configuration and throws an exception in some cases:
26
     * - incorrect configuration format
27
     * - incorrect listener format
28
     * - listener is not a callable
29
     * - listener is meant to be a method of an object which can't be instantiated
30
     *
31
     * @param array $configuration An array in format of [eventClassName => [listeners]]
32
     *
33
     * @psalm-suppress InvalidCatch
34
     */
35 14
    public function check(array $configuration): void
36
    {
37 14
        foreach ($configuration as $eventName => $listeners) {
38 14
            if (!is_string($eventName)) {
39 1
                throw new InvalidEventConfigurationFormatException(
40 1
                    'Incorrect event listener format. Format with event name must be used.'
41
                );
42
            }
43
44 13
            if (!is_iterable($listeners)) {
45 1
                $type = gettype($listeners);
46
47 1
                throw new InvalidEventConfigurationFormatException(
48 1
                    "Event listeners for $eventName must be an iterable, $type given."
49
                );
50
            }
51
52 12
            foreach ($listeners as $listener) {
53
                try {
54 12
                    if (!$this->isCallable($listener)) {
55 6
                        $type = gettype($listener);
56
57 6
                        throw new InvalidListenerConfigurationException(
58 11
                            "Listener must be a callable, $type given."
59
                        );
60
                    }
61 7
                } catch (ContainerExceptionInterface $exception) {
62 1
                    throw new InvalidListenerConfigurationException(
63 1
                        'Could not instantiate event listener or listener class has invalid configuration.',
64 1
                        0,
65
                        $exception
66
                    );
67
                }
68
            }
69
        }
70 5
    }
71
72 12
    private function isCallable($definition): bool
73
    {
74
        if (
75 12
            is_array($definition)
76 12
            && array_keys($definition) === [0, 1]
77 12
            && is_string($definition[0])
78
        ) {
79 6
            if (class_exists($definition[0])) {
80
                try {
81 5
                    $method = new ReflectionMethod($definition[0], $definition[1]);
82 4
                    if ($method->isStatic()) {
83 4
                        return true;
84
                    }
85 1
                } catch (ReflectionException $exception) {
86 1
                    return false;
87
                }
88
            }
89
90 4
            if ($this->container->has($definition[0])) {
91 2
                $object = $this->container->get($definition[0]);
92
93 1
                return method_exists($object, $definition[1]);
94
            }
95
96 2
            return false;
97
        }
98
99 6
        if (is_callable($definition)) {
100 2
            return true;
101
        }
102
103 4
        if (is_string($definition) && $this->container->has($definition)) {
104 1
            return is_callable($this->container->get($definition));
105
        }
106
107 3
        return false;
108
    }
109
}
110