Passed
Push — main ( 2054fe...0c6c03 )
by Breno
02:23
created

ReflectionResolver::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 13
rs 9.9332
1
<?php
2
declare(strict_types=1);
3
4
namespace Habemus\Autowiring;
5
6
use Habemus\Autowiring\Attributes\AttributesInjection;
7
use Habemus\Autowiring\Parameter\DefaultValueParameterResolver;
8
use Habemus\Autowiring\Parameter\InjectionParameterResolver;
9
use Habemus\Autowiring\Parameter\NullableParameterResolver;
10
use Habemus\Autowiring\Parameter\OptionalParameterResolver;
11
use Habemus\Autowiring\Parameter\ParameterResolver;
12
use Habemus\Autowiring\Parameter\TypeHintParameterResolver;
13
use Habemus\Autowiring\Parameter\UserDefinedParameterResolver;
14
use Habemus\Container;
15
use Habemus\Exception\NotFoundException;
16
use Habemus\Exception\NotInstantiableException;
17
use Habemus\Exception\UnresolvableParameterException;
18
use ReflectionClass;
19
use ReflectionFunctionAbstract;
20
21
class ReflectionResolver implements ClassResolver, ArgumentResolver
22
{
23
    /**
24
     * @var Container
25
     */
26
    protected $container;
27
28
    /**
29
     * @var Reflector
30
     */
31
    protected $reflector;
32
33
    /**
34
     * @var AttributesInjection
35
     */
36
    protected $injection;
37
38
    /**
39
     * @var ParameterResolver[]
40
     */
41
    protected $parameterResolverChain;
42
43
    public function __construct(Container $container, AttributesInjection $injection, Reflector $reflector)
44
    {
45
        $this->container = $container;
46
        $this->injection = $injection;
47
        $this->reflector = $reflector;
48
49
        $this->parameterResolverChain = [
50
            new UserDefinedParameterResolver(),
51
            new InjectionParameterResolver($this->container, $this->injection),
52
            new DefaultValueParameterResolver(),
53
            new NullableParameterResolver(),
54
            new OptionalParameterResolver(),
55
            new TypeHintParameterResolver($this->container, $this->reflector)
56
        ];
57
    }
58
59
    /**
60
     * @inheritDoc
61
     */
62
    public function resolveClass(string $className, array $constructorArguments = [])
63
    {
64
        if (!class_exists($className)) {
65
            throw NotFoundException::classNotFound($className);
66
        }
67
68
        $class = new ReflectionClass($className);
69
        if (!$class->isInstantiable()) {
70
            throw new NotInstantiableException($className);
71
        }
72
73
        $constructor = $class->getConstructor();
74
        if ($constructor === null) {
75
            return new $className();
76
        }
77
78
        return
79
            $class->newInstanceArgs(
80
                $this->resolveArguments($constructor, $constructorArguments)
81
            );
82
    }
83
84
    /**
85
     * @inheritDoc
86
     */
87
    public function resolveArguments(ReflectionFunctionAbstract $function, array $arguments = []): array
88
    {
89
        $resolved = [];
90
        $params = [];
91
        foreach ($function->getParameters() as $parameter) {
92
            foreach ($this->parameterResolverChain as $resolver) {
93
                $resolver->resolve($parameter, $arguments, $resolved, $params);
94
            }
95
96
            $name = $parameter->getName();
97
            if (!array_key_exists($name, $resolved)) {
98
                throw UnresolvableParameterException::createForFunction($function, $name);
99
            }
100
        }
101
102
        return $params;
103
    }
104
105
    /**
106
     * @inheritDoc
107
     */
108
    public function canResolve(string $className): bool
109
    {
110
        return class_exists($className);
111
    }
112
}
113