Passed
Push — feature/reset-cache-from-abstr... ( 080d30 )
by Jesús
04:17
created

AbstractClassResolver::resetCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\ClassResolver;
6
7
use Gacela\Framework\ClassResolver\ClassNameFinder\ClassNameFinderInterface;
8
use Gacela\Framework\ClassResolver\GlobalInstance\AnonymousGlobal;
9
use Gacela\Framework\ClassResolver\InstanceCreator\InstanceCreator;
10
use Gacela\Framework\Config\Config;
11
use Gacela\Framework\Config\GacelaFileConfig\GacelaConfigFileInterface;
12
13
use function is_array;
14
use function is_object;
15
16
abstract class AbstractClassResolver
17
{
18
    /** @var array<string,null|object> */
19
    private static array $cachedInstances = [];
20
21
    private ?ClassNameFinderInterface $classNameFinder = null;
22
23
    private ?GacelaConfigFileInterface $gacelaFileConfig = null;
24
25
    private ?InstanceCreator $instanceCreator = null;
26
27
    public static function resetCache(): void
28
    {
29
        self::$cachedInstances = [];
30
    }
31
32
    /**
33
     * @param object|class-string $caller
0 ignored issues
show
Documentation Bug introduced by
The doc comment object|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in object|class-string.
Loading history...
34
     */
35
    abstract public function resolve($caller): ?object;
36
37
    /**
38
     * @param object|class-string $caller
0 ignored issues
show
Documentation Bug introduced by
The doc comment object|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in object|class-string.
Loading history...
39
     */
40 28
    public function doResolve($caller): ?object
41
    {
42 28
        $classInfo = ClassInfo::from($caller, $this->getResolvableType());
43
44 28
        $cacheKey = $classInfo->getCacheKey();
45
46 28
        $resolvedClass = $this->resolveCached($cacheKey);
47 28
        if ($resolvedClass !== null) {
48 8
            return $resolvedClass;
49
        }
50
51 21
        $resolvedClassName = $this->findClassName($classInfo);
52 21
        if ($resolvedClassName === null) {
53
            // Try again with its parent class
54 4
            if (is_object($caller)) {
55 4
                $parentClass = get_parent_class($caller);
56 4
                if ($parentClass !== false) {
57 4
                    return $this->doResolve($parentClass);
58
                }
59
            }
60
61 3
            return null;
62
        }
63
64 20
        self::$cachedInstances[$cacheKey] = $this->createInstance($resolvedClassName);
65
66 20
        return self::$cachedInstances[$cacheKey];
67
    }
68
69
    abstract protected function getResolvableType(): string;
70
71 28
    private function resolveCached(string $cacheKey): ?object
72
    {
73 28
        return AnonymousGlobal::getByKey($cacheKey)
74 27
            ?? self::$cachedInstances[$cacheKey]
75
            ?? null;
76
    }
77
78 21
    private function findClassName(ClassInfo $classInfo): ?string
79
    {
80 21
        return $this->getClassNameFinder()->findClassName(
81
            $classInfo,
82 21
            $this->getPossibleResolvableTypes()
83
        );
84
    }
85
86 21
    private function getClassNameFinder(): ClassNameFinderInterface
87
    {
88 21
        if ($this->classNameFinder === null) {
89 21
            $this->classNameFinder = (new ClassResolverFactory())
90 21
                ->createClassNameFinder();
91
        }
92
93 21
        return $this->classNameFinder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->classNameFinder could return the type null which is incompatible with the type-hinted return Gacela\Framework\ClassRe...lassNameFinderInterface. Consider adding an additional type-check to rule them out.
Loading history...
94
    }
95
96
    /**
97
     * Allow overriding gacela suffixes resolvable types.
98
     *
99
     * @return list<string>
100
     */
101 21
    private function getPossibleResolvableTypes(): array
102
    {
103 21
        $suffixTypes = $this->getGacelaConfigFile()->getSuffixTypes();
104
105 21
        $resolvableTypes = $suffixTypes[$this->getResolvableType()] ?? $this->getResolvableType();
106
107 21
        return is_array($resolvableTypes) ? $resolvableTypes : [$resolvableTypes];
108
    }
109
110 20
    private function createInstance(string $resolvedClassName): ?object
111
    {
112 20
        if ($this->instanceCreator === null) {
113 20
            $this->instanceCreator = new InstanceCreator($this->getGacelaConfigFile());
114
        }
115
116 20
        return $this->instanceCreator->createByClassName($resolvedClassName);
0 ignored issues
show
Bug introduced by
The method createByClassName() does not exist on null. ( Ignorable by Annotation )

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

116
        return $this->instanceCreator->/** @scrutinizer ignore-call */ createByClassName($resolvedClassName);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
117
    }
118
119 21
    private function getGacelaConfigFile(): GacelaConfigFileInterface
120
    {
121 21
        if ($this->gacelaFileConfig === null) {
122 21
            $this->gacelaFileConfig = Config::getInstance()
123 21
                ->getFactory()
124 21
                ->createGacelaFileConfig();
125
        }
126
127 21
        return $this->gacelaFileConfig;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->gacelaFileConfig could return the type null which is incompatible with the type-hinted return Gacela\Framework\Config\...celaConfigFileInterface. Consider adding an additional type-check to rule them out.
Loading history...
128
    }
129
}
130