Skip to content

Commit 3a77bbc

Browse files
authoredDec 7, 2017
Merge pull request #1100 from Haehnchen/feature/1048-form-data-class-set-default
[Form] Calling setDefault for data class does not associates form with binded class #1048
2 parents 001a5f3 + 587470a commit 3a77bbc

File tree

6 files changed

+118
-40
lines changed

6 files changed

+118
-40
lines changed
 

‎src/fr/adrienbrault/idea/symfony2plugin/form/FormTypeReferenceContributor.java

+22-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
1919
import org.jetbrains.annotations.NotNull;
2020

21+
import java.util.ArrayList;
22+
import java.util.Collection;
23+
import java.util.Objects;
24+
2125
/**
2226
* @author Daniel Espendiller <daniel@espendiller.net>
2327
*/
@@ -160,13 +164,27 @@ public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @No
160164
return new PsiReference[0];
161165
}
162166

167+
Collection<String> classes = new ArrayList<>();
168+
169+
// $resolver->setDefaults(['data_class' => User::class]);
163170
PsiElement className = PhpElementsUtil.getArrayKeyValueInsideSignaturePsi(psiElement, FormOptionsUtil.FORM_OPTION_METHODS, "setDefaults", "data_class");
164-
if(className == null) {
165-
return new PsiReference[0];
171+
if(className != null) {
172+
String stringValue = PhpElementsUtil.getStringValue(className);
173+
if(stringValue != null) {
174+
classes.add(stringValue);
175+
}
166176
}
167177

168-
PhpClass phpClass = PhpElementsUtil.resolvePhpClassOnPsiElement(className);
169-
if (phpClass == null) {
178+
// $resolver->setDefault('data_class', User::class);
179+
classes.addAll(FormOptionsUtil.getMethodReferenceStringParameter(psiElement, FormOptionsUtil.FORM_OPTION_METHODS, "setDefault", "data_class"));
180+
181+
// find first class
182+
PhpClass phpClass = classes.stream()
183+
.map(clazz -> PhpElementsUtil.getClassInterface(psiElement.getProject(), clazz))
184+
.filter(Objects::nonNull).findFirst()
185+
.orElse(null);
186+
187+
if(phpClass == null) {
170188
return new PsiReference[0];
171189
}
172190

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

+45
Original file line numberDiff line numberDiff line change
@@ -426,4 +426,49 @@ public static String getTranslationFromScope(@NotNull ArrayCreationExpression ar
426426

427427
return translationDomain;
428428
}
429+
430+
/**
431+
* Find methodReferences in scope by its name and method scope and give string value of matching parameter
432+
*
433+
* $resolver->setDefault('data_class', User::class);
434+
*/
435+
@NotNull
436+
public static Collection<String> getMethodReferenceStringParameter(@NotNull PsiElement scope, String[] scopeMethods, @NotNull String methodName, @NotNull String key) {
437+
PhpClass phpClass = PsiTreeUtil.getParentOfType(scope, PhpClass.class);
438+
if(phpClass == null) {
439+
return Collections.emptyList();
440+
}
441+
442+
Collection<String> values = new HashSet<>();
443+
444+
for (String scopeMethod : scopeMethods) {
445+
Method method = phpClass.findMethodByName(scopeMethod);
446+
447+
if(method == null) {
448+
continue;
449+
}
450+
451+
for (MethodReference methodReference : PsiTreeUtil.collectElementsOfType(method, MethodReference.class)) {
452+
if(!methodName.equals(methodReference.getName())) {
453+
continue;
454+
}
455+
456+
// our key to find
457+
String argument = PhpElementsUtil.getMethodReferenceStringValueParameter(methodReference, 0);
458+
if(!key.equals(argument)) {
459+
continue;
460+
}
461+
462+
// resolve value
463+
String value = PhpElementsUtil.getMethodReferenceStringValueParameter(methodReference, 1);
464+
if(StringUtils.isBlank(value)) {
465+
continue;
466+
}
467+
468+
values.add(value);
469+
}
470+
}
471+
472+
return values;
473+
}
429474
}

‎src/fr/adrienbrault/idea/symfony2plugin/util/PhpElementsUtil.java

+23-35
Original file line numberDiff line numberDiff line change
@@ -537,34 +537,30 @@ static public String getArrayKeyValueInsideSignature(PsiElement psiElementInside
537537
}
538538

539539
@Nullable
540-
static public PsiElement getArrayKeyValueInsideSignaturePsi(Project project, String signature, String methodName, String keyName) {
541-
540+
static private PsiElement getArrayKeyValueInsideSignaturePsi(Project project, String signature, String methodName, String keyName) {
542541
PsiElement psiElement = PhpElementsUtil.getPsiElementsBySignatureSingle(project, signature);
542+
543543
if(psiElement == null) {
544544
return null;
545545
}
546546

547547
for(MethodReference methodReference: PsiTreeUtil.findChildrenOfType(psiElement, MethodReference.class)) {
548-
549548
if(PhpElementsUtil.isEqualMethodReferenceName(methodReference, methodName)) {
550549
PsiElement[] parameters = methodReference.getParameters();
551550
if(parameters.length > 0 && parameters[0] instanceof ArrayCreationExpression) {
552551
return PhpElementsUtil.getArrayValue((ArrayCreationExpression) parameters[0], keyName);
553552
}
554-
555553
}
556554
}
557555

558556
return null;
559557
}
560558

561-
562559
public static Method[] getImplementedMethods(@NotNull Method method) {
563560
ArrayList<Method> items = getImplementedMethods(method.getContainingClass(), method, new ArrayList<>());
564561
return items.toArray(new Method[items.size()]);
565562
}
566563

567-
568564
private static ArrayList<Method> getImplementedMethods(@Nullable PhpClass phpClass, @NotNull Method method, ArrayList<Method> implementedMethods) {
569565
if (phpClass == null) {
570566
return implementedMethods;
@@ -1057,33 +1053,6 @@ public static String getMethodParameterTypeHint(@NotNull Method method) {
10571053
return classReference.getFQN();
10581054
}
10591055

1060-
/**
1061-
* "DateTime", DateTime::class
1062-
*/
1063-
@Nullable
1064-
public static PhpClass resolvePhpClassOnPsiElement(@NotNull PsiElement psiElement) {
1065-
1066-
String dataClass = null;
1067-
if(psiElement instanceof ClassConstantReference) {
1068-
PsiElement lastChild = psiElement.getLastChild();
1069-
// @TODO: FOO::class find PhpElementTyp: toString provides "class"
1070-
if("class".equals(lastChild.getText())) {
1071-
PhpExpression classReference = ((ClassConstantReference) psiElement).getClassReference();
1072-
if(classReference instanceof PhpReference) {
1073-
dataClass = ((PhpReference) classReference).getFQN();
1074-
}
1075-
}
1076-
} else {
1077-
dataClass = getStringValue(psiElement);
1078-
}
1079-
1080-
if(dataClass == null) {
1081-
return null;
1082-
}
1083-
1084-
return getClassInterface(psiElement.getProject(), dataClass);
1085-
}
1086-
10871056
/**
10881057
* Find first variable declaration in parent scope of a given variable:
10891058
*
@@ -1473,18 +1442,37 @@ public static Method[] getMultiResolvedMethod(@NotNull PsiReference psiReference
14731442
return new Method[0];
14741443
}
14751444

1445+
/**
1446+
* Get first string value of MethodReference; Not index access allowed!
1447+
* see getMethodReferenceStringValueParameter for resolving value in detail
1448+
*/
14761449
@Nullable
1477-
public static String getFirstArgumentStringValue(@NotNull MethodReference e) {
1450+
public static String getFirstArgumentStringValue(@NotNull MethodReference methodReference) {
14781451
String stringValue = null;
14791452

1480-
PsiElement[] parameters = e.getParameters();
1453+
PsiElement[] parameters = methodReference.getParameters();
14811454
if (parameters.length > 0 && parameters[0] instanceof StringLiteralExpression) {
14821455
stringValue = ((StringLiteralExpression) parameters[0]).getContents();
14831456
}
14841457

14851458
return stringValue;
14861459
}
14871460

1461+
/**
1462+
* Get resolved string value
1463+
*
1464+
* $f->foo('index_0', 'index_1');
1465+
*/
1466+
@Nullable
1467+
public static String getMethodReferenceStringValueParameter(@NotNull MethodReference methodReference, int parameter) {
1468+
PsiElement[] parameters = methodReference.getParameters();
1469+
if (parameters.length > parameter) {
1470+
return getStringValue(parameters[parameter]);
1471+
}
1472+
1473+
return null;
1474+
}
1475+
14881476
/**
14891477
* Visit and collect all variables in given scope
14901478
*/

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

+18
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,24 @@ public void testDataClassPropertyCompletion() {
9494
);
9595
}
9696

97+
public void testDataClassPropertyCompletionForSetDefault() {
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->setDefault('data_class', \\Form\\DataClass\\Model::class);\n" +
109+
" }\n" +
110+
"}",
111+
"fooBar"
112+
);
113+
}
114+
97115
public void testDataClassWithPublicPropertyCompletion() {
98116
assertCompletionContains(PhpFileType.INSTANCE, "<?php\n" +
99117
"\n" +

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

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.intellij.util.containers.ContainerUtil;
55
import com.jetbrains.php.lang.PhpFileType;
66
import com.jetbrains.php.lang.psi.PhpPsiElementFactory;
7+
import com.jetbrains.php.lang.psi.elements.MethodReference;
78
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
89
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClass;
910
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClassEnum;
@@ -109,4 +110,13 @@ public void testGetFormExtensionsKeysTargets() {
109110
Collection<PsiElement> formExtensionsKeysTargets = FormOptionsUtil.getFormExtensionsKeysTargets(contents, "Options\\Bar\\Foobar");
110111
assertTrue(formExtensionsKeysTargets.size() > 0);
111112
}
113+
114+
115+
/**
116+
* @see FormOptionsUtil#getMethodReferenceStringParameter
117+
*/
118+
public void testGetMethodReferenceStringParameter() {
119+
MethodReference methodReference = PhpPsiElementFactory.createFromText(getProject(), MethodReference.class, "<?php class Foobar { function foo() { $this->bar('test', 'my_value'); } };\n");
120+
assertContainsElements(FormOptionsUtil.getMethodReferenceStringParameter(methodReference, new String[] {"foo"}, "bar", "test"), "my_value");
121+
}
112122
}

‎tests/fr/adrienbrault/idea/symfony2plugin/tests/util/PhpElementsUtilTest.java

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.jetbrains.php.lang.PhpFileType;
66
import com.jetbrains.php.lang.psi.PhpPsiElementFactory;
77
import com.jetbrains.php.lang.psi.elements.ArrayCreationExpression;
8-
import com.jetbrains.php.lang.psi.elements.Method;
98
import com.jetbrains.php.lang.psi.elements.PhpClass;
109
import com.jetbrains.php.lang.psi.elements.Variable;
1110
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;

0 commit comments

Comments
 (0)
Please sign in to comment.