Skip to content

Commit 710a1de

Browse files
committed
add navigation form options of setRequired, setOptional, setDefined and refactor form options to visitor strategy #502
1 parent 24f00e3 commit 710a1de

File tree

7 files changed

+214
-125
lines changed

7 files changed

+214
-125
lines changed

src/fr/adrienbrault/idea/symfony2plugin/form/FormGotoCompletionRegistrar.java

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
9191
@Override
9292
public GotoCompletionProvider getProvider(@NotNull PsiElement psiElement) {
9393

94+
95+
// @TODO: migrate to completion provider, because of performance
9496
PsiElement parent = psiElement.getParent();
9597
if(!(parent instanceof StringLiteralExpression)) {
9698
return null;

src/fr/adrienbrault/idea/symfony2plugin/form/FormOptionGotoCompletionRegistrar.java

+22-48
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
11
package fr.adrienbrault.idea.symfony2plugin.form;
22

33
import com.intellij.codeInsight.lookup.LookupElement;
4-
import com.intellij.codeInsight.lookup.LookupElementBuilder;
5-
import com.intellij.patterns.ElementPattern;
64
import com.intellij.patterns.PlatformPatterns;
75
import com.intellij.psi.PsiElement;
86
import com.jetbrains.php.lang.PhpLanguage;
9-
import com.jetbrains.php.lang.psi.elements.*;
7+
import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression;
8+
import com.jetbrains.php.lang.psi.elements.MethodReference;
9+
import com.jetbrains.php.lang.psi.elements.ParameterList;
10+
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
1011
import com.jetbrains.php.lang.psi.elements.impl.PhpTypedElementImpl;
11-
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
1212
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
1313
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
14-
import fr.adrienbrault.idea.symfony2plugin.TwigHelper;
1514
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionContributor;
1615
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider;
1716
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar;
1817
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter;
18+
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClass;
1919
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormOption;
20+
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormOptionEnum;
2021
import fr.adrienbrault.idea.symfony2plugin.form.util.FormOptionsUtil;
22+
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionLookupVisitor;
23+
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionVisitor;
2124
import fr.adrienbrault.idea.symfony2plugin.util.ParameterBag;
2225
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
2326
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
2427
import org.apache.commons.lang.StringUtils;
2528
import org.jetbrains.annotations.NotNull;
2629
import org.jetbrains.annotations.Nullable;
2730

28-
import java.util.*;
31+
import java.util.ArrayList;
32+
import java.util.Collection;
33+
import java.util.Collections;
2934

3035
public class FormOptionGotoCompletionRegistrar implements GotoCompletionRegistrar {
3136

@@ -88,10 +93,9 @@ private GotoCompletionProvider getMatchingOption(ParameterList parameterList, @N
8893

8994
private static class FormReferenceCompletionProvider extends GotoCompletionProvider {
9095

91-
@Nullable
9296
private final String formType;
9397

94-
public FormReferenceCompletionProvider(@NotNull PsiElement element, @Nullable String formType) {
98+
public FormReferenceCompletionProvider(@NotNull PsiElement element, @NotNull String formType) {
9599
super(element);
96100
this.formType = formType;
97101
}
@@ -104,65 +108,35 @@ public Collection<PsiElement> getPsiTargets(PsiElement psiElement) {
104108
return Collections.emptyList();
105109
}
106110

107-
String value = ((StringLiteralExpression) element).getContents();
111+
final String value = ((StringLiteralExpression) element).getContents();
108112
if(StringUtils.isBlank(value)) {
109113
return Collections.emptyList();
110114
}
111115

112-
Set<String> classNames = new HashSet<String>();
113-
114-
Map<String, String> defaultOptions = FormOptionsUtil.getFormDefaultKeys(element.getProject(), formType);
115-
if(defaultOptions.containsKey(value)) {
116-
classNames.add(defaultOptions.get(value));
117-
}
116+
final Collection<PsiElement> psiElements = new ArrayList<PsiElement>();
118117

119-
Map<String, FormOption> formExtension = FormOptionsUtil.getFormExtensionKeys(getProject(), "form", this.formType);
120-
if(formExtension.containsKey(value)) {
121-
classNames.add(formExtension.get(value).getFormClass().getPhpClass().getPresentableFQN());
122-
}
123-
124-
Collection<PsiElement> psiElements = new ArrayList<PsiElement>();
125-
126-
for(String className: classNames) {
127-
for (String formOptionMethod : FormOptionsUtil.FORM_OPTION_METHODS) {
128-
Method method = PhpElementsUtil.getClassMethod(getProject(), className, formOptionMethod);
129-
if(method != null) {
130-
PsiElement keyValue = PhpElementsUtil.findArrayKeyValueInsideReference(method, "setDefaults", value);
131-
if(keyValue != null) {
132-
psiElements.add(keyValue);
133-
}
118+
FormOptionsUtil.getFormDefaultKeys(getProject(), formType, new FormOptionVisitor() {
119+
@Override
120+
public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNull FormClass formClass, @NotNull FormOptionEnum optionEnum) {
121+
if(option.equals(value)) {
122+
psiElements.add(psiElement);
134123
}
135124
}
136-
}
125+
});
137126

138127
return psiElements;
139128
}
140129

141130
@NotNull
142131
public Collection<LookupElement> getLookupElements() {
143132

144-
Collection<LookupElement> lookupElements = new ArrayList<LookupElement>();
133+
final Collection<LookupElement> lookupElements = new ArrayList<LookupElement>();
145134

146135
for(FormOption formOption: FormOptionsUtil.getFormExtensionKeys(getProject(), "form", this.formType).values()) {
147136
lookupElements.add(FormOptionsUtil.getOptionLookupElement(formOption));
148137
}
149138

150-
for(Map.Entry<String, String> extension: FormOptionsUtil.getFormDefaultKeys(getProject(), this.formType).entrySet()) {
151-
String typeText = extension.getValue();
152-
if(typeText.lastIndexOf("\\") != -1) {
153-
typeText = typeText.substring(typeText.lastIndexOf("\\") + 1);
154-
}
155-
156-
if(typeText.endsWith("Type")) {
157-
typeText = typeText.substring(0, typeText.length() - 4);
158-
}
159-
160-
lookupElements.add(LookupElementBuilder.create(extension.getKey())
161-
.withTypeText(typeText, true)
162-
.withIcon(Symfony2Icons.FORM_OPTION)
163-
);
164-
165-
}
139+
FormOptionsUtil.getFormDefaultKeys(getProject(), formType, new FormOptionLookupVisitor(lookupElements));
166140

167141
return lookupElements;
168142
}

src/fr/adrienbrault/idea/symfony2plugin/form/util/FormOptionsUtil.java

+70-67
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
import com.jetbrains.php.lang.psi.elements.*;
1111
import com.jetbrains.php.phpunit.PhpUnitUtil;
1212
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
13+
import fr.adrienbrault.idea.symfony2plugin.form.FormOptionGotoCompletionRegistrar;
14+
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionLookupVisitor;
1315
import fr.adrienbrault.idea.symfony2plugin.form.dict.*;
16+
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionVisitor;
1417
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1518
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
1619
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
@@ -21,6 +24,9 @@
2124

2225
import java.util.*;
2326

27+
/**
28+
* @author Daniel Espendiller <daniel@espendiller.net>
29+
*/
2430
public class FormOptionsUtil {
2531

2632
private static final String EXTENDED_TYPE_METHOD = "getExtendedType";
@@ -92,7 +98,8 @@ private static void visitExtendedTypeMethod(List<String> formTypeNamesList, List
9298

9399
}
94100

95-
public static Map<String, FormOption> getFormExtensionKeys(Project project, String... formTypeNames) {
101+
@NotNull
102+
public static Map<String, FormOption> getFormExtensionKeys(@NotNull Project project, @NotNull String... formTypeNames) {
96103

97104
List<FormClass> typeClasses = FormOptionsUtil.getExtendedTypeClasses(project, formTypeNames);
98105
Map<String, FormOption> extensionClassMap = new HashMap<String, FormOption>();
@@ -208,18 +215,36 @@ private static void getFormViewVarsAttachKeys(Set<String> stringSet, FieldRefere
208215
}
209216
}
210217

211-
public static Map<String, String> getFormDefaultKeys(Project project, String formTypeName) {
212-
return getFormDefaultKeys(project, formTypeName, new HashMap<String, String>(), new FormUtil.FormTypeCollector(project).collect(), 0);
218+
219+
@Deprecated
220+
public static Map<String, String> getFormDefaultKeys(@NotNull Project project, @NotNull String formTypeName) {
221+
final Map<String, String> items = new HashMap<String, String>();
222+
223+
getFormDefaultKeys(project, formTypeName, new HashMap<String, String>(), new FormUtil.FormTypeCollector(project).collect(), 0, new FormOptionVisitor() {
224+
@Override
225+
public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNull FormClass formClass, @NotNull FormOptionEnum optionEnum) {
226+
String presentableFQN = formClass.getPhpClass().getPresentableFQN();
227+
if(presentableFQN != null) {
228+
items.put(option, presentableFQN);
229+
}
230+
}
231+
});
232+
233+
return items;
213234
}
214235

215-
private static Map<String, String> getFormDefaultKeys(Project project, String formTypeName, HashMap<String, String> defaultValues, FormUtil.FormTypeCollector collector, int depth) {
236+
public static void getFormDefaultKeys(@NotNull Project project, @NotNull String formTypeName, @NotNull FormOptionVisitor visitor) {
237+
getFormDefaultKeys(project, formTypeName, new HashMap<String, String>(), new FormUtil.FormTypeCollector(project).collect(), 0, visitor);
238+
}
239+
240+
private static Map<String, String> getFormDefaultKeys(Project project, String formTypeName, HashMap<String, String> defaultValues, FormUtil.FormTypeCollector collector, int depth, @NotNull FormOptionVisitor visitor) {
216241

217242
PhpClass phpClass = collector.getFormTypeToClass(formTypeName);
218243
if(phpClass == null) {
219244
return defaultValues;
220245
}
221246

222-
attachOnDefaultOptions(project, defaultValues, phpClass);
247+
getDefaultOptions(project, phpClass, new FormClass(FormClassEnum.FORM_TYPE, phpClass, false), visitor);
223248

224249
// recursive search for parent form types
225250
PsiElement parentMethod = PhpElementsUtil.getClassMethod(phpClass, "getParent");
@@ -228,7 +253,7 @@ private static Map<String, String> getFormDefaultKeys(Project project, String fo
228253
if(phpReturn != null) {
229254
PhpPsiElement returnValue = phpReturn.getFirstPsiChild();
230255
if(returnValue instanceof StringLiteralExpression) {
231-
getFormDefaultKeys(project, ((StringLiteralExpression) returnValue).getContents(), defaultValues, collector, ++depth);
256+
getFormDefaultKeys(project, ((StringLiteralExpression) returnValue).getContents(), defaultValues, collector, ++depth, visitor);
232257
}
233258

234259
}
@@ -237,24 +262,26 @@ private static Map<String, String> getFormDefaultKeys(Project project, String fo
237262
return defaultValues;
238263
}
239264

240-
/**
241-
* use getDefaultOptions
242-
*/
243-
@Deprecated
244-
private static void attachOnDefaultOptions(@NotNull Project project, @NotNull Map<String, String> defaultValues, @NotNull PhpClass phpClass) {
245-
// @TODO!!! really remove this :)
246-
for (Map.Entry<String, FormOption> entry : getDefaultOptions(project, phpClass, new FormClass(FormClassEnum.FORM_TYPE, phpClass, false)).entrySet()) {
247-
String presentableFQN = entry.getValue().getFormClass().getPhpClass().getPresentableFQN();
248-
if(presentableFQN != null) {
249-
defaultValues.put(entry.getKey(), presentableFQN);
250-
}
251-
}
252-
}
253-
254265
@NotNull
255266
private static Map<String, FormOption> getDefaultOptions(@NotNull Project project, @NotNull PhpClass phpClass, @NotNull FormClass formClass) {
267+
final Map<String, FormOption> options = new HashMap<String, FormOption>();
268+
269+
getDefaultOptions(project, phpClass, formClass, new FormOptionVisitor() {
270+
@Override
271+
public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNull FormClass formClass, @NotNull FormOptionEnum optionEnum) {
272+
// append REQUIRED, if we already know this value
273+
if(options.containsKey(option)) {
274+
options.get(option).addOptionEnum(optionEnum);
275+
} else {
276+
options.put(option, new FormOption(option, formClass, optionEnum));
277+
}
278+
}
279+
});
280+
281+
return options;
282+
}
256283

257-
Map<String, FormOption> options = new HashMap<String, FormOption>();
284+
private static void getDefaultOptions(@NotNull Project project, @NotNull PhpClass phpClass, @NotNull FormClass formClass, @NotNull FormOptionVisitor visitor) {
258285

259286
for(String methodName: new String[] {"setDefaultOptions", "configureOptions"}) {
260287

@@ -269,8 +296,8 @@ private static Map<String, FormOption> getDefaultOptions(@NotNull Project projec
269296
if(PhpElementsUtil.isEqualMethodReferenceName(methodReference, "setDefaults")) {
270297
PsiElement[] parameters = methodReference.getParameters();
271298
if(parameters.length > 0 && parameters[0] instanceof ArrayCreationExpression) {
272-
for(String key: PhpElementsUtil.getArrayCreationKeys((ArrayCreationExpression) parameters[0])) {
273-
options.put(key, new FormOption(key, formClass));
299+
for(Map.Entry<String, PsiElement> entry: PhpElementsUtil.getArrayCreationKeyMap((ArrayCreationExpression) parameters[0]).entrySet()) {
300+
visitor.visit(entry.getValue(), entry.getKey(), formClass, FormOptionEnum.DEFAULT);
274301
}
275302
}
276303

@@ -280,12 +307,8 @@ private static Map<String, FormOption> getDefaultOptions(@NotNull Project projec
280307
if(PhpElementsUtil.isEqualMethodReferenceName(methodReference, currentMethod)) {
281308
PsiElement[] parameters = methodReference.getParameters();
282309
if(parameters.length > 0 && parameters[0] instanceof ArrayCreationExpression) {
283-
for (String stringValue : PhpElementsUtil.getArrayValuesAsString((ArrayCreationExpression) parameters[0])) {
284-
if(options.containsKey(stringValue)) {
285-
options.get(stringValue).addOptionEnum(FormOptionEnum.getEnum(currentMethod));
286-
} else {
287-
options.put(stringValue, new FormOption(stringValue, formClass, FormOptionEnum.REQUIRED));
288-
}
310+
for (Map.Entry<String, PsiElement> entry : PhpElementsUtil.getArrayValuesAsMap((ArrayCreationExpression) parameters[0]).entrySet()) {
311+
visitor.visit(entry.getValue(), entry.getKey(), formClass, FormOptionEnum.getEnum(currentMethod));
289312
}
290313
}
291314
break;
@@ -301,7 +324,7 @@ private static Map<String, FormOption> getDefaultOptions(@NotNull Project projec
301324
PhpClass phpClassInner = ((Method) parentMethod).getContainingClass();
302325
if(phpClassInner != null) {
303326
// @TODO only use setDefaultOptions, recursive call get setDefaults again
304-
options.putAll(getDefaultOptions(project, phpClassInner, formClass));
327+
getDefaultOptions(project, phpClassInner, formClass, visitor);
305328
}
306329
}
307330
}
@@ -310,7 +333,6 @@ private static Map<String, FormOption> getDefaultOptions(@NotNull Project projec
310333

311334
}
312335

313-
return options;
314336
}
315337

316338
/**
@@ -370,52 +392,33 @@ public static Collection<LookupElement> getFormExtensionKeysLookupElements(Proje
370392
return lookupElements;
371393
}
372394

395+
@Deprecated
373396
@NotNull
374-
public static Collection<PsiElement> getDefaultOptionTargets(StringLiteralExpression element, String formType) {
375-
376-
Map<String, String> defaultOptions = FormOptionsUtil.getFormDefaultKeys(element.getProject(), formType);
377-
String value = element.getContents();
397+
public static Collection<PsiElement> getDefaultOptionTargets(@NotNull StringLiteralExpression element, @NotNull String formType) {
378398

379-
if(!defaultOptions.containsKey(value)) {
399+
final String value = element.getContents();
400+
if(StringUtils.isBlank(value)) {
380401
return Collections.emptySet();
381402
}
382403

383-
String className = defaultOptions.get(value);
404+
final Collection<PsiElement> psiElements = new ArrayList<PsiElement>();
384405

385-
// @TODO: use class core
386-
PsiElement[] psiElements = PhpElementsUtil.getPsiElementsBySignature(element.getProject(), "#M#C\\" + className + ".setDefaultOptions");
387-
if(psiElements.length == 0) {
388-
return Collections.emptySet();
389-
}
390-
391-
PsiElement keyValue = PhpElementsUtil.findArrayKeyValueInsideReference(psiElements[0], "setDefaults", value);
392-
if(keyValue != null) {
393-
return Arrays.asList(psiElements);
394-
}
406+
FormOptionsUtil.getFormDefaultKeys(element.getProject(), formType, new FormOptionVisitor() {
407+
@Override
408+
public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNull FormClass formClass, @NotNull FormOptionEnum optionEnum) {
409+
if(option.equals(value)) {
410+
psiElements.add(psiElement);
411+
}
412+
}
413+
});
395414

396-
return Collections.emptySet();
415+
return psiElements;
397416
}
398417

399-
public static Collection<LookupElement> getDefaultOptionLookupElements(Project project, String formType) {
400-
418+
@NotNull
419+
public static Collection<LookupElement> getDefaultOptionLookupElements(@NotNull Project project, @NotNull String formType) {
401420
Collection<LookupElement> lookupElements = new ArrayList<LookupElement>();
402-
403-
for(Map.Entry<String, String> extension: FormOptionsUtil.getFormDefaultKeys(project, formType).entrySet()) {
404-
String typeText = extension.getValue();
405-
if(typeText.lastIndexOf("\\") != -1) {
406-
typeText = typeText.substring(typeText.lastIndexOf("\\") + 1);
407-
}
408-
409-
if(typeText.endsWith("Type")) {
410-
typeText = typeText.substring(0, typeText.length() - 4);
411-
}
412-
413-
lookupElements.add(LookupElementBuilder.create(extension.getKey())
414-
.withTypeText(typeText)
415-
.withIcon(Symfony2Icons.FORM_OPTION)
416-
);
417-
}
418-
421+
FormOptionsUtil.getFormDefaultKeys(project, formType, new FormOptionLookupVisitor(lookupElements));
419422
return lookupElements;
420423
}
421424

0 commit comments

Comments
 (0)