Skip to content

Commit 60def22

Browse files
committed
migrate Doctrine entity type resolving for "find*" methods #1434
1 parent 43c5c95 commit 60def22

File tree

2 files changed

+51
-62
lines changed

2 files changed

+51
-62
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/doctrine/ObjectRepositoryResultTypeProvider.java

Lines changed: 50 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,35 @@
22

33
import com.intellij.openapi.project.Project;
44
import com.intellij.openapi.util.text.StringUtil;
5-
import com.intellij.patterns.PlatformPatterns;
65
import com.intellij.psi.PsiElement;
76
import com.jetbrains.php.PhpIndex;
8-
import com.jetbrains.php.lang.parser.PhpElementTypes;
97
import com.jetbrains.php.lang.psi.elements.Method;
108
import com.jetbrains.php.lang.psi.elements.MethodReference;
119
import com.jetbrains.php.lang.psi.elements.PhpClass;
1210
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
1311
import com.jetbrains.php.lang.psi.resolve.types.PhpType;
14-
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider3;
12+
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider4;
1513
import fr.adrienbrault.idea.symfony2plugin.Settings;
1614
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
1715
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1816
import fr.adrienbrault.idea.symfony2plugin.util.PhpTypeProviderUtil;
17+
import org.jetbrains.annotations.NotNull;
1918
import org.jetbrains.annotations.Nullable;
20-
2119
import java.util.Arrays;
2220
import java.util.Collection;
23-
import java.util.Collections;
21+
import java.util.HashSet;
2422
import java.util.Set;
23+
import java.util.stream.Collectors;
2524

