8000 support class constant form extensions of getExtendedType · Ma27/idea-php-symfony2-plugin@fd89db6 · GitHub
[go: up one dir, main page]

Skip to content

Commit fd89db6

Browse files
committed
support class constant form extensions of getExtendedType
1 parent a802f30 commit fd89db6

File tree

4 files changed

+140
-54
lines changed

4 files changed

+140
-54
lines changed

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

Lines changed: 32 additions & 53 deletions
Original file li 10000 ne numberDiff line numberDiff line change
@@ -6,20 +6,19 @@
66
import com.intellij.patterns.PlatformPatterns;
77
import com.intellij.psi.PsiElement;
88
import com.intellij.psi.util.PsiTreeUtil;
9+
import com.intellij.util.Function;
10+
import com.intellij.util.containers.ContainerUtil;
911
import com.jetbrains.php.PhpIndex;
1012
import com.jetbrains.php.lang.psi.elements.*;
11-
import com.jetbrains.php.phpunit.PhpUnitUtil;
1213
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
13-
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionLookupVisitor;
1414
import fr.adrienbrault.idea.symfony2plugin.form.dict.*;
15+
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionLookupVisitor;
1516
import fr.adrienbrault.idea.symfony2plugin.form.visitor.FormOptionVisitor;
1617
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1718
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
18-
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
1919
import fr.adrienbrault.idea.symfony2plugin.util.service.ServiceXmlParserFactory;
2020
import org.apache.commons.lang.StringUtils;
2121
import org.jetbrains.annotations.NotNull;
22-
import org.jetbrains.annotations.Nullable;
2322

2423
import java.util.*;
2524

