Completed
Push — master ( e55a66...08d61b )
by Eric
9s
created

CallbackResolver   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 76
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 0
dl 0
loc 76
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A resolve() 0 8 3
B resolveArgumentsForClosure() 0 20 5
A resolveAndCall() 0 9 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Jarvis\Skill\Core;
6
7
use Jarvis\Jarvis;
8
use Jarvis\Skill\DependencyInjection\Reference;
9
10
/**
11
 * @author Eric Chau <[email protected]>
12
 */
13
class CallbackResolver
14
{
15
    /**
16
     * @var Jarvis
17
     */
18
    private $app;
19
20
    public function __construct(Jarvis $app)
21
    {
22
        $this->app = $app;
23
    }
24
25
    /**
26
     * Resolves and replaces placeholders references by the parameter from Jarvis's
27
     * dependency injection container.
28
     *
29
     * @param  mixed $callback
30
     * @return \Closure
31
     */
32
    public function resolve($callback): \Closure
33
    {
34
        if (is_array($callback) && $callback[0] instanceof Reference) {
35
            $callback[0] = $this->app[(string) $callback[0]] ?? $callback[0];
36
        }
37
38
        return \Closure::fromCallable($callback);
39
    }
40
41
    /**
42
     * Resolves and returns an array of arguments according to the given closure.
43
     * This method can also smartly type hint and find the right object to match
44
     * callback requested arguments.
45
     *
46
     * @param  \Closure $callback
47
     * @param  array    $rawArgs
48
     * @return array
49
     */
50
    public function resolveArgumentsForClosure(\Closure $callback, array $rawArgs = []): array
51
    {
52
        $result = [];
53
        $refMethod = new \ReflectionMethod($callback, '__invoke');
54
        foreach ($refMethod->getParameters() as $refParam) {
55
            if (null !== $refClass = $refParam->getClass()) {
56
                if (isset($this->app[$refClass->name])) {
57
                    $result[$refParam->getPosition()] = $this->app[$refClass->name];
58
59
                    continue;
60
                }
61
            }
62
63
            if (in_array($refParam->name, array_keys($rawArgs))) {
64
                $result[$refParam->getPosition()] = $rawArgs[$refParam->name];
65
            }
66
        }
67
68
        return $result;
69
    }
70
71
    /**
72
     * Shortcut that calls successively ::resolve(), ::resolveArgumentsForClosure(),
73
     * call_user_func_array() and returns the result.
74
     *
75
     * @param  mixed $callback
76
     * @param  array  $rawArgs
77
     * @return mixed
78
     */
79
    public function resolveAndCall($callback, array $rawArgs = [])
80
    {
81
        $closure = $this->resolve($callback);
82
83
        return call_user_func_array(
84
            $closure,
85
            $this->resolveArgumentsForClosure($closure, $rawArgs)
86
        );
87
    }
88
}
89