Passed
Pull Request — master (#56)
by Jesús
03:08
created

resolveDependenciesRecursively()   B

Complexity

Conditions 10
Paths 9

Size

Total Lines 47
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 10.7998

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 24
c 2
b 0
f 0
nc 9
nop 1
dl 0
loc 47
ccs 20
cts 25
cp 0.8
crap 10.7998
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
            /** @var ReflectionClass $reflectionClass */
67
            $reflectionClass = $parameter->getDeclaringClass();
68
            throw new RuntimeException("Unable to resolve [$parameter] from {$reflectionClass->getName()}");
69
        }
70
71
        /** @var mixed $mappedClass */
72 1
        $mappedClass = $this->gacelaConfigFile->getMappingInterface($paramTypeName);
73 1
        if (is_callable($mappedClass)) {
74 1
            return $mappedClass();
75
        }
76
77 1
        if (is_object($mappedClass)) {
78 1
            return $mappedClass;
79
        }
80
81 1
        $reflection = $this->resolveReflectionClass($paramTypeName);
82 1
        $constructor = $reflection->getConstructor();
83 1
        if (!$constructor) {
84 1
            return $reflection->newInstance();
85
        }
86
87
        /** @var list<mixed> $innerDependencies */
88 1
        $innerDependencies = [];
89
90 1
        foreach ($constructor->getParameters() as $constructorParameter) {
91 1
            $paramType = $constructorParameter->getType();
92 1
            if ($paramType) {
93
                /** @psalm-suppress MixedAssignment */
94 1
                $innerDependencies[] = $this->resolveDependenciesRecursively($constructorParameter);
95
            }
96
        }
97
98 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

98
        return $reflection->newInstanceArgs(/** @scrutinizer ignore-type */ $innerDependencies);
Loading history...
99
    }
100
101
    /**
102
     * @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...
103
     */
104 1
    private function resolveReflectionClass(string $paramTypeName): ReflectionClass
105
    {
106 1
        $reflection = new ReflectionClass($paramTypeName);
107
108 1
        if ($reflection->isInstantiable()) {
109 1
            return $reflection;
110
        }
111
112
        /** @var mixed $concreteClass */
113 1
        $concreteClass = $this->gacelaConfigFile->getMappingInterface($reflection->getName());
114
115 1
        if (null !== $concreteClass) {
116
            /** @var class-string $concreteClass */
117 1
            return new ReflectionClass($concreteClass);
118
        }
119
120
        throw DependencyResolverNotFoundException::forClassName($reflection->getName());
121
    }
122
}
123