Passed
Pull Request — master (#55)
by Jesús
03:20
created

DependencyResolver::resolveDependencies()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 10
c 2
b 0
f 0
nc 4
nop 1
dl 0
loc 19
ccs 11
cts 11
cp 1
crap 4
rs 9.9332
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\ClassResolver\DependencyResolver;
6
7
use Gacela\Framework\Config\GacelaFileConfig\GacelaConfigFile;
8
use ReflectionClass;
9
use ReflectionNamedType;
10
use ReflectionParameter;
11
use RuntimeException;
12
use function is_callable;
13
14
final class DependencyResolver
15
{
16
    private GacelaConfigFile $gacelaConfigFile;
17
18 12
    public function __construct(GacelaConfigFile $gacelaConfigFile)
19
    {
20 12
        $this->gacelaConfigFile = $gacelaConfigFile;
21 12
    }
22
23
    /**
24
     * @param class-string $resolvedClassName
1 ignored issue
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
25
     *
26
     * @return list<mixed>
27
     */
28 12
    public function resolveDependencies(string $resolvedClassName): array
29
    {
30 12
        $reflection = new ReflectionClass($resolvedClassName);
31 12
        $constructor = $reflection->getConstructor();
32 12
        if (!$constructor) {
33 11
            return [];
1 ignored issue
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type Gacela\Framework\ClassRe...DependencyResolver\list.
Loading history...
34
        }
35
36
        /** @var list<mixed> $dependencies */
37 1
        $dependencies = [];
38 1
        foreach ($constructor->getParameters() as $parameter) {
39 1
            $paramType = $parameter->getType();
40 1
            if ($paramType) {
41
                /** @psalm-suppress MixedAssignment */
42 1
                $dependencies[] = $this->resolveDependenciesRecursively($parameter);
43
            }
44
        }
45
46 1
        return $dependencies;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $dependencies returns the type Gacela\Framework\ClassRe...DependencyResolver\list which is incompatible with the type-hinted return array.
Loading history...
47
    }
48
49
    /**
50
     * @return mixed
51
     */
52 1
    private function resolveDependenciesRecursively(ReflectionParameter $parameter)
53
    {
54 1
        if (!$parameter->hasType()) {
55
            throw new RuntimeException("No parameter type for '{$parameter->getName()}'");
56
        }
57
58
        /** @var ReflectionNamedType $paramType */
59 1
        $paramType = $parameter->getType();
60 1
        $paramTypeName = $paramType->getName();
61 1
        if (!class_exists($paramTypeName) && !interface_exists($paramTypeName)) {
62
            if ($parameter->isDefaultValueAvailable()) {
63
                return $parameter->getDefaultValue();
64
            }
65
66
            /** @psalm-suppress PossiblyNullReference */
67
            throw new RuntimeException("Unable to resolve [$parameter] from {$parameter->getDeclaringClass()->getName()}");
68
        }
69
70
        /** @var mixed $mappedClass */
71 1
        $mappedClass = $this->gacelaConfigFile->getMappingInterface($paramTypeName);
72 1
        if (is_callable($mappedClass)) {
73 1
            return $mappedClass();
74
        }
75
76 1
        if (is_object($mappedClass)) {
77 1
            return $mappedClass;
78
        }
79
80 1
        $reflection = $this->resolveReflectionClass($paramTypeName);
81 1
        $constructor = $reflection->getConstructor();
82 1
        if (!$constructor) {
83 1
            return $reflection->newInstance();
84
        }
85
86
        /** @var list<mixed> $innerDependencies */
87 1
        $innerDependencies = [];
88
89 1
        foreach ($constructor->getParameters() as $constructorParameter) {
90 1
            $paramType = $constructorParameter->getType();
91 1
            if ($paramType) {
92
                /** @psalm-suppress MixedAssignment */
93 1
                $innerDependencies[] = $this->resolveDependenciesRecursively($constructorParameter);
94
            }
95
        }
96
97 1
        return $reflection->newInstanceArgs($innerDependencies);
1 ignored issue
show
Bug introduced by
$innerDependencies of type Gacela\Framework\ClassRe...DependencyResolver\list is incompatible with the type array expected by parameter $args of ReflectionClass::newInstanceArgs(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

97
        return $reflection->newInstanceArgs(/** @scrutinizer ignore-type */ $innerDependencies);
Loading history...
98
    }
99
100
    /**
101
     * @param class-string $paramTypeName
1 ignored issue
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
102
     */
103 1
    private function resolveReflectionClass(string $paramTypeName): ReflectionClass
104
    {
105 1
        $reflection = new ReflectionClass($paramTypeName);
106
107 1
        if ($reflection->isInstantiable()) {
108 1
            return $reflection;
109
        }
110
111
        /** @var mixed $concreteClass */
112 1
        $concreteClass = $this->gacelaConfigFile->getMappingInterface($reflection->getName());
113
114 1
        if (null !== $concreteClass) {
115
            /** @var class-string $concreteClass */
116 1
            return new ReflectionClass($concreteClass);
117
        }
118
119
        throw DependencyResolverNotFoundException::forClassName($reflection->getName());
120
    }
121
}
122