Skip to content

Commit 1bdcde3

Browse files
committed
Detect ObjectStorage contents and add it to the field types
Ref: #158
1 parent 00e18c2 commit 1bdcde3

File tree

5 files changed

+141
-0
lines changed

5 files changed

+141
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.cedricziel.idea.typo3.extbase.persistence;
2+
3+
import com.intellij.openapi.project.DumbService;
4+
import com.intellij.openapi.project.Project;
5+
import com.intellij.psi.PsiElement;
6+
import com.jetbrains.php.PhpClassHierarchyUtils;
7+
import com.jetbrains.php.PhpIndex;
8+
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment;
9+
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocParamTag;
10+
import com.jetbrains.php.lang.psi.elements.Field;
11+
import com.jetbrains.php.lang.psi.elements.PhpClass;
12+
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
13+
import com.jetbrains.php.lang.psi.resolve.types.PhpType;
14+
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider3;
15+
import org.jetbrains.annotations.Nullable;
16+
17+
import java.util.Collection;
18+
import java.util.Set;
19+
import java.util.regex.Matcher;
20+
import java.util.regex.Pattern;
21+
22+
public class ExtbaseModelCollectionReturnTypeProvider implements PhpTypeProvider3 {
23+
24+
public static final String TYPO3_CMS_EXTBASE_DOMAIN_OBJECT_ABSTRACT_ENTITY = "TYPO3\\CMS\\Extbase\\DomainObject\\AbstractEntity";
25+
26+
@Override
27+
public char getKey() {
28+
return '\u0278';
29+
}
30+
31+
@Nullable
32+
@Override
33+
public PhpType getType(PsiElement psiElement) {
34+
if (DumbService.getInstance(psiElement.getProject()).isDumb()) {
35+
return null;
36+
}
37+
38+
if (!(psiElement instanceof Field)) {
39+
return null;
40+
}
41+
42+
PhpClass containingClass = ((Field) psiElement).getContainingClass();
43+
if (containingClass == null) {
44+
return null;
45+
}
46+
47+
Collection<PhpClass> classesByFQN = PhpIndex.getInstance(psiElement.getProject()).getClassesByFQN(TYPO3_CMS_EXTBASE_DOMAIN_OBJECT_ABSTRACT_ENTITY);
48+
if (classesByFQN.isEmpty()) {
49+
return null;
50+
}
51+
52+
PhpClass abstractEntityClass = classesByFQN.iterator().next();
53+
54+
if (!PhpClassHierarchyUtils.isSuperClass(abstractEntityClass, containingClass, true)) {
55+
return null;
56+
}
57+
58+
PhpDocComment docComment = ((Field) psiElement).getDocComment();
59+
if (docComment == null) {
60+
return null;
61+
}
62+
63+
PhpDocParamTag varTag = docComment.getVarTag();
64+
if (varTag == null) {
65+
return null;
66+
}
67+
68+
String text = varTag.getText();
69+
if (!text.contains("ObjectStorage<")) {
70+
return null;
71+
}
72+
73+
PhpType phpType = new PhpType();
74+
75+
String pattern = "<(.*?)>";
76+
Pattern compiled = Pattern.compile(pattern);
77+
Matcher matcher = compiled.matcher(text);
78+
while (matcher.find()) {
79+
phpType.add(matcher.group(1) + "[]");
80+
}
81+
82+
return phpType;
83+
}
84+
85+
@Override
86+
public Collection<? extends PhpNamedElement> getBySignature(String expression, Set<String> visited, int depth, Project project) {
87+
return PhpIndex.getInstance(project).getBySignature(expression);
88+
}
89+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ It is a great inspiration for possible solutions and parts of the code.</p>
143143

144144
<!-- extbase persistence -->
145145
<referenceResolver implementation="com.cedricziel.idea.typo3.extbase.persistence.ExtbasePersistenceReferenceResolver"/>
146+
147+
<typeProvider3 implementation="com.cedricziel.idea.typo3.extbase.persistence.ExtbaseModelCollectionReturnTypeProvider"/>
146148
</extensions>
147149

148150
<extensions defaultExtensionNs="com.intellij">
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.cedricziel.idea.typo3.extbase.persistence;
2+
3+
import com.intellij.psi.PsiElement;
4+
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
5+
import com.jetbrains.php.lang.psi.elements.Field;
6+
7+
import java.util.Set;
8+
9+
public class ExtbaseModelCollectionReturnTypeProviderTest extends LightCodeInsightFixtureTestCase {
10+
@Override
11+
protected String getTestDataPath() {
12+
return "testData/com/cedricziel/idea/typo3/extbase/persistence";
13+
}
14+
15+
public void testResolvesObjectStoragePropertiesToObjectTypes() {
16+
myFixture.copyFileToProject("PersistenceMocks.php");
17+
myFixture.configureByFile("FieldTypeProvider.php");
18+
19+
PsiElement elementAtCaret = myFixture.getElementAtCaret();
20+
21+
assertInstanceOf(elementAtCaret, Field.class);
22+
23+
Set<String> types = ((Field) elementAtCaret).getInferredType().getTypes();
24+
assertTrue(types.contains("\\My\\Extension\\Domain\\Model\\Book[]"));
25+
}
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace MyExt {
4+
5+
class FieldTypeProvider extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
6+
{
7+
/**
8+
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\My\Extension\Domain\Model\Book>
9+
*/
10+
protected $book;
11+
12+
public function getBook()
13+
{
14+
foreach ($this-><caret>book as $b) {
15+
$b->getAuthor();
16+
}
17+
}
18+
}
19+
20+
}

testData/com/cedricziel/idea/typo3/extbase/persistence/PersistenceMocks.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ class QueryResultInterface {}
66
class ObjectStorage {}
77
}
88

9+
namespace TYPO3\CMS\Extbase\DomainObject {
10+
class AbstractEntity {}
11+
}
12+
913
namespace My\Extension\Domain\Model {
1014
class Book extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity {
1115
/**

0 commit comments

Comments
 (0)