8000 add indexer which prefilters doctrine metadata files with class and r… · Koc/idea-php-symfony2-plugin@1691ccb · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1691ccb

Browse files
committed
add indexer which prefilters doctrine metadata files with class and repository Haehnchen#586
1 parent 47ab237 commit 1691ccb

File tree

7 files changed

+389
-2
lines changed

7 files changed

+389
-2
lines changed

META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@
332332
<fileBasedIndex implementation="fr.adrienbrault.idea.symfony2plugin.stubs.indexes.AnnotationRoutesStubIndex"/>
333333
<fileBasedIndex implementation="fr.adrienbrault.idea.symfony2plugin.stubs.indexes.ServicesTagStubIndex"/>
334334
<fileBasedIndex implementation="fr.adrienbrault.idea.symfony2plugin.stubs.indexes.PhpTwigTemplateUsageStubIndex"/>
335+
<fileBasedIndex implementation="fr.adrienbrault.idea.symfony2plugin.stubs.indexes.DoctrineMetadataFileStubIndex"/>
335336

336337
<codeInsight.lineMarkerProvider language="PHP" implementationClass="fr.adrienbrault.idea.symfony2plugin.config.ServiceLineMarkerProvider"/>
337338
<codeInsight.lineMarkerProvider language="PHP" implementationClass="fr.adrienbrault.idea.symfony2plugin.dic.ControllerMethodLineMarkerProvider"/>
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package fr.adrienbrault.idea.symfony2plugin.doctrine;
2+
3+
import com.intellij.openapi.util.Pair;
4+
import com.intellij.psi.PsiFile;
5+
import com.intellij.psi.util.PsiTreeUtil;
6+
import com.intellij.psi.xml.XmlAttribute;
7+
import com.intellij.psi.xml.XmlFile;
8+
import com.intellij.psi.xml.XmlTag;
9+
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
10+
import org.apache.commons.lang.ArrayUtils;
11+
import org.apache.commons.lang.StringUtils;
12+
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.annotations.Nullable;
14+
import org.jetbrains.yaml.psi.YAMLDocument;
15+
import org.jetbrains.yaml.psi.YAMLFile;
16+
import org.jetbrains.yaml.psi.YAMLKeyValue;
17+
18+
import java.util.ArrayList;
19+
import java.util.Collection;
20+
import java.util.Set;
21+
22+
/**
23+
* @author Daniel Espendiller <daniel@espendiller.net>
24+
*/
25+
public class DoctrineUtil {
26+
27+
/**
28+
* Index metadata file with its class and repository.
29+
* As of often class stay in static only context
30+
*/
31+
@Nullable
32+
public static Collection<Pair<String, String>> getClassRepositoryPair(@NotNull PsiFile psiFile) {
33+
34+
Collection<Pair<String, String>> pairs = null;
35+
36+
if(psiFile instanceof XmlFile) {
37+
pairs = getClassRepositoryPair((XmlFile) psiFile);
38+
} else if(psiFile instanceof YAMLFile) {
39+
pairs = getClassRepositoryPair((YAMLFile) psiFile);
40+
}
41+
42+
return pairs;
43+
}
44+
45+
/**
46+
* Extract class and repository from xml meta files
47+
* We support orm and all odm syntax here
48+
*/
49+
@Nullable
50+
private static Collection<Pair<String, String>> getClassRepositoryPair(@NotNull XmlFile xmlFile) {
51+
52+
XmlTag rootTag = xmlFile.getRootTag();
53+
if(rootTag == null || !rootTag.getName().toLowerCase().startsWith("doctrine")) {
54+
return null;
55+
}
56+
57+
Collection<Pair<String, String>> pairs = new ArrayList<Pair<String, String>>();
58+
59+
for (XmlTag xmlTag : (XmlTag[]) ArrayUtils.addAll(rootTag.findSubTags("document"), rootTag.findSubTags("entity"))) {
60+
61+
XmlAttribute attr = xmlTag.getAttribute("name");
62+
if(attr == null) {
63+
continue;
64+
}
65+
66+
String value = attr.getValue();
67+
if(StringUtils.isBlank(value)) {
68+
continue;
69+
}
70+
71+
// extract repository-class; allow nullable
72+
String repositoryClass = null;
73+
XmlAttribute repositoryClassAttribute = xmlTag.getAttribute("repository-class");
74+
if(repositoryClassAttribute != null) {
75+
String repositoryClassAttributeValue = repositoryClassAttribute.getValue();
76+
if(StringUtils.isNotBlank(repositoryClassAttributeValue)) {
77+
repositoryClass = repositoryClassAttributeValue;
78+
}
79+
}
80+
81+
pairs.add(Pair.create(value, repositoryClass));
82+
}
83+
84+
if(pairs.size() == 0) {
85+
return null;
86+
}
87+
88+
return pairs;
89+
}
90+
91+
/**
92+
* Extract class and repository from all yaml files
93+
* We need to filter on some condition, so we dont index files which not holds meta for doctrine
94+
*
95+
* Note: index context method, so file validity in each statement
96+
*/
97+
@Nullable
98+
private static Collection<Pair<String, String>> getClassRepositoryPair(@NotNull YAMLFile yamlFile) {
99+
100+
// we are indexing all yaml files for prefilter on path,
101+
// if false if check on parse
102+
String name = yamlFile.getName().toLowerCase();
103+
boolean iAmMetadataFile = name.contains(".odm.") || name.contains(".orm.") || name.contains(".mongodb.") || name.contains(".couchdb.");
104+
105+
YAMLDocument yamlDocument = PsiTreeUtil.getChildOfType(yamlFile, YAMLDocument.class);
106+
if(yamlDocument == null) {
107+
return null;
108+
}
109+
110+
YAMLKeyValue[] yamlKeys = PsiTreeUtil.getChildrenOfType(yamlDocument, YAMLKeyValue.class);
111+
if(yamlKeys == null) {
112+
return null;
113+
}
114+
115+
Collection<Pair<String, String>> pairs = new ArrayList<Pair<String, String>>();
116+
117+
for (YAMLKeyValue yamlKey : yamlKeys) {
118+
String keyText = yamlKey.getKeyText();
119+
if(StringUtils.isBlank(keyText)) {
120+
continue;
121+
}
122+
123+
String repositoryClass = YamlHelper.getYamlKeyValueAsString(yamlKey, "repositoryClass");
124+
125+
// fine repositoryClass exists a valid metadata file
126+
if(!iAmMetadataFile && repositoryClass != null) {
127+
iAmMetadataFile = true;
128+
}
129+
130+
// currently not valid metadata file find valid keys
131+
// else we are not allowed to store values
132+
if(!iAmMetadataFile) {
133+
Set<String> keySet = YamlHelper.getKeySet(yamlKey);
134+
if(keySet == null) {
135+
continue;
136+
}
137+
138+
if(!(keySet.contains("fields") || keySet.contains("id") || keySet.contains("collection") || keySet.contains("db") || keySet.contains("indexes"))) {
139+
continue;
140+
}
141+
142+
iAmMetadataFile = true;
143+
}
144+
145+
pairs.add(Pair.create(keyText, repositoryClass));
146+
}
147+
148+
if(pairs.size() == 0) {
149+
return null;
150+
}
151+
152+
return pairs;
153+
}
154+
155+
}

