Skip to content

Commit b6c7834

Browse files
committed
Fix up FQCN for property annotations in entity.
1 parent 083f0fe commit b6c7834

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed

src/Annotator/EntityAnnotator.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use IdeHelper\Annotation\AnnotationFactory;
1414
use IdeHelper\Annotation\PropertyAnnotation;
1515
use IdeHelper\Annotation\PropertyReadAnnotation;
16+
use IdeHelper\Annotator\Traits\UseStatementsTrait;
1617
use IdeHelper\Utility\App;
1718
use IdeHelper\View\Helper\DocBlockHelper;
1819
use PHP_CodeSniffer\Files\File;
@@ -21,6 +22,8 @@
2122

2223
class EntityAnnotator extends AbstractAnnotator {
2324

25+
use UseStatementsTrait;
26+
2427
/**
2528
* @var array<string, string>|null
2629
*/
@@ -308,6 +311,8 @@ protected function buildVirtualPropertyHintTypeMap(string $content): array {
308311
return [];
309312
}
310313

314+
$useStatements = null;
315+
311316
$classEndIndex = $tokens[$classIndex]['scope_closer'];
312317

313318
$properties = [];
@@ -334,7 +339,13 @@ protected function buildVirtualPropertyHintTypeMap(string $content): array {
334339

335340
$property = Inflector::underscore($matches[1]);
336341

337-
$properties[$property] = $this->returnType($file, $tokens, $functionIndex);
342+
$type = $this->returnType($file, $tokens, $functionIndex);
343+
if ($useStatements === null) {
344+
$useStatements = $this->getUseStatements($file);
345+
}
346+
$type = $this->fqcnIfNeeded($type, $useStatements);
347+
348+
$properties[$property] = $type;
338349
}
339350

340351
return $properties;
@@ -484,4 +495,27 @@ protected function virtualFields(string $name): array {
484495
return $entity->getVirtual();
485496
}
486497

498+
/**
499+
* @param string $type
500+
* @param array<string, array<string, mixed>> $useStatements
501+
* @return string
502+
*/
503+
protected function fqcnIfNeeded(string $type, array $useStatements): string {
504+
$types = explode('|', $type);
505+
foreach ($types as $key => $type) {
506+
$primitive = ['null', 'true', 'false', 'array', 'iterable', 'string', 'bool', 'float', 'int', 'object', 'callable', 'resource', 'mixed'];
507+
if (in_array($type, $primitive, true) || str_starts_with($type, '\\')) {
508+
continue;
509+
}
510+
511+
if (!isset($useStatements[$type])) {
512+
continue;
513+
}
514+
515+
$types[$key] = '\\' . $useStatements[$type]['fullName'];
516+
}
517+
518+
return implode('|', $types);
519+
}
520+
487521
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
/**
4+
* MIT License
5+
* For full license information, please view the LICENSE file that was distributed with this source code.
6+
*/
7+
8+
namespace IdeHelper\Annotator\Traits;
9+
10+
use PHP_CodeSniffer\Files\File;
11+
use PHP_CodeSniffer\Util\Tokens;
12+
13+
trait UseStatementsTrait {
14+
15+
/**
16+
* @param \PHP_CodeSniffer\Files\File $phpcsFile
17+
*
18+
* @return array<string, array<string, mixed>>
19+
*/
20+
protected function getUseStatements(File $phpcsFile): array {
21+
$tokens = $phpcsFile->getTokens();
22+
23+
$statements = [];
24+
foreach ($tokens as $index => $token) {
25+
if ($token['code'] !== T_USE || $token['level'] > 0) {
26+
continue;
27+
}
28+
29+
$useStatementStartIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $index + 1, null, true);
30+
31+
// Ignore function () use ($foo) {}
32+
if ($tokens[$useStatementStartIndex]['content'] === '(') {
33+
continue;
34+
}
35+
36+
$semicolonIndex = $phpcsFile->findNext(T_SEMICOLON, $useStatementStartIndex + 1);
37+
$useStatementEndIndex = $phpcsFile->findPrevious(Tokens::$emptyTokens, $semicolonIndex - 1, null, true);
38+
39+
$statement = '';
40+
for ($i = $useStatementStartIndex; $i <= $useStatementEndIndex; $i++) {
41+
$statement .= $tokens[$i]['content'];
42+
}
43+
44+
// Another sniff takes care of that, we just ignore then.
45+
if ($this->isMultipleUseStatement($statement)) {
46+
continue;
47+
}
48+
49+
$statementParts = preg_split('/\s+as\s+/i', $statement) ?: [];
50+
51+
if (count($statementParts) === 1) {
52+
$fullName = $statement;
53+
$statementParts = explode('\\', $fullName);
54+
$shortName = end($statementParts);
55+
$alias = null;
56+
} else {
57+
$fullName = $statementParts[0];
58+
$alias = $statementParts[1];
59+
$statementParts = explode('\\', $fullName);
60+
$shortName = end($statementParts);
61+
}
62+
63+
$shortName = trim($shortName);
64+
$fullName = trim($fullName);
65+
$key = $alias ?: $shortName;
66+
67+
$statements[$key] = [
68+
'alias' => $alias,
69+
'end' => $semicolonIndex,
70+
'statement' => $statement,
71+
'fullName' => ltrim($fullName, '\\'),
72+
'shortName' => $shortName,
73+
'start' => $index,
74+
];
75+
}
76+
77+
return $statements;
78+
}
79+
80+
/**
81+
* @param string $statementContent
82+
*
83+
* @return bool
84+
*/
85+
protected function isMultipleUseStatement(string $statementContent): bool {
86+
if (str_contains($statementContent, ',')) {
87+
return true;
88+
}
89+
90+
return false;
91+
}
92+
93+
}

0 commit comments

Comments
 (0)