Test Failed
Branch main (50af1b)
by Chema
04:19 queued 32s
created

AnonymousGlobal::createCacheKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

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