8000 support public property for form field mapping and dropping custom Do… · Koc/idea-php-symfony2-plugin@de0c541 · GitHub
[go: up one dir, main page]

Skip to content

Commit de0c541

Browse files
committed
support public property for form field mapping and dropping custom Doctrine field mapping occurs on PropertyAccess component Haehnchen#786
1 parent c186283 commit de0c541

File tree

6 files changed

+166
-69
lines changed

6 files changed

+166
-69
lines changed

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

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,86 +8,84 @@
88
import com.jetbrains.php.lang.psi.elements.Method;
99
import com.jetbrains.php.lang.psi.elements.PhpClass;
1010
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
11-
import fr.adrienbrault.idea.symfony2plugin.doctrine.EntityHelper;
12-
import fr.adrienbrault.idea.symfony2plugin.doctrine.dict.DoctrineModelField;
13-
import fr.adrienbrault.idea.symfony2plugin.doctrine.dict.DoctrineModelFieldLookupElement;
14-
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1511
import fr.adrienbrault.idea.symfony2plugin.util.StringUtils;
1612
import org.jetbrains.annotations.NotNull;
1713

1814
import java.util.*;
15+
import java.util.stream.Collectors;
1916

2017
/**
2118
* @author Daniel Espendiller <daniel@espendiller.net>
2219
*/
23-
public class FormUnderscoreMethodReference extends PsiPolyVariantReferenceBase<PsiElement> {
24-
25-
private StringLiteralExpression element;
20+
public class FormUnderscoreMethodReference extends PsiPolyVariantReferenceBase<StringLiteralExpression> {
21+
@NotNull
2622
private PhpClass phpClass;
2723

28-
public FormUnderscoreMethodReference(@NotNull StringLiteralExpression element, PhpClass phpClass) {
24+
public FormUnderscoreMethodReference(@NotNull StringLiteralExpression element, @NotNull PhpClass phpClass) {
2925
super(element);
30-
this.element = element;
3126
this.phpClass = phpClass;
3227
}
3328

3429
@NotNull
3530
@Override
3631
public ResolveResult[] multiResolve(boolean incompleteCode) {
37-
3832
Collection<PsiElement> psiElements = new ArrayList<>();
3933

40-
String value = element.getContents();
41-
for(DoctrineModelField field: EntityHelper.getModelFields(this.phpClass)) {
42-
if(value.equals(field.getName())) {
43-
psiElements.addAll(field.getTargets());
44-
}
45-
}
34+
Set<String> methods = getCamelizeAndUnderscoreString(getElement().getContents());
4635

4736
// provide setter fallback for non model class or or unknown methods
48-
String methodCamel = StringUtils.camelize(element.getContents());
49-
Method method = phpClass.findMethodByName("set" + methodCamel);
50-
if (method != null) {
51-
psiElements.add(method);
37+
for (String value : methods) {
38+
Method method = phpClass.findMethodByName("set" + value);
39+
if (method != null) {
40+
psiElements.add(method);
41+
}
5242
}
5343

44+
// property path
45+
psiElements.addAll(this.phpClass.getFields().stream()
46+
.filter(field -> !field.isConstant() && field.getModifier().isPublic() && methods.contains(field.getName()))
47+
.collect(Collectors.toList())
48+
);
49+
5450
return PsiElementResolveResult.createResults(psiElements);
5551
}
5652

5753
@NotNull
5854
@Override
5955
public Object[] getVariants() {
60-
61-
List<LookupElement> lookupElements = new ArrayList<>();
62-
63-
Set<String> strings = new HashSet<>();
64-
for(DoctrineModelField field: EntityHelper.getModelFields(this.phpClass)) {
65-
addCamelUnderscoreName(strings, org.apache.commons.lang.StringUtils.trim(field.getName()));
66-
lookupElements.add(new DoctrineModelFieldLookupElement(field).withBoldness(true));
67-
}
56+
Collection<LookupElement> lookupElements = new ArrayList<>();
6857

6958
// provide setter fallback for non model class or unknown methods
7059
for(Method method: this.phpClass.getMethods()) {
7160
String name = method.getName();
7261
if(name.length() > 3 && name.startsWith("set")) {
73-
name = name.substring(3);
74-
if(!isCamelUnderscoreEqual(strings, name)) {
75-
// @TODO: should we really stay this underscore way?
76-
lookupElements.add(new PhpUnderscoreMethodLookupElement(method));
77-
}
62+
lookupElements.add(new PhpFormPropertyMethodLookupElement(method, StringUtils.lcfirst(name.substring(3))));
7863
}
7964
}
8065

66+
// Symfony\Component\PropertyAccess\PropertyAccessor::getWriteAccessInfo
67+
// property: public $foobar
68+
lookupElements.addAll(this.phpClass.getFields().stream()
69+
.filter(field -> !field.isConstant() && field.getModifier().isPublic())
70+
.map(field -> new PhpFormPropertyMethodLookupElement(field, field.getName()))
71+
.collect(Collectors.toList())
72+
);
73+
8174
return lookupElements.toArray();
8275
}
8376

84-
private boolean isCamelUnderscoreEqual(Set<String> strings, String string) {
85-
return strings.contains(string) || strings.contains(StringUtils.camelize(string)) || strings.contains(StringUtils.underscore(string));
86-
}
77+
@NotNull
78+
private Set<String> getCamelizeAndUnderscoreString(@NotNull String string) {
79+
TreeSet<String> strings = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
8780

88-
private void addCamelUnderscoreName(Set<String> strings, String string) {
89-
strings.add(StringUtils.camelize(string));
90-
strings.add(StringUtils.underscore(string));
91-
}
81+
string = StringUtils.lcfirst(string);
9282

83+
strings.addAll(Arrays.asList(
84+
StringUtils.underscore(string),
85+
StringUtils.camelize(string),
86+
string
87+
));
88+
89+
return strings;
90+
}
9391
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package fr.adrienbrault.idea.symfony2plugin.form;
2+
3+
import com.jetbrains.php.completion.PhpLookupElement;
4+
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
/**
8+
* @author Daniel Espendiller <daniel@espendiller.net>
9+
*/
10+
class PhpFormPropertyMethodLookupElement extends PhpLookupElement {
11+
12+
@NotNull
13+
private final String methodOverwrite;
14+
15+
PhpFormPropertyMethodLookupElement(@NotNull PhpNamedElement namedElement, @NotNull String methodOverwrite) {
16+
super(namedElement);
17+
this.methodOverwrite = methodOverwrite;
18+
}
19+
20+
@NotNull
21+
public String getLookupString() {
22+
return this.methodOverwrite;
23+
}
24+
}

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

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/fr/adrienbrault/idea/symfony2plugin/util/StringUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fr.adrienbrault.idea.symfony2plugin.util;
22

3+
import org.jetbrains.annotations.NotNull;
4+
35
public class StringUtils {
46

57
public static String camelize(String input) {
@@ -33,6 +35,12 @@ public static String ucfirst(String chaine){
3335
return chaine.substring(0, 1).toUpperCase() + chaine.substring(1);
3436
}
3537

38+
@NotNull
39+
public static String lcfirst(@NotNull String input){
40+
return Character.toLowerCase(input.charAt(0)) +
41+
(input.length() > 1 ? input.substring(1) : "");
42+
}
43+
3644
/**
3745
* Simple string compare if class name is in same namespace
3846
* Starting backslash doesnt break equal check

tests/fr/adrienbrault/idea/symfony2plugin/tests/form/FormTypeReferenceContributorTest.java

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.form;
22

3+
import com.intellij.patterns.PlatformPatterns;
34
import com.jetbrains.php.lang.PhpFileType;
5+
import com.jetbrains.php.lang.psi.elements.Field;
6+
import com.jetbrains.php.lang.psi.elements.Method;
47
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
58

69
import java.io.File;
@@ -10,7 +13,6 @@
1013
* @see fr.adrienbrault.idea.symfony2plugin.form.FormTypeReferenceContributor
1114
*/
1215
public class FormTypeReferenceContributorTest extends SymfonyLightCodeInsightFixtureTestCase {
13-
1416
public void setUp() throws Exception {
1517
super.setUp();
1618
myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject("classes.php"));
@@ -20,7 +22,7 @@ protected String getTestDataPath() {
2022
return new File(this.getClass().getResource("fixtures").getFile()).getAbsolutePath();
2123
}
2224

23-
public void testDataClassProperty() {
25+
public void testDataClassPropertyCompletion() {
2426
assertCompletionContains(PhpFileType.INSTANCE, "<?php\n" +
2527
"\n" +
2628
"class FormType\n" +
@@ -72,5 +74,85 @@ public void testDataClassProperty() {
7274
"}",
7375
"timestamp"
7476
);
77+
78+
assertCompletionContains(PhpFileType.INSTANCE, "<?php\n" +
79+
"\n" +
80+
"class FormType\n" +
81+
"{\n" +
82+
" protected $foo = 'DateTime';\n" +
83+
" public function buildForm(\\Symfony\\Component\\Form\\FormBuilderInterface $builder, array $options) {\n" +
84+
" $builder->add('<caret>');\n" +
85+
" }\n" +
86+
" public function setDefaultOptions(OptionsResolverInterface $resolver)\n" +
87+
" {\n" +
88+
" $resolver->setDefaults(array(\n" +
89+
" 'data_class' => \\Form\\DataClass\\Model::class,\n" +
90+
" ));\n" +
91+
" }\n" +
92+
"}",
93+
"fooBar"
94+
);
95+
}
96+
97+
public void testDataClassWithPublicPropertyCompletion() {
98+
assertCompletionContains(PhpFileType.INSTANCE, "<?php\n" +
99+
"\n" +
100+
"class FormType\n" +
101+
"{\n" +
102+
" protected $foo = 'DateTime';\n" +
103+
" public function buildForm(\\Symfony\\Component\\Form\\FormBuilderInterface $builder, array $options) {\n" +
104+
" $builder->add('<caret>');\n" +
105+
" }\n" +
106+
" public function setDefaultOptions(OptionsResolverInterface $resolver)\n" +
107+
" {\n" +
108+
" $resolver->setDefaults(array(\n" +
109+
" 'data_class' => \\Form\\DataClass\\Model::class,\n" +
110+
" ));\n" +
111+
" }\n" +
112+
"}",
113+
"var", "varBar"
114+
);
115+
}
116+
117+
public void testFormDataFieldPropertyPathReferencesForMethod() {
118+
for (String s : new String[]{"foo_bar", "fooBar"}) {
119+
assertReferenceMatchOnParent(PhpFileType.INSTANCE, "<?php\n" +
120+
"\n" +
121+
"class FormType\n" +
122+
"{\n" +
123+
" protected $foo = 'DateTime';\n" +
124+
" public function buildForm(\\Symfony\\Component\\Form\\FormBuilderInterface $builder, array $options) {\n" +
125+
" $builder->add('" + s + "<caret>');\n" +
126+
" }\n" +
127+
" public function setDefaultOptions(OptionsResolverInterface $resolver)\n" +
128+
" {\n" +
129+
" $resolver->setDefaults(array(\n" +
130+
" 'data_class' => \\Form\\DataClass\\Model::class,\n" +
131+
" ));\n" +
132+
" }\n" +
133+
"}", PlatformPatterns.psiElement(Method.class)
134+
);
135+
}
136+
}
137+
138+
public void testFormDataFieldPropertyPathReferencesForProperty() {
139+
for (String s : new String[]{"var", "varBar", "var_bar", "var_Bar"}) {
140+
assertReferenceMatchOnParent(PhpFileType.INSTANCE, "<?php\n" +
141+
"\n" +
142+
"class FormType\n" +
143+
"{\n" +
144+
" protected $foo = 'DateTime';\n" +
145+
" public function buildForm(\\Symfony\\Component\\Form\\FormBuilderInterface $builder, array $options) {\n" +
146+
" $builder->add('" + s + "<caret>');\n" +
147+
" }\n" +
148+
" public function setDefaultOptions(OptionsResolverInterface $resolver)\n" +
149+
" {\n" +
150+
" $resolver->setDefaults(array(\n" +
151+
" 'data_class' => \\Form\\DataClass\\Model::class,\n" +
152+
" ));\n" +
153+
" }\n" +
154+
"}", PlatformPatterns.psiElement(Field.class)
155+
);
156+
}
75157
}
76158
}

tests/fr/adrienbrault/idea/symfony2plugin/tests/form/fixtures/classes.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,16 @@ public function getName()
7575
return 'foo_type';
7676
}
7777
}
78+
}
79+
80+
namespace Form\DataClass
81+
{
82+
class Model {
83+
public $var;
84+
public $varBar;
85+
86+
public function setFooBar()
87+
{
88+
}
89+
}
7890
}

0 commit comments

Comments
 (0)
0