ClassInfo::getCacheKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\ClassResolver;
6
7
use Override;
8
9
use function array_slice;
10
use function count;
11
use function is_object;
12
use function is_string;
13
use function sprintf;
14
15
final class ClassInfo implements ClassInfoInterface
16
{
17
    public const MODULE_NAME_ANONYMOUS = 'module-name@anonymous';
18
19
    /** @var array<string,array<string,self>> */
20
    private static array $callerClassCache;
21
22
    public function __construct(
23
        private readonly string $callerModuleNamespace,
24
        private readonly string $callerModuleName,
25
        private readonly string $cacheKey,
26
        private readonly string $resolvableType = '',
27
    ) {
28
    }
29
30
    /**
31
     * @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...
32
     */
33
    public static function from(object|string $caller, string $resolvableType = ''): self
34
    {
35
        if (is_object($caller)) {
36
            return self::fromObject($caller, $resolvableType);
37
        }
38
39
        return self::fromString($caller, $resolvableType);
40
    }
41
42
    #[Override]
43
    public function getModuleNamespace(): string
44
    {
45
        return $this->callerModuleNamespace;
46
    }
47
48
    #[Override]
49
    public function getModuleName(): string
50
    {
51
        return $this->callerModuleName;
52
    }
53
54
    #[Override]
55
    public function getCacheKey(): string
56
    {
57
        return $this->cacheKey;
58
    }
59
60
    #[Override]
61
    public function getResolvableType(): string
62
    {
63
        return $this->resolvableType;
64
    }
65
66
    #[Override]
67
    public function toString(): string
68
    {
69
        return sprintf(
70
            '{callerModuleNamespace:"%s", callerModuleName:"%s", resolvableType:"%s", cacheKey:"%s"}',
71
            $this->callerModuleNamespace,
72
            $this->callerModuleName,
73
            $this->resolvableType,
74
            $this->cacheKey,
75
        );
76
    }
77
78
    private static function fromObject(object $callerObject, string $resolvableType): self
79
    {
80
        $callerClass = $callerObject::class;
81
82
        return self::fromString($callerClass, $resolvableType);
83
    }
84
85
    private static function fromString(string $callerClass, string $resolvableType): self
86
    {
87
        if (isset(self::$callerClassCache[$callerClass][$resolvableType])) {
88
            return self::$callerClassCache[$callerClass][$resolvableType];
89
        }
90
91
        /** @var list<string> $callerClassParts */
92
        $callerClassParts = explode('\\', ltrim($callerClass, '\\'));
93
        $lastCallerClassPart = end($callerClassParts);
94
        $filepath = is_string($lastCallerClassPart) ? $lastCallerClassPart : '';
95
        $filename = self::normalizeFilename($filepath);
96
97
        if (str_contains($callerClass, 'anonymous')) {
98
            $callerClassParts = [
99
                self::MODULE_NAME_ANONYMOUS . '\\' . $filename,
100
                $filepath,
101
            ];
102
        }
103
104
        $callerFullNamespace = implode('\\', array_slice($callerClassParts, 0, count($callerClassParts) - 1));
105
106
        $callerModuleNamespace = substr($callerFullNamespace, 0, (int)strrpos($callerFullNamespace, '\\'));
107
        /**
108
         * @psalm-suppress InvalidArrayOffset
109
         *
110
         * @var string $callerModuleName
111
         */
112
        $callerModuleName = $callerClassParts[count($callerClassParts) - 2] ?? '';
113
        $cacheKey = GlobalKey::fromClassName(sprintf('\\%s\\%s', $callerFullNamespace, $resolvableType));
114
115
        $self = new self($callerModuleNamespace, $callerModuleName, $cacheKey, $resolvableType);
116
        self::$callerClassCache[$callerClass][$resolvableType] = $self;
117
118
        return $self;
119
    }
120
121
    private static function normalizeFilename(string $filepath): string
122
    {
123
        $filename = basename($filepath);
124
        $filename = substr($filename, 0, (int)strpos($filename, ':'));
125
126
        if (false === ($pos = strpos($filename, '.'))) {
127
            return $filename;
128
        }
129
130
        return substr($filename, 0, $pos);
131
    }
132
}
133