Passed
Push — master ( 2c1367...72194f )
by Alexey
03:21
created

ArgumentResolver   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 67
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 7
c 0
b 0
f 0
lcom 0
cbo 2
dl 0
loc 67
rs 10
ccs 23
cts 23
cp 1

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A reflectCallable() 0 6 2
B resolveArguments() 0 36 4
1
<?php declare(strict_types = 1);
2
3
namespace Venta\Container;
4
5
use Closure;
6
use ReflectionFunction;
7
use ReflectionFunctionAbstract;
8
use ReflectionMethod;
9
use ReflectionParameter;
10
use Venta\Container\Exception\ArgumentResolverException;
11
use Venta\Contracts\Container\ArgumentResolver as ArgumentResolverContract;
12
use Venta\Contracts\Container\Container as ContainerContract;
13
14
/**
15
 * Class ArgumentResolver.
16
 *
17
 * @package Venta\Container
18
 */
19
final class ArgumentResolver implements ArgumentResolverContract
20
{
21
    /**
22
     * @var ContainerContract
23
     */
24
    private $container;
25
26
    /**
27
     * ArgumentResolver constructor.
28
     *
29
     * @param ContainerContract $container
30
     */
31 53
    public function __construct(ContainerContract $container)
32
    {
33 53
        $this->container = $container;
34 53
    }
35
36
    /**
37
     * @inheritDoc
38
     */
39 29
    public function reflectCallable($callable): ReflectionFunctionAbstract
40
    {
41 29
        return is_array($callable)
42 18
            ? new ReflectionMethod($callable[0], $callable[1])
43 29
            : new ReflectionFunction($callable);
44
    }
45
46
    /**
47
     * @inheritDoc
48
     */
49 38
    public function resolveArguments(ReflectionFunctionAbstract $function): Closure
50
    {
51 38
        $parameters = $function->getParameters();
52
53
        return function (array $arguments = []) use ($function, $parameters) {
54
            // Use passed arguments in place of reflected parameters.
55 37
            $provided = array_intersect_key($arguments, $parameters);
56
57
            // Remaining parameters will be resolved by container.
58 37
            $remaining = array_diff_key($parameters, $arguments);
59 37
            $resolved = array_map(function (ReflectionParameter $parameter) use ($function) {
60
61
                // Recursively resolve function arguments.
62 26
                $class = $parameter->getClass();
63 26
                if ($class !== null && $this->container->has($class->getName())) {
64 22
                    return $this->container->get($class->getName());
65
                }
66
67
                // Use argument default value if possible.
68 5
                if ($parameter->isDefaultValueAvailable()) {
69 2
                    return $parameter->getDefaultValue();
70
                }
71
72
                // The argument can't be resolved by this resolver.
73 3
                throw new ArgumentResolverException($parameter, $function);
74
75 37
            }, $remaining);
76
77 31
            $arguments = $provided + $resolved;
78
79
            // Sort combined result array by parameter indexes.
80 31
            ksort($arguments);
81
82 31
            return $arguments;
83 38
        };
84
    }
85
}