Passed
Branch feature/remove-deprecated-clas... (172303)
by Chema
05:06
created

searchClassOverDocBlock()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 5
rs 10
ccs 3
cts 3
cp 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework;
6
7
use Gacela\Framework\ClassResolver\DocBlockService\DocBlockParser;
8
use Gacela\Framework\ClassResolver\DocBlockService\DocBlockServiceResolver;
9
use Gacela\Framework\ClassResolver\DocBlockService\MissingClassDefinitionException;
10
use Gacela\Framework\ClassResolver\DocBlockService\UseBlockParser;
11
use ReflectionClass;
12
13
use function is_string;
14
15
trait DocBlockResolverAwareTrait
16
{
17
    /** @var array<string,string> */
18
    protected static array $fileContentCache = [];
19
20
    /** @var array<string,?object> */
21
    private array $customServices = [];
22
23
    /**
24
     * @param string $method
25
     * @param array $parameters
26
     *
27
     * @return mixed
28
     */
29 6
    public function __call($method, $parameters = [])
30
    {
31 6
        if (!isset($this->customServices[$method])) {
32 6
            $className = $this->getClassFromDoc($method);
33 6
            $resolvableType = $this->normalizeResolvableType($className);
34
35 6
            $this->customServices[$method] = (new DocBlockServiceResolver($resolvableType))
36 6
                ->resolve($className);
37
        }
38
39 6
        $object = $this->customServices[$method];
40
41 6
        if (isset($object)) {
42 6
            return $object;
43
        }
44
45
        if (method_exists(parent::class, '__call')) {
46
            return parent::__call($method, $parameters);
47
        }
48
49
        return null;
50
    }
51
52
    /**
53
     * @return class-string
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...
54
     */
55 6
    private function getClassFromDoc(string $method): string
56
    {
57 6
        $reflectionClass = new ReflectionClass(static::class);
58 6
        $className = $this->searchClassOverDocBlock($reflectionClass, $method);
59 6
        if (class_exists($className)) {
60
            return $className;
61
        }
62 6
        $className = $this->searchClassOverUseStatements($reflectionClass, $className);
63 6
        if (class_exists($className)) {
64 6
            return $className;
65
        }
66
        throw MissingClassDefinitionException::missingDefinition(static::class, $method, $className);
67
    }
68
69 6
    private function searchClassOverDocBlock(ReflectionClass $reflectionClass, string $method): string
70
    {
71 6
        $docBlock = (string)$reflectionClass->getDocComment();
72
73 6
        return (new DocBlockParser())->getClassFromMethod($docBlock, $method);
74
    }
75
76
    /**
77
     * Look the uses, to find the fully-qualified class name for the className.
78
     */
79 6
    private function searchClassOverUseStatements(ReflectionClass $reflectionClass, string $className): string
80
    {
81 6
        $fileName = $reflectionClass->getFileName();
82 6
        if (!isset(static::$fileContentCache[$fileName])) {
83 6
            static::$fileContentCache[$fileName] = file_get_contents($fileName);
84
        }
85 6
        $phpFile = static::$fileContentCache[$fileName];
86
87 6
        return (new UseBlockParser())->getUseStatement($className, $phpFile);
88
    }
89
90 6
    private function normalizeResolvableType(string $resolvableType): string
91
    {
92
        /** @var list<string> $resolvableTypeParts */
93 6
        $resolvableTypeParts = explode('\\', ltrim($resolvableType, '\\'));
94 6
        $normalizedResolvableType = end($resolvableTypeParts);
95
96 6
        return is_string($normalizedResolvableType)
97 6
            ? $normalizedResolvableType
98 6
            : $resolvableType;
99
    }
100
}
101