From c92446c07375de5b218064fa2e78787201827851 Mon Sep 17 00:00:00 2001 From: Daniel Espendiller Date: Sat, 23 May 2020 14:53:29 +0200 Subject: [PATCH] support type resolving for magic Doctrine methods "findBy*" "findOneBy*" #149 --- .../ObjectRepositoryResultTypeProvider.java | 42 +++++++++++++++---- .../QueryBuilderMethodReferenceParser.java | 9 +++- .../util/PhpTypeProviderUtil.java | 3 +- ...bjectRepositoryResultTypeProviderTest.java | 16 +++++++ 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryResultTypeProvider.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryResultTypeProvider.java index e49fa3258..276dde642 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryResultTypeProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryResultTypeProvider.java @@ -16,10 +16,8 @@ import fr.adrienbrault.idea.symfony2plugin.util.PhpTypeProviderUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; + +import java.util.*; import java.util.stream.Collectors; /** @@ -63,7 +61,8 @@ public PhpType getType(PsiElement e) { } String methodRefName = methodRef.getName(); - if(null == methodRefName || !Arrays.asList(new String[] {"find", "findOneBy", "findAll", "findBy"}).contains(methodRefName)) { + + if(null == methodRefName || (!Arrays.asList(new String[] {"find", "findAll"}).contains(methodRefName) && !methodRefName.startsWith("findOneBy") && !methodRefName.startsWith("findBy"))) { return null; } @@ -109,7 +108,7 @@ public PhpType complete(String s, Project project) { PhpIndex phpIndex = PhpIndex.getInstance(project); - Collection typeSignature = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature); + Collection typeSignature = getTypeSignatureMagic(phpIndex, originalSignature); // ->getRepository(SecondaryMarket::class)->findAll() => "findAll", but only if its a instance of this method; // so non Doctrine method are already filtered @@ -124,7 +123,7 @@ public PhpType complete(String s, Project project) { PhpType phpType = new PhpType(); resolveMethods.stream() - .map(name -> name.equals("findAll") || name.equals("findBy") ? phpClass.getFQN() + "[]" : phpClass.getFQN()) + .map(name -> name.equals("findAll") || name.startsWith("findBy") ? phpClass.getFQN() + "[]" : phpClass.getFQN()) .collect(Collectors.toSet()) .forEach(phpType::add); @@ -147,4 +146,33 @@ private Collection getObjectRepositoryCall(Collection getTypeSignatureMagic(@NotNull PhpIndex phpIndex, @NotNull String signature) { + // magic method resolving; we need to have the ObjectRepository method which does not exists for magic methods, so strip it + // #M#x#M#C\FooBar.get?doctrine.odm.mongodb.document_manager.findByName => findBy + // #M#x#M#C\FooBar.get?doctrine.odm.mongodb.document_manager.findOneBy => findOne + Collection elements = new HashSet<>(); + for (String s : signature.split("\\|")) { + int i = s.lastIndexOf("."); + if (i > 0) { + String substring = s.substring(i + 1); + if (substring.startsWith("findOneBy")) { + s = s.substring(0, i + 1) + "findOneBy"; + } else if(substring.startsWith("findBy")) { + s = s.substring(0, i + 1) + "findBy"; + } + } + + elements.addAll(phpIndex.getBySignature(s, null, 0)); + } + + return elements; + } } diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/querybuilder/QueryBuilderMethodReferenceParser.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/querybuilder/QueryBuilderMethodReferenceParser.java index 8e59d7a39..e3a2eec28 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/querybuilder/QueryBuilderMethodReferenceParser.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/querybuilder/QueryBuilderMethodReferenceParser.java @@ -23,6 +23,7 @@ import fr.adrienbrault.idea.symfony2plugin.util.PhpTypeProviderUtil; import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils; import fr.adrienbrault.idea.symfony2plugin.util.dict.DoctrineModel; +import org.jetbrains.annotations.NotNull; import java.util.*; import java.util.regex.Matcher; @@ -184,7 +185,13 @@ private void collectParameter(QueryBuilderScopeContext qb, MethodReference metho } - private Map findRootDefinition(Collection methodReferences) { + /** + * + * @param methodReferences + * @return + */ + @NotNull + private Map findRootDefinition(@NotNull Collection methodReferences) { Map roots = new HashMap<>(); diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpTypeProviderUtil.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpTypeProviderUtil.java index d45dfeee9..32b39b735 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpTypeProviderUtil.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/PhpTypeProviderUtil.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; /** * @author Daniel Espendiller @@ -172,7 +173,7 @@ public static Collection getTypeSignature(@NotNull Ph return phpIndex.getBySignature(signature, null, 0); } - Collection elements = new ArrayList<>(); + Collection elements = new HashSet<>(); for (String s : signature.split("\\|")) { elements.addAll(phpIndex.getBySignature(s, null, 0)); } diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryResultTypeProviderTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryResultTypeProviderTest.java index ee516d76c..3f4542781 100644 --- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryResultTypeProviderTest.java +++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/doctrine/ObjectRepositoryResultTypeProviderTest.java @@ -59,4 +59,20 @@ public void testThatArrayAccessIsResolved() { PlatformPatterns.psiElement(Method.class).withName("getId") ); } + + public void testThatClassAsStringIsResolvedForMagicMethods() { + assertPhpReferenceResolveTo(PhpFileType.INSTANCE, + "getRepository('\\Foo\\Bar')->findOneByName('foobar')->getId();", + PlatformPatterns.psiElement(Method.class).withName("getId") + ); + + assertPhpReferenceResolveTo(PhpFileType.INSTANCE, + "getRepository('\\Foo\\Bar')->findByName('foobar')[0]->getId();", + PlatformPatterns.psiElement(Method.class).withName("getId") + ); + } }