From ce87487d2fd0fbccda8c0d7e74660f2b82afb1d7 Mon Sep 17 00:00:00 2001 From: Daniel Espendiller Date: Thu, 21 May 2020 13:23:58 +0200 Subject: [PATCH] migrate Doctrine entity type resolving for "find*" methods #1434 --- .../ObjectRepositoryResultTypeProvider.java | 101 +++++++++--------- src/main/resources/META-INF/plugin.xml | 2 +- 2 files changed, 51 insertions(+), 52 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 e782aaa8c..792ed6ce4 100644 --- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryResultTypeProvider.java +++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryResultTypeProvider.java @@ -2,32 +2,35 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; import com.jetbrains.php.PhpIndex; -import com.jetbrains.php.lang.parser.PhpElementTypes; import com.jetbrains.php.lang.psi.elements.Method; import com.jetbrains.php.lang.psi.elements.MethodReference; import com.jetbrains.php.lang.psi.elements.PhpClass; import com.jetbrains.php.lang.psi.elements.PhpNamedElement; import com.jetbrains.php.lang.psi.resolve.types.PhpType; -import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider3; +import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider4; import fr.adrienbrault.idea.symfony2plugin.Settings; import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher; import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil; 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.Collections; +import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; /** + * Resolve "find*" at attach the entity + * + * "$om->getRepository('\Foo\Bar')->find('foobar')->getId()" + * * @author Daniel Espendiller */ -public class ObjectRepositoryResultTypeProvider implements PhpTypeProvider3 { - private static MethodMatcher.CallToSignature[] FIND_SIGNATURES = new MethodMatcher.CallToSignature[] { +public class ObjectRepositoryResultTypeProvider implements PhpTypeProvider4 { + private static final MethodMatcher.CallToSignature[] FIND_SIGNATURES = new MethodMatcher.CallToSignature[] { new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "find"), new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findOneBy"), new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findAll"), @@ -48,18 +51,7 @@ public char getKey() { @Nullable @Override public PhpType getType(PsiElement e) { - if (!Settings.getInstance(e.getProject()).pluginEnabled) { - return null; - } - - // filter out method calls without parameter - // $this->get('service_name') - if(!PlatformPatterns - .psiElement(PhpElementTypes.METHOD_REFERENCE) - .withChild(PlatformPatterns - .psiElement(PhpElementTypes.PARAMETER_LIST) - ).accepts(e)) { - + if (!(e instanceof MethodReference) || !Settings.getInstance(e.getProject()).pluginEnabled) { return null; } @@ -105,57 +97,64 @@ public PhpType getType(PsiElement e) { return new PhpType().add("#" + this.getKey() + refSignature + TRIM_KEY + repositorySignature); } + @Nullable @Override - public Collection getBySignature(String expression, Set visited, int depth, Project project) { - // get back our original call - int endIndex = expression.lastIndexOf(TRIM_KEY); + public PhpType complete(String s, Project project) { + int endIndex = s.lastIndexOf(TRIM_KEY); if(endIndex == -1) { - return Collections.emptySet(); - } - - String originalSignature = expression.substring(0, endIndex); - String parameter = expression.substring(endIndex + 1); - - // search for called method - PhpIndex phpIndex = PhpIndex.getInstance(project); - Collection phpNamedElementCollections = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature); - if(phpNamedElementCollections.size() == 0) { - return Collections.emptySet(); - } - - Method method = getObjectRepositoryCall(phpNamedElementCollections); - if(method == null) { - return Collections.emptySet(); + return null; } - // we can also pipe php references signatures and resolve them here - // overwrite parameter to get string value - parameter = PhpTypeProviderUtil.getResolvedParameter(phpIndex, parameter); + String originalSignature = s.substring(0, endIndex); + String parameter = s.substring(endIndex + 1); + parameter = PhpTypeProviderUtil.getResolvedParameter(PhpIndex.getInstance(project), parameter); if(parameter == null) { - return Collections.emptySet(); + return null; } PhpClass phpClass = EntityHelper.resolveShortcutName(project, parameter); if(phpClass == null) { - return Collections.emptySet(); + return null; } - String name = method.getName(); - if(name.equals("findAll") || name.equals("findBy")) { - method.getType().add(phpClass.getFQN() + "[]"); - return phpNamedElementCollections; + PhpIndex phpIndex = PhpIndex.getInstance(project); + + Collection typeSignature = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature); + + // ->getRepository(SecondaryMarket::class)->findAll() => "findAll", but only if its a instance of this method; + // so non Doctrine method are already filtered + Set resolveMethods = getObjectRepositoryCall(typeSignature).stream() + .map(PhpNamedElement::getName) + .collect(Collectors.toSet()); + + if (resolveMethods.isEmpty()) { + return null; } - return PhpTypeProviderUtil.mergeSignatureResults(phpNamedElementCollections, phpClass); + PhpType phpType = new PhpType(); + + resolveMethods.stream() + .map(name -> name.equals("findAll") || name.equals("findBy") ? phpClass.getFQN() + "[]" : phpClass.getFQN()) + .collect(Collectors.toSet()) + .forEach(phpType::add); + + return phpType; } - private Method getObjectRepositoryCall(Collection phpNamedElements) { + @Override + public Collection getBySignature(String expression, Set visited, int depth, Project project) { + return null; + } + + @NotNull + private Collection getObjectRepositoryCall(Collection phpNamedElements) { + Collection methods = new HashSet<>(); for (PhpNamedElement phpNamedElement: phpNamedElements) { if(phpNamedElement instanceof Method && PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, FIND_SIGNATURES)) { - return (Method) phpNamedElement; + methods.add((Method) phpNamedElement); } } - return null; + return methods; } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 83b770cec..d5bf1e951 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -103,7 +103,7 @@ - +