@@ -28,85 +27,65 @@
2827
*/
2928
public class FormOptionsUtil {
3029

31-
private static final String EXTENDED_TYPE_METHOD = "getExtendedType";
30+
public static final String EXTENDED_TYPE_METHOD = "getExtendedType";
3231
public static final String[] FORM_OPTION_METHODS = new String[]{"setDefaultOptions", "configureOptions"};
3332

33+
/**
34+
* Find form extensions extends given form type
35+
*
36+
* @param formTypeNames Fqn class "Foo\Foo", "\Foo\Foo" or string value "foo";
37+
* should have all parents a FormType can have
38+
*/
3439
@NotNull
35-
public static List<FormClass> getExtendedTypeClasses(@NotNull Project project, @NotNull String... formTypeNames) {
36-
37-
List<String> formTypeNamesList = Arrays.asList(formTypeNames);
38-
39-
Set<String> stringSet = getFormTypeExtensionClassNames(project);
40+
public static Collection<FormClass> getExtendedTypeClasses(@NotNull Project project, @NotNull String... formTypeNames) {
4041

41-
List<FormClass> extendedTypeClasses = new ArrayList<FormClass>();
42-
43-
for(String formClass: stringSet) {
44-
visitExtendedTypeMethod(formTypeNamesList, extendedTypeClasses, false, PhpElementsUtil.getClassMethod(project, formClass, EXTENDED_TYPE_METHOD));
45-
}
46-
47-
// use form extension interface if service is empty
48-
for(PhpClass phpClass: PhpIndex.getInstance(project).getAllSubclasses(FormUtil.FORM_EXTENSION_INTERFACE)) {
49-
if(!FormUtil.isValidFormPhpClass(phpClass)) {
50-
continue;
42+
// strip "\"
43+
List<String> formTypeNamesList = ContainerUtil.map(Arrays.asList(formTypeNames), new Function<String, String>() {
44+
@Override
45+
public String fun(String s) {
46+
return StringUtils.stripStart(s, "\\");
5147
}
48+
});
5249

53-
String className = phpClass.getPresentableFQN();
54-
if(className != null && !stringSet.contains(className)) {
55-
visitExtendedTypeMethod(formTypeNamesList, extendedTypeClasses, true, phpClass.findMethodByName(EXTENDED_TYPE_METHOD));
50+
Collection<FormClass> extendedTypeClasses = new ArrayList<FormClass>();
51+
for(PhpClass phpClass: getFormTypeExtensionClassNames(project)) {
52+
String formExtendedType = FormUtil.getFormExtendedType(phpClass);
53+
if(formExtendedType != null && formTypeNamesList.contains(formExtendedType)) {
54+
extendedTypeClasses.add(new FormClass(FormClassEnum.EXTENSION, phpClass, true));
5655
}
5756
}
5857

5958
return extendedTypeClasses;
6059
}
6160

6261
@NotNull
63-
private static Set<String> getFormTypeExtensionClassNames(@NotNull Project project) {
62+
private static Set<PhpClass> getFormTypeExtensionClassNames(@NotNull Project project) {
6463

65-
Set<String> stringSet = new HashSet<String>();
64+
Set<PhpClass> phpClasses = new HashSet<PhpClass>();
6665

66+
// @TODO: should be same as interface?
6767
for (String s : ServiceXmlParserFactory.getInstance(project, FormExtensionServiceParser.class).getFormExtensions().keySet()) {
68-
stringSet.add(s.startsWith("\\") ? s.substring(1) : s);
68+
ContainerUtil.addIfNotNull(
69+
phpClasses,
70+
PhpElementsUtil.getClass(project, s)
71+
);
6972
}
7073

7174
for(PhpClass phpClass: PhpIndex.getInstance(project).getAllSubclasses(FormUtil.FORM_EXTENSION_INTERFACE)) {
7275
if(!FormUtil.isValidFormPhpClass(phpClass)) {
7376
continue;
7477
}
7578

76-
String s = phpClass.getPresentableFQN();
77-
if(s != null) {
78-
stringSet.add(s.startsWith("\\") ? s.substring(1) : s);
79-
}
80-
}
81-
82-
return stringSet;
83-
}
84-
85-
private static void visitExtendedTypeMethod(List<String> formTypeNamesList, List<FormClass> extendedTypeClasses, boolean isWeak, @Nullable Method method) {
86-
if(method == null) {
87-
return;
88-
}
89-
90-
// method without class, exit we need fqn class name
91-
PhpClass containingClass = method.getContainingClass();
92-
if(containingClass == null) {
93-
return;
94-
}
95-
96-
PhpReturn phpReturn = PsiTreeUtil.findChildOfType(method, PhpReturn.class);
97-
if(phpReturn != null) {
98-
PhpPsiElement returnValue = phpReturn.getFirstPsiChild();
99-
if(returnValue instanceof StringLiteralExpression && formTypeNamesList.contains(((StringLiteralExpression) returnValue).getContents())) {
100-
extendedTypeClasses.add(new FormClass(FormClassEnum.EXTENSION, containingClass, isWeak));
101-
}
79+
phpClasses.add(phpClass);
10280
}
10381

82+
return phpClasses;
10483
}
10584

10685
@NotNull
10786
public static Map<String, FormOption> getFormExtensionKeys(@NotNull Project project, @NotNull String... formTypeNames) {
10887

109-
List<FormClass> typeClasses = FormOptionsUtil.getExtendedTypeClasses(project, formTypeNames);
88+
Collection<FormClass> typeClasses = FormOptionsUtil.getExtendedTypeClasses(project, formTypeNames);
11089
Map<String, FormOption> extensionClassMap = new HashMap<String, FormOption>();
11190

11291
for(FormClass extensionClass: typeClasses) {

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ public static void replaceFormStringAliasWithClassConstant(@NotNull StringLitera
493493
/**
494494
* Finds form parent by "getParent" method
495495
*
496-
* Concatenation "__NAMESPACE__.'\Foo' and string 'foo' supported
496+
* Concatenation "__NAMESPACE__.'\Foo', "Foo::class" and string 'foo' supported
497497
*/
498498
@Nullable
499499
public static String getFormParentOfPhpClass(@NotNull PhpClass phpClass) {
@@ -605,6 +605,35 @@ public static String getFormNameOfPhpClass(@NotNull PhpClass phpClass) {
605605
}
606606

607607

608+
return null;
609+
}
610+
611+
/**
612+
* Get getExtendedType as string
613+
*
614+
* 'Foo::class' and string 'foo' supported
615+
*/
616+
@Nullable
617+
public static String getFormExtendedType(@NotNull PhpClass phpClass) {
618+
Method getParent = phpClass.findMethodByName(FormOptionsUtil.EXTENDED_TYPE_METHOD);
619+
if(getParent == null) {
620+
return null;
621+
}
622+
623+
for (PhpReturn phpReturn : PsiTreeUtil.collectElementsOfType(getParent, PhpReturn.class)) {
624+
PhpPsiElement firstPsiChild = phpReturn.getFirstPsiChild();
625+
626+
// Foo::class
627+
if(firstPsiChild instanceof ClassConstantReference) {
628+
return PhpElementsUtil.getClassConstantPhpFqn((ClassConstantReference) firstPsiChild);
629+
}
630+
631+
String stringValue = PhpElementsUtil.getStringValue(firstPsiChild);
632+
if(stringValue != null) {
633+
return stringValue;
634+
}
635+
}
636+
608637
return null;
609638
}
610639
}
Lines changed: 50 additions & 0 deletions
< 57AE td data-grid-cell-id="diff-3684fc79d18906914c3b8de86e311717fdd41f7d008609fd2d6f0963ea16e833-empty-30-2" data-line-anchor="diff-3684fc79d18906914c3b8de86e311717fdd41f7d008609fd2d6f0963ea16e833R30" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-additionLine-bgColor, var(--diffBlob-addition-bgColor-line));padding-right:24px" tabindex="-1" valign="top" class="focusable-grid-cell diff-text-cell right-side-diff-cell left-side">+
public void testGetExtendedTypeClassesAsStringValue() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package fr.adrienbrault.idea.symfony2plugin.tests.form.util;
2+
3+
import com.intellij.util.containers.ContainerUtil;
4+
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClass;
5+
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormClassEnum;
6+
import fr.adrienbrault.idea.symfony2plugin.form.util.FormOptionsUtil;
7+
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
8+
9+
import java.io.File;
10+
11+
/**
12+
* @author Daniel Espendiller <daniel@espendiller.net>
13+
*
14+
* @see fr.adrienbrault.idea.symfony2plugin.form.util.FormOptionsUtil
15+
*/
16+
public class FormOptionsUtilTest extends SymfonyLightCodeInsightFixtureTestCase {
17+
18+
public void setUp() throws Exception {
19+
super.setUp();
20+
myFixture.copyFileToProject("FormOptionsUtil.php");
21+
}
22+
23+
protected String getTestDataPath() {
24+
return new File(this.getClass().getResource("fixtures").getFile()).getAbsolutePath();
25+
}
26+
27+
/**
28+
* @see FormOptionsUtil#getExtendedTypeClasses
29+
*/
30
31+
FormClass foo = ContainerUtil.getFirstItem(FormOptionsUtil.getExtendedTypeClasses(getProject(), "foo"));
32+
33+
assertNotNull(foo);
34+
assertEquals(FormClassEnum.EXTENSION, foo.getType());
35+
assertEquals("\\Foo\\Bar\\MyType", foo.getPhpClass().getFQN());
36+
}
37+
38+
/**
39+
* @see FormOptionsUtil#getExtendedTypeClasses
40+
*/
41+
public void testGetExtendedTypeClassesAsClassConstant() {
42+
for (String s : new String[]{"Foo\\Bar\\MyType", "\\Foo\\Bar\\MyType"}) {
43+
FormClass myType = ContainerUtil.getFirstItem(FormOptionsUtil.getExtendedTypeClasses(getProject(), s));
44+
45+
assertNotNull(myType);
46+
assertEquals(FormClassEnum.EXTENSION, myType.getType());
47+
assertEquals("\\Foo\\Bar\\BarType", myType.getPhpClass().getFQN());
48+
}
49+
}
50+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Symfony\Component\Form
4+
{
5+
interface FormTypeExtensionInterface
6+
{
7+
public function getExtendedType();
8+
}
9+
}
10+
11+
namespace Foo\Bar
12+
{
13+
use Symfony\Component\Form\FormTypeExtensionInterface;
14+
15+
class MyType implements FormTypeExtensionInterface {
16+
public function getExtendedType()
17+
{
18+
return 'foo';
19+
}
20+
}
21+
22+
class BarType implements FormTypeExtensionInterface {
23+
public function getExtendedType()
24+
{
25+
return MyType::class;
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)
0