Passed
Push — improve-reset-in-memory-cache ( 6b01b5 )
by Chema
03:52
created

AnonymousGlobal::resetCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\ClassResolver\GlobalInstance;
6
7
use Gacela\Framework\ClassResolver\ClassInfo;
8
use Gacela\Framework\ClassResolver\GlobalKey;
9
use Gacela\Framework\ClassResolver\ResolvableType;
10
use RuntimeException;
11
12
use function get_class;
13
use function in_array;
14
use function is_string;
15
16
final class AnonymousGlobal
17
{
18
    private const ALLOWED_TYPES_FOR_ANONYMOUS_GLOBAL = ['Config', 'Factory', 'DependencyProvider'];
19
20
    /** @var array<string,object> */
21
    private static array $cachedGlobalInstances = [];
22
23
    /**
24
     * @internal
25
     */
26
    public static function resetCache(): void
27
    {
28
        self::$cachedGlobalInstances = [];
29
    }
30
31
    /**
32
     * @template T
33
     *
34
     * @param class-string<T> $className
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
35
     *
36
     * @return ?T
37
     *
38
     * @internal so the Locator can access to the global instances before creating a new instance
39
     */
40
    public static function getByClassName(string $className)
41
    {
42
        $key = self::getGlobalKeyFromClassName($className);
43
44
        /** @var ?T $instance */
45
        $instance = self::getByKey($key)
46
            ?? self::getByKey('\\' . $key)
47
            ?? null;
48
49
        return $instance;
50
    }
51
52
    public static function getByKey(string $key): ?object
53
    {
54
        return self::$cachedGlobalInstances[$key] ?? null;
55
    }
56
57
    /**
58
     * Add an anonymous class as 'Config', 'Factory' or 'DependencyProvider' as a global resource
59
     * bound to the context that it's pass as first argument. It can be the string-key
60
     * (from a non-class/file context) or the class/object itself.
61
     */
62
    public static function addGlobal(object|string $context, object $resolvedClass): void
63
    {
64
        $contextName = self::extractContextNameFromContext($context);
65
        $parentClass = get_parent_class($resolvedClass);
66
67
        $type = is_string($parentClass)
0 ignored issues
show
introduced by
The condition is_string($parentClass) is always true.
Loading history...
68
            ? ResolvableType::fromClassName($parentClass)->resolvableType()
69
            : $contextName;
70
71
        self::validateTypeForAnonymousGlobalRegistration($type);
72
73
        $key = sprintf('\%s\%s\%s', ClassInfo::MODULE_NAME_ANONYMOUS, $contextName, $type);
74
        self::addCachedGlobalInstance($key, $resolvedClass);
75
    }
76
77
    public static function overrideExistingResolvedClass(string $className, object $resolvedClass): void
78
    {
79
        $key = self::getGlobalKeyFromClassName($className);
80
81
        self::addCachedGlobalInstance($key, $resolvedClass);
82
    }
83
84
    private static function extractContextNameFromContext(object|string $context): string
85
    {
86
        if (is_string($context)) {
87
            return $context;
88
        }
89
90
        $callerClass = get_class($context);
91
        /** @var list<string> $callerClassParts */
92
        $callerClassParts = explode('\\', ltrim($callerClass, '\\'));
93
94
        $lastCallerClassParts = end($callerClassParts);
95
96
        return is_string($lastCallerClassParts) ? $lastCallerClassParts : '';
97
    }
98
99
    private static function validateTypeForAnonymousGlobalRegistration(string $type): void
100
    {
101
        if (!in_array($type, self::ALLOWED_TYPES_FOR_ANONYMOUS_GLOBAL, true)) {
102
            throw new RuntimeException(
103
                "Type '{$type}' not allowed. Valid types: " . implode(', ', self::ALLOWED_TYPES_FOR_ANONYMOUS_GLOBAL),
104
            );
105
        }
106
    }
107
108
    private static function addCachedGlobalInstance(string $key, object $resolvedClass): void
109
    {
110
        self::$cachedGlobalInstances[$key] = $resolvedClass;
111
    }
112
113
    private static function getGlobalKeyFromClassName(string $className): string
114
    {
115
        return GlobalKey::fromClassName($className);
116
    }
117
}
118