Skip to content

Commit c9cadd9

Browse files
committed
add new form extension visitor to reuse type visitor; and support for nested ExtendedType form; resolves #623 #651
1 parent 80a1792 commit c9cadd9

File tree

5 files changed

+167
-21
lines changed

5 files changed

+167
-21
lines changed

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

+4-13
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
import com.intellij.psi.PsiElement;
66
import com.jetbrains.php.lang.PhpLanguage;
77
import com.jetbrains.php.lang.psi.elements.*;
8-
import com.jetbrains.php.lang.psi.elements.impl.PhpTypedElementImpl;
98
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
109
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
1110
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionContributor;
1211
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider;
1312
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar;
1413
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter;
1514
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClass;
16-
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormOption;
1715
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormOptionEnum;
1816
import fr.adrienbrault.idea.symfony2plugin.form.util.FormOptionsUtil;
1917
import fr.adrienbrault.idea.symfony2plugin.form.util.FormUtil;
@@ -113,10 +111,10 @@ public Collection<PsiElement> getPsiTargets(PsiElement psiElement) {
113111

114112
final Collection<PsiElement> psiElements = new ArrayList<PsiElement>();
115113

116-
FormOptionsUtil.getFormDefaultKeys(getProject(), formType, new FormOptionVisitor() {
114+
FormOptionsUtil.visitFormOptions(getProject(), formType, new FormOptionVisitor() {
117115
@Override
118116
public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNull FormClass formClass, @NotNull FormOptionEnum optionEnum) {
119-
if(option.equals(value)) {
117+
if (option.equals(value)) {
120118
psiElements.add(psiElement);
121119
}
122120
}
@@ -127,15 +125,8 @@ public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNu
127125

128126
@NotNull
129127
public Collection<LookupElement> getLookupElements() {
130-
131-
final Collection<LookupElement> lookupElements = new ArrayList<LookupElement>();
132-
133-
for(FormOption formOption: FormOptionsUtil.getFormExtensionKeys(getProject(), "form", this.formType).values()) {
134-
lookupElements.add(FormOptionsUtil.getOptionLookupElement(formOption));
135-
}
136-
137-
FormOptionsUtil.getFormDefaultKeys(getProject(), formType, new FormOptionLookupVisitor(lookupElements));
138-
128+
Collection<LookupElement> lookupElements = new ArrayList<LookupElement>();
129+
FormOptionsUtil.visitFormOptions(getProject(), formType, new FormOptionLookupVisitor(lookupElements));
139130
return lookupElements;
140131
}
141132

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

+27
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,33 @@ public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNu
217217
return items;
218218
}
219219

220+
public static void visitFormOptions(@NotNull Project project, @NotNull String formTypeName, @NotNull FormOptionVisitor visitor) {
221+
visitFormOptions(project, formTypeName, new HashMap<String, String>(), new FormUtil.FormTypeCollector(project).collect(), 0, visitor);
222+
}
223+
224+
private static Map<String, String> visitFormOptions(Project project, String formTypeName, HashMap<String, String> defaultValues, FormUtil.FormTypeCollector collector, int depth, @NotNull FormOptionVisitor visitor) {
225+
226+
PhpClass phpClass = collector.getFormTypeToClass(formTypeName);
227+
if(phpClass == null) {
228+
return defaultValues;
229+
}
230+
231+
getDefaultOptions(project, phpClass, new FormClass(FormClassEnum.FORM_TYPE, phpClass, false), visitor);
232+
for (FormClass formClass : getExtendedTypeClasses(project, formTypeName)) {
233+
getDefaultOptions(project, formClass.getPhpClass(), new FormClass(FormClassEnum.EXTENSION, formClass.getPhpClass(), false), visitor);
234+
}
235+
236+
// recursive search for parent form types
237+
if (depth < 10) {
238+
String formParent = FormUtil.getFormParentOfPhpClass(phpClass);
239+
if(formParent != null) {
240+
visitFormOptions(project, formParent, defaultValues, collector, ++depth, visitor);
241+
}
242+
}
243+
244+
return defaultValues;
245+
}
246+
220247
public static void getFormDefaultKeys(@NotNull Project project, @NotNull String formTypeName, @NotNull FormOptionVisitor visitor) {
221248
getFormDefaultKeys(project, formTypeName, new HashMap<String, String>(), new FormUtil.FormTypeCollector(project).collect(), 0, visitor);
222249
}

tests/fr/adrienbrault/idea/symfony2plugin/tests/form/util/FormOptionsUtilTest.java

+54
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.form.util;
22

3+
import com.intellij.psi.PsiElement;
34
import com.intellij.util.containers.ContainerUtil;
5+
import com.jetbrains.php.lang.PhpFileType;
46
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClass;
57
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClassEnum;
8+
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormOptionEnum;
69
import fr.adrienbrault.idea.symfony2plugin.form.util.FormOptionsUtil;
10+
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionVisitor;
711
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
12+
import org.jetbrains.annotations.NotNull;
813

914
import java.io.File;
15+
import java.util.HashSet;
16+
import java.util.Set;
1017

1118
/**
1219
* @author Daniel Espendiller <daniel@espendiller.net>
@@ -17,7 +24,25 @@ public class FormOptionsUtilTest extends SymfonyLightCodeInsightFixtureTestCase
1724

1825
public void setUp() throws Exception {
1926
super.setUp();
27+
28+
myFixture.configureByText(PhpFileType.INSTANCE, "<?php\n" +
29+
"namespace Symfony\\Component\\Form\n" +
30+
"{\n" +
31+
" interface FormTypeExtensionInterface\n" +
32+
" {\n" +
33+
" public function getExtendedType();\n" +
34+
" }\n" +
35+
"\n" +
36+
" interface FormTypeInterface\n" +
37+
" {\n" +
38+
" public function getName();\n" +
39+
" }\n" +
40+
"}"
41+
);
42+
2043
myFixture.copyFileToProject("FormOptionsUtil.php");
44+
myFixture.copyFileToProject("FormOptionsUtilKeys.php");
45+
2146
}
2247

2348
protected String getTestDataPath() {
@@ -47,4 +72,33 @@ public void testGetExtendedTypeClassesAsClassConstant() {
4772
assertEquals("\\Foo\\Bar\\BarType", myType.getPhpClass().getFQN());
4873
}
4974
}
75+
76+
public void testClassOptionsVisitorWithExtensionAndParents() {
77+
78+
final Set<String> options = new HashSet<String>();
79+
80+
FormOptionsUtil.visitFormOptions(getProject(), "foo", new FormOptionVisitor() {
81+
@Override
82+
public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNull FormClass formClass, @NotNull FormOptionEnum optionEnum) {
83+
options.add(option);
84+
}
85+
});
86+
87+
assertContainsElements(options, "MyType", "BarTypeParent", "BarTypeExtension");
88+
}
89+
90+
public void testClassOptionsVisitorWithExtensionAndParentsWithClassConstant() {
91+
92+
final Set<String> optionsClass = new HashSet<String>();
93+
94+
FormOptionsUtil.visitFormOptions(getProject(), "Options\\Bar\\Foobar", new FormOptionVisitor() {
95+
@Override
96+
public void visit(@NotNull PsiElement psiElement, @NotNull String option, @NotNull FormClass formClass, @NotNull FormOptionEnum optionEnum) {
97+
optionsClass.add(option);
98+
}
99+
});
100+
101+
assertContainsElements(optionsClass, "BarType");
102+
}
103+
50104
}

tests/fr/adrienbrault/idea/symfony2plugin/tests/form/util/fixtures/FormOptionsUtil.php

-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
<?php
22

3-
namespace Symfony\Component\Form
4-
{
5-
interface FormTypeExtensionInterface
6-
{
7-
public function getExtendedType();
8-
}
9-
}
10-
113
namespace Foo\Bar
124
{
135
use Symfony\Component\Form\FormTypeExtensionInterface;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
namespace Options\Bar
4+
{
5+
use Symfony\Component\Form\FormTypeInterface;
6+
use Symfony\Component\Form\OptionsResolverInterface;
7+
8+
use Symfony\Component\Form\FormTypeExtensionInterface;
9+
10+
class MyType implements FormTypeExtensionInterface {
11+
public function configureOptions(OptionsResolver $resolver)
12+
{
13+
$resolver->setDefaults(array(
14+
'MyType' => null,
15+
));
16+
}
17+
18+
public function getExtendedType()
19+
{
20+
return 'foo';
21+
}
22+
}
23+
24+
class BarType implements FormTypeExtensionInterface {
25+
public function configureOptions(OptionsResolver $resolver)
26+
{
27+
$resolver->setDefaults(array(
28+
'BarType' => null,
29+
));
30+
}
31+
32+
public function getExtendedType()
33+
{
34+
return \Options\Bar\Foobar::class;
35+
}
36+
}
37+
38+
class BarTypeExtension implements FormTypeExtensionInterface {
39+
public function configureOptions(OptionsResolver $resolver)
40+
{
41+
$resolver->setDefaults(array(
42+
'BarTypeExtension' => null,
43+
));
44+
}
45+
46+
public function getExtendedType()
47+
{
48+
return 'foo_parent';
49+
}
50+
}
51+
52+
class Foo implements FormTypeInterface
53+
{
54+
public function getName()
55+
{
56+
return 'foo';
57+
}
58+
public function getParent()
59+
{
60+
return 'foo_parent';
61+
}
62+
}
63+
64+
class FooParent implements FormTypeInterface
65+
{
66+
public function configureOptions(OptionsResolver $resolver)
67+
{
68+
$resolver->setDefaults(array(
69+
'BarTypeParent' => null,
70+
));
71+
}
72+
73+
public function getName()
74+
{
75+
return 'foo_parent';
76+
}
77+
}
78+
79+
class Foobar implements FormTypeInterface
80+
{
81+
}
82+
}

0 commit comments

Comments
 (0)