Skip to content

support type resolving for magic Doctrine methods "findBy*" "findOneBy*" #149 #1473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -109,7 +108,7 @@ public PhpType complete(String s, Project project) {

PhpIndex phpIndex = PhpIndex.getInstance(project);

Collection<? extends PhpNamedElement> typeSignature = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature);
Collection<? extends PhpNamedElement> 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
Expand All @@ -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);

Expand All @@ -147,4 +146,33 @@ private Collection<Method> getObjectRepositoryCall(Collection<? extends PhpNamed

return methods;
}

/**
* We can have multiple types inside a TypeProvider; split them on "|" so that we dont get empty types
*
* #M#x#M#C\FooBar.get?doctrine.odm.mongodb.document_manager.getRepository|
* #M#x#M#C\FooBar.get?doctrine.odm.mongodb.document_manager.getRepository
*/
@NotNull
private static Collection<? extends PhpNamedElement> 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<PhpNamedElement> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -184,7 +185,13 @@ private void collectParameter(QueryBuilderScopeContext qb, MethodReference metho
}


private Map<String, String> findRootDefinition(Collection<MethodReference> methodReferences) {
/**
*
* @param methodReferences
* @return
*/
@NotNull
private Map<String, String> findRootDefinition(@NotNull Collection<MethodReference> methodReferences) {

Map<String, String> roots = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

/**
* @author Daniel Espendiller <daniel@espendiller.net>
Expand Down Expand Up @@ -172,7 +173,7 @@ public static Collection<? extends PhpNamedElement> getTypeSignature(@NotNull Ph
return phpIndex.getBySignature(signature, null, 0);
}

Collection<PhpNamedElement> elements = new ArrayList<>();
Collection<PhpNamedElement> elements = new HashSet<>();
for (String s : signature.split("\\|")) {
elements.addAll(phpIndex.getBySignature(s, null, 0));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,20 @@ public void testThatArrayAccessIsResolved() {
PlatformPatterns.psiElement(Method.class).withName("getId")
);
}

public void testThatClassAsStringIsResolvedForMagicMethods() {
assertPhpReferenceResolveTo(PhpFileType.INSTANCE,
"<?php" +
"/** @var \\Doctrine\\Common\\Persistence\\ObjectManager $om */\n" +
"$om->getRepository('\\Foo\\Bar')->findOneByName('foobar')->get<caret>Id();",
PlatformPatterns.psiElement(Method.class).withName("getId")
);

assertPhpReferenceResolveTo(PhpFileType.INSTANCE,
"<?php" +
"/** @var \\Doctrine\\Common\\Persistence\\ObjectManager $om */\n" +
"$om->getRepository('\\Foo\\Bar')->findByName('foobar')[0]->get<caret>Id();",
PlatformPatterns.psiElement(Method.class).withName("getId")
);
}
}