Passed
Push — master ( 949343...ba585c )
by Jesús
03:36 queued 12s
created

AnonymousGlobal::getGlobalKeyFromClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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