Skip to content

Commit ce87487

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

File tree

2 files changed

+51
-52
lines changed

2 files changed

+51
-52
lines changed

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

+50-51
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*" at attach the entity
27+
*
28+
* "$om->getRepository('\Foo\Bar')->find('foobar')->get<caret>Id()"
29+
*
2730
* @author Daniel Espendiller <[email protected]>
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

@@ -105,57 +97,64 @@ public PhpType getType(PsiElement e) {
10597
return new PhpType().add("#" + this.getKey() + refSignature + TRIM_KEY + repositorySignature);
10698
}
10799

100+
@Nullable
108101
@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);
102+
public PhpType complete(String s, Project project) {
103+
int endIndex = s.lastIndexOf(TRIM_KEY);
112104
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();
105+
return null;
129106
}
130107

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);
108+
String originalSignature = s.substring(0, endIndex);
109+
String parameter = s.substring(endIndex + 1);
110+
parameter = PhpTypeProviderUtil.getResolvedParameter(PhpIndex.getInstance(project), parameter);
134111
if(parameter == null) {
135-
return Collections.emptySet();
112+
return null;
136113
}
137114

138115
PhpClass phpClass = EntityHelper.resolveShortcutName(project, parameter);
139116
if(phpClass == null) {
140-
return Collections.emptySet();
117+
return null;
141118
}
142119

143-
String name = method.getName();
144-
if(name.equals("findAll") || name.equals("findBy")) {
145-
method.getType().add(phpClass.getFQN() + "[]");
146-
return phpNamedElementCollections;
120+
PhpIndex phpIndex = PhpIndex.getInstance(project);
121+
122+
Collection<? extends PhpNamedElement> typeSignature = PhpTypeProviderUtil.getTypeSignature(phpIndex, originalSignature);
123+
124+
// ->getRepository(SecondaryMarket::class)->findAll() => "findAll", but only if its a instance of this method;
125+
// so non Doctrine method are already filtered
126+
Set<String> resolveMethods = getObjectRepositoryCall(typeSignature).stream()
127+
.map(PhpNamedElement::getName)
128+
.collect(Collectors.toSet());
129+
130+
if (resolveMethods.isEmpty()) {
131+
return null;
147132
}
148133

149-
return PhpTypeProviderUtil.mergeSignatureResults(phpNamedElementCollections, phpClass);
134+
PhpType phpType = new PhpType();
135+
136+
resolveMethods.stream()
137+
.map(name -> name.equals("findAll") || name.equals("findBy") ? phpClass.getFQN() + "[]" : phpClass.getFQN())
138+
.collect(Collectors.toSet())
139+
.forEach(phpType::add);
140+
141+
return phpType;
150142
}
151143

152-
private Method getObjectRepositoryCall(Collection<? extends PhpNamedElement> phpNamedElements) {
144+
@Override
145+
public Collection<? extends PhpNamedElement> getBySignature(String expression, Set<String> visited, int depth, Project project) {
146+
return null;
147+
}
148+
149+
@NotNull
150+
private Collection<Method> getObjectRepositoryCall(Collection<? extends PhpNamedElement> phpNamedElements) {
151+
Collection<Method> methods = new HashSet<>();
153152
for (PhpNamedElement phpNamedElement: phpNamedElements) {
154153
if(phpNamedElement instanceof Method && PhpElementsUtil.isMethodInstanceOf((Method) phpNamedElement, FIND_SIGNATURES)) {
155-
return (Method) phpNamedElement;
154+
methods.add((Method) phpNamedElement);
156155
}
157156
}
158157

159-
return null;
158+
return methods;
160159
}
161160
}

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

+1-1
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)