Skip to content

Commit 10d7e01

Browse files
authored
feat(core): improve FQCN extraction with PhpToken for accuracy and stability
1 parent f718a9d commit 10d7e01

File tree

1 file changed

+53
-8
lines changed

1 file changed

+53
-8
lines changed

src/RouteRegistrar.php

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use Illuminate\Routing\Router;
66
use Illuminate\Support\Arr;
7-
use Illuminate\Support\Str;
7+
use PhpToken;
88
use ReflectionAttribute;
99
use ReflectionClass;
1010
use Spatie\RouteAttributes\Attributes\Defaults;
@@ -96,15 +96,60 @@ public function registerClass(string $class): void
9696

9797
protected function fullQualifiedClassNameFromFile(SplFileInfo $file): string
9898
{
99-
$class = trim(Str::replaceFirst($this->basePath, '', $file->getRealPath()), DIRECTORY_SEPARATOR);
99+
$path = $file->getRealPath();
100+
if ($path === false) {
101+
return '';
102+
}
103+
104+
$code = file_get_contents($path);
105+
if ($code === false || $code === '') {
106+
return '';
107+
}
108+
109+
$tokens = PhpToken::tokenize($code);
110+
$count = count($tokens);
111+
112+
$namespace = '';
113+
$found = [];
114+
115+
for ($i = 0; $i < $count; $i++) {
116+
$t = $tokens[$i];
117+
118+
if ($t->is(T_NAMESPACE)) {
119+
$namespace = '';
120+
for ($j = $i + 1; $j < $count; $j++) {
121+
$tj = $tokens[$j];
122+
if ($tj->is(T_NAME_QUALIFIED) || $tj->is(T_STRING) || $tj->is(T_NS_SEPARATOR)) {
123+
$namespace .= $tj->text;
124+
125+
continue;
126+
}
127+
if ($tj->text === ';' || $tj->text === '{') {
128+
break;
129+
}
130+
}
100131

101-
$class = str_replace(
102-
[DIRECTORY_SEPARATOR, 'App\\'],
103-
['\\', app()->getNamespace()],
104-
ucfirst(Str::replaceLast('.php', '', $class))
105-
);
132+
continue;
133+
}
134+
135+
if ($t->is(T_CLASS) || $t->is(T_INTERFACE) || $t->is(T_TRAIT) || (defined('T_ENUM') && $t->is(T_ENUM))) {
136+
$j = $i + 1;
137+
while ($j < $count && $tokens[$j]->is(T_WHITESPACE)) {
138+
$j++;
139+
}
140+
if ($j >= $count || ! $tokens[$j]->is(T_STRING)) {
141+
continue;
142+
}
143+
144+
$name = $tokens[$j]->text;
145+
$fqn = ltrim(($namespace !== '' ? $namespace.'\\' : '').$name, '\\');
146+
$found[] = $fqn;
147+
148+
return $fqn;
149+
}
150+
}
106151

107-
return $this->rootNamespace . $class;
152+
return $found[0] ?? '';
108153
}
109154

110155
protected function processAttributes(string $className): void

0 commit comments

Comments
 (0)