Passed
Pull Request — master (#54)
by Jesús
02:44
created

DependencyResolver::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 1
b 0
f 0
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
            return $parameter->getDefaultValue();
63
        }
64
65 1
        $reflection = new ReflectionClass($paramTypeName);
66
67
        // If it's an interface we need to figure out which concrete class do we want to use.
68 1
        if ($reflection->isInterface()) {
69 1
            $mappingInterfaces = $this->gacelaConfigFile->getMappingInterfaces();
70 1
            $concreteClass = $mappingInterfaces[$reflection->getName()] ?? '';
71
            // a callable will be a way to bypass the instantiation and instead
72
            // use the result from the callable that was defined in the gacela config file.
73 1
            if (is_callable($concreteClass)) {
74
                return $concreteClass();
75
            }
76
            // an Exception will be thrown if there is no concrete class found for the interface.
77 1
            if (empty($concreteClass)) {
78
                throw new DependencyResolverNotFoundException($reflection->getName());
79
            }
80
            // finally, override the $reflection (the interface) by the concrete resolved class.
81
            /** @var class-string $concreteClass */
82 1
            $reflection = new ReflectionClass($concreteClass);
83
        }
84
85 1
        $constructor = $reflection->getConstructor();
86 1
        if (!$constructor) {
87 1
            return $reflection->newInstance();
88
        }
89
90
        /** @var list<mixed> $innerDependencies */
91 1
        $innerDependencies = [];
92
93 1
        foreach ($constructor->getParameters() as $constructorParameter) {
94 1
            $paramType = $constructorParameter->getType();
95 1
            if ($paramType) {
96
                /** @psalm-suppress MixedAssignment */
97 1
                $innerDependencies[] = $this->resolveDependenciesRecursively($constructorParameter);
98
            }
99
        }
100
101 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

101
        return $reflection->newInstanceArgs(/** @scrutinizer ignore-type */ $innerDependencies);
Loading history...
102
    }
103
}
104