CallbackResolver   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 94
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

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

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A resolveReference() 0 10 4
A toClosure() 0 8 2
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 Reference by the parameter/service from Jarvis's
27
     * dependency injection container.
28
     *
29
     * @param  mixed $callback
30
     * @return mixed
31
     */
32
    public function resolveReference($callback)
33
    {
34
        if ($callback instanceof Reference) {
35
            $callback = $this->app[(string) $callback] ?? $callback;
36
        } elseif (is_array($callback) && $callback[0] instanceof Reference) {
37
            $callback[0] = $this->app[(string) $callback[0]] ?? $callback[0];
38
        }
39
40
        return $callback;
41
    }
42
43
    /**
44
     * Resolves and replaces placeholders references by the parameter from Jarvis's
45
     * dependency injection container.
46
     *
47
     * @param  mixed $callback
48
     * @return \Closure
49
     */
50
    public function toClosure($callback): \Closure
51
    {
52
        if ($callback instanceof \Closure) {
53
            return $callback;
54
        }
55
56
        return \Closure::fromCallable($this->resolveReference($callback));
57
    }
58
59
    /**
60
     * Resolves and returns an array of arguments according to the given closure.
61
     * This method can also smartly type hint and find the right object to match
62
     * callback requested arguments.
63
     *
64
     * @param  \Closure $callback
65
     * @param  array    $rawArgs
66
     * @return array
67
     */
68
    public function resolveArgumentsForClosure(\Closure $callback, array $rawArgs = []): array
69
    {
70
        $result = [];
71
        $refMethod = new \ReflectionMethod($callback, '__invoke');
72
        foreach ($refMethod->getParameters() as $refParam) {
73
            if (null !== $refClass = $refParam->getClass()) {
74
                if (isset($this->app[$refClass->name])) {
75
                    $result[$refParam->getPosition()] = $this->app[$refClass->name];
76
77
                    continue;
78
                }
79
            }
80
81
            if (in_array($refParam->name, array_keys($rawArgs))) {
82
                $result[$refParam->getPosition()] = $rawArgs[$refParam->name];
83
            }
84
        }
85
86
        return $result;
87
    }
88
89
    /**
90
     * Shortcut that calls successively ::toClosure(), ::resolveArgumentsForClosure(),
91
     * call_user_func_array() and returns the result.
92
     *
93
     * @param  mixed $callback
94
     * @param  array  $rawArgs
95
     * @return mixed
96
     */
97
    public function resolveAndCall($callback, array $rawArgs = [])
98
    {
99
        $closure = $this->toClosure($callback);
100
101
        return call_user_func_array(
102
            $closure,
103
            $this->resolveArgumentsForClosure($closure, $rawArgs)
104
        );
105
    }
106
}
107