Passed
Pull Request — master (#23)
by Sergei
02:05
created

CallableFactory::create()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 10
ccs 5
cts 5
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
use Psr\Container\ContainerInterface;
9
use ReflectionException;
10
use ReflectionMethod;
11
12
use function is_array;
13
use function is_callable;
14
use function is_string;
15
16
/**
17
 * @internal Create real callable listener from configuration.
18
 */
19
final class CallableFactory
20
{
21
    private ContainerInterface $container;
22
23 43
    public function __construct(ContainerInterface $container)
24
    {
25 43
        $this->container = $container;
26 43
    }
27
28
    /**
29
     * @param mixed $definition
30
     *
31
     * @throws InvalidListenerConfigurationException Failed to create listener.
32
     * @throws ContainerExceptionInterface Error while retrieving the entry from container.
33
     */
34 37
    public function create($definition): callable
35
    {
36
        /** @var mixed */
37 37
        $callable = $this->prepare($definition);
38
39 36
        if (is_callable($callable)) {
40 16
            return $callable;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $callable could return the type null which is incompatible with the type-hinted return callable. Consider adding an additional type-check to rule them out.
Loading history...
41
        }
42
43 20
        throw new InvalidListenerConfigurationException();
44
    }
45
46
    /**
47
     * @param mixed $definition
48
     *
49
     * @throws ContainerExceptionInterface Error while retrieving the entry from container.
50
     *
51
     * @return mixed
52
     */
53 37
    private function prepare($definition)
54
    {
55 37
        if (is_string($definition) && $this->container->has($definition)) {
56 3
            return $this->container->get($definition);
57
        }
58
59 35
        if (is_array($definition)
60 35
            && array_keys($definition) === [0, 1]
61 35
            && is_string($definition[0])
62 35
            && is_string($definition[1])
63
        ) {
64 16
            [$className, $methodName] = $definition;
65
66 16
            if (!class_exists($className) && $this->container->has($className)) {
67
                /** @var mixed */
68
                return [
69 5
                    $this->container->get($className),
70 5
                    $methodName,
71
                ];
72
            }
73
74 12
            if (!class_exists($className)) {
75 2
                return null;
76
            }
77
78
            try {
79 10
                $reflection = new ReflectionMethod($className, $methodName);
80 2
            } catch (ReflectionException $e) {
81 2
                return null;
82
            }
83 8
            if ($reflection->isStatic()) {
84 3
                return [$className, $methodName];
85
            }
86 6
            if ($this->container->has($className)) {
87
                return [
88 4
                    $this->container->get($className),
89 3
                    $methodName,
90
                ];
91
            }
92 2
            return null;
93
        }
94
95 20
        return $definition;
96
    }
97
}
98