src/fr/adrienbrault/idea/symfony2plugin/stubs/indexes/ContainerParameterStubIndex.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public int getVersion() {
118118
return 1;
119119
}
120120

121-
private static class StringDataExternalizer implements DataExternalizer<String> {
121+
public static class StringDataExternalizer implements DataExternalizer<String> {
122122

123123
public static final StringDataExternalizer STRING_DATA_EXTERNALIZER = new StringDataExternalizer();
124124
private final EnumeratorStringDescriptor myStringEnumerator = new EnumeratorStringDescriptor();
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package fr.adrienbrault.idea.symfony2plugin.stubs.indexes;
2+
3+
import com.intellij.ide.highlighter.XmlFileType;
4+
import com.intellij.openapi.fileTypes.FileType;
5+
import com.intellij.openapi.util.Pair;
6+
import com.intellij.openapi.vfs.VirtualFile;
7+
import com.intellij.psi.PsiFile;
8+
import com.intellij.util.indexing.*;
9+
import com.intellij.util.io.DataExternalizer;
10+
import com.intellij.util.io.EnumeratorStringDescriptor;
11+
import com.intellij.util.io.KeyDescriptor;
12+
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
13+
import fr.adrienbrault.idea.symfony2plugin.doctrine.DoctrineUtil;
14+
import org.jetbrains.annotations.NotNull;
15+
import org.jetbrains.yaml.YAMLFileType;
16+
17+
import java.util.Collection;
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
21+
public class DoctrineMetadataFileStubIndex extends FileBasedIndexExtension<String, String> {
22+
23+
public static final ID<String, String> KEY = ID.create("fr.adrienbrault.idea.symfony2plugin.doctrine_metadata");
24+
private final KeyDescriptor<String> myKeyDescriptor = new EnumeratorStringDescriptor();
25+
26+
private static class MyStringStringFileContentDataIndexer implements DataIndexer<String, String, FileContent> {
27+
@NotNull
28+
@Override
29+
public Map<String, String> map(@NotNull FileContent fileContent) {
30+
31+
Map<String, String> map = new HashMap<String, String>();
32+
33+
PsiFile psiFile = fileContent.getPsiFile();
34+
if(!Symfony2ProjectComponent.isEnabledForIndex(psiFile.getProject())) {
35+
return map;
36+
}
37+
38+
Collection<Pair<String, String>> classRepositoryPair = DoctrineUtil.getClassRepositoryPair(psiFile);
39+
if(classRepositoryPair != null F438 && classRepositoryPair.size() > 0) {
40+
for (Pair<String, String> pair : classRepositoryPair) {
41+
map.put(pair.getFirst(), pair.getSecond());
42+
}
43+
}
44+
45+
return map;
46+
}
47+
}
48+
49+
@NotNull
50+
@Override
51+
public ID<String, String> getName() {
52+
return KEY;
53+
}
54+
55+
@NotNull
56+
@Override
57+
public DataIndexer<String, String, FileContent> getIndexer() {
58+
return new MyStringStringFileContentDataIndexer();
59+
}
60+
61+
@NotNull
62+
@Override
63+
public KeyDescriptor<String> getKeyDescriptor() {
64+
return this.myKeyDescriptor;
65+
}
66+
67+
@NotNull
68+
@Override
69+
public DataExternalizer<String> getValueExternalizer() {
70+
return ContainerParameterStubIndex.StringDataExternalizer.STRING_DATA_EXTERNALIZER;
71+
}
72+
73+
@NotNull
74+
@Override
75+
public FileBasedIndex.InputFilter getInputFilter() {
76+
return new FileBasedIndex.InputFilter() {
77+
@Override
78+
public boolean acceptInput(@NotNull VirtualFile file) {
79+
FileType fileType = file.getFileType();
80+
return fileType == XmlFileType.INSTANCE || fileType == YAMLFileType.YML;
81+
}
82+
};
83+
}
84+
85+
@Override
86+
public boolean dependsOnFileContent() {
87+
return true;
88+
}
89+
90+
@Override
91+
public int getVersion() {
92+
return 1;
93+
}
94+
}

src/fr/adrienbrault/idea/symfony2plugin/stubs/util/IndexUtil.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ public static void forceReindex() {
1818
TwigMacroFromStubIndex.KEY,
1919
TwigMacroFunctionStubIndex.KEY,
2020
RoutesStubIndex.KEY,
21-
YamlTranslationStubIndex.KEY
21+
YamlTranslationStubIndex.KEY,
22+
DoctrineMetadataFileStubIndex.KEY
2223
};
2324

2425
for(ID<?,?> id: indexIds) {

tests/fr/adrienbrault/idea/symfony2plugin/tests/SymfonyLightCodeInsightFixtureTestCase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@ public boolean process(VirtualFile virtualFile) {
301301
}
302302
}
303303

304+
public void assertIndexContainsKeyWithValue(@NotNull ID<String, String> id, @NotNull String key, @NotNull String value) {
305+
assertContainsElements(FileBasedIndexImpl.getInstance().getValues(id, key, GlobalSearchScope.allScope(getProject())), value);
306+
}
307+
304308
public void assertLocalInspectionContainsContains(String filename, String content, String contains) {
305309
Set<String> matches = new HashSet<String>();
306310

0 commit comments

Comments
 (0)
0