2625
/**
26+
* Resolve "find*" and attach the entity from the getRepository method
27+
*
28+
* "$om->getRepository('\Foo\Bar')->find('foobar')->get<caret>Id()"
29+
*
2730
* @author Daniel Espendiller <daniel@espendiller.net>
2831
*/
29-
public class ObjectRepositoryResultTypeProvider implements PhpTypeProvider3 {
30-
private static MethodMatcher.CallToSignature[] FIND_SIGNATURES = new MethodMatcher.CallToSignature[] {
32+
public class ObjectRepositoryResultTypeProvider implements PhpTypeProvider4 {
33+
private static final MethodMatcher.CallToSignature[] FIND_SIGNATURES = new MethodMatcher.CallToSignature[] {
3134
new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "find"),
3235
new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findOneBy"),
3336
new MethodMatcher.CallToSignature("\\Doctrine\\Common\\Persistence\\ObjectRepository", "findAll"),
@@ -48,18 +51,7 @@ public char getKey() {
4851
@Nullable
4952
@Override
5053
public PhpType getType(PsiElement e) {
51-
if (!Settings.getInstance(e.getProject()).pluginEnabled) {
52-
return null;
53-
}
54-
55-
// filter out method calls without parameter
56-
// $this->get('service_name')
57-
if(!PlatformPatterns
58-
.psiElement(PhpElementTypes.METHOD_REFERENCE)
59-
.withChild(PlatformPatterns
60-
.psiElement(PhpElementTypes.PARAMETER_LIST)
61-
).accepts(e)) {
62-
54+
if (!(e instanceof MethodReference) || !Settings.getInstance(e.getProject()).pluginEnabled) {
6355
return null;
6456
}
6557

@@ -75,16 +67,6 @@ public PhpType getType(PsiElement e) {
7567
return null;
7668
}
7769

78-
// at least one parameter is necessary on some finds
79-
PsiElement[] parameters = methodRef.getParameters();
80-
if(!methodRefName.equals("findAll")) {
81-
if(parameters.length == 0) {
82-
return null;
83-
}
84-
} else if(parameters.length != 0) {
85-
return null;
86-
}
87-
8870
// we can get the repository name from the signature calls
8971
// #M#?#M#?#M#C\Foo\Bar\Controller\BarController.get?doctrine.getRepository?EntityBundle:User.find
9072
String repositorySignature = methodRef.getSignature();
@@ -105,57 +87,64 @@ public PhpType getType(PsiElement e) {
10587
return new PhpType().add("#" + this.getKey() + refSignature + TRIM_KEY + repositorySignature);
10688
}
10789

90+
@Nullable
10891
@Override
109-
public Collection<? extends PhpNamedElement> getBySignature(String expression, Set<String> visited, int depth, Project project) {
110-
// get back our original call
111-
int endIndex = expression.lastIndexOf(TRIM_KEY);
92+
public PhpType complete(String s, Project project) {
93+
int endIndex = s.lastIndexOf(TRIM_KEY);
11294
if(endIndex == -1) {
113-
return Collections.emptySet();
114-
}
115-
116-
String originalSignature = expression.substring(0, endIndex);
117-
String parameter = expression.substring(endIndex + 1);
118-
119-
// search for called method
120-
PhpIndex phpIndex = PhpIndex.getInstance(project);
121-
Collection<? extends PhpNamedElement> phpNamedElementCollections = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature);
122-
if(phpNamedElementCollections.size() == 0) {
123-
return Collections.emptySet();
124-
}
125-
126-
Method method = getObjectRepositoryCall(phpNamedElementCollections);
127-
if(method == null) {
128-
return Collections.emptySet();
95+
return null;
12996
}
13097

131-
// we can also pipe php references signatures and resolve them here
132-
// overwrite parameter to get string value
133-
parameter = PhpTypeProviderUtil.getResolvedParameter(phpIndex, parameter);
98+
String originalSignature = s.substring(0, endIndex);
99+
String parameter = s.substring(endIndex + 1);
100+
parameter = PhpTypeProviderUtil.getResolvedParameter(PhpIndex.getInstance(project), parameter);
134101
if(parameter == null) {
135-
return Collections.emptySet();
102+
return null;
136103
}
137104

138105
PhpClass phpClass = EntityHelper.resolveShortcutName(project, parameter);
139106
if(phpClass == null) {
140-
return Collections.emptySet();
107+
return null;
141108
}
142109

143-
String name = method.getName();
144-
if(name.equals("findAll") || name.equals("findBy")) {
145-
method.getType().add(phpClass.getFQN() + "[]");
146-
return phpNamedElementCollections;
110+
PhpIndex phpIndex = PhpIndex.getInstance(project);
111+
112+
Collection<? extends PhpNamedElement> typeSignature = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature);
113+
114+
// ->getRepository(SecondaryMarket::class)->findAll() => "findAll", but only if its a instance of this method;
115+
// so non Doctrine method are already filtered
116+
Set<String> resolveMethods = getObjectRepositoryCall(typeSignature).stream()
117+
.map(PhpNamedElement::getName)
118+
.collect(Collectors.toSet());
119+
120+
if (resolveMethods.isEmpty()) {
121+
return null;
147122
}
148123

149-
return PhpTypeProviderUtil.mergeSignatureResults(phpNamedElementCollections, phpClass);
124+
PhpType phpType = new PhpType();
125+
126+
resolveMethods.stream()
127+
.map(name -> name.equals("findAll") || name.equals("findBy") ? phpClass.getFQN() + "[]" : phpClass.getFQN())
128+
.collect(Collectors.toSet())
129+
.forEach(phpType::add);
130+
131+
return phpType;
132+
}
133+
134+
@Override
135+
public Collection<? extends PhpNamedElement> getBySignature(String expression, Set<String> visited, int depth, Project project) {
136+
return null;
150137
}
151138

152-
private Method getObjectRepositoryCall(Collection<? extends PhpNamedElement> phpNamedElements) {
139+
@NotNull
140+
private Collection<Method> getObjectRepositoryCall(Collection<? extends PhpNamedElement> phpNamedElements) {
141+
Collection<Method> methods = new HashSet<>();
153142
for (PhpNamedElement phpNamedElement: phpNamedElements) {
154143
if(phpNamedElement instanceof Method && PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, FIND_SIGNATURES)) {
155-
return (Method) phpNamedElement;
144+
methods.add((Method) phpNamedElement);
156145
}
157146
}
158147

159-
return null;
148+
return methods;
160149
}
161150
}

src/main/resources/META-INF/plugin.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.dic.SymfonyContainerTypeProvider"/>
104104
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.util.EventDispatcherTypeProvider"/>
105105
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryTypeProvider"/>
106-
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryResultTypeProvider"/>
106+
<typeProvider4 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectRepositoryResultTypeProvider"/>
107107
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.doctrine.ObjectManagerFindTypeProvider"/>
108108
<typeProvider3 implementation="fr.adrienbrault.idea.symfony2plugin.assistant.signature.MethodSignatureTypeProvider"/>
109109
<libraryRoot id="symfony_meta" path="/symfony-meta/" runtime="false"/>

0 commit comments

Comments
 (0)