Test Failed
Push — master ( 73c405...d57cd2 )
by Konstantins
03:14
created

ArgumentResolver   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 67
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 30%

Importance

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

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 2
    public function __construct(ContainerContract $container)
32
    {
33 2
        $this->container = $container;
34 2
    }
35
36
    /**
37
     * @inheritDoc
38
     */
39
    public function reflectCallable($callable): ReflectionFunctionAbstract
40
    {
41
        return is_array($callable)
42
            ? new ReflectionMethod($callable[0], $callable[1])
43
            : new ReflectionFunction($callable);
44
    }
45
46
    /**
47
     * @inheritDoc
48
     */
49
    public function resolveArguments(ReflectionFunctionAbstract $function): Closure
50
    {
51
        $parameters = $function->getParameters();
52
53
        return function (array $arguments = []) use ($function, $parameters) {
54
            // Use passed arguments in place of reflected parameters.
55
            $provided = array_intersect_key($arguments, $parameters);
56
57
            // Remaining parameters will be resolved by container.
58
            $remaining = array_diff_key($parameters, $arguments);
59
            $resolved = array_map(function (ReflectionParameter $parameter) use ($function) {
60
61
                // Recursively resolve function arguments.
62
                $class = $parameter->getClass();
63
                if ($class !== null && $this->container->has($class->getName())) {
64
                    return $this->container->get($class->getName());
65
                }
66
67
                // Use argument default value if possible.
68
                if ($parameter->isDefaultValueAvailable()) {
69
                    return $parameter->getDefaultValue();
70
                }
71
72
                // The argument can't be resolved by this resolver.
73
                throw new ArgumentResolverException($parameter, $function);
74
75
            }, $remaining);
76
77
            $arguments = $provided + $resolved;
78
79
            // Sort combined result array by parameter indexes.
80
            ksort($arguments);
81
82
            return $arguments;
83
        };
84
    }
85
}